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