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 26namespace panda::es2panda::aot { 27void 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 44void 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 83void 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 97void 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 127void 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