• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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