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 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/ecma_vm.h" 23 #include "ecmascript/js_handle.h" 24 #include "ecmascript/js_tagged_value.h" 25 #include "ecmascript/stackmap/llvm/llvm_stackmap_type.h" 26 27 namespace panda::ecmascript { 28 class JSThread; 29 enum class SpecVregIndex: int { 30 PC_OFFSET_INDEX = -1, 31 ACC_INDEX = -2, 32 ENV_INDEX = -3, 33 FUNC_INDEX = -4, 34 NEWTARGET_INDEX = -5, 35 THIS_OBJECT_INDEX = -6, 36 ACTUAL_ARGC_INDEX = -7, 37 FIRST_METHOD_OFFSET_INDEX = -8, 38 PADDING1 = -9, 39 PADDING2 = -10, 40 PADDING3 = -11, 41 MAX_METHOD_OFFSET_INDEX = -12, 42 }; 43 44 static constexpr uint32_t MAX_METHOD_OFFSET_NUM = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) - 45 static_cast<int32_t>(SpecVregIndex::MAX_METHOD_OFFSET_INDEX) + 1; 46 47 struct Context { 48 uintptr_t callsiteSp; 49 uintptr_t callsiteFp; 50 kungfu::CalleeRegAndOffsetVec calleeRegAndOffset; 51 }; 52 53 struct AsmStackContext : public base::AlignedStruct<base::AlignedPointer::Size(), 54 base::AlignedPointer, 55 base::AlignedPointer, 56 base::AlignedPointer, 57 base::AlignedPointer> { 58 enum class Index : size_t { 59 INLINE_DEPTH_INDEX = 0, 60 CALLFRAME_TOP_INDEX, 61 RETURN_ADDRESS_INDEX, 62 CALLERFRAME_POINTER_INDEX, 63 NUM_OF_MEMBER 64 }; 65 66 static_assert(static_cast<size_t>(Index::NUM_OF_MEMBER) == NumOfTypes); 67 GetInlineDepthOffsetAsmStackContext68 static size_t GetInlineDepthOffset(bool isArch32) 69 { 70 return GetOffset<static_cast<size_t>(Index::INLINE_DEPTH_INDEX)>(isArch32); 71 } 72 GetCallFrameTopOffsetAsmStackContext73 static size_t GetCallFrameTopOffset(bool isArch32) 74 { 75 return GetOffset<static_cast<size_t>(Index::CALLFRAME_TOP_INDEX)>(isArch32); 76 } 77 GetReturnAddressOffsetAsmStackContext78 static size_t GetReturnAddressOffset(bool isArch32) 79 { 80 return GetOffset<static_cast<size_t>(Index::RETURN_ADDRESS_INDEX)>(isArch32); 81 } 82 GetCallerFpOffsetAsmStackContext83 static size_t GetCallerFpOffset(bool isArch32) 84 { 85 return GetOffset<static_cast<size_t>(Index::CALLERFRAME_POINTER_INDEX)>(isArch32); 86 } 87 GetSizeAsmStackContext88 static constexpr size_t GetSize(bool isArch32) 89 { 90 return isArch32 ? AsmStackContext::SizeArch32 : AsmStackContext::SizeArch64; 91 } 92 93 alignas(EAS) size_t inlineDepth_ {0}; 94 alignas(EAS) uintptr_t callFrameTop_{0}; 95 alignas(EAS) uintptr_t returnAddr_{0}; 96 alignas(EAS) uintptr_t callerFp_{0}; 97 // out put data 98 }; 99 100 class FrameWriter; 101 class Deoptimizier { 102 public: 103 using ARKDeopt = kungfu::ARKDeopt; 104 using CalleeReg = kungfu::CalleeReg; 105 using CalleeRegAndOffsetVec = kungfu::CalleeRegAndOffsetVec; 106 using CommonArgIdx = kungfu::CommonArgIdx; 107 using DeoptType = kungfu::DeoptType; 108 using DwarfRegType = kungfu::LLVMStackMapType::DwarfRegType; 109 using DwarfRegAndOffsetType = kungfu::LLVMStackMapType::DwarfRegAndOffsetType; 110 using IntType = kungfu::LLVMStackMapType::IntType; 111 using LargeInt = kungfu::LLVMStackMapType::LargeInt; 112 using LocationTy = kungfu::LocationTy; 113 using OffsetType = kungfu::LLVMStackMapType::OffsetType; 114 using VRegId = kungfu::LLVMStackMapType::VRegId; 115 116 explicit Deoptimizier(JSThread *thread, size_t depth); 117 118 void CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle, size_t shift); 119 template<class T> 120 void AssistCollectDeoptBundleVec(FrameIterator &it, T &frame); 121 void CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle); 122 JSTaggedType ConstructAsmInterpretFrame(); 123 void UpdateAndDumpDeoptInfo(kungfu::DeoptType type); 124 static PUBLIC_API std::string DisplayItems(kungfu::DeoptType type); 125 static PUBLIC_API int32_t EncodeDeoptVregIndex(int32_t index, size_t depth, size_t shift); 126 static PUBLIC_API size_t ComputeShift(size_t depth); 127 static int32_t DecodeVregIndex(OffsetType id, size_t shift); 128 static size_t DecodeDeoptDepth(OffsetType id, size_t shift); GetThread()129 JSThread *GetThread() const 130 { 131 return thread_; 132 } 133 GetLLVMDeoptRelocateSymbol()134 static const char *GetLLVMDeoptRelocateSymbol() 135 { 136 return "__llvm_deoptimize"; 137 } 138 139 private: GetFrameIndex(CommonArgIdx index)140 size_t GetFrameIndex(CommonArgIdx index) 141 { 142 return static_cast<size_t>(index) - static_cast<size_t>(CommonArgIdx::FUNC); 143 } GetFrameArgv(size_t idx)144 JSTaggedValue GetFrameArgv(size_t idx) 145 { 146 ASSERT(frameArgvs_ != nullptr); 147 ASSERT(idx < frameArgc_); 148 return JSTaggedValue(frameArgvs_[idx]); 149 } GetFrameArgv(CommonArgIdx index)150 JSTaggedValue GetFrameArgv(CommonArgIdx index) 151 { 152 return GetFrameArgv(GetFrameIndex(index)); 153 } GetActualFrameArgs(int32_t index)154 JSTaggedValue GetActualFrameArgs(int32_t index) 155 { 156 index += NUM_MANDATORY_JSFUNC_ARGS; 157 return GetFrameArgv(static_cast<size_t>(index)); 158 } 159 bool CollectVirtualRegisters(JSTaggedValue callTarget, Method *method, FrameWriter *frameWriter, size_t curDepth); HasDeoptValue(size_t curDepth,int32_t index)160 bool HasDeoptValue(size_t curDepth, int32_t index) const 161 { 162 ASSERT(curDepth <= inlineDepth_); 163 return deoptVregs_.find({curDepth, static_cast<OffsetType>(index)}) != deoptVregs_.end(); 164 } GetDeoptValue(size_t curDepth,int32_t index)165 JSTaggedValue GetDeoptValue(size_t curDepth, int32_t index) const 166 { 167 ASSERT(curDepth <= inlineDepth_); 168 if (!HasDeoptValue(curDepth, index)) { 169 return JSTaggedValue::Undefined(); 170 } 171 return deoptVregs_.at({curDepth, static_cast<OffsetType>(index)}).GetTaggedValue(); 172 } 173 Method* GetMethod(JSTaggedValue &target); 174 void RelocateCalleeSave(); 175 void Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth); 176 size_t GetCallSize(size_t curDepth, const uint8_t *resumePc); 177 void ClearCompiledCodeStatusWhenDeopt(JSFunction *fun, Method *method); 178 void ResetJitHotness(JSFunction *jsFunc) const; 179 JSThread *thread_ {nullptr}; 180 uintptr_t *calleeRegAddr_ {nullptr}; 181 size_t numCalleeRegs_ {0}; 182 AsmStackContext stackContext_; 183 184 std::map<std::pair<size_t, OffsetType>, JSHandle<JSTaggedValue>> deoptVregs_; 185 struct Context context_ {0, 0, {}}; 186 std::unordered_map<size_t, size_t> pc_; 187 std::unordered_map<size_t, size_t> jumpSize_; 188 size_t frameArgc_ {0}; 189 JSTaggedType *frameArgvs_ {nullptr}; 190 bool traceDeopt_{false}; 191 size_t inlineDepth_ {0}; 192 }; 193 194 } // namespace panda::ecmascript 195 #endif // ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H