* Copyright (c) 2023-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "emitFiles.h"
#include <assembly-emitter.h>
#include "utils/perfMetrics.h"
#include "utils/timers.h"
#include <protobufSnapshotGenerator.h>
#include <util/commonUtil.h>
namespace panda::es2panda::aot {
void EmitFileQueue::ScheduleEmitCacheJobs()
{
* The programKey is usually the fileName of the source file. If the program generated from the abc file,
* the programKey format is the abc filePath + verticalLine + recordName.
*/
for (const auto &[programKey, programCache]: progsInfo_) {
if (!programCache->needUpdateCache) {
continue;
}
auto outputCacheIter = options_->CompilerOptions().cacheFiles.find(programKey);
if (outputCacheIter != options_->CompilerOptions().cacheFiles.end()) {
auto emitProtoJob = new EmitCacheJob(outputCacheIter->second, programCache);
jobs_.push_back(emitProtoJob);
jobsCount_++;
}
}
}
void EmitFileQueue::Schedule()
{
ASSERT(jobsCount_ == 0);
std::unique_lock<std::mutex> lock(m_);
if (mergeAbc_) {
if (!options_->CompilerOptions().requireGlobalOptimization) {
ScheduleEmitCacheJobs();
}
} else {
auto targetApi = options_->CompilerOptions().targetApiVersion;
auto targetSubApi = options_->CompilerOptions().targetApiSubVersion;
for (const auto &info: progsInfo_) {
try {
auto outputFileName = options_->OutputFiles().empty() ? options_->CompilerOutput() :
options_->OutputFiles().at(info.first);
auto emitSingleAbcJob = new EmitSingleAbcJob(outputFileName, &(info.second->program), statp_,
targetApi, targetSubApi);
jobs_.push_back(emitSingleAbcJob);
jobsCount_++;
} catch (std::exception &error) {
throw Error(ErrorType::GENERIC, error.what());
}
}
}
lock.unlock();
jobsAvailable_.notify_all();
}
void EmitSingleAbcJob::Run()
{
ES2ABC_PERF_SCOPE("@EVENT_EMIT_SINGLE_PROGRAM");
panda::Timer::timerStart(panda::EVENT_EMIT_SINGLE_PROGRAM, outputFileName_);
if (!panda::pandasm::AsmEmitter::Emit(panda::os::file::File::GetExtendedFilePath(outputFileName_), *prog_, statp_,
nullptr, true, nullptr, targetApiVersion_, targetApiSubVersion_)) {
throw Error(ErrorType::GENERIC, "Failed to emit " + outputFileName_ + ", error: " +
panda::pandasm::AsmEmitter::GetLastError());
}
for (auto *dependant : dependants_) {
dependant->Signal();
}
panda::Timer::timerEnd(panda::EVENT_EMIT_SINGLE_PROGRAM, outputFileName_);
}
void EmitMergedAbcJob::Run()
{
std::unique_lock<std::mutex> lock(m_);
cond_.wait(lock, [this] { return dependencies_ == 0; });
ES2ABC_PERF_SCOPE("@EVENT_EMIT_MERGED_PROGRAM");
panda::Timer::timerStart(panda::EVENT_EMIT_MERGED_PROGRAM, "");
std::vector<panda::pandasm::Program*> progs;
progs.reserve(progsInfo_.size());
for (const auto &info: progsInfo_) {
progs.push_back(&(info.second->program));
}
panda::pandasm::EmitterConfig emitConfig {targetApiVersion_, targetApiSubVersion_,
options_->CompilerOptions().isDebug, options_->CompilerOptions().fileThreadCount};
bool success = panda::pandasm::AsmEmitter::EmitPrograms(
panda::os::file::File::GetExtendedFilePath(outputFileName_), progs, true,
emitConfig, statp_);
panda::Timer::timerEnd(panda::EVENT_EMIT_MERGED_PROGRAM, "");
if (!success) {
throw Error(ErrorType::GENERIC, "Failed to emit " + outputFileName_ + ", error: " +
panda::pandasm::AsmEmitter::GetLastError() +
"\nIf you're using any cache file generated by older version of SDK, " +
"please try cleaning the cache files and rebuild");
}
if (!transformLib_.empty()) {
util::Helpers::AopTransform(outputFileName_, transformLib_);
}
}
void EmitCacheJob::Run()
{
ES2ABC_PERF_SCOPE("@EVENT_EMIT_CACHE_FILE" + outputProtoName_);
panda::Timer::timerStart(panda::EVENT_EMIT_CACHE_FILE, outputProtoName_);
panda::proto::ProtobufSnapshotGenerator::UpdateCacheFile(progCache_, outputProtoName_);
for (auto *dependant : dependants_) {
dependant->Signal();
}
panda::Timer::timerEnd(panda::EVENT_EMIT_CACHE_FILE, outputProtoName_);
}
}