13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2023 - 2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "emitFiles.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <assembly-emitter.h>
193af6ab5fSopenharmony_ci#include <mem/arena_allocator.h>
203af6ab5fSopenharmony_ci#include "utils/timers.h"
213af6ab5fSopenharmony_ci
223af6ab5fSopenharmony_ci#include <es2panda.h>
233af6ab5fSopenharmony_ci#include <protobufSnapshotGenerator.h>
243af6ab5fSopenharmony_ci#include <util/helpers.h>
253af6ab5fSopenharmony_ci
263af6ab5fSopenharmony_cinamespace panda::es2panda::aot {
273af6ab5fSopenharmony_civoid EmitFileQueue::ScheduleEmitCacheJobs(EmitMergedAbcJob *emitMergedAbcJob)
283af6ab5fSopenharmony_ci{
293af6ab5fSopenharmony_ci    for (const auto &info: progsInfo_) {
303af6ab5fSopenharmony_ci        // generate cache protoBins and set dependencies
313af6ab5fSopenharmony_ci        if (!info.second->needUpdateCache) {
323af6ab5fSopenharmony_ci            continue;
333af6ab5fSopenharmony_ci        }
343af6ab5fSopenharmony_ci        auto outputCacheIter = options_->CompilerOptions().cacheFiles.find(info.first);
353af6ab5fSopenharmony_ci        if (outputCacheIter != options_->CompilerOptions().cacheFiles.end()) {
363af6ab5fSopenharmony_ci            auto emitProtoJob = new EmitCacheJob(outputCacheIter->second, info.second);
373af6ab5fSopenharmony_ci            emitProtoJob->DependsOn(emitMergedAbcJob);
383af6ab5fSopenharmony_ci            jobs_.push_back(emitProtoJob);
393af6ab5fSopenharmony_ci            jobsCount_++;
403af6ab5fSopenharmony_ci        }
413af6ab5fSopenharmony_ci    }
423af6ab5fSopenharmony_ci}
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_civoid EmitFileQueue::Schedule()
453af6ab5fSopenharmony_ci{
463af6ab5fSopenharmony_ci    ASSERT(jobsCount_ == 0);
473af6ab5fSopenharmony_ci    std::unique_lock<std::mutex> lock(m_);
483af6ab5fSopenharmony_ci    auto targetApi = options_->CompilerOptions().targetApiVersion;
493af6ab5fSopenharmony_ci    auto targetSubApi = options_->CompilerOptions().targetApiSubVersion;
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ci    if (mergeAbc_) {
523af6ab5fSopenharmony_ci        // generate merged abc
533af6ab5fSopenharmony_ci        auto emitMergedAbcJob = new EmitMergedAbcJob(options_->CompilerOutput(),
543af6ab5fSopenharmony_ci            options_->CompilerOptions().transformLib, progsInfo_, targetApi, targetSubApi);
553af6ab5fSopenharmony_ci        // Disable generating cached files when cross-program optimization is required, to prevent cached files from
563af6ab5fSopenharmony_ci        // not being invalidated when their dependencies are changed
573af6ab5fSopenharmony_ci        if (!options_->CompilerOptions().requireGlobalOptimization) {
583af6ab5fSopenharmony_ci            ScheduleEmitCacheJobs(emitMergedAbcJob);
593af6ab5fSopenharmony_ci        }
603af6ab5fSopenharmony_ci        //  One job should be placed after those jobs which depend on it to prevent blocking
613af6ab5fSopenharmony_ci        jobs_.push_back(emitMergedAbcJob);
623af6ab5fSopenharmony_ci        jobsCount_++;
633af6ab5fSopenharmony_ci    } else {
643af6ab5fSopenharmony_ci        for (const auto &info: progsInfo_) {
653af6ab5fSopenharmony_ci            try {
663af6ab5fSopenharmony_ci                // generate multi abcs
673af6ab5fSopenharmony_ci                auto outputFileName = options_->OutputFiles().empty() ? options_->CompilerOutput() :
683af6ab5fSopenharmony_ci                    options_->OutputFiles().at(info.first);
693af6ab5fSopenharmony_ci                auto emitSingleAbcJob = new EmitSingleAbcJob(outputFileName, &(info.second->program), statp_,
703af6ab5fSopenharmony_ci                                                             targetApi, targetSubApi);
713af6ab5fSopenharmony_ci                jobs_.push_back(emitSingleAbcJob);
723af6ab5fSopenharmony_ci                jobsCount_++;
733af6ab5fSopenharmony_ci            } catch (std::exception &error) {
743af6ab5fSopenharmony_ci                throw Error(ErrorType::GENERIC, error.what());
753af6ab5fSopenharmony_ci            }
763af6ab5fSopenharmony_ci        }
773af6ab5fSopenharmony_ci    }
783af6ab5fSopenharmony_ci
793af6ab5fSopenharmony_ci    lock.unlock();
803af6ab5fSopenharmony_ci    jobsAvailable_.notify_all();
813af6ab5fSopenharmony_ci}
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_civoid EmitSingleAbcJob::Run()
843af6ab5fSopenharmony_ci{
853af6ab5fSopenharmony_ci    panda::Timer::timerStart(panda::EVENT_EMIT_SINGLE_PROGRAM, outputFileName_);
863af6ab5fSopenharmony_ci    if (!panda::pandasm::AsmEmitter::Emit(panda::os::file::File::GetExtendedFilePath(outputFileName_), *prog_, statp_,
873af6ab5fSopenharmony_ci        nullptr, true, nullptr, targetApiVersion_, targetApiSubVersion_)) {
883af6ab5fSopenharmony_ci        throw Error(ErrorType::GENERIC, "Failed to emit " + outputFileName_ + ", error: " +
893af6ab5fSopenharmony_ci            panda::pandasm::AsmEmitter::GetLastError());
903af6ab5fSopenharmony_ci    }
913af6ab5fSopenharmony_ci    for (auto *dependant : dependants_) {
923af6ab5fSopenharmony_ci        dependant->Signal();
933af6ab5fSopenharmony_ci    }
943af6ab5fSopenharmony_ci    panda::Timer::timerEnd(panda::EVENT_EMIT_SINGLE_PROGRAM, outputFileName_);
953af6ab5fSopenharmony_ci}
963af6ab5fSopenharmony_ci
973af6ab5fSopenharmony_civoid EmitMergedAbcJob::Run()
983af6ab5fSopenharmony_ci{
993af6ab5fSopenharmony_ci    panda::Timer::timerStart(panda::EVENT_EMIT_MERGED_PROGRAM, "");
1003af6ab5fSopenharmony_ci    std::vector<panda::pandasm::Program*> progs;
1013af6ab5fSopenharmony_ci    progs.reserve(progsInfo_.size());
1023af6ab5fSopenharmony_ci    for (const auto &info: progsInfo_) {
1033af6ab5fSopenharmony_ci        progs.push_back(&(info.second->program));
1043af6ab5fSopenharmony_ci    }
1053af6ab5fSopenharmony_ci
1063af6ab5fSopenharmony_ci    bool success = panda::pandasm::AsmEmitter::EmitPrograms(
1073af6ab5fSopenharmony_ci        panda::os::file::File::GetExtendedFilePath(outputFileName_), progs, true,
1083af6ab5fSopenharmony_ci        targetApiVersion_, targetApiSubVersion_);
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_ci    for (auto *dependant : dependants_) {
1113af6ab5fSopenharmony_ci        dependant->Signal();
1123af6ab5fSopenharmony_ci    }
1133af6ab5fSopenharmony_ci    panda::Timer::timerEnd(panda::EVENT_EMIT_MERGED_PROGRAM, "");
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_ci    if (!success) {
1163af6ab5fSopenharmony_ci        throw Error(ErrorType::GENERIC, "Failed to emit " + outputFileName_ + ", error: " +
1173af6ab5fSopenharmony_ci            panda::pandasm::AsmEmitter::GetLastError() +
1183af6ab5fSopenharmony_ci            "\nIf you're using any cache file generated by older version of SDK, " +
1193af6ab5fSopenharmony_ci            "please try cleaning the cache files and rebuild");
1203af6ab5fSopenharmony_ci    }
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci    if (!transformLib_.empty()) {
1233af6ab5fSopenharmony_ci        util::Helpers::AopTransform(outputFileName_, transformLib_);
1243af6ab5fSopenharmony_ci    }
1253af6ab5fSopenharmony_ci}
1263af6ab5fSopenharmony_ci
1273af6ab5fSopenharmony_civoid EmitCacheJob::Run()
1283af6ab5fSopenharmony_ci{
1293af6ab5fSopenharmony_ci    std::unique_lock<std::mutex> lock(m_);
1303af6ab5fSopenharmony_ci    cond_.wait(lock, [this] { return dependencies_ == 0; });
1313af6ab5fSopenharmony_ci    panda::Timer::timerStart(panda::EVENT_EMIT_CACHE_FILE, outputProtoName_);
1323af6ab5fSopenharmony_ci    panda::proto::ProtobufSnapshotGenerator::UpdateCacheFile(progCache_, outputProtoName_);
1333af6ab5fSopenharmony_ci    panda::Timer::timerEnd(panda::EVENT_EMIT_CACHE_FILE, outputProtoName_);
1343af6ab5fSopenharmony_ci}
1353af6ab5fSopenharmony_ci
1363af6ab5fSopenharmony_ci}  // namespace panda::es2panda::util
137