1 /*
2 * Copyright (c) 2023 - 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "emitFiles.h"
17
18 #include <assembly-emitter.h>
19 #include <mem/arena_allocator.h>
20 #include "utils/timers.h"
21
22 #include <es2panda.h>
23 #include <protobufSnapshotGenerator.h>
24 #include <util/helpers.h>
25
26 namespace panda::es2panda::aot {
ScheduleEmitCacheJobs(EmitMergedAbcJob *emitMergedAbcJob)27 void EmitFileQueue::ScheduleEmitCacheJobs(EmitMergedAbcJob *emitMergedAbcJob)
28 {
29 for (const auto &info: progsInfo_) {
30 // generate cache protoBins and set dependencies
31 if (!info.second->needUpdateCache) {
32 continue;
33 }
34 auto outputCacheIter = options_->CompilerOptions().cacheFiles.find(info.first);
35 if (outputCacheIter != options_->CompilerOptions().cacheFiles.end()) {
36 auto emitProtoJob = new EmitCacheJob(outputCacheIter->second, info.second);
37 emitProtoJob->DependsOn(emitMergedAbcJob);
38 jobs_.push_back(emitProtoJob);
39 jobsCount_++;
40 }
41 }
42 }
43
Schedule()44 void EmitFileQueue::Schedule()
45 {
46 ASSERT(jobsCount_ == 0);
47 std::unique_lock<std::mutex> lock(m_);
48 auto targetApi = options_->CompilerOptions().targetApiVersion;
49 auto targetSubApi = options_->CompilerOptions().targetApiSubVersion;
50
51 if (mergeAbc_) {
52 // generate merged abc
53 auto emitMergedAbcJob = new EmitMergedAbcJob(options_->CompilerOutput(),
54 options_->CompilerOptions().transformLib, progsInfo_, targetApi, targetSubApi);
55 // Disable generating cached files when cross-program optimization is required, to prevent cached files from
56 // not being invalidated when their dependencies are changed
57 if (!options_->CompilerOptions().requireGlobalOptimization) {
58 ScheduleEmitCacheJobs(emitMergedAbcJob);
59 }
60 // One job should be placed after those jobs which depend on it to prevent blocking
61 jobs_.push_back(emitMergedAbcJob);
62 jobsCount_++;
63 } else {
64 for (const auto &info: progsInfo_) {
65 try {
66 // generate multi abcs
67 auto outputFileName = options_->OutputFiles().empty() ? options_->CompilerOutput() :
68 options_->OutputFiles().at(info.first);
69 auto emitSingleAbcJob = new EmitSingleAbcJob(outputFileName, &(info.second->program), statp_,
70 targetApi, targetSubApi);
71 jobs_.push_back(emitSingleAbcJob);
72 jobsCount_++;
73 } catch (std::exception &error) {
74 throw Error(ErrorType::GENERIC, error.what());
75 }
76 }
77 }
78
79 lock.unlock();
80 jobsAvailable_.notify_all();
81 }
82
Run()83 void EmitSingleAbcJob::Run()
84 {
85 panda::Timer::timerStart(panda::EVENT_EMIT_SINGLE_PROGRAM, outputFileName_);
86 if (!panda::pandasm::AsmEmitter::Emit(panda::os::file::File::GetExtendedFilePath(outputFileName_), *prog_, statp_,
87 nullptr, true, nullptr, targetApiVersion_, targetApiSubVersion_)) {
88 throw Error(ErrorType::GENERIC, "Failed to emit " + outputFileName_ + ", error: " +
89 panda::pandasm::AsmEmitter::GetLastError());
90 }
91 for (auto *dependant : dependants_) {
92 dependant->Signal();
93 }
94 panda::Timer::timerEnd(panda::EVENT_EMIT_SINGLE_PROGRAM, outputFileName_);
95 }
96
Run()97 void EmitMergedAbcJob::Run()
98 {
99 panda::Timer::timerStart(panda::EVENT_EMIT_MERGED_PROGRAM, "");
100 std::vector<panda::pandasm::Program*> progs;
101 progs.reserve(progsInfo_.size());
102 for (const auto &info: progsInfo_) {
103 progs.push_back(&(info.second->program));
104 }
105
106 bool success = panda::pandasm::AsmEmitter::EmitPrograms(
107 panda::os::file::File::GetExtendedFilePath(outputFileName_), progs, true,
108 targetApiVersion_, targetApiSubVersion_);
109
110 for (auto *dependant : dependants_) {
111 dependant->Signal();
112 }
113 panda::Timer::timerEnd(panda::EVENT_EMIT_MERGED_PROGRAM, "");
114
115 if (!success) {
116 throw Error(ErrorType::GENERIC, "Failed to emit " + outputFileName_ + ", error: " +
117 panda::pandasm::AsmEmitter::GetLastError() +
118 "\nIf you're using any cache file generated by older version of SDK, " +
119 "please try cleaning the cache files and rebuild");
120 }
121
122 if (!transformLib_.empty()) {
123 util::Helpers::AopTransform(outputFileName_, transformLib_);
124 }
125 }
126
Run()127 void EmitCacheJob::Run()
128 {
129 std::unique_lock<std::mutex> lock(m_);
130 cond_.wait(lock, [this] { return dependencies_ == 0; });
131 panda::Timer::timerStart(panda::EVENT_EMIT_CACHE_FILE, outputProtoName_);
132 panda::proto::ProtobufSnapshotGenerator::UpdateCacheFile(progCache_, outputProtoName_);
133 panda::Timer::timerEnd(panda::EVENT_EMIT_CACHE_FILE, outputProtoName_);
134 }
135
136 } // namespace panda::es2panda::util
137