• 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     FIRST_METHOD_OFFSET_INDEX = -8,
37     PADDING1 = -9,
38     PADDING2 = -10,
39     PADDING3 = -11,
40     MAX_METHOD_OFFSET_INDEX = -12,
41 };
42 
43 static constexpr uint32_t MAX_METHOD_OFFSET_NUM = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) -
44                                                   static_cast<int32_t>(SpecVregIndex::MAX_METHOD_OFFSET_INDEX) + 1;
45 
46 struct Context {
47     uintptr_t callsiteSp;
48     uintptr_t callsiteFp;
49     kungfu::CalleeRegAndOffsetVec calleeRegAndOffset;
50 };
51 
52 struct AsmStackContext : public base::AlignedStruct<base::AlignedPointer::Size(),
53                                                     base::AlignedPointer,
54                                                     base::AlignedPointer,
55                                                     base::AlignedPointer,
56                                                     base::AlignedPointer> {
57     enum class Index : size_t {
58         INLINE_DEPTH_INDEX = 0,
59         CALLFRAME_TOP_INDEX,
60         RETURN_ADDRESS_INDEX,
61         CALLERFRAME_POINTER_INDEX,
62         NUM_OF_MEMBER
63     };
64 
65     static_assert(static_cast<size_t>(Index::NUM_OF_MEMBER) == NumOfTypes);
66 
GetInlineDepthOffsetAsmStackContext67     static size_t GetInlineDepthOffset(bool isArch32)
68     {
69         return GetOffset<static_cast<size_t>(Index::INLINE_DEPTH_INDEX)>(isArch32);
70     }
71 
GetCallFrameTopOffsetAsmStackContext72     static size_t GetCallFrameTopOffset(bool isArch32)
73     {
74         return GetOffset<static_cast<size_t>(Index::CALLFRAME_TOP_INDEX)>(isArch32);
75     }
76 
GetReturnAddressOffsetAsmStackContext77     static size_t GetReturnAddressOffset(bool isArch32)
78     {
79         return GetOffset<static_cast<size_t>(Index::RETURN_ADDRESS_INDEX)>(isArch32);
80     }
81 
GetCallerFpOffsetAsmStackContext82     static size_t GetCallerFpOffset(bool isArch32)
83     {
84         return GetOffset<static_cast<size_t>(Index::CALLERFRAME_POINTER_INDEX)>(isArch32);
85     }
86 
GetSizeAsmStackContext87     static constexpr size_t GetSize(bool isArch32)
88     {
89         return isArch32 ? AsmStackContext::SizeArch32 : AsmStackContext::SizeArch64;
90     }
91 
92     alignas(EAS) size_t inlineDepth_ {0};
93     alignas(EAS) uintptr_t callFrameTop_{0};
94     alignas(EAS) uintptr_t returnAddr_{0};
95     alignas(EAS) uintptr_t callerFp_{0};
96     // out put data
97 };
98 
99 class FrameWriter;
100 class Deoptimizier {
101 public:
102     using ARKDeopt = kungfu::ARKDeopt;
103     using CalleeReg = kungfu::CalleeReg;
104     using CalleeRegAndOffsetVec = kungfu::CalleeRegAndOffsetVec;
105     using CommonArgIdx = kungfu::CommonArgIdx;
106     using DeoptType = kungfu::DeoptType;
107     using DwarfRegType = kungfu::LLVMStackMapType::DwarfRegType;
108     using DwarfRegAndOffsetType = kungfu::LLVMStackMapType::DwarfRegAndOffsetType;
109     using IntType = kungfu::LLVMStackMapType::IntType;
110     using LargeInt = kungfu::LLVMStackMapType::LargeInt;
111     using LocationTy = kungfu::LocationTy;
112     using OffsetType = kungfu::LLVMStackMapType::OffsetType;
113     using VRegId = kungfu::LLVMStackMapType::VRegId;
114 
Deoptimizier(JSThread * thread,size_t depth)115     explicit Deoptimizier(JSThread *thread, size_t depth) : thread_(thread), inlineDepth_(depth)
116     {
117         CalleeReg callreg;
118         numCalleeRegs_ = static_cast<size_t>(callreg.GetCallRegNum());
119         JSRuntimeOptions options = thread_->GetEcmaVM()->GetJSOptions();
120         traceDeopt_ = options.GetTraceDeopt();
121     }
122     void CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle, size_t shift);
123     void CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle);
124     JSTaggedType ConstructAsmInterpretFrame();
125     void UpdateAndDumpDeoptInfo(kungfu::DeoptType type);
126     static std::string DisplayItems(kungfu::DeoptType type);
127     static int32_t EncodeDeoptVregIndex(int32_t index, size_t depth, size_t shift);
128     static size_t ComputeShift(size_t depth);
129     static int32_t DecodeVregIndex(OffsetType id, size_t shift);
130     static size_t DecodeDeoptDepth(OffsetType id, size_t shift);
GetThread()131     JSThread *GetThread() const
132     {
133         return thread_;
134     }
135 
GetLLVMDeoptRelocateSymbol()136     static const char *GetLLVMDeoptRelocateSymbol()
137     {
138         return "__llvm_deoptimize";
139     }
140 
141 private:
GetFrameIndex(CommonArgIdx index)142     size_t GetFrameIndex(CommonArgIdx index)
143     {
144         return static_cast<size_t>(index) - static_cast<size_t>(CommonArgIdx::FUNC);
145     }
GetFrameArgv(size_t idx)146     JSTaggedValue GetFrameArgv(size_t idx)
147     {
148         ASSERT(frameArgvs_ != nullptr);
149         ASSERT(idx < frameArgc_);
150         return JSTaggedValue(frameArgvs_[idx]);
151     }
GetFrameArgv(CommonArgIdx index)152     JSTaggedValue GetFrameArgv(CommonArgIdx index)
153     {
154         return GetFrameArgv(GetFrameIndex(index));
155     }
GetActualFrameArgs(int32_t index)156     JSTaggedValue GetActualFrameArgs(int32_t index)
157     {
158         index += NUM_MANDATORY_JSFUNC_ARGS;
159         return GetFrameArgv(static_cast<size_t>(index));
160     }
161     bool CollectVirtualRegisters(Method* method, FrameWriter *frameWriter, size_t curDepth);
HasDeoptValue(size_t curDepth,int32_t index)162     bool HasDeoptValue(size_t curDepth, int32_t index) const
163     {
164         ASSERT(curDepth <= inlineDepth_);
165         return deoptVregs_.find({curDepth, static_cast<OffsetType>(index)}) != deoptVregs_.end();
166     }
GetDeoptValue(size_t curDepth,int32_t index)167     JSTaggedValue GetDeoptValue(size_t curDepth, int32_t index) const
168     {
169         ASSERT(curDepth <= inlineDepth_);
170         if (!HasDeoptValue(curDepth, index)) {
171             return JSTaggedValue::Undefined();
172         }
173         return deoptVregs_.at({curDepth, static_cast<OffsetType>(index)}).GetTaggedValue();
174     }
175     Method* GetMethod(JSTaggedValue &target);
176     void RelocateCalleeSave();
177     void Dump(Method* method, kungfu::DeoptType type, size_t depth);
178     size_t GetCallSize(size_t curDepth, const uint8_t *resumePc);
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