diff --git a/ecmascript/compiler/bytecode_info_collector.h b/ecmascript/compiler/bytecode_info_collector.h index 9055e52274..b96fe8dac6 100644 --- a/ecmascript/compiler/bytecode_info_collector.h +++ b/ecmascript/compiler/bytecode_info_collector.h @@ -196,25 +196,63 @@ public: bool IsPGO() const { - return isPgoMarked_; + return CompileStateBit::PGOBit::Decode(compileState_.value_); } void SetIsPGO(bool pgoMark) { - isPgoMarked_ = pgoMark; + CompileStateBit::PGOBit::Set(pgoMark, &compileState_.value_); } bool IsCompiled() const { - return isCompiled_; + return CompileStateBit::CompiledBit::Decode(compileState_.value_); } void SetIsCompiled(bool isCompiled) { - isCompiled_ = isCompiled; + CompileStateBit::CompiledBit::Set(isCompiled, &compileState_.value_); + } + + bool IsTypeInferAbort() const + { + return CompileStateBit::TypeInferAbortBit::Decode(compileState_.value_); + } + + void SetTypeInferAbort(bool halfCompiled) + { + CompileStateBit::TypeInferAbortBit::Set(halfCompiled, &compileState_.value_); + } + + bool IsResolvedMethod() const + { + return CompileStateBit::ResolvedMethodBit::Decode(compileState_.value_); + } + + void SetResolvedMethod(bool isDeoptResolveNeed) + { + CompileStateBit::ResolvedMethodBit::Set(isDeoptResolveNeed, &compileState_.value_); } private: + class CompileStateBit { + public: + explicit CompileStateBit(uint8_t value) : value_(value) {} + CompileStateBit() = default; + ~CompileStateBit() = default; + DEFAULT_COPY_SEMANTIC(CompileStateBit); + DEFAULT_MOVE_SEMANTIC(CompileStateBit); + + static constexpr size_t BOOL_FLAG_BIT_LENGTH = 1; + using PGOBit = panda::BitField; + using CompiledBit = PGOBit::NextField; + using TypeInferAbortBit = CompiledBit::NextField; + using ResolvedMethodBit = TypeInferAbortBit::NextField; + + private: + uint8_t value_ {0}; + friend class MethodInfo; + }; // used to record the index of the current MethodInfo to speed up the lookup of lexEnv uint32_t methodInfoIndex_ { 0 }; // used to obtain MethodPcInfo from the vector methodPcInfos of struct BCInfo @@ -224,8 +262,7 @@ private: uint32_t outerMethodOffset_ { MethodInfo::DEFAULT_OUTMETHOD_OFFSET }; uint32_t numOfLexVars_ { 0 }; LexicalEnvStatus status_ { LexicalEnvStatus::VIRTUAL_LEXENV }; - bool isPgoMarked_ {false}; - bool isCompiled_ {false}; + CompileStateBit compileState_ { 0 }; }; diff --git a/ecmascript/compiler/compilation_driver.h b/ecmascript/compiler/compilation_driver.h index 77f7199312..40b7d57910 100644 --- a/ecmascript/compiler/compilation_driver.h +++ b/ecmascript/compiler/compilation_driver.h @@ -38,7 +38,9 @@ public: void UpdateCompileQueue(const CString &recordName, EntityId resolvedMethod) { - if (pfLoader_.Match(recordName, resolvedMethod)) { + const auto &methodList = bytecodeInfo_.GetMethodList(); + auto &resolvedMethodInfo = methodList.at(resolvedMethod.GetOffset()); + if (pfLoader_.Match(recordName, resolvedMethod) && !resolvedMethodInfo.IsTypeInferAbort()) { return; } // update profile and update compile queue @@ -88,7 +90,12 @@ public: if (!methodInfo.IsCompiled()) { methodInfo.SetIsCompiled(true); cb(bytecodeInfo_.GetRecordName(index), methodName, methodLiteral, compilingMethod, - methodPcInfo, methodInfo.GetMethodInfoIndex()); + methodPcInfo, methodInfo); + } else if (NeedSecondaryCompile(methodInfo)) { + // if a method used to be not full compiled but now it's a deopt resolved method + // it should be full compiled again + cb(bytecodeInfo_.GetRecordName(index), methodName, methodLiteral, compilingMethod, + methodPcInfo, methodInfo); } } auto &innerMethods = methodInfo.GetInnerMethods(); @@ -106,6 +113,9 @@ public: return; } uint32_t resolvedMethod = bytecodeInfo_.GetDefineMethod(classLiteralOffset); + auto &methodList = bytecodeInfo_.GetMethodList(); + auto &methodInfo = methodList.at(resolvedMethod); + methodInfo.SetResolvedMethod(true); panda_file::File::EntityId resolvedMethodId(resolvedMethod); UpdateCompileQueue(recordName, resolvedMethodId); } @@ -114,6 +124,11 @@ private: void InitializeCompileQueue(); + bool NeedSecondaryCompile(const MethodInfo &methodInfo) const + { + return methodInfo.IsTypeInferAbort() && methodInfo.IsResolvedMethod(); + } + void SearchForCompilation(const std::unordered_set &methodSet, std::unordered_set &newMethodSet, uint32_t mainMethodOffset, bool needUpdateCompile) { @@ -132,7 +147,7 @@ private: auto &methodInfo = methodList.at(methodOffset); auto outMethodOffset = methodInfo.GetOutMethodOffset(); // if current method has already been marked as PGO, stop searching upper layer of the define chain - if (methodInfo.IsPGO()) { + if (methodInfo.IsPGO() && !methodInfo.IsTypeInferAbort()) { return; } // we need to collect these new-marked PGO methods to update PGO profile @@ -152,6 +167,7 @@ private: auto outMethodInfo = methodList.at(outMethodOffset); if (outMethodInfo.IsPGO()) { compileQueue_.push(methodOffset); + return; } } else { // if current searched method is an un-marked main method, just push it to compile queue diff --git a/ecmascript/compiler/compiler_log.cpp b/ecmascript/compiler/compiler_log.cpp index deb517ed22..275a29c402 100644 --- a/ecmascript/compiler/compiler_log.cpp +++ b/ecmascript/compiler/compiler_log.cpp @@ -34,7 +34,7 @@ CompilerLog::CompilerLog(const std::string &logOpt, bool TraceBC) traceBc_ = TraceBC; } -void CompilerLog::SetMethodLog(const std::string &fileName, const CString& recordName, +void CompilerLog::SetMethodLog(const std::string &fileName, const std::string &methodName, AotMethodLogList *logList) { bool enableMethodLog = !NoneMethod(); @@ -42,7 +42,6 @@ void CompilerLog::SetMethodLog(const std::string &fileName, const CString& recor enableMethodLog = logList->IncludesMethod(fileName, methodName); } SetEnableMethodLog(enableMethodLog); - AddCompiledMethod(methodName, recordName); } bool MethodLogList::IncludesMethod(const std::string &methodName) const diff --git a/ecmascript/compiler/compiler_log.h b/ecmascript/compiler/compiler_log.h index 48ee892e59..8b8f6f53fe 100644 --- a/ecmascript/compiler/compiler_log.h +++ b/ecmascript/compiler/compiler_log.h @@ -102,8 +102,9 @@ public: return GetEnableMethodLog() && OutputCIR(); } - void SetMethodLog(const std::string &fileName, const CString& recordName, + void SetMethodLog(const std::string &fileName, const std::string &methodName, AotMethodLogList *logList); + void AddCompiledMethod(const std::string& name, const CString& recordName); void Print() const; void AddMethodTime(const std::string& name, uint32_t id, double time); void AddPassTime(const std::string& name, double time); @@ -125,7 +126,6 @@ private: void PrintMethodTime() const; void PrintTime() const; void PrintCompiledMethod() const; - void AddCompiledMethod(const std::string& name, const CString& recordName); int idx_ {0}; bool allMethod_ {false}; diff --git a/ecmascript/compiler/pass.h b/ecmascript/compiler/pass.h index 84f2404f15..89715b729e 100644 --- a/ecmascript/compiler/pass.h +++ b/ecmascript/compiler/pass.h @@ -36,12 +36,12 @@ class PassInfo; class PassData { public: PassData(BytecodeCircuitBuilder *builder, Circuit *circuit, PassInfo *info, CompilerLog *log, - std::string methodName, size_t methodInfoIndex = 0, bool hasTypes = false, + std::string methodName, MethodInfo *methodInfo = nullptr, bool hasTypes = false, const CString &recordName = "", MethodLiteral *methodLiteral = nullptr, uint32_t methodOffset = 0, NativeAreaAllocator *allocator = nullptr) : builder_(builder), circuit_(circuit), info_(info), log_(log), methodName_(methodName), - methodInfoIndex_(methodInfoIndex), hasTypes_(hasTypes), recordName_(recordName), - methodLiteral_(methodLiteral), methodOffset_(methodOffset), allocator_(allocator) + methodInfo_(methodInfo), hasTypes_(hasTypes), recordName_(recordName), methodLiteral_(methodLiteral), + methodOffset_(methodOffset), allocator_(allocator) { } @@ -112,9 +112,14 @@ public: return methodOffset_; } + MethodInfo* GetMethodInfo() const + { + return methodInfo_; + } + size_t GetMethodInfoIndex() const { - return methodInfoIndex_; + return methodInfo_->GetMethodInfoIndex(); } bool HasTypes() const @@ -132,6 +137,31 @@ public: return allocator_; } + bool IsTypeAbort() const + { + if (hasTypes_) { + // A ts method which has low type percent and not marked as a resolved method + // should be skipped from full compilation. + if (methodInfo_->IsTypeInferAbort() && !methodInfo_->IsResolvedMethod()) { + info_->GetBytecodeInfo().AddSkippedMethod(methodOffset_); + return true; + } + } else { + // For js method, type infer pass will be skipped and it don't have a type percent. + // If we set an non zero type threshold, js method will be skipped from full compilation. + // The default Type threshold is -1. + if (info_->GetTSManager()->GetTypeThreshold() >= 0) { + info_->GetBytecodeInfo().AddSkippedMethod(methodOffset_); + return true; + } + } + // when a method will be full compiled, we should confirm its TypeInferAbortBit to be false + // maybe it used to be true in the first round of compilation. + methodInfo_->SetTypeInferAbort(false); + log_->AddCompiledMethod(methodName_, recordName_); + return false; + } + private: BytecodeCircuitBuilder *builder_ {nullptr}; Circuit *circuit_ {nullptr}; @@ -139,7 +169,7 @@ private: PassInfo *info_ {nullptr}; CompilerLog *log_ {nullptr}; std::string methodName_; - size_t methodInfoIndex_; + MethodInfo *methodInfo_ {nullptr}; bool hasTypes_; const CString &recordName_; MethodLiteral *methodLiteral_ {nullptr}; @@ -171,7 +201,7 @@ public: if (data->HasTypes()) { bool enableLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType(); TypeInfer typeInfer(data->GetBuilder(), data->GetCircuit(), data->GetInfo(), data->GetMethodInfoIndex(), - enableLog, data->GetMethodName(), data->GetRecordName()); + enableLog, data->GetMethodName(), data->GetRecordName(), data->GetMethodInfo()); typeInfer.TraverseCircuit(); } return true; diff --git a/ecmascript/compiler/pass_manager.cpp b/ecmascript/compiler/pass_manager.cpp index 5b59eefde4..4801aa5954 100644 --- a/ecmascript/compiler/pass_manager.cpp +++ b/ecmascript/compiler/pass_manager.cpp @@ -68,14 +68,14 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat cmpDriver.Run([this, &fileName, &info] (const CString recordName, const std::string &methodName, MethodLiteral *methodLiteral, - uint32_t methodOffset, const MethodPcInfo &methodPCInfo, size_t methodInfoIndex) { + uint32_t methodOffset, const MethodPcInfo &methodPCInfo, MethodInfo &methodInfo) { auto jsPandaFile = info.GetJSPandaFile(); auto cmpCfg = info.GetCompilerConfig(); auto tsManager = info.GetTSManager(); // note: TSManager need to set current constantpool before all pass tsManager->SetCurConstantPool(jsPandaFile, methodOffset); - log_->SetMethodLog(fileName, recordName, methodName, logList_); + log_->SetMethodLog(fileName, methodName, logList_); std::string fullName = methodName + "@" + fileName; bool enableMethodLog = log_->GetEnableMethodLog(); @@ -99,12 +99,15 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat } PassData data(&builder, &circuit, &info, log_, fullName, - methodInfoIndex, hasTypes, recordName, + &methodInfo, hasTypes, recordName, methodLiteral, methodOffset, vm_->GetNativeAreaAllocator()); PassRunner pipeline(&data); if (EnableTypeInfer()) { pipeline.RunPass(); } + if (data.IsTypeAbort()) { + return; + } pipeline.RunPass(); if (EnableTypeLowering()) { pipeline.RunPass(); diff --git a/ecmascript/compiler/pass_manager.h b/ecmascript/compiler/pass_manager.h index a6f0b00190..439f9efe9e 100644 --- a/ecmascript/compiler/pass_manager.h +++ b/ecmascript/compiler/pass_manager.h @@ -104,7 +104,8 @@ public: CompilerLog *log, AotMethodLogList *logList, size_t maxAotMethodSize, bool enableTypeLowering, const std::string &profIn, uint32_t hotnessThreshold) : vm_(vm), entry_(entry), triple_(triple), optLevel_(optLevel), relocMode_(relocMode), log_(log), - logList_(logList), maxAotMethodSize_(maxAotMethodSize), enableTypeLowering_(enableTypeLowering), + logList_(logList), maxAotMethodSize_(maxAotMethodSize), + enableTypeLowering_(enableTypeLowering), enableTypeInfer_(enableTypeLowering || vm_->GetTSManager()->AssertTypes()), profilerLoader_(profIn, hotnessThreshold) {}; PassManager() = default; diff --git a/ecmascript/compiler/ts_inline_lowering.cpp b/ecmascript/compiler/ts_inline_lowering.cpp index fd70e0009e..1bdaf8f507 100644 --- a/ecmascript/compiler/ts_inline_lowering.cpp +++ b/ecmascript/compiler/ts_inline_lowering.cpp @@ -162,7 +162,7 @@ void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPC } PassData data(&builder, circuit_, info_, log, fullName, - methodInfo.GetMethodInfoIndex(), hasTyps, recordName, + &methodInfo, hasTyps, recordName, method, method->GetMethodId().GetOffset()); PassRunner pipeline(&data); pipeline.RunPass(); diff --git a/ecmascript/compiler/type_inference/type_infer.cpp b/ecmascript/compiler/type_inference/type_infer.cpp index 79541ebf1c..dbe36f65b8 100644 --- a/ecmascript/compiler/type_inference/type_infer.cpp +++ b/ecmascript/compiler/type_inference/type_infer.cpp @@ -42,6 +42,8 @@ void TypeInfer::TraverseCircuit() PrintAllByteCodesTypes(); } + VerifyTypePercent(); + if (tsManager_->AssertTypes()) { Verify(); } @@ -113,7 +115,7 @@ void TypeInfer::UpdateQueueForLoopPhi() bool TypeInfer::UpdateType(GateRef gate, const GateType type, bool savePreType) { GateType preType = gateAccessor_.GetGateType(gate); - + needInferGates_.insert(gate); // When the type after type inference is any and you want to save previous type, it wolud not update. if (savePreType && type.IsAnyType()) { return false; @@ -159,7 +161,8 @@ bool TypeInfer::ShouldInfer(const GateRef gate) const * panda::ecmascript::kungfu::LexEnv which are created during the building of IR. So in the type inference, * newlexenv is ignored. */ - if (opcode != OpCode::CONSTANT && opcode != OpCode::RETURN && opcode != OpCode::JS_BYTECODE) { + if (opcode != OpCode::CONSTANT && opcode != OpCode::CONST_DATA && + opcode != OpCode::RETURN && opcode != OpCode::JS_BYTECODE) { return false; } if (jsgateToBytecode_.find(gate) == jsgateToBytecode_.end()) { @@ -587,7 +590,7 @@ bool TypeInfer::InferLdObjByIndex(GateRef gate) auto type = GetPropType(inValueType, key); return UpdateType(gate, type); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC) @@ -627,7 +630,7 @@ bool TypeInfer::InferLdGlobalVar(GateRef gate) if (iter != stringIdToGateType_.end()) { return UpdateType(gate, iter->second); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferReturnUndefined(GateRef gate) @@ -649,7 +652,7 @@ bool TypeInfer::InferLdObjByName(GateRef gate) ASSERT(gateAccessor_.GetNumValueIn(gate) == 3); auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2)); // 2: the third parameter is receiver if (objType.IsAnyType()) { - return false; + return UpdateType(gate, GateType::AnyType()); } if (ShouldConvertToBuiltinArray(objType)) { @@ -669,7 +672,7 @@ bool TypeInfer::InferLdObjByName(GateRef gate) uint16_t index = gateAccessor_.GetConstDataId(gateAccessor_.GetValueIn(gate, 1)).GetId(); return GetObjPropWithName(gate, objType, index); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferNewObject(GateRef gate) @@ -683,7 +686,7 @@ bool TypeInfer::InferNewObject(GateRef gate) return UpdateType(gate, classInstanceType); } } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferLdStr(GateRef gate) @@ -755,7 +758,7 @@ bool TypeInfer::InferCallFunction(GateRef gate) // For simplicity, calling and constructing are considered equivalent. return UpdateType(gate, tsManager_->CreateClassInstanceType(funcType)); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferLdObjByValue(GateRef gate) @@ -780,7 +783,7 @@ bool TypeInfer::InferLdObjByValue(GateRef gate) return GetObjPropWithName(gate, objType, index); } } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferGetNextPropName(GateRef gate) @@ -805,7 +808,7 @@ bool TypeInfer::InferSuperCall(GateRef gate) auto classInstanceType = tsManager_->CreateClassInstanceType(classType); return UpdateType(gate, classInstanceType); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferSuperPropertyByName(GateRef gate) @@ -827,7 +830,7 @@ bool TypeInfer::InferSuperPropertyByValue(GateRef gate) return GetSuperProp(gate, index, false); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::GetSuperProp(GateRef gate, uint64_t index, bool isString) @@ -852,7 +855,7 @@ bool TypeInfer::GetSuperProp(GateRef gate, uint64_t index, bool isString) } return UpdateType(gate, type); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferGetIterator(GateRef gate) @@ -866,7 +869,7 @@ bool TypeInfer::InferGetIterator(GateRef gate) } else if (inValueType.IsStringType()) { elementGt.SetType(GateType::StringType().Value()); } else { - return false; + return UpdateType(gate, GateType::AnyType()); } GlobalTSTypeRef iteratorInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType( TSRuntimeType::ITERATOR, elementGt); @@ -883,7 +886,7 @@ bool TypeInfer::InferTryLdGlobalByName(GateRef gate) if (iter != stringIdToGateType_.end()) { return UpdateType(gate, iter->second); } - return false; + return UpdateType(gate, GateType::AnyType()); } bool TypeInfer::InferLdLexVarDyn(GateRef gate) @@ -1168,4 +1171,31 @@ std::string TypeInfer::CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor * log += "\n[compiler] "; return log; } + +void TypeInfer::VerifyTypePercent() +{ + shouldInferNum_ = needInferGates_.size(); + for (auto gate : needInferGates_) { + if (!gateAccessor_.GetGateType(gate).IsAnyType()) { + normalInferNum_++; + } + } + double rate = (double)normalInferNum_ / (double)shouldInferNum_; + auto typeThreshold = tsManager_->GetTypeThreshold(); + if (rate <= typeThreshold) { + methodInfo_->SetTypeInferAbort(true); + } + if (IsLogEnabled()) { + LOG_COMPILER(INFO) << ""; + LOG_COMPILER(INFO) << "[TypeCoverage] print method type coverage: \n" + << "[compiler] [TypeCoverage] [ShouldInferedGate]: " << shouldInferNum_ + << " || [NormalInferedGate]: " << normalInferNum_ << "\n" + << "[compiler] [TypeCoverage] [TypeCoverage Percentage]: " + << std::fixed << std::setprecision(PERCENT_LENS) << rate * HUNDRED_TIME << "%"; + if (rate <= typeThreshold) { + LOG_COMPILER(INFO) << "[TypeCoverage] TypeCoverage Percentage is lower than threshold: [" + << typeThreshold << "]"; + } + } +} } // namespace panda::ecmascript diff --git a/ecmascript/compiler/type_inference/type_infer.h b/ecmascript/compiler/type_inference/type_infer.h index 05318ef992..8403f8df21 100644 --- a/ecmascript/compiler/type_inference/type_infer.h +++ b/ecmascript/compiler/type_inference/type_infer.h @@ -37,13 +37,15 @@ class TypeInfer { public: TypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit, PassInfo *info, size_t methodId, bool enableLog, - const std::string& name, const CString &recordName) + const std::string &name, const CString &recordName, + MethodInfo *methodInfo) : builder_(builder), circuit_(circuit), gateAccessor_(circuit), tsManager_(info->GetTSManager()), lexEnvManager_(info->GetLexEnvManager()), methodId_(methodId), enableLog_(enableLog), methodName_(name), recordName_(recordName), + methodInfo_(methodInfo), inQueue_(circuit_->GetGateCount(), true) { } @@ -66,6 +68,9 @@ public: } private: + static constexpr int PERCENT_LENS = 2; + static constexpr int HUNDRED_TIME = 100; + // savePreType: save the previous type, which is true by default bool UpdateType(GateRef gate, const GateType type, bool savePreType = true); bool UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef, bool savePreType = true); @@ -148,6 +153,7 @@ private: void PrintAllByteCodesTypes() const; void Verify() const; + void VerifyTypePercent(); void TypeCheck(GateRef gate) const; void FilterAnyTypeGates() const; @@ -177,7 +183,11 @@ private: std::unordered_map jsgateToBytecode_ {}; std::map loopPhiState_ {}; const CString &recordName_; + size_t shouldInferNum_ {0}; + size_t normalInferNum_ {0}; + MethodInfo *methodInfo_ {nullptr}; std::vector inQueue_; + std::unordered_set needInferGates_ {}; std::queue pendingQueue_ {}; }; } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index 89d4cd3877..11cc9b2fbe 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -60,6 +60,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = " Default: 'none'\n" "--compiler-log-methods: Specific method list for compiler log, only used when compiler-log." "Default: 'none'\n" + "--compiler-type-threshold: enable to skip methods whose type coverage is no more than threshold.. Default: -1\n" "--compiler-log-snapshot: Enable to print snapshot information. Default: 'false'\n" "--compiler-log-time: Enable to print pass compiler time. Default: 'false'\n" "--enable-ark-tools: Enable ark tools to debug. Default: 'false'\n" @@ -133,6 +134,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-log-methods", required_argument, nullptr, OPTION_COMPILER_LOG_METHODS}, {"compiler-log-snapshot", required_argument, nullptr, OPTION_COMPILER_LOG_SNAPSHOT}, {"compiler-log-time", required_argument, nullptr, OPTION_COMPILER_LOG_TIME}, + {"compiler-type-threshold", required_argument, nullptr, OPTION_COMPILER_TYPE_THRESHOLD}, {"enable-ark-tools", required_argument, nullptr, OPTION_ENABLE_ARK_TOOLS}, {"trace-bc", required_argument, nullptr, OPTION_TRACE_BC}, {"trace-deopt", required_argument, nullptr, OPTION_TRACE_DEOPT}, @@ -183,6 +185,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) uint32_t argUint32 = 0; int argInt = 0; bool argBool = false; + double argDouble = 0.0; static std::string COLON = ":"; if (argc <= 1) { @@ -404,6 +407,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) return false; } break; + case OPTION_COMPILER_TYPE_THRESHOLD: + ret = ParseDoubleParam("compiler-type-threshold", &argDouble); + if (ret) { + SetTypeThreshold(argDouble); + } else { + return false; + } + break; case OPTION_MAX_NONMOVABLE_SPACE_CAPACITY: ret = ParseUint32Param("maxNonmovableSpaceCapacity", &argUint32); if (ret) { @@ -544,7 +555,18 @@ bool JSRuntimeOptions::ParseBoolParam(bool* argBool) return true; } -bool JSRuntimeOptions::ParseIntParam(const std::string &option, int* argInt) +bool JSRuntimeOptions::ParseDoubleParam(const std::string &option, double *argDouble) +{ + *argDouble = std::stod(optarg, nullptr); + if (errno == ERANGE) { + std::cerr << "getopt: \"" << option << "\" argument has invalid parameter value \"" + << optarg <<"\"\n" << std::endl; + return false; + } + return true; +} + +bool JSRuntimeOptions::ParseIntParam(const std::string &option, int *argInt) { if (StartsWith(optarg, "0x")) { const int HEX = 16; @@ -554,7 +576,7 @@ bool JSRuntimeOptions::ParseIntParam(const std::string &option, int* argInt) } if (errno == ERANGE) { - std::cerr << "getopt: \"" << option <<"\" argument has invalid parameter value \"" + std::cerr << "getopt: \"" << option << "\" argument has invalid parameter value \"" << optarg <<"\"\n" << std::endl; return false; } @@ -572,7 +594,7 @@ bool JSRuntimeOptions::ParseUint32Param(const std::string &option, uint32_t *arg } if (errno == ERANGE) { - std::cerr << "getopt: \"" << option <<"\" argument has invalid parameter value \"" + std::cerr << "getopt: \"" << option << "\" argument has invalid parameter value \"" << optarg <<"\"\n" << std::endl; return false; } @@ -590,7 +612,7 @@ bool JSRuntimeOptions::ParseUint64Param(const std::string &option, uint64_t *arg } if (errno == ERANGE) { - std::cerr << "getopt: \"" << option <<"\" argument has invalid parameter value \"" + std::cerr << "getopt: \"" << option << "\" argument has invalid parameter value \"" << optarg <<"\"\n" << std::endl; return false; } diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 82199026aa..1c3a1074f0 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -82,6 +82,7 @@ enum CommandValues { OPTION_STARTUP_TIME, OPTION_COMPILER_LOG_OPT, OPTION_COMPILER_LOG_METHODS, + OPTION_COMPILER_TYPE_THRESHOLD, OPTION_ENABLE_RUNTIME_STAT, OPTION_ASSERT_TYPES, OPTION_PRINT_ANY_TYPES, @@ -749,6 +750,16 @@ public: maxAotMethodSize_ = value; } + double GetTypeThreshold() const + { + return typeThreshold_; + } + + void SetTypeThreshold(double threshold) + { + typeThreshold_ = threshold; + } + std::string GetEntryPoint() const { return entryPoint_; @@ -870,6 +881,7 @@ private: } bool ParseBoolParam(bool* argBool); + bool ParseDoubleParam(const std::string &option, double* argDouble); bool ParseIntParam(const std::string &option, int* argInt); bool ParseUint32Param(const std::string &option, uint32_t *argUInt32); bool ParseUint64Param(const std::string &option, uint64_t *argUInt64); @@ -915,6 +927,7 @@ private: arg_list_t logComponents_ {{"all"}}; bool enableAOT_ {false}; uint32_t maxAotMethodSize_ {32_KB}; + double typeThreshold_ {-1}; std::string entryPoint_ {"_GLOBAL::func_main_0"}; bool mergeAbc_ {false}; bool enableTypeLowering_ {true}; diff --git a/ecmascript/ts_types/ts_manager.cpp b/ecmascript/ts_types/ts_manager.cpp index 705e4f41c0..defb43b797 100644 --- a/ecmascript/ts_types/ts_manager.cpp +++ b/ecmascript/ts_types/ts_manager.cpp @@ -23,7 +23,8 @@ namespace panda::ecmascript { TSManager::TSManager(EcmaVM *vm) : vm_(vm), thread_(vm_->GetJSThread()), factory_(vm_->GetFactory()), assertTypes_(vm_->GetJSOptions().AssertTypes()), - printAnyTypes_(vm_->GetJSOptions().PrintAnyTypes()) + printAnyTypes_(vm_->GetJSOptions().PrintAnyTypes()), + typeThreshold_(vm_->GetJSOptions().GetTypeThreshold()) { JSHandle mTable = factory_->NewTSModuleTable(TSModuleTable::DEFAULT_TABLE_CAPACITY); SetTSModuleTable(mTable); diff --git a/ecmascript/ts_types/ts_manager.h b/ecmascript/ts_types/ts_manager.h index 2a7d8fa5a2..9e2bd2db1f 100644 --- a/ecmascript/ts_types/ts_manager.h +++ b/ecmascript/ts_types/ts_manager.h @@ -352,6 +352,11 @@ public: return printAnyTypes_; } + double PUBLIC_API GetTypeThreshold() const + { + return typeThreshold_; + } + bool IsBuiltinsDTSEnabled() const { return vm_->GetJSOptions().WasSetBuiltinsDTS(); @@ -730,6 +735,7 @@ private: std::map gtIhcMap_ {}; bool assertTypes_ {false}; bool printAnyTypes_ {false}; + double typeThreshold_ {-1}; // when the passmanager iterates each method, the curCP_ and curCPID_ should be updated // so that subsequent passes (type_infer, ts_type_lowering) can obtain the correct constpool.