14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022-2024 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#include "ecmascript/deoptimizer/deoptimizer.h" 164514f5e3Sopenharmony_ci 174514f5e3Sopenharmony_ci#include <cmath> 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/dfx/stackinfo/js_stackinfo.h" 204514f5e3Sopenharmony_ci#include "ecmascript/interpreter/slow_runtime_stub.h" 214514f5e3Sopenharmony_ci#include "ecmascript/jit/jit.h" 224514f5e3Sopenharmony_ci#include "ecmascript/stubs/runtime_stubs-inl.h" 234514f5e3Sopenharmony_ci 244514f5e3Sopenharmony_cinamespace panda::ecmascript { 254514f5e3Sopenharmony_ciclass FrameWriter { 264514f5e3Sopenharmony_cipublic: 274514f5e3Sopenharmony_ci explicit FrameWriter(Deoptimizier *deoptimizier) : thread_(deoptimizier->GetThread()) 284514f5e3Sopenharmony_ci { 294514f5e3Sopenharmony_ci JSTaggedType *prevSp = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame()); 304514f5e3Sopenharmony_ci start_ = top_ = EcmaInterpreter::GetInterpreterFrameEnd(thread_, prevSp); 314514f5e3Sopenharmony_ci } 324514f5e3Sopenharmony_ci 334514f5e3Sopenharmony_ci void PushValue(JSTaggedType value) 344514f5e3Sopenharmony_ci { 354514f5e3Sopenharmony_ci *(--top_) = value; 364514f5e3Sopenharmony_ci } 374514f5e3Sopenharmony_ci 384514f5e3Sopenharmony_ci void PushRawValue(uintptr_t value) 394514f5e3Sopenharmony_ci { 404514f5e3Sopenharmony_ci *(--top_) = value; 414514f5e3Sopenharmony_ci } 424514f5e3Sopenharmony_ci 434514f5e3Sopenharmony_ci bool Reserve(size_t size) 444514f5e3Sopenharmony_ci { 454514f5e3Sopenharmony_ci return !thread_->DoStackOverflowCheck(top_ - size); 464514f5e3Sopenharmony_ci } 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ci AsmInterpretedFrame *ReserveAsmInterpretedFrame() 494514f5e3Sopenharmony_ci { 504514f5e3Sopenharmony_ci auto frame = AsmInterpretedFrame::GetFrameFromSp(top_); 514514f5e3Sopenharmony_ci top_ = reinterpret_cast<JSTaggedType *>(frame); 524514f5e3Sopenharmony_ci return frame; 534514f5e3Sopenharmony_ci } 544514f5e3Sopenharmony_ci 554514f5e3Sopenharmony_ci JSTaggedType *GetStart() const 564514f5e3Sopenharmony_ci { 574514f5e3Sopenharmony_ci return start_; 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci 604514f5e3Sopenharmony_ci JSTaggedType *GetTop() const 614514f5e3Sopenharmony_ci { 624514f5e3Sopenharmony_ci return top_; 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci 654514f5e3Sopenharmony_ci JSTaggedType *GetFirstFrame() const 664514f5e3Sopenharmony_ci { 674514f5e3Sopenharmony_ci return firstFrame_; 684514f5e3Sopenharmony_ci } 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ci void RecordFirstFrame() 714514f5e3Sopenharmony_ci { 724514f5e3Sopenharmony_ci firstFrame_ = top_; 734514f5e3Sopenharmony_ci } 744514f5e3Sopenharmony_ci 754514f5e3Sopenharmony_ci void ReviseValueByIndex(JSTaggedType value, size_t index) 764514f5e3Sopenharmony_ci { 774514f5e3Sopenharmony_ci ASSERT(index < static_cast<size_t>(start_ - top_)); 784514f5e3Sopenharmony_ci *(top_ + index) = value; 794514f5e3Sopenharmony_ci } 804514f5e3Sopenharmony_ci 814514f5e3Sopenharmony_ciprivate: 824514f5e3Sopenharmony_ci JSThread *thread_ {nullptr}; 834514f5e3Sopenharmony_ci JSTaggedType *start_ {nullptr}; 844514f5e3Sopenharmony_ci JSTaggedType *top_ {nullptr}; 854514f5e3Sopenharmony_ci JSTaggedType *firstFrame_ {nullptr}; 864514f5e3Sopenharmony_ci}; 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ciDeoptimizier::Deoptimizier(JSThread *thread, size_t depth) : thread_(thread), inlineDepth_(depth) 894514f5e3Sopenharmony_ci{ 904514f5e3Sopenharmony_ci CalleeReg callreg; 914514f5e3Sopenharmony_ci numCalleeRegs_ = static_cast<size_t>(callreg.GetCallRegNum()); 924514f5e3Sopenharmony_ci JSRuntimeOptions options = thread_->GetEcmaVM()->GetJSOptions(); 934514f5e3Sopenharmony_ci traceDeopt_ = options.GetTraceDeopt(); 944514f5e3Sopenharmony_ci} 954514f5e3Sopenharmony_ci 964514f5e3Sopenharmony_civoid Deoptimizier::CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle, size_t shift) 974514f5e3Sopenharmony_ci{ 984514f5e3Sopenharmony_ci deoptVregs_.clear(); 994514f5e3Sopenharmony_ci for (size_t i = 0; i < deoptBundle.size(); i++) { 1004514f5e3Sopenharmony_ci ARKDeopt deopt = deoptBundle.at(i); 1014514f5e3Sopenharmony_ci JSTaggedType v; 1024514f5e3Sopenharmony_ci VRegId id = deopt.id; 1034514f5e3Sopenharmony_ci if (std::holds_alternative<DwarfRegAndOffsetType>(deopt.value)) { 1044514f5e3Sopenharmony_ci ASSERT(deopt.kind == LocationTy::Kind::INDIRECT); 1054514f5e3Sopenharmony_ci auto value = std::get<DwarfRegAndOffsetType>(deopt.value); 1064514f5e3Sopenharmony_ci DwarfRegType dwarfReg = value.first; 1074514f5e3Sopenharmony_ci OffsetType offset = value.second; 1084514f5e3Sopenharmony_ci ASSERT (dwarfReg == GCStackMapRegisters::FP || dwarfReg == GCStackMapRegisters::SP); 1094514f5e3Sopenharmony_ci uintptr_t addr; 1104514f5e3Sopenharmony_ci if (dwarfReg == GCStackMapRegisters::SP) { 1114514f5e3Sopenharmony_ci addr = context_.callsiteSp + offset; 1124514f5e3Sopenharmony_ci } else { 1134514f5e3Sopenharmony_ci addr = context_.callsiteFp + offset; 1144514f5e3Sopenharmony_ci } 1154514f5e3Sopenharmony_ci v = *(reinterpret_cast<JSTaggedType *>(addr)); 1164514f5e3Sopenharmony_ci } else if (std::holds_alternative<LargeInt>(deopt.value)) { 1174514f5e3Sopenharmony_ci ASSERT(deopt.kind == LocationTy::Kind::CONSTANTNDEX); 1184514f5e3Sopenharmony_ci v = JSTaggedType(static_cast<int64_t>(std::get<LargeInt>(deopt.value))); 1194514f5e3Sopenharmony_ci } else { 1204514f5e3Sopenharmony_ci ASSERT(std::holds_alternative<IntType>(deopt.value)); 1214514f5e3Sopenharmony_ci ASSERT(deopt.kind == LocationTy::Kind::CONSTANT); 1224514f5e3Sopenharmony_ci v = JSTaggedType(static_cast<int64_t>(std::get<IntType>(deopt.value))); 1234514f5e3Sopenharmony_ci } 1244514f5e3Sopenharmony_ci size_t curDepth = DecodeDeoptDepth(id, shift); 1254514f5e3Sopenharmony_ci OffsetType vregId = static_cast<OffsetType>(DecodeVregIndex(id, shift)); 1264514f5e3Sopenharmony_ci if (vregId != static_cast<OffsetType>(SpecVregIndex::PC_OFFSET_INDEX)) { 1274514f5e3Sopenharmony_ci deoptVregs_.insert({{curDepth, vregId}, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(v))}); 1284514f5e3Sopenharmony_ci } else { 1294514f5e3Sopenharmony_ci pc_.insert({curDepth, static_cast<size_t>(v)}); 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci } 1324514f5e3Sopenharmony_ci} 1334514f5e3Sopenharmony_ci 1344514f5e3Sopenharmony_ci// when AOT trigger deopt, frame layout as the following 1354514f5e3Sopenharmony_ci// * OptimizedJSFunctionFrame layout description as the following: 1364514f5e3Sopenharmony_ci// +--------------------------+ --------------- 1374514f5e3Sopenharmony_ci// | ...... | ^ 1384514f5e3Sopenharmony_ci// | ...... | callerFunction 1394514f5e3Sopenharmony_ci// | ...... | | 1404514f5e3Sopenharmony_ci// |--------------------------| | 1414514f5e3Sopenharmony_ci// | args | v 1424514f5e3Sopenharmony_ci// +--------------------------+ --------------- 1434514f5e3Sopenharmony_ci// | returnAddr | ^ 1444514f5e3Sopenharmony_ci// |--------------------------| | 1454514f5e3Sopenharmony_ci// | callsiteFp | | 1464514f5e3Sopenharmony_ci// |--------------------------| OptimizedJSFunction FrameType:OPTIMIZED_JS_FUNCTION_FRAME 1474514f5e3Sopenharmony_ci// | frameType | | 1484514f5e3Sopenharmony_ci// |--------------------------| | 1494514f5e3Sopenharmony_ci// | call-target | | 1504514f5e3Sopenharmony_ci// |--------------------------| | 1514514f5e3Sopenharmony_ci// | lexEnv | | 1524514f5e3Sopenharmony_ci// |--------------------------| | 1534514f5e3Sopenharmony_ci// | ........... | v 1544514f5e3Sopenharmony_ci// +--------------------------+ --------------- 1554514f5e3Sopenharmony_ci// | returnAddr | ^ 1564514f5e3Sopenharmony_ci// |--------------------------| | 1574514f5e3Sopenharmony_ci// | callsiteFp | | 1584514f5e3Sopenharmony_ci// |--------------------------| __llvm_deoptimize FrameType:OPTIMIZED_FRAME 1594514f5e3Sopenharmony_ci// | frameType | | 1604514f5e3Sopenharmony_ci// |--------------------------| | 1614514f5e3Sopenharmony_ci// | No CalleeSave | | 1624514f5e3Sopenharmony_ci// | Registers | v 1634514f5e3Sopenharmony_ci// +--------------------------+ --------------- 1644514f5e3Sopenharmony_ci// | returnAddr | ^ 1654514f5e3Sopenharmony_ci// |--------------------------| | 1664514f5e3Sopenharmony_ci// | callsiteFp | | 1674514f5e3Sopenharmony_ci// |--------------------------| DeoptHandlerAsm FrameType:ASM_BRIDGE_FRAME 1684514f5e3Sopenharmony_ci// | frameType | | 1694514f5e3Sopenharmony_ci// |--------------------------| | 1704514f5e3Sopenharmony_ci// | glue | | 1714514f5e3Sopenharmony_ci// |--------------------------| | 1724514f5e3Sopenharmony_ci// | CalleeSave Registers | v 1734514f5e3Sopenharmony_ci// +--------------------------+ --------------- 1744514f5e3Sopenharmony_ci// | ......... | ^ 1754514f5e3Sopenharmony_ci// | ......... | CallRuntime FrameType:LEAVE_FRAME 1764514f5e3Sopenharmony_ci// | ......... | | 1774514f5e3Sopenharmony_ci// | ......... | v 1784514f5e3Sopenharmony_ci// |--------------------------| --------------- 1794514f5e3Sopenharmony_ci 1804514f5e3Sopenharmony_ci// After gathering the necessary information(After Call Runtime), frame layout after constructing 1814514f5e3Sopenharmony_ci// asminterpreterframe is shown as the following: 1824514f5e3Sopenharmony_ci// +----------------------------------+---------+ 1834514f5e3Sopenharmony_ci// | ...... | ^ 1844514f5e3Sopenharmony_ci// | ...... | callerFunction 1854514f5e3Sopenharmony_ci// | ...... | | 1864514f5e3Sopenharmony_ci// |----------------------------------| | 1874514f5e3Sopenharmony_ci// | args | v 1884514f5e3Sopenharmony_ci// +----------------------------------+---------+ 1894514f5e3Sopenharmony_ci// | returnAddr | ^ 1904514f5e3Sopenharmony_ci// |----------------------------------| | 1914514f5e3Sopenharmony_ci// | frameType | | 1924514f5e3Sopenharmony_ci// |----------------------------------| ASM_INTERPRETER_BRIDGE_FRAME 1934514f5e3Sopenharmony_ci// | callsiteFp | | 1944514f5e3Sopenharmony_ci// |----------------------------------| | 1954514f5e3Sopenharmony_ci// | ........... | v 1964514f5e3Sopenharmony_ci// +----------------------------------+---------+ 1974514f5e3Sopenharmony_ci// | returnAddr | 1984514f5e3Sopenharmony_ci// |----------------------------------| 1994514f5e3Sopenharmony_ci// | argv[n-1] | 2004514f5e3Sopenharmony_ci// |----------------------------------| 2014514f5e3Sopenharmony_ci// | ...... | 2024514f5e3Sopenharmony_ci// |----------------------------------| 2034514f5e3Sopenharmony_ci// | thisArg [maybe not exist] | 2044514f5e3Sopenharmony_ci// |----------------------------------| 2054514f5e3Sopenharmony_ci// | newTarget [maybe not exist] | 2064514f5e3Sopenharmony_ci// |----------------------------------| 2074514f5e3Sopenharmony_ci// | ...... | 2084514f5e3Sopenharmony_ci// |----------------------------------| 2094514f5e3Sopenharmony_ci// | Vregs [not exist in native] | 2104514f5e3Sopenharmony_ci// +----------------------------------+--------+ 2114514f5e3Sopenharmony_ci// | . . . . | ^ 2124514f5e3Sopenharmony_ci// | InterpretedFrameBase | | 2134514f5e3Sopenharmony_ci// | . . . . | | 2144514f5e3Sopenharmony_ci// |----------------------------------| | 2154514f5e3Sopenharmony_ci// | pc(bytecode addr) | | 2164514f5e3Sopenharmony_ci// |----------------------------------| | 2174514f5e3Sopenharmony_ci// | sp(current stack pointer) | | 2184514f5e3Sopenharmony_ci// |----------------------------------| AsmInterpretedFrame 0 2194514f5e3Sopenharmony_ci// | callSize | | 2204514f5e3Sopenharmony_ci// |----------------------------------| | 2214514f5e3Sopenharmony_ci// | env | | 2224514f5e3Sopenharmony_ci// |----------------------------------| | 2234514f5e3Sopenharmony_ci// | acc | | 2244514f5e3Sopenharmony_ci// |----------------------------------| | 2254514f5e3Sopenharmony_ci// | thisObj | | 2264514f5e3Sopenharmony_ci// |----------------------------------| | 2274514f5e3Sopenharmony_ci// | call-target | v 2284514f5e3Sopenharmony_ci// +----------------------------------+--------+ 2294514f5e3Sopenharmony_ci// | argv[n-1] | 2304514f5e3Sopenharmony_ci// |----------------------------------| 2314514f5e3Sopenharmony_ci// | ...... | 2324514f5e3Sopenharmony_ci// |----------------------------------| 2334514f5e3Sopenharmony_ci// | thisArg [maybe not exist] | 2344514f5e3Sopenharmony_ci// |----------------------------------| 2354514f5e3Sopenharmony_ci// | newTarget [maybe not exist] | 2364514f5e3Sopenharmony_ci// |----------------------------------| 2374514f5e3Sopenharmony_ci// | ...... | 2384514f5e3Sopenharmony_ci// |----------------------------------| 2394514f5e3Sopenharmony_ci// | Vregs [not exist in native] | 2404514f5e3Sopenharmony_ci// +----------------------------------+--------+ 2414514f5e3Sopenharmony_ci// | . . . . | ^ 2424514f5e3Sopenharmony_ci// | InterpretedFrameBase | | 2434514f5e3Sopenharmony_ci// | . . . . | | 2444514f5e3Sopenharmony_ci// |----------------------------------| | 2454514f5e3Sopenharmony_ci// | pc(bytecode addr) | | 2464514f5e3Sopenharmony_ci// |----------------------------------| | 2474514f5e3Sopenharmony_ci// | sp(current stack pointer) | | 2484514f5e3Sopenharmony_ci// |----------------------------------| AsmInterpretedFrame 1 2494514f5e3Sopenharmony_ci// | callSize | | 2504514f5e3Sopenharmony_ci// |----------------------------------| | 2514514f5e3Sopenharmony_ci// | env | | 2524514f5e3Sopenharmony_ci// |----------------------------------| | 2534514f5e3Sopenharmony_ci// | acc | | 2544514f5e3Sopenharmony_ci// |----------------------------------| | 2554514f5e3Sopenharmony_ci// | thisObj | | 2564514f5e3Sopenharmony_ci// |----------------------------------| | 2574514f5e3Sopenharmony_ci// | call-target | v 2584514f5e3Sopenharmony_ci// +----------------------------------+--------+ 2594514f5e3Sopenharmony_ci// | . . . . | ^ 2604514f5e3Sopenharmony_ci// | . . . . | AsmInterpretedFrame n 2614514f5e3Sopenharmony_ci// | . . . . | v 2624514f5e3Sopenharmony_ci// +----------------------------------+--------+ 2634514f5e3Sopenharmony_ci 2644514f5e3Sopenharmony_citemplate<class T> 2654514f5e3Sopenharmony_civoid Deoptimizier::AssistCollectDeoptBundleVec(FrameIterator &it, T &frame) 2664514f5e3Sopenharmony_ci{ 2674514f5e3Sopenharmony_ci CalleeRegAndOffsetVec calleeRegInfo; 2684514f5e3Sopenharmony_ci frame->GetFuncCalleeRegAndOffset(it, calleeRegInfo); 2694514f5e3Sopenharmony_ci context_.calleeRegAndOffset = calleeRegInfo; 2704514f5e3Sopenharmony_ci context_.callsiteSp = it.GetCallSiteSp(); 2714514f5e3Sopenharmony_ci context_.callsiteFp = reinterpret_cast<uintptr_t>(it.GetSp()); 2724514f5e3Sopenharmony_ci auto preFrameSp = frame->ComputePrevFrameSp(it); 2734514f5e3Sopenharmony_ci frameArgc_ = frame->GetArgc(preFrameSp); 2744514f5e3Sopenharmony_ci frameArgvs_ = frame->GetArgv(preFrameSp); 2754514f5e3Sopenharmony_ci stackContext_.callFrameTop_ = it.GetPrevFrameCallSiteSp(); 2764514f5e3Sopenharmony_ci stackContext_.returnAddr_ = frame->GetReturnAddr(); 2774514f5e3Sopenharmony_ci stackContext_.callerFp_ = reinterpret_cast<uintptr_t>(frame->GetPrevFrameFp()); 2784514f5e3Sopenharmony_ci} 2794514f5e3Sopenharmony_ci 2804514f5e3Sopenharmony_civoid Deoptimizier::CollectDeoptBundleVec(std::vector<ARKDeopt>& deoptBundle) 2814514f5e3Sopenharmony_ci{ 2824514f5e3Sopenharmony_ci JSTaggedType *lastLeave = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame()); 2834514f5e3Sopenharmony_ci FrameIterator it(lastLeave, thread_); 2844514f5e3Sopenharmony_ci // note: last deopt bridge frame is generated by DeoptHandlerAsm, callee Regs is grow from this frame 2854514f5e3Sopenharmony_ci for (; !it.Done() && deoptBundle.empty(); it.Advance<GCVisitedFlag::DEOPT>()) { 2864514f5e3Sopenharmony_ci FrameType type = it.GetFrameType(); 2874514f5e3Sopenharmony_ci switch (type) { 2884514f5e3Sopenharmony_ci case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 2894514f5e3Sopenharmony_ci case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { 2904514f5e3Sopenharmony_ci auto frame = it.GetFrame<OptimizedJSFunctionFrame>(); 2914514f5e3Sopenharmony_ci frame->GetDeoptBundleInfo(it, deoptBundle); 2924514f5e3Sopenharmony_ci AssistCollectDeoptBundleVec(it, frame); 2934514f5e3Sopenharmony_ci break; 2944514f5e3Sopenharmony_ci } 2954514f5e3Sopenharmony_ci case FrameType::FASTJIT_FUNCTION_FRAME: 2964514f5e3Sopenharmony_ci case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 2974514f5e3Sopenharmony_ci auto frame = it.GetFrame<FASTJITFunctionFrame>(); 2984514f5e3Sopenharmony_ci frame->GetDeoptBundleInfo(it, deoptBundle); 2994514f5e3Sopenharmony_ci AssistCollectDeoptBundleVec(it, frame); 3004514f5e3Sopenharmony_ci break; 3014514f5e3Sopenharmony_ci } 3024514f5e3Sopenharmony_ci case FrameType::ASM_BRIDGE_FRAME: { 3034514f5e3Sopenharmony_ci auto sp = reinterpret_cast<uintptr_t*>(it.GetSp()); 3044514f5e3Sopenharmony_ci static constexpr size_t TYPE_GLUE_SLOT = 2; // 2: skip type & glue 3054514f5e3Sopenharmony_ci sp -= TYPE_GLUE_SLOT; 3064514f5e3Sopenharmony_ci calleeRegAddr_ = sp - numCalleeRegs_; 3074514f5e3Sopenharmony_ci break; 3084514f5e3Sopenharmony_ci } 3094514f5e3Sopenharmony_ci case FrameType::OPTIMIZED_FRAME: 3104514f5e3Sopenharmony_ci case FrameType::LEAVE_FRAME: 3114514f5e3Sopenharmony_ci break; 3124514f5e3Sopenharmony_ci default: { 3134514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "frame type error!"; 3144514f5e3Sopenharmony_ci UNREACHABLE(); 3154514f5e3Sopenharmony_ci } 3164514f5e3Sopenharmony_ci } 3174514f5e3Sopenharmony_ci } 3184514f5e3Sopenharmony_ci ASSERT(!it.Done()); 3194514f5e3Sopenharmony_ci} 3204514f5e3Sopenharmony_ci 3214514f5e3Sopenharmony_ciMethod* Deoptimizier::GetMethod(JSTaggedValue &target) 3224514f5e3Sopenharmony_ci{ 3234514f5e3Sopenharmony_ci ECMAObject *callTarget = reinterpret_cast<ECMAObject*>(target.GetTaggedObject()); 3244514f5e3Sopenharmony_ci ASSERT(callTarget != nullptr); 3254514f5e3Sopenharmony_ci Method *method = callTarget->GetCallTarget(); 3264514f5e3Sopenharmony_ci return method; 3274514f5e3Sopenharmony_ci} 3284514f5e3Sopenharmony_ci 3294514f5e3Sopenharmony_civoid Deoptimizier::RelocateCalleeSave() 3304514f5e3Sopenharmony_ci{ 3314514f5e3Sopenharmony_ci CalleeReg callreg; 3324514f5e3Sopenharmony_ci for (auto &it: context_.calleeRegAndOffset) { 3334514f5e3Sopenharmony_ci auto reg = it.first; 3344514f5e3Sopenharmony_ci auto offset = it.second; 3354514f5e3Sopenharmony_ci uintptr_t value = *(reinterpret_cast<uintptr_t *>(context_.callsiteFp + offset)); 3364514f5e3Sopenharmony_ci int order = callreg.FindCallRegOrder(reg); 3374514f5e3Sopenharmony_ci calleeRegAddr_[order] = value; 3384514f5e3Sopenharmony_ci } 3394514f5e3Sopenharmony_ci} 3404514f5e3Sopenharmony_ci 3414514f5e3Sopenharmony_cibool Deoptimizier::CollectVirtualRegisters(JSTaggedValue callTarget, Method *method, FrameWriter *frameWriter, 3424514f5e3Sopenharmony_ci size_t curDepth) 3434514f5e3Sopenharmony_ci{ 3444514f5e3Sopenharmony_ci int32_t actualNumArgs = 0; 3454514f5e3Sopenharmony_ci int32_t declaredNumArgs = 0; 3464514f5e3Sopenharmony_ci if (curDepth == 0) { 3474514f5e3Sopenharmony_ci actualNumArgs = static_cast<int32_t>(GetDeoptValue(curDepth, 3484514f5e3Sopenharmony_ci static_cast<int32_t>(SpecVregIndex::ACTUAL_ARGC_INDEX)).GetInt()); 3494514f5e3Sopenharmony_ci declaredNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField()); 3504514f5e3Sopenharmony_ci } else { 3514514f5e3Sopenharmony_ci // inline method actualNumArgs equal to declaredNumArgs 3524514f5e3Sopenharmony_ci actualNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField()); 3534514f5e3Sopenharmony_ci declaredNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField()); 3544514f5e3Sopenharmony_ci } 3554514f5e3Sopenharmony_ci 3564514f5e3Sopenharmony_ci int32_t callFieldNumVregs = static_cast<int32_t>(method->GetNumVregsWithCallField()); 3574514f5e3Sopenharmony_ci 3584514f5e3Sopenharmony_ci // layout of frame: 3594514f5e3Sopenharmony_ci // [maybe argc] [actual args] [reserved args] [call field virtual regs] 3604514f5e3Sopenharmony_ci 3614514f5e3Sopenharmony_ci // [maybe argc] 3624514f5e3Sopenharmony_ci bool isFastCall = JSFunctionBase::IsFastCallFromCallTarget(callTarget); 3634514f5e3Sopenharmony_ci if (!isFastCall && declaredNumArgs != actualNumArgs) { 3644514f5e3Sopenharmony_ci auto value = JSTaggedValue(actualNumArgs); 3654514f5e3Sopenharmony_ci frameWriter->PushValue(value.GetRawData()); 3664514f5e3Sopenharmony_ci } 3674514f5e3Sopenharmony_ci int32_t virtualIndex = declaredNumArgs + callFieldNumVregs + 3684514f5e3Sopenharmony_ci static_cast<int32_t>(method->GetNumRevervedArgs()) - 1; 3694514f5e3Sopenharmony_ci if (!frameWriter->Reserve(static_cast<size_t>(virtualIndex))) { 3704514f5e3Sopenharmony_ci return false; 3714514f5e3Sopenharmony_ci } 3724514f5e3Sopenharmony_ci for (int32_t i = static_cast<int32_t>(declaredNumArgs - 1); i >= 0; i--) { 3734514f5e3Sopenharmony_ci JSTaggedValue value = JSTaggedValue::Undefined(); 3744514f5e3Sopenharmony_ci // deopt value 3754514f5e3Sopenharmony_ci if (HasDeoptValue(curDepth, virtualIndex)) { 3764514f5e3Sopenharmony_ci value = GetDeoptValue(curDepth, virtualIndex); 3774514f5e3Sopenharmony_ci } 3784514f5e3Sopenharmony_ci frameWriter->PushValue(value.GetRawData()); 3794514f5e3Sopenharmony_ci virtualIndex--; 3804514f5e3Sopenharmony_ci } 3814514f5e3Sopenharmony_ci 3824514f5e3Sopenharmony_ci // [reserved args] 3834514f5e3Sopenharmony_ci if (method->HaveThisWithCallField()) { 3844514f5e3Sopenharmony_ci JSTaggedValue value = deoptVregs_.at( 3854514f5e3Sopenharmony_ci {curDepth, static_cast<OffsetType>(SpecVregIndex::THIS_OBJECT_INDEX)}).GetTaggedValue(); 3864514f5e3Sopenharmony_ci frameWriter->PushValue(value.GetRawData()); 3874514f5e3Sopenharmony_ci virtualIndex--; 3884514f5e3Sopenharmony_ci } 3894514f5e3Sopenharmony_ci if (method->HaveNewTargetWithCallField()) { 3904514f5e3Sopenharmony_ci JSTaggedValue value = deoptVregs_.at( 3914514f5e3Sopenharmony_ci {curDepth, static_cast<OffsetType>(SpecVregIndex::NEWTARGET_INDEX)}).GetTaggedValue(); 3924514f5e3Sopenharmony_ci frameWriter->PushValue(value.GetRawData()); 3934514f5e3Sopenharmony_ci virtualIndex--; 3944514f5e3Sopenharmony_ci } 3954514f5e3Sopenharmony_ci if (method->HaveFuncWithCallField()) { 3964514f5e3Sopenharmony_ci JSTaggedValue value = deoptVregs_.at( 3974514f5e3Sopenharmony_ci {curDepth, static_cast<OffsetType>(SpecVregIndex::FUNC_INDEX)}).GetTaggedValue(); 3984514f5e3Sopenharmony_ci frameWriter->PushValue(value.GetRawData()); 3994514f5e3Sopenharmony_ci virtualIndex--; 4004514f5e3Sopenharmony_ci } 4014514f5e3Sopenharmony_ci 4024514f5e3Sopenharmony_ci // [call field virtual regs] 4034514f5e3Sopenharmony_ci for (int32_t i = virtualIndex; i >= 0; i--) { 4044514f5e3Sopenharmony_ci JSTaggedValue value = GetDeoptValue(curDepth, virtualIndex); 4054514f5e3Sopenharmony_ci frameWriter->PushValue(value.GetRawData()); 4064514f5e3Sopenharmony_ci virtualIndex--; 4074514f5e3Sopenharmony_ci } 4084514f5e3Sopenharmony_ci // revise correct a0 - aN virtual regs , for example: ldobjbyname key; sta a2; update value to a2 4094514f5e3Sopenharmony_ci // +--------------------------+ ^ 4104514f5e3Sopenharmony_ci // | aN | | 4114514f5e3Sopenharmony_ci // +--------------------------+ | 4124514f5e3Sopenharmony_ci // | ... | | 4134514f5e3Sopenharmony_ci // +--------------------------+ | 4144514f5e3Sopenharmony_ci // | a2(this) | | 4154514f5e3Sopenharmony_ci // +--------------------------+ revise correct vreg 4164514f5e3Sopenharmony_ci // | a1(newtarget) | | 4174514f5e3Sopenharmony_ci // +--------------------------+ | 4184514f5e3Sopenharmony_ci // | a0(func) | | 4194514f5e3Sopenharmony_ci // |--------------------------| v 4204514f5e3Sopenharmony_ci // | v0 - vN | 4214514f5e3Sopenharmony_ci // sp --> |--------------------------| 4224514f5e3Sopenharmony_ci int32_t vregsAndArgsNum = declaredNumArgs + callFieldNumVregs + 4234514f5e3Sopenharmony_ci static_cast<int32_t>(method->GetNumRevervedArgs()); 4244514f5e3Sopenharmony_ci for (int32_t i = callFieldNumVregs; i < vregsAndArgsNum; i++) { 4254514f5e3Sopenharmony_ci JSTaggedValue value = JSTaggedValue::Undefined(); 4264514f5e3Sopenharmony_ci if (HasDeoptValue(curDepth, i)) { 4274514f5e3Sopenharmony_ci value = GetDeoptValue(curDepth, i); 4284514f5e3Sopenharmony_ci frameWriter->ReviseValueByIndex(value.GetRawData(), i); 4294514f5e3Sopenharmony_ci } 4304514f5e3Sopenharmony_ci } 4314514f5e3Sopenharmony_ci return true; 4324514f5e3Sopenharmony_ci} 4334514f5e3Sopenharmony_ci 4344514f5e3Sopenharmony_civoid Deoptimizier::Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth) 4354514f5e3Sopenharmony_ci{ 4364514f5e3Sopenharmony_ci if (thread_->IsPGOProfilerEnable()) { 4374514f5e3Sopenharmony_ci JSFunction *function = JSFunction::Cast(callTarget); 4384514f5e3Sopenharmony_ci auto profileTypeInfo = function->GetProfileTypeInfo(); 4394514f5e3Sopenharmony_ci if (profileTypeInfo.IsUndefined()) { 4404514f5e3Sopenharmony_ci SlowRuntimeStub::NotifyInlineCache(thread_, function); 4414514f5e3Sopenharmony_ci } 4424514f5e3Sopenharmony_ci } 4434514f5e3Sopenharmony_ci if (traceDeopt_) { 4444514f5e3Sopenharmony_ci std::string checkType = DisplayItems(type); 4454514f5e3Sopenharmony_ci LOG_TRACE(INFO) << "Check Type: " << checkType; 4464514f5e3Sopenharmony_ci std::string data = JsStackInfo::BuildJsStackTrace(thread_, true); 4474514f5e3Sopenharmony_ci LOG_COMPILER(INFO) << "Deoptimize" << data; 4484514f5e3Sopenharmony_ci const uint8_t *pc = GetMethod(callTarget)->GetBytecodeArray() + pc_.at(depth); 4494514f5e3Sopenharmony_ci BytecodeInstruction inst(pc); 4504514f5e3Sopenharmony_ci LOG_COMPILER(INFO) << inst; 4514514f5e3Sopenharmony_ci } 4524514f5e3Sopenharmony_ci} 4534514f5e3Sopenharmony_ci 4544514f5e3Sopenharmony_cistd::string Deoptimizier::DisplayItems(DeoptType type) 4554514f5e3Sopenharmony_ci{ 4564514f5e3Sopenharmony_ci const std::map<DeoptType, const char *> strMap = { 4574514f5e3Sopenharmony_ci#define DEOPT_NAME_MAP(NAME, TYPE) {DeoptType::TYPE, #NAME}, 4584514f5e3Sopenharmony_ci GATE_META_DATA_DEOPT_REASON(DEOPT_NAME_MAP) 4594514f5e3Sopenharmony_ci#undef DEOPT_NAME_MAP 4604514f5e3Sopenharmony_ci }; 4614514f5e3Sopenharmony_ci if (strMap.count(type) > 0) { 4624514f5e3Sopenharmony_ci return strMap.at(type); 4634514f5e3Sopenharmony_ci } 4644514f5e3Sopenharmony_ci return "DeoptType-" + std::to_string(static_cast<uint8_t>(type)); 4654514f5e3Sopenharmony_ci} 4664514f5e3Sopenharmony_ci 4674514f5e3Sopenharmony_ci// layout of frameWriter 4684514f5e3Sopenharmony_ci// |--------------------------| --------------> start(n) 4694514f5e3Sopenharmony_ci// | args | 4704514f5e3Sopenharmony_ci// | this | 4714514f5e3Sopenharmony_ci// | newTarget | 4724514f5e3Sopenharmony_ci// | callTarget | 4734514f5e3Sopenharmony_ci// | vregs | 4744514f5e3Sopenharmony_ci// |--------------------------- 4754514f5e3Sopenharmony_ci// | ASM Interpreter | 4764514f5e3Sopenharmony_ci// +--------------------------+ --------------> end(n) 4774514f5e3Sopenharmony_ci// | outputcounts | outputcounts = end(n) - start(n) 4784514f5e3Sopenharmony_ci// |--------------------------| --------------> start(n-1) 4794514f5e3Sopenharmony_ci// | args | 4804514f5e3Sopenharmony_ci// | this | 4814514f5e3Sopenharmony_ci// | newTarget | 4824514f5e3Sopenharmony_ci// | callTarget | 4834514f5e3Sopenharmony_ci// | vregs | 4844514f5e3Sopenharmony_ci// |------------------------------------------- 4854514f5e3Sopenharmony_ci// | ASM Interpreter | 4864514f5e3Sopenharmony_ci// +--------------------------+ --------------> end(n-1) 4874514f5e3Sopenharmony_ci// | outputcounts | outputcounts = end(n-1) - start(n-1) 4884514f5e3Sopenharmony_ci// |--------------------------| --------------> start(n-1) 4894514f5e3Sopenharmony_ci// | ...... | 4904514f5e3Sopenharmony_ci// +--------------------------+ --------------- 4914514f5e3Sopenharmony_ci// | callerFp_ | ^ 4924514f5e3Sopenharmony_ci// | returnAddr_ | stackContext 4934514f5e3Sopenharmony_ci// | callFrameTop_ | | 4944514f5e3Sopenharmony_ci// | inlineDepth | v 4954514f5e3Sopenharmony_ci// |--------------------------| --------------- 4964514f5e3Sopenharmony_ci 4974514f5e3Sopenharmony_ciJSTaggedType Deoptimizier::ConstructAsmInterpretFrame() 4984514f5e3Sopenharmony_ci{ 4994514f5e3Sopenharmony_ci FrameWriter frameWriter(this); 5004514f5e3Sopenharmony_ci // Push asm interpreter frame 5014514f5e3Sopenharmony_ci for (int32_t curDepth = static_cast<int32_t>(inlineDepth_); curDepth >= 0; curDepth--) { 5024514f5e3Sopenharmony_ci auto start = frameWriter.GetTop(); 5034514f5e3Sopenharmony_ci JSTaggedValue callTarget = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::FUNC_INDEX)); 5044514f5e3Sopenharmony_ci auto method = GetMethod(callTarget); 5054514f5e3Sopenharmony_ci if (!CollectVirtualRegisters(callTarget, method, &frameWriter, curDepth)) { 5064514f5e3Sopenharmony_ci return JSTaggedValue::Exception().GetRawData(); 5074514f5e3Sopenharmony_ci } 5084514f5e3Sopenharmony_ci AsmInterpretedFrame *statePtr = frameWriter.ReserveAsmInterpretedFrame(); 5094514f5e3Sopenharmony_ci const uint8_t *resumePc = method->GetBytecodeArray() + pc_.at(curDepth); 5104514f5e3Sopenharmony_ci JSTaggedValue thisObj = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::THIS_OBJECT_INDEX)); 5114514f5e3Sopenharmony_ci auto acc = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::ACC_INDEX)); 5124514f5e3Sopenharmony_ci statePtr->function = callTarget; 5134514f5e3Sopenharmony_ci statePtr->acc = acc; 5144514f5e3Sopenharmony_ci statePtr->env = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::ENV_INDEX)); 5154514f5e3Sopenharmony_ci statePtr->callSize = GetCallSize(curDepth, resumePc); 5164514f5e3Sopenharmony_ci statePtr->fp = 0; // need update 5174514f5e3Sopenharmony_ci statePtr->thisObj = thisObj; 5184514f5e3Sopenharmony_ci statePtr->pc = resumePc; 5194514f5e3Sopenharmony_ci // -uintptr_t skip lr 5204514f5e3Sopenharmony_ci if (curDepth == 0) { 5214514f5e3Sopenharmony_ci statePtr->base.prev = reinterpret_cast<JSTaggedType *>(stackContext_.callFrameTop_ - sizeof(uintptr_t)); 5224514f5e3Sopenharmony_ci } else { 5234514f5e3Sopenharmony_ci statePtr->base.prev = 0; // need update 5244514f5e3Sopenharmony_ci } 5254514f5e3Sopenharmony_ci 5264514f5e3Sopenharmony_ci statePtr->base.type = FrameType::ASM_INTERPRETER_FRAME; 5274514f5e3Sopenharmony_ci 5284514f5e3Sopenharmony_ci // construct stack context 5294514f5e3Sopenharmony_ci auto end = frameWriter.GetTop(); 5304514f5e3Sopenharmony_ci auto outputCount = start - end; 5314514f5e3Sopenharmony_ci frameWriter.PushRawValue(outputCount); 5324514f5e3Sopenharmony_ci } 5334514f5e3Sopenharmony_ci 5344514f5e3Sopenharmony_ci RelocateCalleeSave(); 5354514f5e3Sopenharmony_ci 5364514f5e3Sopenharmony_ci frameWriter.PushRawValue(stackContext_.callerFp_); 5374514f5e3Sopenharmony_ci frameWriter.PushRawValue(stackContext_.returnAddr_); 5384514f5e3Sopenharmony_ci frameWriter.PushRawValue(stackContext_.callFrameTop_); 5394514f5e3Sopenharmony_ci frameWriter.PushRawValue(inlineDepth_); 5404514f5e3Sopenharmony_ci return reinterpret_cast<JSTaggedType>(frameWriter.GetTop()); 5414514f5e3Sopenharmony_ci} 5424514f5e3Sopenharmony_ci 5434514f5e3Sopenharmony_civoid Deoptimizier::ResetJitHotness(JSFunction *jsFunc) const 5444514f5e3Sopenharmony_ci{ 5454514f5e3Sopenharmony_ci if (jsFunc->GetMachineCode().IsMachineCodeObject()) { 5464514f5e3Sopenharmony_ci JSTaggedValue profileTypeInfoVal = jsFunc->GetProfileTypeInfo(); 5474514f5e3Sopenharmony_ci if (!profileTypeInfoVal.IsUndefined()) { 5484514f5e3Sopenharmony_ci ProfileTypeInfo *profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject()); 5494514f5e3Sopenharmony_ci profileTypeInfo->SetJitHotnessCnt(0); 5504514f5e3Sopenharmony_ci constexpr uint16_t thresholdStep = 4; 5514514f5e3Sopenharmony_ci constexpr uint16_t thresholdLimit = ProfileTypeInfo::JIT_DISABLE_FLAG / thresholdStep; 5524514f5e3Sopenharmony_ci uint16_t threshold = profileTypeInfo->GetJitHotnessThreshold(); 5534514f5e3Sopenharmony_ci threshold = threshold >= thresholdLimit ? ProfileTypeInfo::JIT_DISABLE_FLAG : threshold * thresholdStep; 5544514f5e3Sopenharmony_ci profileTypeInfo->SetJitHotnessThreshold(threshold); 5554514f5e3Sopenharmony_ci ProfileTypeInfoCell::Cast(jsFunc->GetRawProfileTypeInfo())->SetMachineCode(thread_, JSTaggedValue::Hole()); 5564514f5e3Sopenharmony_ci Method *method = Method::Cast(jsFunc->GetMethod().GetTaggedObject()); 5574514f5e3Sopenharmony_ci LOG_JIT(DEBUG) << "reset jit hotness for func: " << method->GetMethodName() << ", threshold:" << threshold; 5584514f5e3Sopenharmony_ci } 5594514f5e3Sopenharmony_ci } 5604514f5e3Sopenharmony_ci} 5614514f5e3Sopenharmony_ci 5624514f5e3Sopenharmony_civoid Deoptimizier::ClearCompiledCodeStatusWhenDeopt(JSFunction *func, Method *method) 5634514f5e3Sopenharmony_ci{ 5644514f5e3Sopenharmony_ci if (func->GetMachineCode().IsMachineCodeObject()) { 5654514f5e3Sopenharmony_ci Jit::GetInstance()->GetJitDfx()->SetJitDeoptCount(); 5664514f5e3Sopenharmony_ci } 5674514f5e3Sopenharmony_ci if (func->IsCompiledCode()) { 5684514f5e3Sopenharmony_ci bool isFastCall = func->IsCompiledFastCall(); // get this flag before clear it 5694514f5e3Sopenharmony_ci uintptr_t entry = 5704514f5e3Sopenharmony_ci isFastCall ? thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_FastCallToAsmInterBridge) 5714514f5e3Sopenharmony_ci : thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_AOTCallToAsmInterBridge); 5724514f5e3Sopenharmony_ci func->SetCodeEntry(entry); 5734514f5e3Sopenharmony_ci method->ClearAOTStatusWhenDeopt(entry); 5744514f5e3Sopenharmony_ci func->ClearCompiledCodeFlags(); 5754514f5e3Sopenharmony_ci ResetJitHotness(func); 5764514f5e3Sopenharmony_ci func->ClearMachineCode(thread_); 5774514f5e3Sopenharmony_ci } // Do not change the func code entry if the method is not aot or deopt has happened already 5784514f5e3Sopenharmony_ci} 5794514f5e3Sopenharmony_ci 5804514f5e3Sopenharmony_civoid Deoptimizier::UpdateAndDumpDeoptInfo(kungfu::DeoptType type) 5814514f5e3Sopenharmony_ci{ 5824514f5e3Sopenharmony_ci // depth records the number of layers of nested calls when deopt occurs 5834514f5e3Sopenharmony_ci for (size_t i = 0; i <= inlineDepth_; i++) { 5844514f5e3Sopenharmony_ci JSTaggedValue callTarget = GetDeoptValue(i, static_cast<int32_t>(SpecVregIndex::FUNC_INDEX)); 5854514f5e3Sopenharmony_ci auto func = JSFunction::Cast(callTarget.GetTaggedObject()); 5864514f5e3Sopenharmony_ci if (func->GetMachineCode().IsMachineCodeObject()) { 5874514f5e3Sopenharmony_ci MachineCode *machineCode = MachineCode::Cast(func->GetMachineCode().GetTaggedObject()); 5884514f5e3Sopenharmony_ci if (type != kungfu::DeoptType::OSRLOOPEXIT && 5894514f5e3Sopenharmony_ci machineCode->GetOSROffset() != MachineCode::INVALID_OSR_OFFSET) { 5904514f5e3Sopenharmony_ci machineCode->SetOsrDeoptFlag(true); 5914514f5e3Sopenharmony_ci } 5924514f5e3Sopenharmony_ci } 5934514f5e3Sopenharmony_ci auto method = GetMethod(callTarget); 5944514f5e3Sopenharmony_ci if (i == inlineDepth_) { 5954514f5e3Sopenharmony_ci Dump(callTarget, type, i); 5964514f5e3Sopenharmony_ci } 5974514f5e3Sopenharmony_ci ASSERT(thread_ != nullptr); 5984514f5e3Sopenharmony_ci uint8_t deoptThreshold = method->GetDeoptThreshold(); 5994514f5e3Sopenharmony_ci if (deoptThreshold > 0) { 6004514f5e3Sopenharmony_ci method->SetDeoptType(type); 6014514f5e3Sopenharmony_ci method->SetDeoptThreshold(--deoptThreshold); 6024514f5e3Sopenharmony_ci } else { 6034514f5e3Sopenharmony_ci ClearCompiledCodeStatusWhenDeopt(func, method); 6044514f5e3Sopenharmony_ci } 6054514f5e3Sopenharmony_ci } 6064514f5e3Sopenharmony_ci} 6074514f5e3Sopenharmony_ci 6084514f5e3Sopenharmony_ci// call instructions need compute jumpSize 6094514f5e3Sopenharmony_cisize_t Deoptimizier::GetCallSize(size_t curDepth, const uint8_t *resumePc) 6104514f5e3Sopenharmony_ci{ 6114514f5e3Sopenharmony_ci if (inlineDepth_ > 0 && curDepth != inlineDepth_) { 6124514f5e3Sopenharmony_ci auto op = BytecodeInstruction(resumePc).GetOpcode(); 6134514f5e3Sopenharmony_ci size_t jumpSize = BytecodeInstruction::Size(op); 6144514f5e3Sopenharmony_ci return jumpSize; 6154514f5e3Sopenharmony_ci } 6164514f5e3Sopenharmony_ci return 0; 6174514f5e3Sopenharmony_ci} 6184514f5e3Sopenharmony_ci 6194514f5e3Sopenharmony_ciint32_t Deoptimizier::EncodeDeoptVregIndex(int32_t index, size_t depth, size_t shift) 6204514f5e3Sopenharmony_ci{ 6214514f5e3Sopenharmony_ci if (index >= 0) { 6224514f5e3Sopenharmony_ci return (index << shift) | depth; 6234514f5e3Sopenharmony_ci } 6244514f5e3Sopenharmony_ci return -((-index << shift) | depth); 6254514f5e3Sopenharmony_ci} 6264514f5e3Sopenharmony_ci 6274514f5e3Sopenharmony_cisize_t Deoptimizier::ComputeShift(size_t depth) 6284514f5e3Sopenharmony_ci{ 6294514f5e3Sopenharmony_ci size_t shift = 0; 6304514f5e3Sopenharmony_ci if (depth != 0) { 6314514f5e3Sopenharmony_ci shift = std::floor(std::log2(depth)) + 1; 6324514f5e3Sopenharmony_ci } 6334514f5e3Sopenharmony_ci return shift; 6344514f5e3Sopenharmony_ci} 6354514f5e3Sopenharmony_ci 6364514f5e3Sopenharmony_ciint32_t Deoptimizier::DecodeVregIndex(OffsetType id, size_t shift) 6374514f5e3Sopenharmony_ci{ 6384514f5e3Sopenharmony_ci if (id >= 0) { 6394514f5e3Sopenharmony_ci return id >> shift; 6404514f5e3Sopenharmony_ci } 6414514f5e3Sopenharmony_ci return -((-id) >> shift); 6424514f5e3Sopenharmony_ci} 6434514f5e3Sopenharmony_ci 6444514f5e3Sopenharmony_cisize_t Deoptimizier::DecodeDeoptDepth(OffsetType id, size_t shift) 6454514f5e3Sopenharmony_ci{ 6464514f5e3Sopenharmony_ci size_t mask = (1 << shift) - 1; 6474514f5e3Sopenharmony_ci if (id >= 0) { 6484514f5e3Sopenharmony_ci return id & mask; 6494514f5e3Sopenharmony_ci } 6504514f5e3Sopenharmony_ci return (-id) & mask; 6514514f5e3Sopenharmony_ci} 6524514f5e3Sopenharmony_ci} // namespace panda::ecmascript 653