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