• 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_COMPILER_TYPED_BYTECODE_LOWERING_H
17 #define ECMASCRIPT_COMPILER_TYPED_BYTECODE_LOWERING_H
18 
19 #include "ecmascript/builtin_entries.h"
20 #include "ecmascript/compiler/argument_accessor.h"
21 #include "ecmascript/compiler/aot_compiler_preprocessor.h"
22 #include "ecmascript/compiler/builtins/builtins_call_signature.h"
23 #include "ecmascript/compiler/bytecode_circuit_builder.h"
24 #include "ecmascript/compiler/circuit_builder-inl.h"
25 #include "ecmascript/compiler/lazy_deopt_dependency.h"
26 #include "ecmascript/compiler/pass_manager.h"
27 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
28 #include "ecmascript/compiler/type_info_accessors.h"
29 #include "ecmascript/enum_conversion.h"
30 
31 namespace panda::ecmascript::kungfu {
32 class TypedBytecodeLowering {
33 public:
TypedBytecodeLowering(Circuit * circuit,PassContext * ctx,Chunk * chunk,bool enableLog,bool enableTypeLog,const std::string & name,bool enableLoweringBuiltin,bool enableMergePoly,bool enableLazyDeopt,const CString & recordName,const CallMethodFlagMap * callMethodFlagMap,PGOProfilerDecoder * decoder,const std::string optBCRange,const MethodLiteral * currentMethod)34     TypedBytecodeLowering(Circuit* circuit,
35                          PassContext* ctx,
36                          Chunk* chunk,
37                          bool enableLog,
38                          bool enableTypeLog,
39                          const std::string& name,
40                          bool enableLoweringBuiltin,
41                          bool enableMergePoly,
42                          bool enableLazyDeopt,
43                          const CString& recordName,
44                          const CallMethodFlagMap* callMethodFlagMap,
45                          PGOProfilerDecoder *decoder,
46                          const std::string optBCRange,
47                          const MethodLiteral *currentMethod)
48         : circuit_(circuit),
49           acc_(circuit),
50           ctx_(ctx),
51           builder_(circuit, ctx->GetCompilerConfig()),
52           dependEntry_(circuit->GetDependRoot()),
53           chunk_(chunk),
54           enableLog_(enableLog),
55           enableTypeLog_(enableTypeLog),
56           profiling_(ctx->GetCompilerConfig()->IsProfiling()),
57           verifyVTable_(ctx->GetCompilerConfig()->IsVerifyVTbale()),
58           traceBc_(ctx->GetCompilerConfig()->IsTraceBC()),
59           methodName_(name),
60           glue_(acc_.GetGlueFromArgList()),
61           argAcc_(circuit->GetArgumentAccessor()),
62           pgoTypeLog_(circuit),
63           noCheck_(ctx->GetCompilationEnv()->GetJSOptions().IsCompilerNoCheck()),
64           compilationEnv_(ctx->GetCompilationEnv()),
65           enableLoweringBuiltin_(enableLoweringBuiltin),
66           enableMergePoly_(enableMergePoly),
67           enableLazyDeopt_(enableLazyDeopt),
68           recordName_(recordName),
69           callMethodFlagMap_(callMethodFlagMap),
70           decoder_(decoder),
71           optBCRange_(optBCRange),
72           currentMethod_(currentMethod)
73     {
74         auto currentMethodId = currentMethod_->GetMethodId();
75         panda_file::IndexAccessor indexAccessor(*(ctx_->GetJSPandaFile()->GetPandaFile()),
76                                                 panda_file::File::EntityId(currentMethodId));
77         constPoolId_ = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
78     }
79 
80     ~TypedBytecodeLowering() = default;
81 
82     void RunTypedBytecodeLowering();
83 
84 private:
85     struct LoadObjByNameDataInfo {
LoadObjByNameDataInfoLoadObjByNameDataInfo86         LoadObjByNameDataInfo(std::vector<Label> &loaderLabels, std::vector<Label> &failLabels,
87             const LoadObjPropertyTypeInfoAccessor &ldTacc, Variable &resVar, Label &exitLabel) : loaders(loaderLabels),
88             fails(failLabels), tacc(ldTacc), result(resVar), exit(exitLabel) {}
89         ~LoadObjByNameDataInfo() = default;
90         std::vector<Label> &loaders;
91         std::vector<Label> &fails;
92         const LoadObjPropertyTypeInfoAccessor &tacc;
93         Variable &result;
94         Label &exit;
95     };
96 
97     struct LoadObjByNameOnProtoTypeInfo {
98         GateRef gate;
99         GateRef frameState;
100         GateRef receiverHC;
101         Label *exit;
102         size_t typeIndex;
103     };
104 
IsLogEnabled()105     bool IsLogEnabled() const
106     {
107         return enableLog_;
108     }
109 
IsTypeLogEnabled()110     bool IsTypeLogEnabled() const
111     {
112         return enableTypeLog_;
113     }
114 
IsProfiling()115     bool IsProfiling() const
116     {
117         return profiling_;
118     }
119 
IsVerifyVTbale()120     bool IsVerifyVTbale() const
121     {
122         return verifyVTable_;
123     }
124 
IsTraceBC()125     bool IsTraceBC() const
126     {
127         return traceBc_;
128     }
129 
GetMethodName()130     const std::string& GetMethodName() const
131     {
132         return methodName_;
133     }
134 
135     void Lower(GateRef gate);
136     template<TypedBinOp Op>
137     void LowerTypedBinOp(GateRef gate);
138     template<TypedUnOp Op>
139     void LowerTypedUnOp(GateRef gate);
140     template<TypedBinOp Op>
141     void LowerTypedEqOrNotEq(GateRef gate);
142     void LowerTypeToNumeric(GateRef gate);
143     void LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc);
144     void LowerConditionJump(GateRef gate, bool flag);
145 
146     void LowerTypedTryLdGlobalByName(GateRef gate);
147 
148     void LowerTypedStPrivateProperty(GateRef gate);
149     void LowerTypedLdPrivateProperty(GateRef gate);
150     GateRef GetPrimitiveTypeProto(PrimitiveType primitiveType);
151     void PolyPrimitiveTypeCheckAndLoad(LoadObjByNameDataInfo &info,
152         std::map<size_t, uint32_t> &typeIndex2HeapConstantIndex);
153     void GenerateMergedHClassListCheck(LoadObjByNameDataInfo &info, Label &hclassCheckExit,
154         Variable &checkResult, size_t index, GateRef receiverHC);
155     void PolyHeapObjectCheckAndLoad(LoadObjByNameDataInfo &info,
156         const std::map<size_t, uint32_t> &typeIndex2HeapConstantIndex);
157     void ReplaceHirWithCheckingAccessor(GateRef glue, GateRef hirGate, StateDepend replacement,
158         GateRef value, bool IsAccessor);
159     void LoadOnPrototypeForHeapObjectReceiver(const LoadObjPropertyTypeInfoAccessor &tacc, Variable &result,
160                                               LoadObjByNameOnProtoTypeInfo ldProtoInfo);
161     void LowerTypedMonoLdObjByNameOnProto(const LoadObjPropertyTypeInfoAccessor &tacc, Variable &result);
162     void LowerTypedMonoLdObjByName(const LoadObjPropertyTypeInfoAccessor &tacc);
163     void LowerTypedPolyLdObjByName(const LoadObjPropertyTypeInfoAccessor &tacc);
164 
IsNonExist(const LoadObjPropertyTypeInfoAccessor & tacc,uint32_t index)165     bool IsNonExist(const LoadObjPropertyTypeInfoAccessor &tacc, uint32_t index)
166     {
167         return compilationEnv_->SupportNonExistIC() && tacc.GetHolderHClass(index) == nullptr;
168     }
169 
170     void LowerTypedLdObjByName(GateRef gate);
171     void LowerTypedStObjByName(GateRef gate);
172     void TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
173                                     Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i);
174     void LowerTypedStOwnByName(GateRef gate);
175     GateRef BuildNamedPropertyAccess(GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr);
176     GateRef BuildNamedPropertyAccess(GateRef hir, GateRef receiver, GateRef holder,
177                                      GateRef value, PropertyLookupResult plr, uint32_t receiverHClassIndex = 0);
178     bool TryLowerTypedLdObjByNameForBuiltin(GateRef gate);
179     bool TryLowerTypedLdObjByNameForBuiltinsId(const LoadBuiltinObjTypeInfoAccessor &tacc, BuiltinTypeId type);
180     bool TryLowerTypedLdObjByNameForBuiltin(const LoadBuiltinObjTypeInfoAccessor &tacc);
181     bool TryLowerTypedLdObjByNameForGlobalsId(const LoadBuiltinObjTypeInfoAccessor &tacc, GlobalIndex globalsId);
182     void LowerTypedLdArrayLength(const LoadBuiltinObjTypeInfoAccessor &tacc);
183     void LowerTypedLdTypedArrayLength(const LoadBuiltinObjTypeInfoAccessor &tacc);
184     void LowerTypedLdStringLength(const LoadBuiltinObjTypeInfoAccessor &tacc);
185     void LowerTypedLdMapSize(const LoadBuiltinObjTypeInfoAccessor &tacc);
186     bool TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBuiltinObjTypeInfoAccessor &tacc, BuiltinTypeId type);
187 
188     void LowerTypedLdObjByIndex(GateRef gate);
189     bool TryLowerTypedLdObjByIndexForBuiltin(GateRef gate);
190     void LowerTypedStObjByIndex(GateRef gate);
191     bool TryLowerTypedStObjByIndexForBuiltin(GateRef gate);
192 
193     void LowerTypedLdObjByValue(GateRef gate);
194     bool TryLowerTypedLdObjByValueForBuiltin(GateRef gate);
195     void LowerTypedStObjByValue(GateRef gate);
196     void LowerTypedStOwnByValue(GateRef gate);
197     bool TryLowerTypedStObjByValueForBuiltin(GateRef gate);
198 
199     void LowerTypedIsTrueOrFalse(GateRef gate, bool flag);
200 
201     void LowerTypedNewObjRange(GateRef gate);
202     void LowerCreateEmptyObject(GateRef gate);
203     void LowerCreateObjectWithBuffer(GateRef gate);
204     void LowerTypedSuperCall(GateRef gate);
205 
206     void LowerTypedCallArg0(GateRef gate);
207     void LowerTypedCallArg1(GateRef gate);
208     void LowerTypedCallArg2(GateRef gate);
209     void LowerTypedCallArg3(GateRef gate);
210     void LowerTypedCallrange(GateRef gate);
211     void LowerTypedCallthis0(GateRef gate);
212     void LowerTypedCallthis1(GateRef gate);
213     void LowerTypedCallthis2(GateRef gate);
214     void LowerTypedCallthis3(GateRef gate);
215     void LowerTypedCallthisrange(GateRef gate);
216     void LowerTypedCallInit(GateRef gate);
217 
218     template<class TypeAccessor>
219     bool InSameConstPool(const TypeAccessor &tacc) const;
220 
221     template<class TypeAccessor>
222     void CheckFastCallThisCallTarget(const TypeAccessor &tacc);
223 
224     template<class TypeAccessor>
225     void CheckCallThisCallTarget(const TypeAccessor &tacc);
226 
227     template<class TypeAccessor>
228     void CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
229         const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall);
230 
231     template<class TypeAccessor>
232     void CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
233         const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC);
234 
235     template<class TypeAccessor>
236     void ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(const TypeAccessor &tacc,
237         const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall,
238         uint32_t heapConstantIndex, bool isNoGC);
239 
240     template<class TypeAccessor>
241     void CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
242         const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall);
243 
244     template<EcmaOpcode Op, class TypeAccessor>
245     void LowerTypedCall(const TypeAccessor &tacc);
246 
247     template<EcmaOpcode Op, class TypeAccessor>
248     void LowerTypedThisCall(const TypeAccessor &tacc);
249 
250     bool IsLoadVtable(GateRef func);
251     void LowerFastCall(GateRef gate, GateRef func, const std::vector<GateRef> &argsFastCall, bool isNoGC);
252     void LowerCall(GateRef gate, GateRef func, const std::vector<GateRef> &args, bool isNoGC);
253     void LowerTypedTypeOf(GateRef gate);
254     void LowerInstanceOf(GateRef gate);
255     void LowerGetIterator(GateRef gate);
256     GateRef LoadStringByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc);
257     GateRef LoadJSArrayByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc);
258     GateRef LoadTypedArrayByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc);
259     GateRef LoadElmentFromFloat64Array(const LoadBuiltinObjTypeInfoAccessor &tacc);
260     void StoreJSArrayByIndex(const StoreBuiltinObjTypeInfoAccessor &tacc);
261     void StoreTypedArrayByIndex(const StoreBuiltinObjTypeInfoAccessor &tacc);
262 
263     void AddBytecodeCount(EcmaOpcode op);
264     void DeleteBytecodeCount(EcmaOpcode op);
265     void AddHitBytecodeCount();
266 
TraceLazyDeoptNum(std::string_view func,bool success,GateRef gate)267     void TraceLazyDeoptNum([[maybe_unused]] std::string_view func,
268                            [[maybe_unused]] bool success, [[maybe_unused]] GateRef gate)
269     {
270 #if ECMASCRIPT_ENABLE_LAZY_DEOPT_TRACE
271         if (success) {
272             builder_.CallRuntime(glue_, RTSTUB_ID(TraceLazyDeoptNum),
273                 Gate::InvalidGateRef, {}, gate);
274         } else {
275             builder_.CallRuntime(glue_, RTSTUB_ID(TraceLazyDeoptFailNum),
276                 Gate::InvalidGateRef, {}, gate);
277         }
278 #endif
279     }
280 
281     template<class T>
TryLazyDeoptStableProtoChain(T & tacc,size_t index,GateRef gate)282     bool TryLazyDeoptStableProtoChain(T& tacc, size_t index, [[maybe_unused]] GateRef gate)
283     {
284         // enableLazyDeopt_ is always false in Aot now.
285         if (!enableLazyDeopt_) {
286             return false;
287         }
288 
289         auto holderHC = tacc.GetHolderHClass(index);
290         auto receiverHC = tacc.GetReceiverHClass(index);
291         bool success = compilationEnv_->GetDependencies()->DependOnStableProtoChain(compilationEnv_->GetJSThread(),
292                                                                                     receiverHC, holderHC);
293         TraceLazyDeoptNum(__PRETTY_FUNCTION__, success, gate);
294         return success;
295     }
296 
TryLazyDeoptNotPrototype(StoreObjByNameTypeInfoAccessor & tacc,size_t index,GateRef gate)297     bool TryLazyDeoptNotPrototype(StoreObjByNameTypeInfoAccessor& tacc,
298                                   size_t index, [[maybe_unused]] GateRef gate)
299     {
300         // enableLazyDeopt_ is always false in Aot now.
301         if (!enableLazyDeopt_) {
302             return false;
303         }
304 
305         auto receiverHC = tacc.GetReceiverHClass(index);
306         bool success = compilationEnv_->GetDependencies()->
307                                         DependOnNotPrototype(receiverHC);
308         TraceLazyDeoptNum(__PRETTY_FUNCTION__, success, gate);
309         return success;
310     }
311 
TryLazyDeoptBuiltinStableProtoChain(LoadBuiltinObjTypeInfoAccessor & tacc,size_t index,GateRef gate,JSHandle<GlobalEnv> globalEnv)312     bool TryLazyDeoptBuiltinStableProtoChain(LoadBuiltinObjTypeInfoAccessor& tacc,
313                                              size_t index, [[maybe_unused]] GateRef gate,
314                                              JSHandle<GlobalEnv> globalEnv)
315     {
316         // enableLazyDeopt_ is always false in Aot now.
317         if (!enableLazyDeopt_) {
318             return false;
319         }
320 
321         auto receiverHC = tacc.GetReceiverHClass(index);
322         bool success = compilationEnv_->GetDependencies()->DependOnStableProtoChain(
323             compilationEnv_->GetJSThread(), receiverHC, nullptr, globalEnv.GetObject<GlobalEnv>());
324         TraceLazyDeoptNum(__PRETTY_FUNCTION__, success, gate);
325         return success;
326     }
327 
TryLazyDeoptArrayGuardianCheck(GateRef gate)328     bool TryLazyDeoptArrayGuardianCheck([[maybe_unused]] GateRef gate)
329     {
330         // enableLazyDeopt_ is always false in Aot now.
331         if (!enableLazyDeopt_) {
332             return false;
333         }
334 
335         bool success = compilationEnv_->GetDependencies()->
336                                         DependOnArrayDetector(compilationEnv_->GetGlobalEnv().GetObject<GlobalEnv>());
337         TraceLazyDeoptNum(__PRETTY_FUNCTION__, success, gate);
338         return success;
339     }
340 
341     GateRef InternStringCheck(GateRef gate);
342     template<TypedBinOp Op>
343     void SpeculateInternStrings(const BinOpTypeInfoAccessor& tacc);
344     template<TypedBinOp Op>
345     void SpeculateStrings(const BinOpTypeInfoAccessor& tacc);
346     template<TypedBinOp Op>
347     void SpeculateNumbers(const BinOpTypeInfoAccessor& tacc);
348     template<TypedBinOp Op>
349     void SpeculateNumbersOrString(const BinOpTypeInfoAccessor& tacc);
350     template<TypedUnOp Op>
351     void SpeculateNumber(const UnOpTypeInfoAccessor& tacc);
352     void SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag);
353     void SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
354                               BuiltinsStubCSigns::ID id, bool isThrow);
355     void SpeculateCallBuiltinFromGlobal(GateRef gate, const std::vector<GateRef> &args,
356                                         BuiltinsStubCSigns::ID id, bool isThrow, bool isSideEffect = false);
357     void DeleteConstDataIfNoUser(GateRef gate);
358     bool TryLowerNewBuiltinConstructor(GateRef gate);
359     bool TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate);
360     bool CheckIsInOptBCIgnoreRange(int32_t index, EcmaOpcode ecmaOpcode);
361     bool IsTrueOrFalseHasProfileType(GateRef gate) const;
362     int32_t GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode);
363     void ParseOptBytecodeRange();
364     void ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend, GateRef value);
365 
366     const JSPandaFile* GetCalleePandaFile(GateRef gate);
367 
368     void AddProfiling(GateRef gate);
369 
IsFuncFromGlobal(GateRef gate)370     bool IsFuncFromGlobal(GateRef gate) const
371     {
372         return acc_.GetOpCode(gate) == OpCode::LOAD_BUILTIN_OBJECT;
373     }
374 
Uncheck()375     bool Uncheck() const
376     {
377         return noCheck_;
378     }
379 
380     Circuit *circuit_ {nullptr};
381     GateAccessor acc_;
382     PassContext *ctx_ {nullptr};
383     CircuitBuilder builder_;
384     GateRef dependEntry_ {Gate::InvalidGateRef};
385     Chunk *chunk_ {nullptr};
386     bool enableLog_ {false};
387     bool enableTypeLog_ {false};
388     bool profiling_ {false};
389     bool verifyVTable_ {false};
390     bool traceBc_ {false};
391     size_t allJSBcCount_ {0};
392     size_t allNonTypedOpCount_ {0};
393     size_t hitTypedOpCount_ {0};
394     std::string methodName_;
395     GateRef glue_ {Circuit::NullGate()};
396     ArgumentAccessor *argAcc_;
397     EcmaOpcode currentOp_ {static_cast<EcmaOpcode>(0xff)};
398     PGOTypeLogList pgoTypeLog_;
399     std::unordered_map<EcmaOpcode, uint32_t> bytecodeMap_;
400     std::unordered_map<EcmaOpcode, uint32_t> bytecodeHitTimeMap_;
401     bool noCheck_ {false};
402     CompilationEnv *compilationEnv_ {nullptr};
403     bool enableLoweringBuiltin_ {false};
404     bool enableMergePoly_ {true};
405     bool enableLazyDeopt_ {false};
406     const CString &recordName_;
407     const CallMethodFlagMap *callMethodFlagMap_;
408     PGOProfilerDecoder *decoder_ {nullptr};
409     std::string optBCRange_;
410     std::vector<std::vector<int32_t>> optBCRangeList_;
411     const MethodLiteral *currentMethod_ {nullptr};
412     uint32_t constPoolId_ {0};
413 };
414 }  // panda::ecmascript::kungfu
415 #endif  // ECMASCRIPT_COMPILER_TYPED_BYTECODE_LOWERING_H
416