1 2/* 3 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "ecmascript/interpreter/frame_handler.h" 18 19#include "ecmascript/jspandafile/program_object.h" 20 21namespace panda::ecmascript { 22FrameHandler::FrameHandler(const JSThread *thread) 23 : sp_(const_cast<JSTaggedType *>(thread->GetCurrentFrame())), thread_(thread) 24{ 25 AdvanceToJSFrame(); 26} 27 28ARK_INLINE void FrameHandler::AdvanceToJSFrame() 29{ 30 if (!thread_->IsAsmInterpreter()) { 31 return; 32 } 33 FrameIterator it(sp_, thread_); 34 for (; !it.Done(); it.Advance()) { 35 FrameType t = it.GetFrameType(); 36 if (IsBaselineBuiltinFrame(t)) { 37 FindAndSetBaselineNativePc(it); 38 } 39 if (IsJSFrame(t) || IsJSEntryFrame(t)) { 40 break; 41 } 42 } 43 sp_ = it.GetSp(); 44} 45 46ARK_INLINE void FrameHandler::PrevJSFrame() 47{ 48 if (!thread_->IsAsmInterpreter()) { 49 FrameIterator it(sp_, thread_); 50 if (IsBaselineBuiltinFrame(it.GetFrameType())) { 51 FindAndSetBaselineNativePc(it); 52 } 53 it.Advance(); 54 sp_ = it.GetSp(); 55 return; 56 } 57 AdvanceToJSFrame(); 58 FrameIterator it(sp_, thread_); 59 FrameType t = it.GetFrameType(); 60 if (t == FrameType::ASM_INTERPRETER_FRAME) { 61 auto frame = it.GetFrame<AsmInterpretedFrame>(); 62 if (thread_->IsAsmInterpreter()) { 63 fp_ = frame->GetCurrentFramePointer(); 64 } 65 } 66 it.Advance(); 67 sp_ = it.GetSp(); 68 AdvanceToJSFrame(); 69} 70 71JSTaggedType* FrameHandler::GetPrevJSFrame() 72{ 73 PrevJSFrame(); 74 return GetSp(); 75} 76 77uint32_t FrameHandler::GetNumberArgs() 78{ 79 if (thread_->IsAsmInterpreter()) { 80 auto *frame = AsmInterpretedFrame::GetFrameFromSp(sp_); 81 return static_cast<uint32_t>(frame->GetCurrentFramePointer() - sp_); 82 } 83 ASSERT(IsInterpretedFrame()); 84 JSTaggedType *prevSp = nullptr; 85 FrameIterator it(sp_, thread_); 86 if (IsAsmInterpretedFrame()) { 87 auto *frame = it.GetFrame<AsmInterpretedFrame>(); 88 prevSp = frame->GetPrevFrameFp(); 89 } else { 90 auto *frame = it.GetFrame<InterpretedFrame>(); 91 prevSp = frame->GetPrevFrameFp(); 92 } 93 auto prevSpEnd = reinterpret_cast<JSTaggedType*>(GetInterpretedFrameEnd(prevSp)); 94 return static_cast<uint32_t>(prevSpEnd - sp_); 95} 96 97JSTaggedValue FrameHandler::GetVRegValue(size_t index) const 98{ 99 ASSERT(IsInterpretedFrame()); 100 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 101 return JSTaggedValue(sp_[index]); 102} 103 104void FrameHandler::SetVRegValue(size_t index, JSTaggedValue value) 105{ 106 ASSERT(IsInterpretedFrame()); 107 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 108 sp_[index] = value.GetRawData(); 109} 110 111void FrameHandler::FindAndSetBaselineNativePc(FrameIterator it) 112{ 113 ASSERT(IsBaselineBuiltinFrame(it.GetFrameType())); 114 auto *frame = it.GetFrame<BaselineBuiltinFrame>(); 115 baselineNativePc_ = frame->GetReturnAddr(); 116} 117 118JSTaggedValue FrameHandler::GetAcc() const 119{ 120 ASSERT(IsInterpretedFrame()); 121 FrameIterator it(sp_, thread_); 122 if (IsAsmInterpretedFrame()) { 123 auto *frame = it.GetFrame<AsmInterpretedFrame>(); 124 return frame->acc; 125 } else { 126 auto *frame = it.GetFrame<InterpretedFrame>(); 127 return frame->acc; 128 } 129} 130 131uint32_t FrameHandler::GetBytecodeOffset() const 132{ 133 ASSERT(IsInterpretedFrame()); 134 Method *method = GetMethod(); 135 auto offset = GetPc() - method->GetBytecodeArray(); 136 return static_cast<uint32_t>(offset); 137} 138 139Method *FrameHandler::GetMethod() const 140{ 141 ASSERT(IsJSFrame()); 142 auto function = GetFunction(); 143 return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget(); 144} 145 146const JSPandaFile* FrameHandler::GetJSPandaFile() const 147{ 148 auto method = GetMethod(); 149 return method->GetJSPandaFile(); 150} 151 152std::string FrameHandler::GetFileName() const 153{ 154 auto pandaFile = GetJSPandaFile(); 155 ASSERT(pandaFile != nullptr); 156 return pandaFile->GetJSPandaFileDesc().c_str(); 157} 158 159uint32_t FrameHandler::GetAbcId() const 160{ 161 std::string abcName = GetFileName(); 162 pgo::PGOProfilerManager* pm = pgo::PGOProfilerManager::GetInstance(); 163 uint32_t abcId; 164 if (!pm->GetPandaFileId(CString(abcName), abcId) && !abcName.empty()) { 165 LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << abcName; 166 } 167 return abcId; 168} 169 170uint32_t FrameHandler::GetMethodId() const 171{ 172 return GetMethod()->GetMethodId().GetOffset(); 173} 174 175Method *FrameHandler::CheckAndGetMethod() const 176{ 177 ASSERT(IsJSFrame()); 178 auto function = GetFunction(); 179 if (function.IsJSFunctionBase() || function.IsJSProxy()) { 180 return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget(); 181 } 182 return nullptr; 183} 184 185JSTaggedValue FrameHandler::GetThis() const 186{ 187 ASSERT(IsInterpretedFrame()); 188 FrameIterator it(sp_, thread_); 189 if (IsAsmInterpretedFrame()) { 190 auto *frame = it.GetFrame<AsmInterpretedFrame>(); 191 return frame->thisObj; 192 } else { 193 auto *frame = it.GetFrame<InterpretedFrame>(); 194 return frame->thisObj; 195 } 196} 197 198JSTaggedValue FrameHandler::GetFunction() const 199{ 200 ASSERT(IsJSFrame()); 201 if (thread_->IsAsmInterpreter()) { 202 FrameType type = GetFrameType(); 203 switch (type) { 204 case FrameType::ASM_INTERPRETER_FRAME: 205 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 206 auto frame = AsmInterpretedFrame::GetFrameFromSp(sp_); 207 return frame->function; 208 } 209 case FrameType::BUILTIN_FRAME_WITH_ARGV: { 210 auto *frame = BuiltinWithArgvFrame::GetFrameFromSp(sp_); 211 return frame->GetFunction(); 212 } 213 case FrameType::BUILTIN_ENTRY_FRAME: 214 case FrameType::BUILTIN_FRAME: { 215 auto *frame = BuiltinFrame::GetFrameFromSp(sp_); 216 return frame->GetFunction(); 217 } 218 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 219 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { 220 auto *frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp_); 221 return frame->GetFunction(); 222 } 223 case FrameType::FASTJIT_FUNCTION_FRAME: 224 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 225 auto *frame = FASTJITFunctionFrame::GetFrameFromSp(sp_); 226 return frame->GetFunction(); 227 } 228 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME : 229 case FrameType::INTERPRETER_FRAME: 230 case FrameType::INTERPRETER_FAST_NEW_FRAME: 231 case FrameType::INTERPRETER_ENTRY_FRAME: 232 case FrameType::ASM_INTERPRETER_ENTRY_FRAME: 233 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: 234 case FrameType::INTERPRETER_BUILTIN_FRAME: 235 case FrameType::OPTIMIZED_FRAME: 236 case FrameType::BASELINE_BUILTIN_FRAME: 237 case FrameType::ASM_BRIDGE_FRAME: 238 case FrameType::LEAVE_FRAME: 239 case FrameType::LEAVE_FRAME_WITH_ARGV: 240 case FrameType::BUILTIN_CALL_LEAVE_FRAME: 241 case FrameType::OPTIMIZED_ENTRY_FRAME: 242 default: { 243 LOG_FULL(FATAL) << "frame type error!"; 244 UNREACHABLE(); 245 } 246 } 247 } else { 248 FrameType type = GetFrameType(); 249 if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) { 250 auto *frame = InterpretedFrame::GetFrameFromSp(sp_); 251 return frame->function; 252 } else { 253 auto *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp_); 254 return frame->function; 255 } 256 } 257} 258 259const uint8_t *FrameHandler::GetPc() const 260{ 261 ASSERT(IsJSFrame()); 262 FrameIterator it(sp_, thread_); 263 if (IsAsmInterpretedFrame()) { 264 auto *frame = it.GetFrame<AsmInterpretedFrame>(); 265 return frame->GetPc(); 266 } else { 267 auto *frame = it.GetFrame<InterpretedFrame>(); 268 return frame->GetPc(); 269 } 270} 271 272ConstantPool *FrameHandler::GetConstpool() const 273{ 274 ASSERT(IsInterpretedFrame()); 275 auto method = GetMethod(); 276 JSTaggedValue constpool = method->GetConstantPool(); 277 return ConstantPool::Cast(constpool.GetTaggedObject()); 278} 279 280JSTaggedValue FrameHandler::GetEnv() const 281{ 282 ASSERT(IsInterpretedFrame()); 283 FrameIterator it(sp_, thread_); 284 if (IsAsmInterpretedFrame()) { 285 auto *frame = it.GetFrame<AsmInterpretedFrame>(); 286 return frame->GetEnv(); 287 } else { 288 auto *frame = it.GetFrame<InterpretedFrame>(); 289 return frame->env; 290 } 291} 292 293void FrameHandler::DumpStack(std::ostream &os) const 294{ 295 size_t i = 0; 296 FrameHandler frameHandler(thread_); 297 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) { 298 os << "[" << i++ 299 << "]:" << frameHandler.GetMethod()->ParseFunctionName() 300 << "\n"; 301 } 302} 303 304void FrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const 305{ 306 FrameHandler frameHandler(thread_); 307 ASSERT(frameHandler.HasFrame()); 308 // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions) 309 int offset = pc - frameHandler.GetMethod()->GetBytecodeArray(); 310 os << "offset: " << offset << "\n"; 311} 312 313ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp) const 314{ 315 uintptr_t end = 0U; 316 FrameIterator it(prevSp, thread_); 317 FrameType type = it.GetFrameType(); 318 switch (type) { 319 case FrameType::ASM_INTERPRETER_FRAME: 320 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 321 auto frame = it.GetFrame<AsmInterpretedFrame>(); 322 end = ToUintPtr(frame); 323 break; 324 } 325 case FrameType::INTERPRETER_FRAME: 326 case FrameType::INTERPRETER_FAST_NEW_FRAME: { 327 auto frame = it.GetFrame<InterpretedFrame>(); 328 end = ToUintPtr(frame); 329 break; 330 } 331 case FrameType::INTERPRETER_ENTRY_FRAME: { 332 auto frame = it.GetFrame<InterpretedEntryFrame>(); 333 end = ToUintPtr(frame); 334 break; 335 } 336 case FrameType::INTERPRETER_BUILTIN_FRAME: { 337 auto frame = it.GetFrame<InterpretedBuiltinFrame>(); 338 end = ToUintPtr(frame); 339 break; 340 } 341 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME : 342 case FrameType::BUILTIN_FRAME_WITH_ARGV: 343 case FrameType::BUILTIN_ENTRY_FRAME: 344 case FrameType::BUILTIN_FRAME: 345 case FrameType::OPTIMIZED_FRAME: 346 case FrameType::ASM_BRIDGE_FRAME: 347 case FrameType::LEAVE_FRAME: 348 case FrameType::BASELINE_BUILTIN_FRAME: 349 case FrameType::LEAVE_FRAME_WITH_ARGV: 350 case FrameType::BUILTIN_CALL_LEAVE_FRAME: 351 case FrameType::OPTIMIZED_ENTRY_FRAME: 352 case FrameType::ASM_INTERPRETER_ENTRY_FRAME: 353 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: 354 default: { 355 LOG_FULL(FATAL) << "frame type error!"; 356 UNREACHABLE(); 357 } 358 } 359 return end; 360} 361 362void FrameHandler::IterateAssembleStack(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, 363 const RootBaseAndDerivedVisitor &derivedVisitor) 364{ 365 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame()); 366 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor); 367} 368 369// We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable. 370// To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually. 371// And only InterpretedEntryFrame is on thread sp when asm interpreter is enable. 372void FrameHandler::IterateEcmaRuntimeCallInfo(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) 373{ 374 ASSERT(thread_->IsAsmInterpreter()); 375 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame()); 376 for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) { 377 ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME); 378 auto frame = it.GetFrame<InterpretedEntryFrame>(); 379 frame->GCIterate(it, visitor, rangeVisitor); 380 } 381} 382 383void FrameHandler::Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, 384 const RootBaseAndDerivedVisitor &derivedVisitor) 385{ 386 if (thread_->IsAsmInterpreter()) { 387 IterateEcmaRuntimeCallInfo(visitor, rangeVisitor); 388 IterateAssembleStack(visitor, rangeVisitor, derivedVisitor); 389 return; 390 } 391 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame()); 392 FrameType frameType = FrameHandler::GetFrameType(current); 393 if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) { 394 auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame()); 395 if (leaveFrame != nullptr) { 396 current = leaveFrame; 397 } 398 } 399 // lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance 400 if (arkStackMapParser_ == nullptr) { 401 arkStackMapParser_ = 402 const_cast<JSThread *>(thread_)->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser(); 403 } 404 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor); 405} 406 407void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &visitor, 408 const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const 409{ 410 JSTaggedType *current = start; 411 // if the current frame type is BASELINE_BUILTIN_FRAME, the upper frame must be BaselineFrame. 412 // isBaselineFrame is used to differentiate the AsmInterpterFrame and BaselineFrame 413 bool isBaselineFrame = false; 414 for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) { 415 FrameType type = it.GetFrameType(); 416 switch (type) { 417 case FrameType::OPTIMIZED_FRAME: { 418 auto frame = it.GetFrame<OptimizedFrame>(); 419 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor); 420 break; 421 } 422 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 423 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { 424 auto frame = it.GetFrame<OptimizedJSFunctionFrame>(); 425 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, type); 426 break; 427 } 428 case FrameType::BASELINE_BUILTIN_FRAME: { 429 isBaselineFrame = true; 430 auto frame = it.GetFrame<BaselineBuiltinFrame>(); 431 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor); 432 break; 433 } 434 case FrameType::FASTJIT_FUNCTION_FRAME: 435 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 436 auto frame = it.GetFrame<FASTJITFunctionFrame>(); 437 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, type); 438 break; 439 } 440 case FrameType::ASM_INTERPRETER_FRAME: 441 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 442 auto frame = it.GetFrame<AsmInterpretedFrame>(); 443 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, isBaselineFrame); 444 isBaselineFrame = false; 445 break; 446 } 447 case FrameType::INTERPRETER_FRAME: 448 case FrameType::INTERPRETER_FAST_NEW_FRAME: { 449 auto frame = it.GetFrame<InterpretedFrame>(); 450 frame->GCIterate(it, visitor, rangeVisitor); 451 break; 452 } 453 case FrameType::INTERPRETER_BUILTIN_FRAME: { 454 auto frame = it.GetFrame<InterpretedBuiltinFrame>(); 455 frame->GCIterate(it, visitor, rangeVisitor); 456 break; 457 } 458 case FrameType::LEAVE_FRAME: { 459 auto frame = it.GetFrame<OptimizedLeaveFrame>(); 460 frame->GCIterate(it, visitor, rangeVisitor); 461 break; 462 } 463 case FrameType::LEAVE_FRAME_WITH_ARGV: { 464 auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>(); 465 frame->GCIterate(it, visitor, rangeVisitor); 466 break; 467 } 468 case FrameType::BUILTIN_CALL_LEAVE_FRAME: { 469 auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>(); 470 frame->GCIterate(it, visitor, rangeVisitor); 471 break; 472 } 473 case FrameType::BUILTIN_FRAME_WITH_ARGV: { 474 auto frame = it.GetFrame<BuiltinWithArgvFrame>(); 475 frame->GCIterate(it, visitor, rangeVisitor); 476 break; 477 } 478 case FrameType::BUILTIN_ENTRY_FRAME: 479 case FrameType::BUILTIN_FRAME: { 480 auto frame = it.GetFrame<BuiltinFrame>(); 481 frame->GCIterate(it, visitor, rangeVisitor); 482 break; 483 } 484 case FrameType::INTERPRETER_ENTRY_FRAME: { 485 auto frame = it.GetFrame<InterpretedEntryFrame>(); 486 frame->GCIterate(it, visitor, rangeVisitor); 487 break; 488 } 489 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME: 490 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: 491 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: 492 case FrameType::OPTIMIZED_ENTRY_FRAME: 493 case FrameType::ASM_BRIDGE_FRAME: 494 case FrameType::ASM_INTERPRETER_ENTRY_FRAME: 495 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: { 496 break; 497 } 498 default: { 499 LOG_FULL(FATAL) << "frame type error!"; 500 UNREACHABLE(); 501 } 502 } 503 } 504} 505} // namespace panda::ecmascript 506