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