14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_JIT_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_JIT_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include "ecmascript/common.h"
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/compilation_env.h"
214514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h"
224514f5e3Sopenharmony_ci#include "ecmascript/ecma_vm.h"
234514f5e3Sopenharmony_ci#include "ecmascript/mem/clock_scope.h"
244514f5e3Sopenharmony_ci#include "ecmascript/mem/machine_code.h"
254514f5e3Sopenharmony_ci#include "ecmascript/compiler/compiler_log.h"
264514f5e3Sopenharmony_ci#include "ecmascript/jit/jit_thread.h"
274514f5e3Sopenharmony_ci#include "ecmascript/jit/jit_dfx.h"
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_cinamespace panda::ecmascript {
304514f5e3Sopenharmony_ciclass JitTask;
314514f5e3Sopenharmony_cienum JitCompileMode {
324514f5e3Sopenharmony_ci    SYNC = 0,
334514f5e3Sopenharmony_ci    ASYNC
344514f5e3Sopenharmony_ci};
354514f5e3Sopenharmony_ci
364514f5e3Sopenharmony_cienum class CompilerTier : uint8_t {
374514f5e3Sopenharmony_ci    BASELINE,
384514f5e3Sopenharmony_ci    FAST,
394514f5e3Sopenharmony_ci};
404514f5e3Sopenharmony_ci
414514f5e3Sopenharmony_cistruct ThreadTaskInfo {
424514f5e3Sopenharmony_ci    std::deque<std::shared_ptr<JitTask>> installJitTasks_;
434514f5e3Sopenharmony_ci    bool skipInstallTask_ { false };
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_ci    std::atomic<uint32_t> jitTaskCnt_;
464514f5e3Sopenharmony_ci    ConditionVariable jitTaskCntCv_;
474514f5e3Sopenharmony_ci};
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_ciclass Jit {
504514f5e3Sopenharmony_cipublic:
514514f5e3Sopenharmony_ci    Jit() {}
524514f5e3Sopenharmony_ci    ~Jit();
534514f5e3Sopenharmony_ci    static PUBLIC_API Jit *GetInstance();
544514f5e3Sopenharmony_ci    void SetJitEnablePostFork(EcmaVM *vm, const std::string &bundleName);
554514f5e3Sopenharmony_ci    void ConfigJit(EcmaVM *vm);
564514f5e3Sopenharmony_ci    void SwitchProfileStubs(EcmaVM *vm);
574514f5e3Sopenharmony_ci    void ConfigOptions(EcmaVM *vm) const;
584514f5e3Sopenharmony_ci    void ConfigJitFortOptions(EcmaVM *vm);
594514f5e3Sopenharmony_ci    void SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJit, bool isEnableBaselineJit);
604514f5e3Sopenharmony_ci    bool PUBLIC_API IsEnableFastJit() const;
614514f5e3Sopenharmony_ci    bool PUBLIC_API IsEnableBaselineJit() const;
624514f5e3Sopenharmony_ci    bool PUBLIC_API IsEnableJitFort() const;
634514f5e3Sopenharmony_ci    void SetEnableJitFort(bool isEnableJitFort);
644514f5e3Sopenharmony_ci    bool IsDisableCodeSign() const;
654514f5e3Sopenharmony_ci    void SetDisableCodeSign(bool isEnableCodeSign);
664514f5e3Sopenharmony_ci    bool PUBLIC_API IsEnableAsyncCopyToFort() const;
674514f5e3Sopenharmony_ci    void SetEnableAsyncCopyToFort(bool isEnableiAsyncCopyToFort);
684514f5e3Sopenharmony_ci    void Initialize();
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_ci    static void Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier = CompilerTier::FAST,
714514f5e3Sopenharmony_ci                        int32_t offset = MachineCode::INVALID_OSR_OFFSET, JitCompileMode mode = SYNC);
724514f5e3Sopenharmony_ci    bool JitCompile(void *compiler, JitTask *jitTask);
734514f5e3Sopenharmony_ci    bool JitFinalize(void *compiler, JitTask *jitTask);
744514f5e3Sopenharmony_ci    void *CreateJitCompilerTask(JitTask *jitTask);
754514f5e3Sopenharmony_ci    bool IsInitialized() const
764514f5e3Sopenharmony_ci    {
774514f5e3Sopenharmony_ci        return initialized_;
784514f5e3Sopenharmony_ci    }
794514f5e3Sopenharmony_ci
804514f5e3Sopenharmony_ci    void DeleteJitCompile(void *compiler);
814514f5e3Sopenharmony_ci
824514f5e3Sopenharmony_ci    void RequestInstallCode(std::shared_ptr<JitTask> jitTask);
834514f5e3Sopenharmony_ci    void InstallTasks(JSThread *jsThread);
844514f5e3Sopenharmony_ci    void ClearTask(const std::function<bool(Task *task)> &checkClear);
854514f5e3Sopenharmony_ci    void ClearTask(EcmaContext *ecmaContext);
864514f5e3Sopenharmony_ci    void ClearTaskWithVm(EcmaVM *vm);
874514f5e3Sopenharmony_ci    void Destroy();
884514f5e3Sopenharmony_ci    uint32_t GetRunningTaskCnt(EcmaVM *vm);
894514f5e3Sopenharmony_ci    void CheckMechineCodeSpaceMemory(JSThread *thread, int remainSize);
904514f5e3Sopenharmony_ci    void ChangeTaskPoolState(bool inBackground);
914514f5e3Sopenharmony_ci
924514f5e3Sopenharmony_ci    // dfx for jit warmup compile
934514f5e3Sopenharmony_ci    static void CountInterpExecFuncs(JSHandle<JSFunction> &jsFunction);
944514f5e3Sopenharmony_ci
954514f5e3Sopenharmony_ci    bool IsAppJit() const
964514f5e3Sopenharmony_ci    {
974514f5e3Sopenharmony_ci        return isApp_;
984514f5e3Sopenharmony_ci    }
994514f5e3Sopenharmony_ci
1004514f5e3Sopenharmony_ci    uint32_t GetHotnessThreshold() const
1014514f5e3Sopenharmony_ci    {
1024514f5e3Sopenharmony_ci        return hotnessThreshold_;
1034514f5e3Sopenharmony_ci    }
1044514f5e3Sopenharmony_ci
1054514f5e3Sopenharmony_ci    void SetProfileNeedDump(bool isNeed)
1064514f5e3Sopenharmony_ci    {
1074514f5e3Sopenharmony_ci        isProfileNeedDump_ = isNeed;
1084514f5e3Sopenharmony_ci    }
1094514f5e3Sopenharmony_ci
1104514f5e3Sopenharmony_ci    bool IsProfileNeedDump() const
1114514f5e3Sopenharmony_ci    {
1124514f5e3Sopenharmony_ci        return isProfileNeedDump_;
1134514f5e3Sopenharmony_ci    }
1144514f5e3Sopenharmony_ci
1154514f5e3Sopenharmony_ci    JitDfx *GetJitDfx() const
1164514f5e3Sopenharmony_ci    {
1174514f5e3Sopenharmony_ci        return jitDfx_;
1184514f5e3Sopenharmony_ci    }
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ci    void IncJitTaskCnt(JSThread *thread);
1214514f5e3Sopenharmony_ci    void DecJitTaskCnt(JSThread *thread);
1224514f5e3Sopenharmony_ci
1234514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(Jit);
1244514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(Jit);
1254514f5e3Sopenharmony_ci
1264514f5e3Sopenharmony_ci    class TimeScope : public ClockScope {
1274514f5e3Sopenharmony_ci    public:
1284514f5e3Sopenharmony_ci        explicit TimeScope(EcmaVM *vm, CString message, CompilerTier tier = CompilerTier::FAST, bool outPutLog = true,
1294514f5e3Sopenharmony_ci            bool isDebugLevel = false)
1304514f5e3Sopenharmony_ci            : vm_(vm), message_(message), tier_(tier), outPutLog_(outPutLog), isDebugLevel_(isDebugLevel) {}
1314514f5e3Sopenharmony_ci        explicit TimeScope(EcmaVM *vm)
1324514f5e3Sopenharmony_ci            : vm_(vm), message_(""), tier_(CompilerTier::FAST), outPutLog_(false), isDebugLevel_(true) {}
1334514f5e3Sopenharmony_ci        PUBLIC_API ~TimeScope();
1344514f5e3Sopenharmony_ci    private:
1354514f5e3Sopenharmony_ci        EcmaVM *vm_;
1364514f5e3Sopenharmony_ci        CString message_;
1374514f5e3Sopenharmony_ci        CompilerTier tier_;
1384514f5e3Sopenharmony_ci        bool outPutLog_;
1394514f5e3Sopenharmony_ci        bool isDebugLevel_;
1404514f5e3Sopenharmony_ci    };
1414514f5e3Sopenharmony_ci
1424514f5e3Sopenharmony_ci    class JitLockHolder {
1434514f5e3Sopenharmony_ci    public:
1444514f5e3Sopenharmony_ci        explicit JitLockHolder(JSThread *thread) : thread_(nullptr), scope_(thread->GetEcmaVM())
1454514f5e3Sopenharmony_ci        {
1464514f5e3Sopenharmony_ci            if (thread->IsJitThread()) {
1474514f5e3Sopenharmony_ci                thread_ = static_cast<JitThread*>(thread);
1484514f5e3Sopenharmony_ci                if (thread_->GetState() != ThreadState::RUNNING) {
1494514f5e3Sopenharmony_ci                    thread_->ManagedCodeBegin();
1504514f5e3Sopenharmony_ci                    isInManagedCode_ = true;
1514514f5e3Sopenharmony_ci                }
1524514f5e3Sopenharmony_ci                thread_->GetHostThread()->GetJitLock()->Lock();
1534514f5e3Sopenharmony_ci            }
1544514f5e3Sopenharmony_ci        }
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_ci        explicit JitLockHolder(const CompilationEnv *env, CString message) : thread_(nullptr),
1574514f5e3Sopenharmony_ci            scope_(env->GetJSThread()->GetEcmaVM(),
1584514f5e3Sopenharmony_ci                "Jit Compile Pass: " + message + ", Time:", CompilerTier::FAST, false)
1594514f5e3Sopenharmony_ci        {
1604514f5e3Sopenharmony_ci            if (env->IsJitCompiler()) {
1614514f5e3Sopenharmony_ci                JSThread *thread = env->GetJSThread();
1624514f5e3Sopenharmony_ci                ASSERT(thread->IsJitThread());
1634514f5e3Sopenharmony_ci                thread_ = static_cast<JitThread*>(thread);
1644514f5e3Sopenharmony_ci                if (thread_->GetState() != ThreadState::RUNNING) {
1654514f5e3Sopenharmony_ci                    thread_->ManagedCodeBegin();
1664514f5e3Sopenharmony_ci                    isInManagedCode_ = true;
1674514f5e3Sopenharmony_ci                }
1684514f5e3Sopenharmony_ci                thread_->GetHostThread()->GetJitLock()->Lock();
1694514f5e3Sopenharmony_ci            }
1704514f5e3Sopenharmony_ci        }
1714514f5e3Sopenharmony_ci
1724514f5e3Sopenharmony_ci        ~JitLockHolder()
1734514f5e3Sopenharmony_ci        {
1744514f5e3Sopenharmony_ci            if (thread_ != nullptr) {
1754514f5e3Sopenharmony_ci                thread_->GetHostThread()->GetJitLock()->Unlock();
1764514f5e3Sopenharmony_ci                if (isInManagedCode_) {
1774514f5e3Sopenharmony_ci                    thread_->ManagedCodeEnd();
1784514f5e3Sopenharmony_ci                }
1794514f5e3Sopenharmony_ci            }
1804514f5e3Sopenharmony_ci        }
1814514f5e3Sopenharmony_ci        JitThread *thread_ {nullptr};
1824514f5e3Sopenharmony_ci        TimeScope scope_;
1834514f5e3Sopenharmony_ci        bool isInManagedCode_{false};
1844514f5e3Sopenharmony_ci        ALLOW_HEAP_ACCESS
1854514f5e3Sopenharmony_ci        NO_COPY_SEMANTIC(JitLockHolder);
1864514f5e3Sopenharmony_ci        NO_MOVE_SEMANTIC(JitLockHolder);
1874514f5e3Sopenharmony_ci    };
1884514f5e3Sopenharmony_ci
1894514f5e3Sopenharmony_ci    class JitGCLockHolder {
1904514f5e3Sopenharmony_ci    public:
1914514f5e3Sopenharmony_ci        explicit JitGCLockHolder(JSThread *thread) : thread_(thread)
1924514f5e3Sopenharmony_ci        {
1934514f5e3Sopenharmony_ci            ASSERT(!thread->IsJitThread());
1944514f5e3Sopenharmony_ci            if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) {
1954514f5e3Sopenharmony_ci                LockJit(thread_);
1964514f5e3Sopenharmony_ci                locked_ = true;
1974514f5e3Sopenharmony_ci            }
1984514f5e3Sopenharmony_ci        }
1994514f5e3Sopenharmony_ci
2004514f5e3Sopenharmony_ci        static void LockJit(JSThread *thread)
2014514f5e3Sopenharmony_ci        {
2024514f5e3Sopenharmony_ci            Clock::time_point start = Clock::now();
2034514f5e3Sopenharmony_ci            thread->GetJitLock()->Lock();
2044514f5e3Sopenharmony_ci            Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime(
2054514f5e3Sopenharmony_ci            std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - start).count());
2064514f5e3Sopenharmony_ci        }
2074514f5e3Sopenharmony_ci
2084514f5e3Sopenharmony_ci        static void UnlockJit(JSThread *thread)
2094514f5e3Sopenharmony_ci        {
2104514f5e3Sopenharmony_ci            thread->GetJitLock()->Unlock();
2114514f5e3Sopenharmony_ci        }
2124514f5e3Sopenharmony_ci
2134514f5e3Sopenharmony_ci        ~JitGCLockHolder()
2144514f5e3Sopenharmony_ci        {
2154514f5e3Sopenharmony_ci            if (locked_) {
2164514f5e3Sopenharmony_ci                UnlockJit(thread_);
2174514f5e3Sopenharmony_ci                locked_ = false;
2184514f5e3Sopenharmony_ci            }
2194514f5e3Sopenharmony_ci        }
2204514f5e3Sopenharmony_ci
2214514f5e3Sopenharmony_ci    private:
2224514f5e3Sopenharmony_ci        JSThread *thread_;
2234514f5e3Sopenharmony_ci        bool locked_ { false };
2244514f5e3Sopenharmony_ci
2254514f5e3Sopenharmony_ci        NO_COPY_SEMANTIC(JitGCLockHolder);
2264514f5e3Sopenharmony_ci        NO_MOVE_SEMANTIC(JitGCLockHolder);
2274514f5e3Sopenharmony_ci    };
2284514f5e3Sopenharmony_ci
2294514f5e3Sopenharmony_ciprivate:
2304514f5e3Sopenharmony_ci    bool SupportJIT(JSHandle<JSFunction> &jsFunction, EcmaVM *vm, CompilerTier tier) const;
2314514f5e3Sopenharmony_ci    bool initialized_ { false };
2324514f5e3Sopenharmony_ci    bool fastJitEnable_ { false };
2334514f5e3Sopenharmony_ci    bool baselineJitEnable_ { false };
2344514f5e3Sopenharmony_ci    bool isApp_ { false };
2354514f5e3Sopenharmony_ci    bool isProfileNeedDump_ { true };
2364514f5e3Sopenharmony_ci    uint32_t hotnessThreshold_ { 0 };
2374514f5e3Sopenharmony_ci    std::string bundleName_;
2384514f5e3Sopenharmony_ci    bool isEnableAppPGO_ { true };
2394514f5e3Sopenharmony_ci
2404514f5e3Sopenharmony_ci    std::unordered_map<JSThread*, ThreadTaskInfo> threadTaskInfo_;
2414514f5e3Sopenharmony_ci    RecursiveMutex threadTaskInfoLock_;
2424514f5e3Sopenharmony_ci    bool isEnableJitFort_ { true };
2434514f5e3Sopenharmony_ci    bool isDisableCodeSign_ { true };
2444514f5e3Sopenharmony_ci    bool isEnableAsyncCopyToFort_ { true };
2454514f5e3Sopenharmony_ci
2464514f5e3Sopenharmony_ci    Mutex setEnableLock_;
2474514f5e3Sopenharmony_ci
2484514f5e3Sopenharmony_ci    JitDfx *jitDfx_ { nullptr };
2494514f5e3Sopenharmony_ci    static constexpr int MIN_CODE_SPACE_SIZE = 1_KB;
2504514f5e3Sopenharmony_ci
2514514f5e3Sopenharmony_ci    static void (*initJitCompiler_)(JSRuntimeOptions);
2524514f5e3Sopenharmony_ci    static bool(*jitCompile_)(void*, JitTask*);
2534514f5e3Sopenharmony_ci    static bool(*jitFinalize_)(void*, JitTask*);
2544514f5e3Sopenharmony_ci    static void*(*createJitCompilerTask_)(JitTask*);
2554514f5e3Sopenharmony_ci    static void(*deleteJitCompile_)(void*);
2564514f5e3Sopenharmony_ci    static void *libHandle_;
2574514f5e3Sopenharmony_ci    static bool CheckJitCompileStatus(JSHandle<JSFunction> &jsFunction,
2584514f5e3Sopenharmony_ci        const CString &methodName, CompilerTier tier);
2594514f5e3Sopenharmony_ci};
2604514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
2614514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_JIT_H
262