1/* 2 * Copyright (c) 2022-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#include "ecmascript/deoptimizer/deoptimizer.h" 16 17#include <cmath> 18 19#include "ecmascript/dfx/stackinfo/js_stackinfo.h" 20#include "ecmascript/interpreter/slow_runtime_stub.h" 21#include "ecmascript/jit/jit.h" 22#include "ecmascript/stubs/runtime_stubs-inl.h" 23 24namespace panda::ecmascript { 25class FrameWriter { 26public: 27 explicit FrameWriter(Deoptimizier *deoptimizier) : thread_(deoptimizier->GetThread()) 28 { 29 JSTaggedType *prevSp = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame()); 30 start_ = top_ = EcmaInterpreter::GetInterpreterFrameEnd(thread_, prevSp); 31 } 32 33 void PushValue(JSTaggedType value) 34 { 35 *(--top_) = value; 36 } 37 38 void PushRawValue(uintptr_t value) 39 { 40 *(--top_) = value; 41 } 42 43 bool Reserve(size_t size) 44 { 45 return !thread_->DoStackOverflowCheck(top_ - size); 46 } 47 48 AsmInterpretedFrame *ReserveAsmInterpretedFrame() 49 { 50 auto frame = AsmInterpretedFrame::GetFrameFromSp(top_); 51 top_ = reinterpret_cast<JSTaggedType *>(frame); 52 return frame; 53 } 54 55 JSTaggedType *GetStart() const 56 { 57 return start_; 58 } 59 60 JSTaggedType *GetTop() const 61 { 62 return top_; 63 } 64 65 JSTaggedType *GetFirstFrame() const 66 { 67 return firstFrame_; 68 } 69 70 void RecordFirstFrame() 71 { 72 firstFrame_ = top_; 73 } 74 75 void ReviseValueByIndex(JSTaggedType value, size_t index) 76 { 77 ASSERT(index < static_cast<size_t>(start_ - top_)); 78 *(top_ + index) = value; 79 } 80 81private: 82 JSThread *thread_ {nullptr}; 83 JSTaggedType *start_ {nullptr}; 84 JSTaggedType *top_ {nullptr}; 85 JSTaggedType *firstFrame_ {nullptr}; 86}; 87 88Deoptimizier::Deoptimizier(JSThread *thread, size_t depth) : thread_(thread), inlineDepth_(depth) 89{ 90 CalleeReg callreg; 91 numCalleeRegs_ = static_cast<size_t>(callreg.GetCallRegNum()); 92 JSRuntimeOptions options = thread_->GetEcmaVM()->GetJSOptions(); 93 traceDeopt_ = options.GetTraceDeopt(); 94} 95 96void Deoptimizier::CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle, size_t shift) 97{ 98 deoptVregs_.clear(); 99 for (size_t i = 0; i < deoptBundle.size(); i++) { 100 ARKDeopt deopt = deoptBundle.at(i); 101 JSTaggedType v; 102 VRegId id = deopt.id; 103 if (std::holds_alternative<DwarfRegAndOffsetType>(deopt.value)) { 104 ASSERT(deopt.kind == LocationTy::Kind::INDIRECT); 105 auto value = std::get<DwarfRegAndOffsetType>(deopt.value); 106 DwarfRegType dwarfReg = value.first; 107 OffsetType offset = value.second; 108 ASSERT (dwarfReg == GCStackMapRegisters::FP || dwarfReg == GCStackMapRegisters::SP); 109 uintptr_t addr; 110 if (dwarfReg == GCStackMapRegisters::SP) { 111 addr = context_.callsiteSp + offset; 112 } else { 113 addr = context_.callsiteFp + offset; 114 } 115 v = *(reinterpret_cast<JSTaggedType *>(addr)); 116 } else if (std::holds_alternative<LargeInt>(deopt.value)) { 117 ASSERT(deopt.kind == LocationTy::Kind::CONSTANTNDEX); 118 v = JSTaggedType(static_cast<int64_t>(std::get<LargeInt>(deopt.value))); 119 } else { 120 ASSERT(std::holds_alternative<IntType>(deopt.value)); 121 ASSERT(deopt.kind == LocationTy::Kind::CONSTANT); 122 v = JSTaggedType(static_cast<int64_t>(std::get<IntType>(deopt.value))); 123 } 124 size_t curDepth = DecodeDeoptDepth(id, shift); 125 OffsetType vregId = static_cast<OffsetType>(DecodeVregIndex(id, shift)); 126 if (vregId != static_cast<OffsetType>(SpecVregIndex::PC_OFFSET_INDEX)) { 127 deoptVregs_.insert({{curDepth, vregId}, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(v))}); 128 } else { 129 pc_.insert({curDepth, static_cast<size_t>(v)}); 130 } 131 } 132} 133 134// when AOT trigger deopt, frame layout as the following 135// * OptimizedJSFunctionFrame layout description as the following: 136// +--------------------------+ --------------- 137// | ...... | ^ 138// | ...... | callerFunction 139// | ...... | | 140// |--------------------------| | 141// | args | v 142// +--------------------------+ --------------- 143// | returnAddr | ^ 144// |--------------------------| | 145// | callsiteFp | | 146// |--------------------------| OptimizedJSFunction FrameType:OPTIMIZED_JS_FUNCTION_FRAME 147// | frameType | | 148// |--------------------------| | 149// | call-target | | 150// |--------------------------| | 151// | lexEnv | | 152// |--------------------------| | 153// | ........... | v 154// +--------------------------+ --------------- 155// | returnAddr | ^ 156// |--------------------------| | 157// | callsiteFp | | 158// |--------------------------| __llvm_deoptimize FrameType:OPTIMIZED_FRAME 159// | frameType | | 160// |--------------------------| | 161// | No CalleeSave | | 162// | Registers | v 163// +--------------------------+ --------------- 164// | returnAddr | ^ 165// |--------------------------| | 166// | callsiteFp | | 167// |--------------------------| DeoptHandlerAsm FrameType:ASM_BRIDGE_FRAME 168// | frameType | | 169// |--------------------------| | 170// | glue | | 171// |--------------------------| | 172// | CalleeSave Registers | v 173// +--------------------------+ --------------- 174// | ......... | ^ 175// | ......... | CallRuntime FrameType:LEAVE_FRAME 176// | ......... | | 177// | ......... | v 178// |--------------------------| --------------- 179 180// After gathering the necessary information(After Call Runtime), frame layout after constructing 181// asminterpreterframe is shown as the following: 182// +----------------------------------+---------+ 183// | ...... | ^ 184// | ...... | callerFunction 185// | ...... | | 186// |----------------------------------| | 187// | args | v 188// +----------------------------------+---------+ 189// | returnAddr | ^ 190// |----------------------------------| | 191// | frameType | | 192// |----------------------------------| ASM_INTERPRETER_BRIDGE_FRAME 193// | callsiteFp | | 194// |----------------------------------| | 195// | ........... | v 196// +----------------------------------+---------+ 197// | returnAddr | 198// |----------------------------------| 199// | argv[n-1] | 200// |----------------------------------| 201// | ...... | 202// |----------------------------------| 203// | thisArg [maybe not exist] | 204// |----------------------------------| 205// | newTarget [maybe not exist] | 206// |----------------------------------| 207// | ...... | 208// |----------------------------------| 209// | Vregs [not exist in native] | 210// +----------------------------------+--------+ 211// | . . . . | ^ 212// | InterpretedFrameBase | | 213// | . . . . | | 214// |----------------------------------| | 215// | pc(bytecode addr) | | 216// |----------------------------------| | 217// | sp(current stack pointer) | | 218// |----------------------------------| AsmInterpretedFrame 0 219// | callSize | | 220// |----------------------------------| | 221// | env | | 222// |----------------------------------| | 223// | acc | | 224// |----------------------------------| | 225// | thisObj | | 226// |----------------------------------| | 227// | call-target | v 228// +----------------------------------+--------+ 229// | argv[n-1] | 230// |----------------------------------| 231// | ...... | 232// |----------------------------------| 233// | thisArg [maybe not exist] | 234// |----------------------------------| 235// | newTarget [maybe not exist] | 236// |----------------------------------| 237// | ...... | 238// |----------------------------------| 239// | Vregs [not exist in native] | 240// +----------------------------------+--------+ 241// | . . . . | ^ 242// | InterpretedFrameBase | | 243// | . . . . | | 244// |----------------------------------| | 245// | pc(bytecode addr) | | 246// |----------------------------------| | 247// | sp(current stack pointer) | | 248// |----------------------------------| AsmInterpretedFrame 1 249// | callSize | | 250// |----------------------------------| | 251// | env | | 252// |----------------------------------| | 253// | acc | | 254// |----------------------------------| | 255// | thisObj | | 256// |----------------------------------| | 257// | call-target | v 258// +----------------------------------+--------+ 259// | . . . . | ^ 260// | . . . . | AsmInterpretedFrame n 261// | . . . . | v 262// +----------------------------------+--------+ 263 264template<class T> 265void Deoptimizier::AssistCollectDeoptBundleVec(FrameIterator &it, T &frame) 266{ 267 CalleeRegAndOffsetVec calleeRegInfo; 268 frame->GetFuncCalleeRegAndOffset(it, calleeRegInfo); 269 context_.calleeRegAndOffset = calleeRegInfo; 270 context_.callsiteSp = it.GetCallSiteSp(); 271 context_.callsiteFp = reinterpret_cast<uintptr_t>(it.GetSp()); 272 auto preFrameSp = frame->ComputePrevFrameSp(it); 273 frameArgc_ = frame->GetArgc(preFrameSp); 274 frameArgvs_ = frame->GetArgv(preFrameSp); 275 stackContext_.callFrameTop_ = it.GetPrevFrameCallSiteSp(); 276 stackContext_.returnAddr_ = frame->GetReturnAddr(); 277 stackContext_.callerFp_ = reinterpret_cast<uintptr_t>(frame->GetPrevFrameFp()); 278} 279 280void Deoptimizier::CollectDeoptBundleVec(std::vector<ARKDeopt>& deoptBundle) 281{ 282 JSTaggedType *lastLeave = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame()); 283 FrameIterator it(lastLeave, thread_); 284 // note: last deopt bridge frame is generated by DeoptHandlerAsm, callee Regs is grow from this frame 285 for (; !it.Done() && deoptBundle.empty(); it.Advance<GCVisitedFlag::DEOPT>()) { 286 FrameType type = it.GetFrameType(); 287 switch (type) { 288 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 289 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { 290 auto frame = it.GetFrame<OptimizedJSFunctionFrame>(); 291 frame->GetDeoptBundleInfo(it, deoptBundle); 292 AssistCollectDeoptBundleVec(it, frame); 293 break; 294 } 295 case FrameType::FASTJIT_FUNCTION_FRAME: 296 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 297 auto frame = it.GetFrame<FASTJITFunctionFrame>(); 298 frame->GetDeoptBundleInfo(it, deoptBundle); 299 AssistCollectDeoptBundleVec(it, frame); 300 break; 301 } 302 case FrameType::ASM_BRIDGE_FRAME: { 303 auto sp = reinterpret_cast<uintptr_t*>(it.GetSp()); 304 static constexpr size_t TYPE_GLUE_SLOT = 2; // 2: skip type & glue 305 sp -= TYPE_GLUE_SLOT; 306 calleeRegAddr_ = sp - numCalleeRegs_; 307 break; 308 } 309 case FrameType::OPTIMIZED_FRAME: 310 case FrameType::LEAVE_FRAME: 311 break; 312 default: { 313 LOG_FULL(FATAL) << "frame type error!"; 314 UNREACHABLE(); 315 } 316 } 317 } 318 ASSERT(!it.Done()); 319} 320 321Method* Deoptimizier::GetMethod(JSTaggedValue &target) 322{ 323 ECMAObject *callTarget = reinterpret_cast<ECMAObject*>(target.GetTaggedObject()); 324 ASSERT(callTarget != nullptr); 325 Method *method = callTarget->GetCallTarget(); 326 return method; 327} 328 329void Deoptimizier::RelocateCalleeSave() 330{ 331 CalleeReg callreg; 332 for (auto &it: context_.calleeRegAndOffset) { 333 auto reg = it.first; 334 auto offset = it.second; 335 uintptr_t value = *(reinterpret_cast<uintptr_t *>(context_.callsiteFp + offset)); 336 int order = callreg.FindCallRegOrder(reg); 337 calleeRegAddr_[order] = value; 338 } 339} 340 341bool Deoptimizier::CollectVirtualRegisters(JSTaggedValue callTarget, Method *method, FrameWriter *frameWriter, 342 size_t curDepth) 343{ 344 int32_t actualNumArgs = 0; 345 int32_t declaredNumArgs = 0; 346 if (curDepth == 0) { 347 actualNumArgs = static_cast<int32_t>(GetDeoptValue(curDepth, 348 static_cast<int32_t>(SpecVregIndex::ACTUAL_ARGC_INDEX)).GetInt()); 349 declaredNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField()); 350 } else { 351 // inline method actualNumArgs equal to declaredNumArgs 352 actualNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField()); 353 declaredNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField()); 354 } 355 356 int32_t callFieldNumVregs = static_cast<int32_t>(method->GetNumVregsWithCallField()); 357 358 // layout of frame: 359 // [maybe argc] [actual args] [reserved args] [call field virtual regs] 360 361 // [maybe argc] 362 bool isFastCall = JSFunctionBase::IsFastCallFromCallTarget(callTarget); 363 if (!isFastCall && declaredNumArgs != actualNumArgs) { 364 auto value = JSTaggedValue(actualNumArgs); 365 frameWriter->PushValue(value.GetRawData()); 366 } 367 int32_t virtualIndex = declaredNumArgs + callFieldNumVregs + 368 static_cast<int32_t>(method->GetNumRevervedArgs()) - 1; 369 if (!frameWriter->Reserve(static_cast<size_t>(virtualIndex))) { 370 return false; 371 } 372 for (int32_t i = static_cast<int32_t>(declaredNumArgs - 1); i >= 0; i--) { 373 JSTaggedValue value = JSTaggedValue::Undefined(); 374 // deopt value 375 if (HasDeoptValue(curDepth, virtualIndex)) { 376 value = GetDeoptValue(curDepth, virtualIndex); 377 } 378 frameWriter->PushValue(value.GetRawData()); 379 virtualIndex--; 380 } 381 382 // [reserved args] 383 if (method->HaveThisWithCallField()) { 384 JSTaggedValue value = deoptVregs_.at( 385 {curDepth, static_cast<OffsetType>(SpecVregIndex::THIS_OBJECT_INDEX)}).GetTaggedValue(); 386 frameWriter->PushValue(value.GetRawData()); 387 virtualIndex--; 388 } 389 if (method->HaveNewTargetWithCallField()) { 390 JSTaggedValue value = deoptVregs_.at( 391 {curDepth, static_cast<OffsetType>(SpecVregIndex::NEWTARGET_INDEX)}).GetTaggedValue(); 392 frameWriter->PushValue(value.GetRawData()); 393 virtualIndex--; 394 } 395 if (method->HaveFuncWithCallField()) { 396 JSTaggedValue value = deoptVregs_.at( 397 {curDepth, static_cast<OffsetType>(SpecVregIndex::FUNC_INDEX)}).GetTaggedValue(); 398 frameWriter->PushValue(value.GetRawData()); 399 virtualIndex--; 400 } 401 402 // [call field virtual regs] 403 for (int32_t i = virtualIndex; i >= 0; i--) { 404 JSTaggedValue value = GetDeoptValue(curDepth, virtualIndex); 405 frameWriter->PushValue(value.GetRawData()); 406 virtualIndex--; 407 } 408 // revise correct a0 - aN virtual regs , for example: ldobjbyname key; sta a2; update value to a2 409 // +--------------------------+ ^ 410 // | aN | | 411 // +--------------------------+ | 412 // | ... | | 413 // +--------------------------+ | 414 // | a2(this) | | 415 // +--------------------------+ revise correct vreg 416 // | a1(newtarget) | | 417 // +--------------------------+ | 418 // | a0(func) | | 419 // |--------------------------| v 420 // | v0 - vN | 421 // sp --> |--------------------------| 422 int32_t vregsAndArgsNum = declaredNumArgs + callFieldNumVregs + 423 static_cast<int32_t>(method->GetNumRevervedArgs()); 424 for (int32_t i = callFieldNumVregs; i < vregsAndArgsNum; i++) { 425 JSTaggedValue value = JSTaggedValue::Undefined(); 426 if (HasDeoptValue(curDepth, i)) { 427 value = GetDeoptValue(curDepth, i); 428 frameWriter->ReviseValueByIndex(value.GetRawData(), i); 429 } 430 } 431 return true; 432} 433 434void Deoptimizier::Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth) 435{ 436 if (thread_->IsPGOProfilerEnable()) { 437 JSFunction *function = JSFunction::Cast(callTarget); 438 auto profileTypeInfo = function->GetProfileTypeInfo(); 439 if (profileTypeInfo.IsUndefined()) { 440 SlowRuntimeStub::NotifyInlineCache(thread_, function); 441 } 442 } 443 if (traceDeopt_) { 444 std::string checkType = DisplayItems(type); 445 LOG_TRACE(INFO) << "Check Type: " << checkType; 446 std::string data = JsStackInfo::BuildJsStackTrace(thread_, true); 447 LOG_COMPILER(INFO) << "Deoptimize" << data; 448 const uint8_t *pc = GetMethod(callTarget)->GetBytecodeArray() + pc_.at(depth); 449 BytecodeInstruction inst(pc); 450 LOG_COMPILER(INFO) << inst; 451 } 452} 453 454std::string Deoptimizier::DisplayItems(DeoptType type) 455{ 456 const std::map<DeoptType, const char *> strMap = { 457#define DEOPT_NAME_MAP(NAME, TYPE) {DeoptType::TYPE, #NAME}, 458 GATE_META_DATA_DEOPT_REASON(DEOPT_NAME_MAP) 459#undef DEOPT_NAME_MAP 460 }; 461 if (strMap.count(type) > 0) { 462 return strMap.at(type); 463 } 464 return "DeoptType-" + std::to_string(static_cast<uint8_t>(type)); 465} 466 467// layout of frameWriter 468// |--------------------------| --------------> start(n) 469// | args | 470// | this | 471// | newTarget | 472// | callTarget | 473// | vregs | 474// |--------------------------- 475// | ASM Interpreter | 476// +--------------------------+ --------------> end(n) 477// | outputcounts | outputcounts = end(n) - start(n) 478// |--------------------------| --------------> start(n-1) 479// | args | 480// | this | 481// | newTarget | 482// | callTarget | 483// | vregs | 484// |------------------------------------------- 485// | ASM Interpreter | 486// +--------------------------+ --------------> end(n-1) 487// | outputcounts | outputcounts = end(n-1) - start(n-1) 488// |--------------------------| --------------> start(n-1) 489// | ...... | 490// +--------------------------+ --------------- 491// | callerFp_ | ^ 492// | returnAddr_ | stackContext 493// | callFrameTop_ | | 494// | inlineDepth | v 495// |--------------------------| --------------- 496 497JSTaggedType Deoptimizier::ConstructAsmInterpretFrame() 498{ 499 FrameWriter frameWriter(this); 500 // Push asm interpreter frame 501 for (int32_t curDepth = static_cast<int32_t>(inlineDepth_); curDepth >= 0; curDepth--) { 502 auto start = frameWriter.GetTop(); 503 JSTaggedValue callTarget = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::FUNC_INDEX)); 504 auto method = GetMethod(callTarget); 505 if (!CollectVirtualRegisters(callTarget, method, &frameWriter, curDepth)) { 506 return JSTaggedValue::Exception().GetRawData(); 507 } 508 AsmInterpretedFrame *statePtr = frameWriter.ReserveAsmInterpretedFrame(); 509 const uint8_t *resumePc = method->GetBytecodeArray() + pc_.at(curDepth); 510 JSTaggedValue thisObj = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::THIS_OBJECT_INDEX)); 511 auto acc = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::ACC_INDEX)); 512 statePtr->function = callTarget; 513 statePtr->acc = acc; 514 statePtr->env = GetDeoptValue(curDepth, static_cast<int32_t>(SpecVregIndex::ENV_INDEX)); 515 statePtr->callSize = GetCallSize(curDepth, resumePc); 516 statePtr->fp = 0; // need update 517 statePtr->thisObj = thisObj; 518 statePtr->pc = resumePc; 519 // -uintptr_t skip lr 520 if (curDepth == 0) { 521 statePtr->base.prev = reinterpret_cast<JSTaggedType *>(stackContext_.callFrameTop_ - sizeof(uintptr_t)); 522 } else { 523 statePtr->base.prev = 0; // need update 524 } 525 526 statePtr->base.type = FrameType::ASM_INTERPRETER_FRAME; 527 528 // construct stack context 529 auto end = frameWriter.GetTop(); 530 auto outputCount = start - end; 531 frameWriter.PushRawValue(outputCount); 532 } 533 534 RelocateCalleeSave(); 535 536 frameWriter.PushRawValue(stackContext_.callerFp_); 537 frameWriter.PushRawValue(stackContext_.returnAddr_); 538 frameWriter.PushRawValue(stackContext_.callFrameTop_); 539 frameWriter.PushRawValue(inlineDepth_); 540 return reinterpret_cast<JSTaggedType>(frameWriter.GetTop()); 541} 542 543void Deoptimizier::ResetJitHotness(JSFunction *jsFunc) const 544{ 545 if (jsFunc->GetMachineCode().IsMachineCodeObject()) { 546 JSTaggedValue profileTypeInfoVal = jsFunc->GetProfileTypeInfo(); 547 if (!profileTypeInfoVal.IsUndefined()) { 548 ProfileTypeInfo *profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject()); 549 profileTypeInfo->SetJitHotnessCnt(0); 550 constexpr uint16_t thresholdStep = 4; 551 constexpr uint16_t thresholdLimit = ProfileTypeInfo::JIT_DISABLE_FLAG / thresholdStep; 552 uint16_t threshold = profileTypeInfo->GetJitHotnessThreshold(); 553 threshold = threshold >= thresholdLimit ? ProfileTypeInfo::JIT_DISABLE_FLAG : threshold * thresholdStep; 554 profileTypeInfo->SetJitHotnessThreshold(threshold); 555 ProfileTypeInfoCell::Cast(jsFunc->GetRawProfileTypeInfo())->SetMachineCode(thread_, JSTaggedValue::Hole()); 556 Method *method = Method::Cast(jsFunc->GetMethod().GetTaggedObject()); 557 LOG_JIT(DEBUG) << "reset jit hotness for func: " << method->GetMethodName() << ", threshold:" << threshold; 558 } 559 } 560} 561 562void Deoptimizier::ClearCompiledCodeStatusWhenDeopt(JSFunction *func, Method *method) 563{ 564 if (func->GetMachineCode().IsMachineCodeObject()) { 565 Jit::GetInstance()->GetJitDfx()->SetJitDeoptCount(); 566 } 567 if (func->IsCompiledCode()) { 568 bool isFastCall = func->IsCompiledFastCall(); // get this flag before clear it 569 uintptr_t entry = 570 isFastCall ? thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_FastCallToAsmInterBridge) 571 : thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_AOTCallToAsmInterBridge); 572 func->SetCodeEntry(entry); 573 method->ClearAOTStatusWhenDeopt(entry); 574 func->ClearCompiledCodeFlags(); 575 ResetJitHotness(func); 576 func->ClearMachineCode(thread_); 577 } // Do not change the func code entry if the method is not aot or deopt has happened already 578} 579 580void Deoptimizier::UpdateAndDumpDeoptInfo(kungfu::DeoptType type) 581{ 582 // depth records the number of layers of nested calls when deopt occurs 583 for (size_t i = 0; i <= inlineDepth_; i++) { 584 JSTaggedValue callTarget = GetDeoptValue(i, static_cast<int32_t>(SpecVregIndex::FUNC_INDEX)); 585 auto func = JSFunction::Cast(callTarget.GetTaggedObject()); 586 if (func->GetMachineCode().IsMachineCodeObject()) { 587 MachineCode *machineCode = MachineCode::Cast(func->GetMachineCode().GetTaggedObject()); 588 if (type != kungfu::DeoptType::OSRLOOPEXIT && 589 machineCode->GetOSROffset() != MachineCode::INVALID_OSR_OFFSET) { 590 machineCode->SetOsrDeoptFlag(true); 591 } 592 } 593 auto method = GetMethod(callTarget); 594 if (i == inlineDepth_) { 595 Dump(callTarget, type, i); 596 } 597 ASSERT(thread_ != nullptr); 598 uint8_t deoptThreshold = method->GetDeoptThreshold(); 599 if (deoptThreshold > 0) { 600 method->SetDeoptType(type); 601 method->SetDeoptThreshold(--deoptThreshold); 602 } else { 603 ClearCompiledCodeStatusWhenDeopt(func, method); 604 } 605 } 606} 607 608// call instructions need compute jumpSize 609size_t Deoptimizier::GetCallSize(size_t curDepth, const uint8_t *resumePc) 610{ 611 if (inlineDepth_ > 0 && curDepth != inlineDepth_) { 612 auto op = BytecodeInstruction(resumePc).GetOpcode(); 613 size_t jumpSize = BytecodeInstruction::Size(op); 614 return jumpSize; 615 } 616 return 0; 617} 618 619int32_t Deoptimizier::EncodeDeoptVregIndex(int32_t index, size_t depth, size_t shift) 620{ 621 if (index >= 0) { 622 return (index << shift) | depth; 623 } 624 return -((-index << shift) | depth); 625} 626 627size_t Deoptimizier::ComputeShift(size_t depth) 628{ 629 size_t shift = 0; 630 if (depth != 0) { 631 shift = std::floor(std::log2(depth)) + 1; 632 } 633 return shift; 634} 635 636int32_t Deoptimizier::DecodeVregIndex(OffsetType id, size_t shift) 637{ 638 if (id >= 0) { 639 return id >> shift; 640 } 641 return -((-id) >> shift); 642} 643 644size_t Deoptimizier::DecodeDeoptDepth(OffsetType id, size_t shift) 645{ 646 size_t mask = (1 << shift) - 1; 647 if (id >= 0) { 648 return id & mask; 649 } 650 return (-id) & mask; 651} 652} // namespace panda::ecmascript 653