1 /* 2 * Copyright (c) 2022 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 16 #ifndef ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H 17 #define ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H 18 19 #include "ecmascript/base/aligned_struct.h" 20 #include "ecmascript/compiler/argument_accessor.h" 21 #include "ecmascript/deoptimizer/calleeReg.h" 22 #include "ecmascript/js_handle.h" 23 #include "ecmascript/js_tagged_value.h" 24 #include "ecmascript/stackmap/llvm_stackmap_type.h" 25 26 namespace panda::ecmascript { 27 class JSThread; 28 enum class SpecVregIndex: int { 29 PC_INDEX = -1, 30 ACC_INDEX = -2, 31 BC_OFFSET_INDEX = -3, 32 ENV_INDEX = -4, 33 }; 34 35 struct Context { 36 uintptr_t callsiteSp; 37 uintptr_t callsiteFp; 38 kungfu::CalleeRegAndOffsetVec calleeRegAndOffset; 39 }; 40 41 struct AsmStackContext : public base::AlignedStruct<base::AlignedPointer::Size(), 42 base::AlignedPointer, 43 base::AlignedPointer, 44 base::AlignedPointer, 45 base::AlignedPointer> { 46 enum class Index : size_t { 47 OUTPUT_COUNT_INDEX = 0, 48 CALLFRAME_TOP_INDEX, 49 RETURN_ADDRESS_INDEX, 50 CALLERFRAME_POINTER_INDEX, 51 NUM_OF_MEMBER 52 }; 53 54 static_assert(static_cast<size_t>(Index::NUM_OF_MEMBER) == NumOfTypes); 55 GetOutputCountOffsetAsmStackContext56 static size_t GetOutputCountOffset(bool isArch32) 57 { 58 return GetOffset<static_cast<size_t>(Index::OUTPUT_COUNT_INDEX)>(isArch32); 59 } 60 GetCallFrameTopOffsetAsmStackContext61 static size_t GetCallFrameTopOffset(bool isArch32) 62 { 63 return GetOffset<static_cast<size_t>(Index::CALLFRAME_TOP_INDEX)>(isArch32); 64 } 65 GetReturnAddressOffsetAsmStackContext66 static size_t GetReturnAddressOffset(bool isArch32) 67 { 68 return GetOffset<static_cast<size_t>(Index::RETURN_ADDRESS_INDEX)>(isArch32); 69 } 70 GetCallerFpOffsetAsmStackContext71 static size_t GetCallerFpOffset(bool isArch32) 72 { 73 return GetOffset<static_cast<size_t>(Index::CALLERFRAME_POINTER_INDEX)>(isArch32); 74 } 75 GetSizeAsmStackContext76 static constexpr size_t GetSize(bool isArch32) 77 { 78 return isArch32 ? AsmStackContext::SizeArch32 : AsmStackContext::SizeArch64; 79 } 80 81 alignas(EAS) size_t outputCount_ {0}; 82 alignas(EAS) uintptr_t callFrameTop_{0}; 83 alignas(EAS) uintptr_t returnAddr_{0}; 84 alignas(EAS) uintptr_t callerFp_{0}; 85 // out put data 86 }; 87 88 class FrameWriter; 89 class Deoptimizier { 90 public: Deoptimizier(JSThread * thread)91 explicit Deoptimizier(JSThread * thread) : thread_(thread) 92 { 93 kungfu::CalleeReg callreg; 94 numCalleeRegs_ = static_cast<size_t>(callreg.GetCallRegNum()); 95 JSRuntimeOptions options = thread_->GetEcmaVM()->GetJSOptions(); 96 traceDeopt_= options.GetTraceDeopt(); 97 } 98 void CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle); 99 void CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle); 100 JSTaggedType ConstructAsmInterpretFrame(kungfu::DeoptType type); 101 static std::string DisplayItems(kungfu::DeoptType type); 102 GetThread()103 JSThread *GetThread() const 104 { 105 return thread_; 106 } 107 GetLLVMDeoptRelocateSymbol()108 static const char *GetLLVMDeoptRelocateSymbol() 109 { 110 return "__llvm_deoptimize"; 111 } 112 113 private: GetFrameIndex(kungfu::CommonArgIdx index)114 size_t GetFrameIndex(kungfu::CommonArgIdx index) 115 { 116 return static_cast<size_t>(index) - static_cast<size_t>(kungfu::CommonArgIdx::FUNC); 117 } GetFrameArgv(size_t idx)118 JSTaggedValue GetFrameArgv(size_t idx) 119 { 120 ASSERT(frameArgvs_ != nullptr); 121 ASSERT(idx < frameArgc_); 122 return JSTaggedValue(frameArgvs_[idx]); 123 } GetFrameArgv(kungfu::CommonArgIdx index)124 JSTaggedValue GetFrameArgv(kungfu::CommonArgIdx index) 125 { 126 return GetFrameArgv(GetFrameIndex(index)); 127 } GetActualFrameArgs(int32_t index)128 JSTaggedValue GetActualFrameArgs(int32_t index) 129 { 130 index += NUM_MANDATORY_JSFUNC_ARGS; 131 return GetFrameArgv(static_cast<size_t>(index)); 132 } 133 bool CollectVirtualRegisters(Method* method, FrameWriter *frameWriter); HasDeoptValue(int32_t index)134 bool HasDeoptValue(int32_t index) const 135 { 136 return deoptVregs_.find(static_cast<kungfu::OffsetType>(index)) != deoptVregs_.end(); 137 } GetDeoptValue(int32_t index)138 JSTaggedValue GetDeoptValue(int32_t index) const 139 { 140 if (!HasDeoptValue(index)) { 141 return JSTaggedValue::Undefined(); 142 } 143 return deoptVregs_.at(static_cast<kungfu::OffsetType>(index)); 144 } 145 Method* GetMethod(JSTaggedValue &target); 146 void RelocateCalleeSave(); 147 void Dump(Method* method, kungfu::DeoptType type); 148 JSThread *thread_ {nullptr}; 149 uintptr_t *calleeRegAddr_ {nullptr}; 150 size_t numCalleeRegs_ {0}; 151 AsmStackContext stackContext_; 152 153 std::unordered_map<kungfu::OffsetType, JSTaggedValue> deoptVregs_; 154 struct Context context_ {0, 0, {}}; 155 uint32_t pc_ {0}; 156 JSTaggedValue env_ {JSTaggedValue::Undefined()}; 157 size_t frameArgc_ {0}; 158 JSTaggedType *frameArgvs_ {nullptr}; 159 bool traceDeopt_{false}; 160 }; 161 162 } // namespace panda::ecmascript 163 #endif // ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H