From d43094722c3e179455ac6be735d886e09e1acddd Mon Sep 17 00:00:00 2001 From: huoqingyi Date: Wed, 28 Jun 2023 11:00:02 +0800 Subject: [PATCH] Support typeinfer for enum Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7GMOJ Tests: aot test, typeinfer test Signed-off-by: huoqingyi Change-Id: I8ee936b8009b6608aabfecbab76ba9ef67a32c29 --- .../compiler/bytecode_circuit_builder.h | 2 +- .../compiler/bytecode_info_collector.cpp | 14 ++- ecmascript/compiler/bytecode_info_collector.h | 40 +++--- ecmascript/compiler/type.h | 5 + .../type_inference/global_type_infer.cpp | 36 +++++- .../type_inference/global_type_infer.h | 10 ++ .../type_inference/method_type_infer.cpp | 116 +++++++++++++----- .../type_inference/method_type_infer.h | 18 +-- ecmascript/dump.cpp | 39 +++++- ecmascript/global_env_constants.cpp | 2 + ecmascript/global_env_constants.h | 1 + ecmascript/js_hclass.h | 13 +- ecmascript/js_runtime_options.cpp | 2 +- ecmascript/js_runtime_options.h | 2 +- ecmascript/js_tagged_value-inl.h | 5 + ecmascript/js_tagged_value.h | 1 + .../jspandafile/type_literal_extractor.cpp | 17 ++- .../jspandafile/type_literal_extractor.h | 14 ++- ecmascript/mem/object_xray.h | 3 + ecmascript/object_factory.cpp | 23 +++- ecmascript/object_factory.h | 2 + ecmascript/tests/dump_test.cpp | 8 +- ecmascript/ts_types/global_ts_type_ref.h | 1 + ecmascript/ts_types/ts_manager.cpp | 19 +-- ecmascript/ts_types/ts_manager.h | 15 ++- ecmascript/ts_types/ts_type.cpp | 55 +++------ ecmascript/ts_types/ts_type.h | 24 ++-- ecmascript/ts_types/ts_type_accessor.h | 3 +- test/typeinfer/es2abc_feature/BUILD.gn | 3 + test/typeinfer/es2abc_feature/enum/BUILD.gn | 19 +++ test/typeinfer/es2abc_feature/enum/enum.ts | 66 ++++++++++ .../es2abc_feature/enum_export/BUILD.gn | 20 +++ .../es2abc_feature/enum_export/enum_export.ts | 41 +++++++ .../es2abc_feature/enum_export/export1.ts | 26 ++++ .../es2abc_feature/enum_export/export2.ts | 26 ++++ .../es2abc_feature/enum_expr/BUILD.gn | 19 +++ .../es2abc_feature/enum_expr/enum_expr.ts | 87 +++++++++++++ 37 files changed, 651 insertions(+), 146 deletions(-) create mode 100644 test/typeinfer/es2abc_feature/enum/BUILD.gn create mode 100644 test/typeinfer/es2abc_feature/enum/enum.ts create mode 100644 test/typeinfer/es2abc_feature/enum_export/BUILD.gn create mode 100644 test/typeinfer/es2abc_feature/enum_export/enum_export.ts create mode 100644 test/typeinfer/es2abc_feature/enum_export/export1.ts create mode 100644 test/typeinfer/es2abc_feature/enum_export/export2.ts create mode 100644 test/typeinfer/es2abc_feature/enum_expr/BUILD.gn create mode 100644 test/typeinfer/es2abc_feature/enum_expr/enum_expr.ts diff --git a/ecmascript/compiler/bytecode_circuit_builder.h b/ecmascript/compiler/bytecode_circuit_builder.h index 5e2e8ad5de..535ea765f5 100644 --- a/ecmascript/compiler/bytecode_circuit_builder.h +++ b/ecmascript/compiler/bytecode_circuit_builder.h @@ -265,7 +265,7 @@ public: std::string name, const CString &recordName, PGOProfilerDecoder *decoder, - bool isInline) + bool isInline = false) : tsManager_(tsManager), circuit_(circuit), file_(jsPandaFile), method_(methodLiteral), gateAcc_(circuit), argAcc_(circuit, method_), typeRecorder_(jsPandaFile, method_, tsManager, recordName, decoder, methodPCInfo, bytecodes), diff --git a/ecmascript/compiler/bytecode_info_collector.cpp b/ecmascript/compiler/bytecode_info_collector.cpp index 6a03a7059c..dfe08b85cf 100644 --- a/ecmascript/compiler/bytecode_info_collector.cpp +++ b/ecmascript/compiler/bytecode_info_collector.cpp @@ -170,9 +170,10 @@ void BytecodeInfoCollector::CollectFunctionTypeId(panda_file::File::EntityId fie uint32_t typeId = annoExtractor.GetMethodTypeOffset(); if (typeId != 0) { bytecodeInfo_.SetFunctionTypeIDAndMethodOffset(typeId, offset); - } - if (annoExtractor.IsNamespace()) { - MarkMethodNamespace(offset); + } else if (annoExtractor.IsNamespace()) { + SetMethodKind(offset, TSMethodKind::NAMESPACE); + } else if (annoExtractor.IsEnum()) { + SetMethodKind(offset, TSMethodKind::ENUM); } } @@ -332,17 +333,18 @@ void BytecodeInfoCollector::CollectInnerMethods(uint32_t methodId, uint32_t inne methodList.emplace(innerMethodOffset, innerInfo); } -void BytecodeInfoCollector::MarkMethodNamespace(const uint32_t methodOffset) +void BytecodeInfoCollector::SetMethodKind(const uint32_t methodOffset, TSMethodKind kind) { auto &methodList = bytecodeInfo_.GetMethodList(); auto iter = methodList.find(methodOffset); if (iter != methodList.end()) { MethodInfo &methodInfo = iter->second; - methodInfo.MarkMethodNamespace(); + methodInfo.SetMethodKind(kind); return; } MethodInfo info(GetMethodInfoID(), 0, LexEnv::DEFAULT_ROOT, MethodInfo::DEFAULT_OUTMETHOD_OFFSET, - 0, LexicalEnvStatus::VIRTUAL_LEXENV, true); + 0, LexicalEnvStatus::VIRTUAL_LEXENV); + info.SetMethodKind(kind); methodList.emplace(methodOffset, info); } diff --git a/ecmascript/compiler/bytecode_info_collector.h b/ecmascript/compiler/bytecode_info_collector.h index 153ae3ae7a..a297f4e433 100644 --- a/ecmascript/compiler/bytecode_info_collector.h +++ b/ecmascript/compiler/bytecode_info_collector.h @@ -186,13 +186,19 @@ private: std::unordered_set starExportRecord_ {}; }; +enum class TSMethodKind : uint8_t { + DEFAULT, + NAMESPACE, + ENUM +}; + class MethodInfo { public: MethodInfo(uint32_t methodInfoIndex, uint32_t methodPcInfoIndex, uint32_t outMethodIdx, uint32_t outMethodOffset = MethodInfo::DEFAULT_OUTMETHOD_OFFSET, uint32_t num = 0, - LexicalEnvStatus lexEnvStatus = LexicalEnvStatus::VIRTUAL_LEXENV, bool isNamespace = false) + LexicalEnvStatus lexEnvStatus = LexicalEnvStatus::VIRTUAL_LEXENV) : methodInfoIndex_(methodInfoIndex), methodPcInfoIndex_(methodPcInfoIndex), outerMethodId_(outMethodIdx), - outerMethodOffset_(outMethodOffset), numOfLexVars_(num), status_(lexEnvStatus), isNamespace_(isNamespace) + outerMethodOffset_(outMethodOffset), numOfLexVars_(num), status_(lexEnvStatus) { } @@ -284,16 +290,6 @@ public: return bcToFuncTypeId_; } - inline void MarkMethodNamespace() - { - isNamespace_ = true; - } - - inline bool IsNamespace() const - { - return isNamespace_; - } - inline const std::vector &GetInnerMethods() const { return innerMethods_; @@ -354,6 +350,22 @@ public: CompileStateBit::ResolvedMethodBit::Set(isDeoptResolveNeed, &compileState_.value_); } + inline void SetMethodKind(TSMethodKind kind) + { + ASSERT(methodKind_ == TSMethodKind::DEFAULT); + methodKind_ = kind; + } + + inline bool IsNamespace() const + { + return methodKind_ == TSMethodKind::NAMESPACE; + } + + inline bool IsEnum() const + { + return methodKind_ == TSMethodKind::ENUM; + } + private: class CompileStateBit { public: @@ -386,7 +398,7 @@ private: LexicalEnvStatus status_ { LexicalEnvStatus::VIRTUAL_LEXENV }; std::set importIndex_ {}; CompileStateBit compileState_ { 0 }; - bool isNamespace_ {false}; + TSMethodKind methodKind_ { TSMethodKind::DEFAULT }; }; @@ -791,7 +803,7 @@ private: void CollectRecordReferenceREL(); void CollectRecordImportInfo(const CString &recordName); void CollectRecordExportInfo(const CString &recordName); - void MarkMethodNamespace(const uint32_t methodOffset); + void SetMethodKind(const uint32_t methodOffset, TSMethodKind kind); EcmaVM *vm_; JSPandaFile *jsPandaFile_ {nullptr}; diff --git a/ecmascript/compiler/type.h b/ecmascript/compiler/type.h index 82d85c0346..d91727728b 100644 --- a/ecmascript/compiler/type.h +++ b/ecmascript/compiler/type.h @@ -202,6 +202,11 @@ public: return (m == 0) && (l == static_cast(TSPrimitiveType::BIG_INT)); } + bool IsNullOrUndefinedType() const + { + return IsNullType() || IsUndefinedType(); + } + bool IsNJSValueType() const { return type_ == NJS_VALUE; diff --git a/ecmascript/compiler/type_inference/global_type_infer.cpp b/ecmascript/compiler/type_inference/global_type_infer.cpp index 3158d98a06..1a622e7210 100644 --- a/ecmascript/compiler/type_inference/global_type_infer.cpp +++ b/ecmascript/compiler/type_inference/global_type_infer.cpp @@ -134,10 +134,14 @@ void GlobalTypeInfer::ProcessTypeInference(BytecodeCircuitBuilder *builder, Circ GateType type; std::tie(type, methodId) = infer->TraverseInfer(); if (IsLegalMethod(methodId)) { + if (tsManager->IsEnumTypeKind(type)) { + InferEnum(methodId, type); + continue; + } MethodTypeInfer *nextInfer = GetTypeInfer(methodId); if (nextInfer != nullptr) { - nextInfer->SetNamespaceArgType(type); - tsManager->StoreNamespaceType(methodId, type); + nextInfer->SetIIFEArgType(type); + tsManager->StoreIIFEObjType(methodId, type); typeInferStack.push(nextInfer); continue; } @@ -149,6 +153,34 @@ void GlobalTypeInfer::ProcessTypeInference(BytecodeCircuitBuilder *builder, Circ RunTypeCheck(); } +void GlobalTypeInfer::InferIIFE(const uint32_t methodOffset, GateType type) +{ + auto module = ctx_->GetAOTModule(); + auto &methodList = bcInfo_.GetMethodList(); + MethodInfo &methodInfo = methodList.at(methodOffset); + const auto &methodPcInfos = bcInfo_.GetMethodPcInfos(); + auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()]; + auto methodLiteral = jsPandaFile_->FindMethodLiteral(methodOffset); + std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile_); + + Circuit circuit(ctx_->GetNativeAreaAllocator(), module->GetDebugInfo(), + fullName.c_str(), ctx_->GetCompilerConfig()->Is64Bit()); + circuit.SetFrameType(FrameType::OPTIMIZED_JS_FUNCTION_FRAME); + + BytecodeCircuitBuilder builder(jsPandaFile_, methodLiteral, methodPcInfo, ctx_->GetTSManager(), &circuit, + ctx_->GetByteCodes(), jsPandaFile_->HasTSTypes(recordName_), enableLog_, true, + fullName, recordName_, decoder_); + builder.BytecodeToCircuit(); + + MethodTypeInfer typeInfer(&builder, &circuit, ctx_, methodInfo.GetMethodInfoIndex(), + enableLog_, fullName, recordName_, &methodInfo, + methodLiteral, enableGlobalTypeInfer_); + typeInfer.SetIIFEArgType(type); + ctx_->GetTSManager()->StoreIIFEObjType(methodOffset, type); + typeInfer.TraverseInfer(); + typeInfer.CheckAndPrint(); +} + void GlobalTypeInfer::RunTypeCheck() { for (auto it : typeInfers_) { diff --git a/ecmascript/compiler/type_inference/global_type_infer.h b/ecmascript/compiler/type_inference/global_type_infer.h index 190cc0f63c..9ba7d2352d 100644 --- a/ecmascript/compiler/type_inference/global_type_infer.h +++ b/ecmascript/compiler/type_inference/global_type_infer.h @@ -44,9 +44,18 @@ private: return (methodOffset != 0); } + inline void InferEnum(const uint32_t methodId, GateType type) + { + if (inferredMethod_.find(methodId) == inferredMethod_.end()) { + InferIIFE(methodId, type); + inferredMethod_.insert(methodId); + } + } + void NewTypeInfer(const uint32_t methodOffset); void CollectNamespaceMethod(const uint32_t methodOffset); void CollectNamespaceMethods(const uint32_t methodOffset); + void InferIIFE(const uint32_t methodOffset, GateType type); void RunTypeCheck(); PassContext *ctx_ {nullptr}; @@ -61,6 +70,7 @@ private: std::vector builders_ {}; std::vector circuits_ {}; std::map typeInfers_ {}; + std::set inferredMethod_ {}; }; } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_TYPE_INFERENCE_GLOBAL_TYPE_INFER_H diff --git a/ecmascript/compiler/type_inference/method_type_infer.cpp b/ecmascript/compiler/type_inference/method_type_infer.cpp index 220daaae9a..4104f72e13 100644 --- a/ecmascript/compiler/type_inference/method_type_infer.cpp +++ b/ecmascript/compiler/type_inference/method_type_infer.cpp @@ -29,10 +29,10 @@ MethodTypeInfer::MethodTypeInfer(BytecodeCircuitBuilder *builder, Circuit *circu recordName_(recordName), methodInfo_(methodInfo), methodLiteral_(methodLiteral), inQueue_(circuit_->GetGateCount(), true), enableGlobalTypeInfer_(enableGlobalTypeInfer) { - if (enableGlobalTypeInfer_ && methodInfo->IsNamespace()) { + if (enableGlobalTypeInfer_ && (methodInfo->IsNamespace() || methodInfo->IsEnum())) { uint32_t methodOffset = methodLiteral_->GetMethodId().GetOffset(); - if (tsManager_->HasInferredNamespaceType(methodOffset)) { - SetNamespaceArgType(tsManager_->GetNamespaceObjType(methodOffset)); + if (tsManager_->HasInferredIIFEObjType(methodOffset)) { + SetIIFEArgType(tsManager_->GetIIFEObjType(methodOffset)); } } @@ -84,8 +84,12 @@ std::pair MethodTypeInfer::TraverseInfer() inQueue_[gateId] = true; pendingQueue_.push(*useIt); } - if (enableGlobalTypeInfer_ && IsNamespace(*useIt)) { - return SetAndReturnNamespaceObjType(*useIt); + if (!enableGlobalTypeInfer_) { + continue; + } + auto kind = IsIIFE(*useIt); + if (kind != TSMethodKind::DEFAULT) { + return SetAndReturnIIFEObjType(*useIt, kind); } } if (pendingQueue_.empty() && needUpdateForLoopPhi_) { @@ -346,6 +350,9 @@ bool MethodTypeInfer::Infer(GateRef gate) case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8: case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8: return InferStObjByName(gate); + case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8: + case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8: + return InferStObjByValue(gate); default: break; } @@ -372,7 +379,7 @@ bool MethodTypeInfer::InferPhiGate(GateRef gate) } if (valueInType.IsNumberType()) { numberTypeSet.insert(valueInType.GetGTRef()); - } else { + } else if (!valueInType.IsNullOrUndefinedType()) { typeList.emplace_back(valueInType.GetGTRef()); } } @@ -717,8 +724,9 @@ bool MethodTypeInfer::InferStObjByName(GateRef gate) uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1)); // 1: index of key JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(index); - if (tsManager_->IsNamespaceTypeKind(receiverType)) { - tsManager_->AddNamespacePropType(receiverType, propKey, valueType); + if (tsManager_->IsNamespaceTypeKind(receiverType) || + tsManager_->IsEnumTypeKind(receiverType)) { + tsManager_->AddIIFEObjPropType(receiverType, propKey, valueType); return true; } @@ -734,6 +742,35 @@ bool MethodTypeInfer::InferStObjByName(GateRef gate) return false; } +bool MethodTypeInfer::InferStObjByValue(GateRef gate) +{ + GateRef value = gateAccessor_.GetValueIn(gate, 3); // 3: index of value + GateType valueType = gateAccessor_.GetGateType(value); + if (valueType.IsAnyType()) { + return false; + } + + GateRef receiver = gateAccessor_.GetValueIn(gate, 1); // 1: index of receiver + GateType receiverType = gateAccessor_.GetGateType(receiver); + if (!tsManager_->IsEnumTypeKind(receiverType)) { + return false; + } + + GateRef key = gateAccessor_.GetValueIn(gate, 2); // 2: index of key + if (!IsByteCodeGate(key)) { + return false; + } + auto &info = GetByteCodeInfo(key); + if (!info.IsBc(EcmaOpcode::LDA_STR_ID16)) { + return false; + } + + uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(key, 0)); // 0: index of string + JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(index); + tsManager_->AddIIFEObjPropType(receiverType, propKey, valueType); + return true; +} + bool MethodTypeInfer::InferNewObject(GateRef gate) { auto objType = gateAccessor_.GetGateType(gate); @@ -1166,9 +1203,9 @@ GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const uint64_t return tsManager_->GetIndexSignType(objGT, GateType::NumberType()); } -// In TS, a namespace can be thought of as a formalization of the IIFE pattern. -// The function has only one parameter, which corresponds to the namespace object. -void MethodTypeInfer::SetNamespaceArgType(GateType type) +// In TS, a namespace/enum can be thought of as a formalization of the IIFE pattern. +// The function has only one parameter, which corresponds to the namespace/enum object. +void MethodTypeInfer::SetIIFEArgType(GateType type) { ArgumentAccessor argAcc(circuit_, methodLiteral_); // the last position is where the only parameter of the function are placed @@ -1176,68 +1213,77 @@ void MethodTypeInfer::SetNamespaceArgType(GateType type) gateAccessor_.SetGateType(gate, type); } -// When a IIFE which corresponds to namespaces declaration being called, -// A namespace type will be set to the namespace object. -std::pair MethodTypeInfer::SetAndReturnNamespaceObjType(GateRef gate) +// When a IIFE which corresponds to namespaces/enums declaration being called, +// A namespace/enum type will be set to the namespace/enum object. +std::pair MethodTypeInfer::SetAndReturnIIFEObjType(GateRef gate, TSMethodKind kind) { GateRef func = gateAccessor_.GetValueIn(gate, 1); // 1: index of func uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0)); // 0: index of methodId GateRef obj = gateAccessor_.GetValueIn(gate, 0); // 0: index of obj - // the obj must be phi gate due to the conversion of syntax sugar of namespace + // the obj must be phi gate due to the conversion of syntax sugar of namespace/enum ASSERT(gateAccessor_.IsValueSelector(obj)); - GlobalTSTypeRef gt = TryGetNamespaceType(obj); + GlobalTSTypeRef gt = TryGetIIFEObjType(obj); uint32_t methodId = ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset(); uint32_t length = gateAccessor_.GetNumValueIn(obj); for (uint32_t i = 0; i < length; i++) { - GateRef namespaceObj = gateAccessor_.GetValueIn(obj, i); - if (!IsByteCodeGate(namespaceObj)) { + GateRef value = gateAccessor_.GetValueIn(obj, i); + if (!IsByteCodeGate(value)) { continue; } - auto &bytecodeInfo = GetByteCodeInfo(namespaceObj); + auto &bytecodeInfo = GetByteCodeInfo(value); if (!bytecodeInfo.IsBc(EcmaOpcode::CREATEEMPTYOBJECT)) { continue; } if (gt.IsDefault()) { - gt = tsManager_->CreateNamespaceType(); + if (kind == TSMethodKind::NAMESPACE) { + gt = tsManager_->CreateNamespaceType(); + } else if (kind == TSMethodKind::ENUM) { + gt = tsManager_->CreateEnumType(); + } else { + continue; + } } - gateAccessor_.SetGateType(namespaceObj, GateType(gt)); + gateAccessor_.SetGateType(value, GateType(gt)); return std::make_pair(GateType(gt), methodId); } return std::make_pair((GateType(gt)), methodId); } -GlobalTSTypeRef MethodTypeInfer::TryGetNamespaceType(GateRef gate) const +GlobalTSTypeRef MethodTypeInfer::TryGetIIFEObjType(GateRef gate) const { ASSERT(gateAccessor_.IsValueSelector(gate)); uint32_t length = gateAccessor_.GetNumValueIn(gate); for (uint32_t i = 0; i < length; i++) { - GateRef namespaceObj = gateAccessor_.GetValueIn(gate, i); - GateType type = gateAccessor_.GetGateType(namespaceObj); - GlobalTSTypeRef namespaceGT(type.Value()); - if (tsManager_->IsNamespaceTypeKind(namespaceGT)) { - return namespaceGT; + GateRef obj = gateAccessor_.GetValueIn(gate, i); + GateType type = gateAccessor_.GetGateType(obj); + GlobalTSTypeRef objGT(type.Value()); + if (tsManager_->IsNamespaceTypeKind(objGT) || + tsManager_->IsEnumTypeKind(objGT)) { + return objGT; } } return GlobalTSTypeRef::Default(); } -bool MethodTypeInfer::IsNamespace(GateRef gate) const +TSMethodKind MethodTypeInfer::IsIIFE(GateRef gate) const { if (IsByteCodeGate(gate)) { auto &bytecodeInfo = GetByteCodeInfo(gate); if (bytecodeInfo.IsBc(EcmaOpcode::CALLARG1_IMM8_V8)) { GateRef obj = gateAccessor_.GetValueIn(gate, 0); // 0: index of obj GateRef func = gateAccessor_.GetValueIn(gate, 1); // 1: index of func - return CheckNamespaceFunc(func) && gateAccessor_.IsValueSelector(obj); + if (gateAccessor_.IsValueSelector(obj)) { + return CheckIIFEFunc(func); + } } } - return false; + return TSMethodKind::DEFAULT; } -bool MethodTypeInfer::CheckNamespaceFunc(GateRef func) const +TSMethodKind MethodTypeInfer::CheckIIFEFunc(GateRef func) const { if (IsByteCodeGate(func)) { auto &bytecodeInfo = GetByteCodeInfo(func); @@ -1249,10 +1295,14 @@ bool MethodTypeInfer::CheckNamespaceFunc(GateRef func) const auto &bcInfo = ctx_->GetBytecodeInfo(); auto &methodLists = bcInfo.GetMethodList(); auto &methodInfo = methodLists.at(methodId); - return methodInfo.IsNamespace(); + if (methodInfo.IsNamespace()) { + return TSMethodKind::NAMESPACE; + } else if (methodInfo.IsEnum()) { + return TSMethodKind::ENUM; + } } } - return false; + return TSMethodKind::DEFAULT; } void MethodTypeInfer::PrintTypeAnnotation() const diff --git a/ecmascript/compiler/type_inference/method_type_infer.h b/ecmascript/compiler/type_inference/method_type_infer.h index 072e17290a..fd340954c0 100644 --- a/ecmascript/compiler/type_inference/method_type_infer.h +++ b/ecmascript/compiler/type_inference/method_type_infer.h @@ -47,7 +47,7 @@ public: std::pair TraverseInfer(); void CheckAndPrint(); - void SetNamespaceArgType(GateType type); + void SetIIFEArgType(GateType type); bool IsLogEnabled() const { @@ -107,6 +107,7 @@ private: bool InferLdLocalModuleVar(GateRef gate); bool InferLdExternalModuleVar(GateRef gate); bool InferStObjByName(GateRef gate); + bool InferStObjByValue(GateRef gate); bool IsNewLexEnv(EcmaOpcode opcode) const; bool InferGetIterator(GateRef gate); bool InferLoopBeginPhiGate(GateRef gate); @@ -127,8 +128,11 @@ private: inline bool ShouldInferWithLdObjByName(const GateType &type) const { - return ShouldInferWithLdObjByValue(type) || tsManager_->IsIteratorInstanceTypeKind(type) || - tsManager_->IsInterfaceTypeKind(type) || tsManager_->IsNamespaceTypeKind(type); + return ShouldInferWithLdObjByValue(type) || + tsManager_->IsIteratorInstanceTypeKind(type) || + tsManager_->IsInterfaceTypeKind(type) || + tsManager_->IsNamespaceTypeKind(type) || + tsManager_->IsEnumTypeKind(type); } inline bool ShouldConvertToBuiltinArray(const GateType &type) const @@ -152,10 +156,10 @@ private: return builder_->GetBytecodeInfo(bcIndex); } - std::pair SetAndReturnNamespaceObjType(GateRef gate); - GlobalTSTypeRef TryGetNamespaceType(GateRef gate) const; - bool IsNamespace(GateRef gate) const; - bool CheckNamespaceFunc(GateRef func) const; + std::pair SetAndReturnIIFEObjType(GateRef gate, TSMethodKind kind); + GlobalTSTypeRef TryGetIIFEObjType(GateRef gate) const; + TSMethodKind IsIIFE(GateRef gate) const; + TSMethodKind CheckIIFEFunc(GateRef func) const; bool IsByteCodeGate(const GateRef gate) const { diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index 9b2178ba3a..78a9950877 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -373,6 +373,8 @@ CString JSHClass::DumpJSType(JSType type) return "TSIteratorInstanceType"; case JSType::TS_NAMESPACE_TYPE: return "TSNamespaceType"; + case JSType::TS_ENUM_TYPE: + return "TSEnumType"; case JSType::JS_API_ARRAYLIST_ITERATOR: return "JSArraylistIterator"; case JSType::LINKED_NODE: @@ -969,6 +971,9 @@ static void DumpObject(TaggedObject *obj, std::ostream &os) case JSType::TS_NAMESPACE_TYPE: TSNamespaceType::Cast(obj)->Dump(os); break; + case JSType::TS_ENUM_TYPE: + TSEnumType::Cast(obj)->Dump(os); + break; case JSType::LINKED_NODE: case JSType::RB_TREENODE: break; @@ -3397,7 +3402,27 @@ void TSNamespaceType::Dump(std::ostream &os) const os << localTypeId; os << "\n"; os << " - Properties: "; - DumpArrayClass(TaggedArray::Cast(GetPropertyType().GetTaggedObject()), os); + DumpArrayClass(TaggedArray::Cast(GetObjLayoutInfo().GetTaggedObject()), os); +} + +void TSEnumType::Dump(std::ostream &os) const +{ + os << " - Dump Enum Type - " << "\n"; + os << " - TSEnumType globalTSTypeRef: "; + GlobalTSTypeRef gt = GetGT(); + uint64_t globalTSTypeRef = gt.GetType(); + os << globalTSTypeRef; + os << "\n"; + os << " - TSEnumType moduleId: "; + uint32_t moduleId = gt.GetModuleId(); + os << moduleId; + os << "\n"; + os << " - TSEnumType localTypeId: "; + uint32_t localTypeId = gt.GetLocalId(); + os << localTypeId; + os << "\n"; + os << " - Properties: "; + DumpArrayClass(TaggedArray::Cast(GetObjLayoutInfo().GetTaggedObject()), os); } void SourceTextModule::Dump(std::ostream &os) const @@ -4109,6 +4134,9 @@ static void DumpObject(TaggedObject *obj, case JSType::TS_NAMESPACE_TYPE: TSNamespaceType::Cast(obj)->DumpForSnapshot(vec); return; + case JSType::TS_ENUM_TYPE: + TSEnumType::Cast(obj)->DumpForSnapshot(vec); + return; case JSType::METHOD: Method::Cast(obj)->DumpForSnapshot(vec); return; @@ -5308,7 +5336,14 @@ void TSIteratorInstanceType::DumpForSnapshot(std::vector> &vec) const { - vec.emplace_back("PropertyType", GetPropertyType()); + vec.emplace_back("ObjLayoutInfo", GetObjLayoutInfo()); + vec.emplace_back("IndexSigns", GetIndexSigns()); +} + +void TSEnumType::DumpForSnapshot(std::vector> &vec) const +{ + vec.emplace_back("ObjLayoutInfo", GetObjLayoutInfo()); + vec.emplace_back("IndexSigns", GetIndexSigns()); } void SourceTextModule::DumpForSnapshot(std::vector> &vec) const diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 47b2ae39d1..50c1f5b19b 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -229,6 +229,8 @@ void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass) JSType::TS_ITERATOR_INSTANCE_TYPE)); SetConstant(ConstantIndex::TS_NAMESPACE_TYPE_CLASS_INDEX, factory->NewEcmaReadOnlyHClass(hClass, TSNamespaceType::SIZE, JSType::TS_NAMESPACE_TYPE)); + SetConstant(ConstantIndex::TS_ENUM_TYPE_CLASS_INDEX, + factory->NewEcmaReadOnlyHClass(hClass, TSEnumType::SIZE, JSType::TS_ENUM_TYPE)); SetConstant(ConstantIndex::JS_REGEXP_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSRegExpIterator::SIZE, JSType::JS_REG_EXP_ITERATOR)); SetConstant(ConstantIndex::JS_SET_ITERATOR_CLASS_INDEX, diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index 22e0cf14b0..b2a07fe253 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -92,6 +92,7 @@ class ObjectFactory; V(JSTaggedValue, TSArrayTypeClass, TS_ARRAY_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSIteratorInstanceTypeClass, TS_ITERATOR_INSTANCE_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSNamespaceTypeClass, TS_NAMESPACE_TYPE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, TSEnumTypeClass, TS_ENUM_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSSetIteratorClass, JS_SET_ITERATOR_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSRegExpIteratorClass, JS_REGEXP_ITERATOR_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSMapIteratorClass, JS_MAP_ITERATOR_CLASS_INDEX, ecma_roots_class) \ diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index 66f30431e8..714c0241d8 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -247,6 +247,7 @@ class PropertyLookupResult; TS_INTERFACE_TYPE, /* //////////////////////////////////////////////////////////////////////////-PADDING */ \ TS_ITERATOR_INSTANCE_TYPE, /* //////////////////////////////////////////////////////////////////-PADDING */ \ TS_NAMESPACE_TYPE, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ + TS_ENUM_TYPE, /* /////////////////////////////////////////////////////////////////////////////////-PADDING */ \ \ VTABLE, /* //////////////////////////////////////////////////////////////////-PADDING */ \ AOT_LITERAL_INFO, /* //////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -277,7 +278,7 @@ class PropertyLookupResult; MODULE_RECORD_LAST = SOURCE_TEXT_MODULE_RECORD, /* ////////////////////////////////////////////////-PADDING */ \ \ TS_TYPE_FIRST = TS_ARRAY_TYPE, /* /////////////////////////////////////////////////////////////////-PADDING */ \ - TS_TYPE_LAST = TS_NAMESPACE_TYPE, /* ///////////////////////////////////////////////////////////////-PADDING */\ + TS_TYPE_LAST = TS_ENUM_TYPE, /* ////////////////////////////////////////////////////////////////////-PADDING */\ \ STRING_FIRST = LINE_STRING, /* /////////////////////////////////////////////////////////////////////-PADDING */\ STRING_LAST = TREE_STRING /* /////////////////////////////////////////////////////////////////////-PADDING */ @@ -1353,7 +1354,10 @@ public: inline bool IsTSObjectType() const { - return GetObjectType() == JSType::TS_OBJECT_TYPE; + JSType jsType = GetObjectType(); + return jsType == JSType::TS_OBJECT_TYPE || + jsType == JSType::TS_NAMESPACE_TYPE || + jsType == JSType::TS_ENUM_TYPE; } inline bool IsTSClassType() const @@ -1396,6 +1400,11 @@ public: return GetObjectType() == JSType::TS_NAMESPACE_TYPE; } + inline bool IsTSEnumType() const + { + return GetObjectType() == JSType::TS_ENUM_TYPE; + } + inline bool IsAOTLiteralInfo() const { return GetObjectType() == JSType::AOT_LITERAL_INFO; diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index 5a7cc3ab57..d79a94358e 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -63,7 +63,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = "Default: 'none'\n" "--compiler-type-threshold: enable to skip methods whose type is no more than threshold. Default: -1\n" "--compiler-log-snapshot: Enable to print snapshot information. Default: 'false'\n" - "--compiler-opt-global-typeinfer: Enable global typeinfer for aot compiler: Default: 'false'\n" + "--compiler-opt-global-typeinfer: Enable global typeinfer for aot compiler: Default: 'true'\n" "--compiler-log-time: Enable to print pass compiler time. Default: 'false'\n" "--enable-ark-tools: Enable ark tools to debug. Default: 'false'\n" "--compiler-trace-bc: Enable tracing bytecode for aot runtime. Default: 'false'\n" diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 1086bd451d..fdf941b3bb 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -1204,7 +1204,7 @@ private: bool enableValueNumbering_ {true}; bool enableOptInlining_ {false}; bool enableOptPGOType_ {true}; - bool enableGlobalTypeInfer_ {false}; + bool enableGlobalTypeInfer_ {true}; uint32_t compilerModuleMethods_ {100}; uint64_t wasSet_ {0}; bool enablePrintExecuteTime_ {false}; diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 0d5be6ffa8..d3f18be904 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -1334,6 +1334,11 @@ inline bool JSTaggedValue::IsTSNamespaceType() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSNamespaceType(); } +inline bool JSTaggedValue::IsTSEnumType() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSEnumType(); +} + inline bool JSTaggedValue::IsModuleRecord() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsModuleRecord(); diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index afe68e793a..c32d49e4f0 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -675,6 +675,7 @@ public: bool IsTSArrayType() const; bool IsTSIteratorInstanceType() const; bool IsTSNamespaceType() const; + bool IsTSEnumType() const; bool IsCjsExports() const; bool IsCjsModule() const; diff --git a/ecmascript/jspandafile/type_literal_extractor.cpp b/ecmascript/jspandafile/type_literal_extractor.cpp index 38d46813ec..0216321667 100644 --- a/ecmascript/jspandafile/type_literal_extractor.cpp +++ b/ecmascript/jspandafile/type_literal_extractor.cpp @@ -284,10 +284,9 @@ void TypeAnnotationExtractor::CollectTSMethodKind() return; } - if (typeIds_[i] == METHOD_ANNOTATION_NAMESPACE) { - isNamespace_ = true; - } + methodKind_ = static_cast(typeIds_[i]); typeIds_[i] = 0; // set default value + return; } } @@ -297,7 +296,7 @@ void TypeAnnotationExtractor::Print() const ASSERT(bcOffsets_.size() == typeIds_.size()); ASSERT(tags_.size() == typeIds_.size()); LOG_COMPILER(INFO) << "===================================================================="; - LOG_COMPILER(INFO) << "[TypeAnnotation]"; + LOG_COMPILER(INFO) << "[TypeAnnotation] " << PrintMethodKind(); uint32_t length = bcOffsets_.size(); for (uint32_t i = 0; i < length; ++i) { LOG_COMPILER(INFO) << "Order of bytecodes: " << std::setw(typeRightAdjustment) << bcOffsets_[i] << ", " @@ -306,6 +305,16 @@ void TypeAnnotationExtractor::Print() const } } +std::string TypeAnnotationExtractor::PrintMethodKind() const +{ + if (IsNamespace()) { + return "Method kind: namespace"; + } else if (IsEnum()) { + return "Method kind: enum"; + } + return ""; +} + std::string TypeAnnotationExtractor::PrintTag(LiteralTag tag) const { switch (tag) { diff --git a/ecmascript/jspandafile/type_literal_extractor.h b/ecmascript/jspandafile/type_literal_extractor.h index f884c62293..cfb9629271 100644 --- a/ecmascript/jspandafile/type_literal_extractor.h +++ b/ecmascript/jspandafile/type_literal_extractor.h @@ -188,7 +188,12 @@ public: bool IsNamespace() const { - return isNamespace_; + return methodKind_ == METHOD_ANNOTATION_NAMESPACE; + } + + bool IsEnum() const + { + return methodKind_ == METHOD_ANNOTATION_ENUM; } void Print() const; @@ -196,18 +201,19 @@ public: private: static constexpr const char *TYPE_ANNO_ELEMENT_NAME = "_TypeOfInstruction"; static constexpr int METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET = -1; - static constexpr int METHOD_ANNOTATION_NAMESPACE = 255; - static constexpr int METHOD_ANNOTATION_ENUM = 254; + static constexpr uint8_t METHOD_ANNOTATION_NAMESPACE = 255; + static constexpr uint8_t METHOD_ANNOTATION_ENUM = 254; void ProcessTypeAnnotation(const JSPandaFile *jsPandaFile, const uint32_t methodOffset); void CollectTSMethodKind(); std::string PrintTag(LiteralTag tag) const; + std::string PrintMethodKind() const; uint32_t methodTypeOffset_ {0}; std::vector bcOffsets_ {}; std::vector typeIds_ {}; std::vector tags_ {}; - bool isNamespace_ {false}; + uint8_t methodKind_ {0}; }; class ExportTypeTableExtractor { diff --git a/ecmascript/mem/object_xray.h b/ecmascript/mem/object_xray.h index badfbaeef4..2751adeb89 100644 --- a/ecmascript/mem/object_xray.h +++ b/ecmascript/mem/object_xray.h @@ -512,6 +512,9 @@ public: case JSType::TS_NAMESPACE_TYPE: TSNamespaceType::Cast(object)->VisitRangeSlot(visitor); break; + case JSType::TS_ENUM_TYPE: + TSEnumType::Cast(object)->VisitRangeSlot(visitor); + break; case JSType::RB_TREENODE: RBTreeNode::Cast(object)->VisitRangeSlot(visitor); break; diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 99b20013a6..74ef152073 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -3282,7 +3282,6 @@ JSHandle ObjectFactory::NewTSInterfaceType() return interfaceType; } - JSHandle ObjectFactory::NewTSUnionType(uint32_t length) { NewObjectHook(); @@ -3401,11 +3400,29 @@ JSHandle ObjectFactory::NewTSNamespaceType() JSHClass::Cast(thread_->GlobalConstants()->GetTSNamespaceTypeClass().GetTaggedObject())); JSHandle namespaceType(thread_, header); - namespaceType->SetPropertyType(thread_, JSTaggedValue::Undefined()); + namespaceType->SetObjLayoutInfo(thread_, JSTaggedValue::Undefined()); + namespaceType->SetIndexSigns(thread_, JSTaggedValue::Undefined()); + namespaceType->SetGT(GlobalTSTypeRef::Default()); JSHandle tsPropInfo = CreateTSObjLayoutInfo(TSObjLayoutInfo::DEFAULT_CAPACITY); - namespaceType->SetPropertyType(thread_, tsPropInfo); + namespaceType->SetObjLayoutInfo(thread_, tsPropInfo); return namespaceType; } + +JSHandle ObjectFactory::NewTSEnumType() +{ + NewObjectHook(); + + TaggedObject *header = heap_->AllocateYoungOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetTSEnumTypeClass().GetTaggedObject())); + JSHandle enumType(thread_, header); + + enumType->SetObjLayoutInfo(thread_, JSTaggedValue::Undefined()); + enumType->SetIndexSigns(thread_, JSTaggedValue::Undefined()); + enumType->SetGT(GlobalTSTypeRef::Default()); + JSHandle valueInfo = CreateTSObjLayoutInfo(TSObjLayoutInfo::DEFAULT_CAPACITY); + enumType->SetObjLayoutInfo(thread_, valueInfo); + return enumType; +} // ----------------------------------- new string ---------------------------------------- JSHandle ObjectFactory::NewFromASCII(const CString &data) { diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index 2958193967..7389092912 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -107,6 +107,7 @@ class TSFunctionType; class TSArrayType; class TSIteratorInstanceType; class TSNamespaceType; +class TSEnumType; class JSAPIArrayList; class JSAPIArrayListIterator; class JSAPIDeque; @@ -512,6 +513,7 @@ public: JSHandle NewTSArrayType(); JSHandle NewTSIteratorInstanceType(); JSHandle NewTSNamespaceType(); + JSHandle NewTSEnumType(); // ----------------------------------- new string ---------------------------------------- JSHandle NewFromASCII(const CString &data); diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index 5eab10144c..f9bba544de 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -1037,11 +1037,17 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) break; } case JSType::TS_NAMESPACE_TYPE: { - CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), TSNamespaceType::SIZE, 2U); + CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), TSNamespaceType::SIZE, 3U); JSHandle namespaceType = factory->NewTSNamespaceType(); DUMP_FOR_HANDLE(namespaceType) break; } + case JSType::TS_ENUM_TYPE: { + CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), TSEnumType::SIZE, 3U); + JSHandle enumType = factory->NewTSEnumType(); + DUMP_FOR_HANDLE(enumType) + break; + } case JSType::JS_API_ARRAY_LIST: { // 1 : 1 dump fileds number CHECK_DUMP_FIELDS(JSObject::SIZE, JSAPIArrayList::SIZE, 1U); diff --git a/ecmascript/ts_types/global_ts_type_ref.h b/ecmascript/ts_types/global_ts_type_ref.h index 2e23090118..472c56639c 100644 --- a/ecmascript/ts_types/global_ts_type_ref.h +++ b/ecmascript/ts_types/global_ts_type_ref.h @@ -38,6 +38,7 @@ enum class TSTypeKind : uint8_t { // the following typekinds are not recorded in abc files and will be created at compile time ITERATOR_INSTANCE, NAMESPACE, + ENUM, UNKNOWN, TYPEKIND_FIRST = CLASS, diff --git a/ecmascript/ts_types/ts_manager.cpp b/ecmascript/ts_types/ts_manager.cpp index dee6cade6a..b655b79c15 100644 --- a/ecmascript/ts_types/ts_manager.cpp +++ b/ecmascript/ts_types/ts_manager.cpp @@ -176,14 +176,10 @@ GlobalTSTypeRef TSManager::GetPropType(GlobalTSTypeRef gt, JSHandleIsTSInterfaceType()) { JSHandle interfaceType(type); return TSInterfaceType::GetPropTypeGT(thread, interfaceType, propertyName); - } else if (type->IsTSNamespaceType()) { - JSHandle namespaceType(type); - return TSNamespaceType::GetPropTypeGT(thread, namespaceType, propertyName); } return GlobalTSTypeRef::Default(); } - GlobalTSTypeRef TSManager::GetIndexSignType(GlobalTSTypeRef objType, kungfu::GateType indexType) const { JSThread *thread = vm_->GetJSThread(); @@ -316,6 +312,8 @@ TSTypeKind TSManager::GetTypeKind(const GlobalTSTypeRef >) const return TSTypeKind::ITERATOR_INSTANCE; case JSType::TS_NAMESPACE_TYPE: return TSTypeKind::NAMESPACE; + case JSType::TS_ENUM_TYPE: + return TSTypeKind::ENUM; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -635,13 +633,18 @@ GlobalTSTypeRef TSManager::CreateNamespaceType() return AddTSTypeToInferredTable(JSHandle(namespaceType)); } -void TSManager::AddNamespacePropType(kungfu::GateType objType, JSTaggedValue name, kungfu::GateType valueType) +GlobalTSTypeRef TSManager::CreateEnumType() +{ + JSHandle enumType = factory_->NewTSEnumType(); + return AddTSTypeToInferredTable(JSHandle(enumType)); +} + +void TSManager::AddIIFEObjPropType(kungfu::GateType objType, JSTaggedValue name, kungfu::GateType valueType) { JSHandle tsType = GetTSType(GlobalTSTypeRef(objType.Value())); - JSHandle namespaceType(tsType); JSHandle key(thread_, name); JSHandle value(thread_, JSTaggedValue(valueType.Value())); - TSNamespaceType::AddKeyAndValue(thread_, namespaceType, key, value); + TSObjectType::AddKeyAndValue(thread_, JSHandle(tsType), key, value); } GlobalTSTypeRef TSManager::GetClassType(GlobalTSTypeRef classInstanceGT) const @@ -1046,6 +1049,8 @@ std::string TSManager::GetTypeStr(kungfu::GateType gateType) const return "unknown"; case TSTypeKind::NAMESPACE: return "namespace"; + case TSTypeKind::ENUM: + return "enum"; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); diff --git a/ecmascript/ts_types/ts_manager.h b/ecmascript/ts_types/ts_manager.h index 229b5954d1..bf6a8fda57 100644 --- a/ecmascript/ts_types/ts_manager.h +++ b/ecmascript/ts_types/ts_manager.h @@ -369,7 +369,9 @@ public: GlobalTSTypeRef PUBLIC_API CreateNamespaceType(); - void AddNamespacePropType(kungfu::GateType objType, JSTaggedValue name, kungfu::GateType valueType); + GlobalTSTypeRef PUBLIC_API CreateEnumType(); + + void AddIIFEObjPropType(kungfu::GateType objType, JSTaggedValue name, kungfu::GateType valueType); inline bool IsUserDefinedClassTypeKind(const kungfu::GateType &gateType) const { @@ -382,18 +384,18 @@ public: return IsClassTypeKind(gt) && (!gt.IsBuiltinModule()); } - inline void StoreNamespaceType(const uint32_t methodOffset, const kungfu::GateType type) + inline void StoreIIFEObjType(const uint32_t methodOffset, const kungfu::GateType type) { methodOffsetToType_.insert(std::make_pair(methodOffset, type)); } - inline kungfu::GateType GetNamespaceObjType(const uint32_t methodOffset) const + inline kungfu::GateType GetIIFEObjType(const uint32_t methodOffset) const { - ASSERT(HasInferredNamespaceType(methodOffset)); + ASSERT(HasInferredIIFEObjType(methodOffset)); return methodOffsetToType_.at(methodOffset); } - inline bool HasInferredNamespaceType(const uint32_t methodOffset) const + inline bool HasInferredIIFEObjType(const uint32_t methodOffset) const { return methodOffsetToType_.find(methodOffset) != methodOffsetToType_.end(); } @@ -419,7 +421,8 @@ public: V(Import, TSTypeKind::IMPORT) \ V(Interface, TSTypeKind::INTERFACE) \ V(IteratorInstance, TSTypeKind::ITERATOR_INSTANCE) \ - V(Namespace, TSTypeKind::NAMESPACE) + V(Namespace, TSTypeKind::NAMESPACE) \ + V(Enum, TSTypeKind::ENUM) #define IS_TSTYPEKIND(NAME, TSTYPEKIND) \ inline bool PUBLIC_API Is##NAME##TypeKind(const kungfu::GateType &gateType) const \ diff --git a/ecmascript/ts_types/ts_type.cpp b/ecmascript/ts_types/ts_type.cpp index d8976d5fb7..4968140853 100644 --- a/ecmascript/ts_types/ts_type.cpp +++ b/ecmascript/ts_types/ts_type.cpp @@ -219,6 +219,10 @@ GlobalTSTypeRef TSObjectType::GetPropTypeGT(JSThread *thread, JSHandle propName) { DISALLOW_GARBAGE_COLLECTION; + if (objectType->GetObjLayoutInfo().IsUndefined()) { + return GlobalTSTypeRef::Default(); + } + JSHandle layout(thread, objectType->GetObjLayoutInfo().GetTaggedObject()); uint32_t numOfProps = layout->GetNumOfProperties(); JSMutableHandle propKey(thread, JSTaggedValue::Undefined()); @@ -266,6 +270,17 @@ GlobalTSTypeRef TSObjectType::GetIndexSignType(JSThread *thread, const JSHandle< return GlobalTSTypeRef::Default(); } +void TSObjectType::AddKeyAndValue(const JSThread *thread, const JSHandle &enumType, + const JSHandle &key, const JSHandle &value) +{ + JSHandle propLayout(thread, enumType->GetObjLayoutInfo()); + if (propLayout->Find(key.GetTaggedValue())) { + return; + } + JSHandle newPropLayout = TSObjLayoutInfo::PushBack(thread, propLayout, key, value); + enumType->SetObjLayoutInfo(thread, newPropLayout.GetTaggedValue()); +} + GlobalTSTypeRef TSFunctionType::GetParameterTypeGT(int index) const { DISALLOW_GARBAGE_COLLECTION; @@ -363,44 +378,4 @@ GlobalTSTypeRef TSInterfaceType::GetIndexSignType(JSThread *thread, const JSHand } return GlobalTSTypeRef::Default(); } - - -void TSNamespaceType::AddKeyAndValue(const JSThread *thread, const JSHandle &namespaceType, - const JSHandle &key, const JSHandle &value) -{ - JSHandle propLayout(thread, namespaceType->GetPropertyType()); - if (propLayout->Find(key.GetTaggedValue())) { - return; - } - JSHandle newPropLayout = TSObjLayoutInfo::PushBack(thread, propLayout, key, value); - namespaceType->SetPropertyType(thread, newPropLayout.GetTaggedValue()); -} - -GlobalTSTypeRef TSNamespaceType::GetPropTypeGT(JSThread *thread, const JSHandle &namespaceType, - const JSHandle &propName) -{ - DISALLOW_GARBAGE_COLLECTION; - if (namespaceType->GetPropertyType().IsUndefined()) { - return GlobalTSTypeRef::Default(); - } - - JSHandle properties(thread, namespaceType->GetPropertyType()); - - if (properties->IsUndefined()) { - return GlobalTSTypeRef::Default(); - } - - JSHandle layout(thread, namespaceType->GetPropertyType().GetTaggedObject()); - uint32_t numOfProps = layout->GetNumOfProperties(); - JSMutableHandle propKey(thread, JSTaggedValue::Undefined()); - for (uint32_t i = 0; i < numOfProps; ++i) { - propKey.Update(layout->GetKey(i)); - if (!JSTaggedValue::Equal(thread, propName, propKey)) { - continue; - } - uint32_t gtRawData = static_cast(layout->GetTypeId(i).GetInt()); - return GlobalTSTypeRef(gtRawData); - } - return GlobalTSTypeRef::Default(); -} } // namespace panda::ecmascript diff --git a/ecmascript/ts_types/ts_type.h b/ecmascript/ts_types/ts_type.h index 4f526bc5df..f75662df93 100644 --- a/ecmascript/ts_types/ts_type.h +++ b/ecmascript/ts_types/ts_type.h @@ -62,6 +62,9 @@ public: static GlobalTSTypeRef GetIndexSignType(JSThread *thread, const JSHandle &objectType, const uint32_t typeId); + static void AddKeyAndValue(const JSThread *thread, const JSHandle &objectType, + const JSHandle &key, const JSHandle &value); + ACCESSORS(ObjLayoutInfo, PROPERTIES_OFFSET, INDEX_SIGNS_OFFSET); ACCESSORS(IndexSigns, INDEX_SIGNS_OFFSET, SIZE); @@ -237,20 +240,19 @@ public: DECL_DUMP() }; -class TSNamespaceType : public TSType { +class TSNamespaceType : public TSObjectType { public: CAST_CHECK(TSNamespaceType, IsTSNamespaceType); - static constexpr size_t PROTOTYPE_TYPE_OFFSET = TSType::SIZE; - - ACCESSORS(PropertyType, PROTOTYPE_TYPE_OFFSET, SIZE); - - static void AddKeyAndValue(const JSThread *thread, const JSHandle &namespaceType, - const JSHandle &key, const JSHandle &value); - - static GlobalTSTypeRef GetPropTypeGT(JSThread *thread, const JSHandle &namespaceType, - const JSHandle &propName); + static constexpr size_t SIZE = TSObjectType::SIZE; + DECL_VISIT_OBJECT(TSType::SIZE, SIZE); + DECL_DUMP() +}; - DECL_VISIT_OBJECT(PROTOTYPE_TYPE_OFFSET, SIZE) +class TSEnumType : public TSObjectType { +public: + CAST_CHECK(TSEnumType, IsTSEnumType); + static constexpr size_t SIZE = TSObjectType::SIZE; + DECL_VISIT_OBJECT(TSType::SIZE, SIZE); DECL_DUMP() }; } // namespace panda::ecmascript diff --git a/ecmascript/ts_types/ts_type_accessor.h b/ecmascript/ts_types/ts_type_accessor.h index 08be69085a..7c4b35a221 100644 --- a/ecmascript/ts_types/ts_type_accessor.h +++ b/ecmascript/ts_types/ts_type_accessor.h @@ -29,7 +29,8 @@ namespace panda::ecmascript { V(Object, JSHandle) \ V(Interface, JSHandle) \ V(IteratorInstance, JSHandle) \ - V(Namespace, JSHandle) + V(Namespace, JSHandle) \ + V(Enum, JSHandle) #define CLASS_TYPE_BITFIELD_ACCESSOR_LIST(V) \ V(HasLinked) \ diff --git a/test/typeinfer/es2abc_feature/BUILD.gn b/test/typeinfer/es2abc_feature/BUILD.gn index 78543c85f4..e0184930a4 100644 --- a/test/typeinfer/es2abc_feature/BUILD.gn +++ b/test/typeinfer/es2abc_feature/BUILD.gn @@ -16,6 +16,9 @@ group("ark_typeinfer_es2abc_feature_test") { test_list = [ "arrow_function", "arrow_function_in_foreach", + "enum", + "enum_export", + "enum_expr", "indexsignature_class", "indexsignature_object", "member_variable_Initialization", diff --git a/test/typeinfer/es2abc_feature/enum/BUILD.gn b/test/typeinfer/es2abc_feature/enum/BUILD.gn new file mode 100644 index 0000000000..64a9788f3b --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_typeinfer_test_action("enum") { + deps = [] + is_enable_global_typeinfer = true +} diff --git a/test/typeinfer/es2abc_feature/enum/enum.ts b/test/typeinfer/es2abc_feature/enum/enum.ts new file mode 100644 index 0000000000..b8e9d6b764 --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum/enum.ts @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare function AssertType(value:any, type:string):void; + +enum Test1 { + A, + B, + C, +} + +AssertType(Test1, "enum"); +AssertType(Test1.A, "int"); +AssertType(Test1.B, "int"); +AssertType(Test1.C, "int"); + +enum Test2 { + A = 1.1, + B = 2.2, + C = 3.3, +} + +AssertType(Test2, "enum"); +AssertType(Test2.A, "double"); +AssertType(Test2.B, "double"); +AssertType(Test2.C, "double"); + +enum Test3 { + A = "a", + B = "b", + C = "c", +} + +AssertType(Test3, "enum"); +AssertType(Test3.A, "string"); +AssertType(Test3.B, "string"); +AssertType(Test3.C, "string"); + +function foo () { + AssertType(Test1, "enum"); + AssertType(Test1.A, "int"); + AssertType(Test1.B, "int"); + AssertType(Test1.C, "int"); + AssertType(Test2, "enum"); + AssertType(Test2.A, "double"); + AssertType(Test2.B, "double"); + AssertType(Test2.C, "double"); + AssertType(Test3, "enum"); + AssertType(Test3.A, "string"); + AssertType(Test3.B, "string"); + AssertType(Test3.C, "string"); +} + +foo(); diff --git a/test/typeinfer/es2abc_feature/enum_export/BUILD.gn b/test/typeinfer/es2abc_feature/enum_export/BUILD.gn new file mode 100644 index 0000000000..751620aaec --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum_export/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_typeinfer_test_action("enum_export") { + deps = [] + is_multi_file_tests = true + is_enable_global_typeinfer = true +} diff --git a/test/typeinfer/es2abc_feature/enum_export/enum_export.ts b/test/typeinfer/es2abc_feature/enum_export/enum_export.ts new file mode 100644 index 0000000000..8bfcc0d276 --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum_export/enum_export.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare function AssertType(value:any, type:string):void; + +import {Test1} from "./export1" +import {Test2} from "./export2" + +AssertType(Test1, "enum"); +AssertType(Test1.A, "int"); +AssertType(Test1.B, "int"); +AssertType(Test1.C, "int"); +AssertType(Test2, "enum"); +AssertType(Test2.A, "string"); +AssertType(Test2.B, "string"); +AssertType(Test2.C, "string"); + +function foo () { + AssertType(Test1, "enum"); + AssertType(Test1.A, "int"); + AssertType(Test1.B, "int"); + AssertType(Test1.C, "int"); + AssertType(Test2, "enum"); + AssertType(Test2.A, "string"); + AssertType(Test2.B, "string"); + AssertType(Test2.C, "string"); +} + +foo(); diff --git a/test/typeinfer/es2abc_feature/enum_export/export1.ts b/test/typeinfer/es2abc_feature/enum_export/export1.ts new file mode 100644 index 0000000000..1dae7e83c4 --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum_export/export1.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare function AssertType(value:any, type:string):void; +export enum Test1 { + A, + B, + C, +} + +AssertType(Test1, "enum"); +AssertType(Test1.A, "int"); +AssertType(Test1.B, "int"); +AssertType(Test1.C, "int"); diff --git a/test/typeinfer/es2abc_feature/enum_export/export2.ts b/test/typeinfer/es2abc_feature/enum_export/export2.ts new file mode 100644 index 0000000000..069b37f0db --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum_export/export2.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare function AssertType(value:any, type:string):void; +export enum Test2 { + A = "a", + B = "b", + C = "c", +} + +AssertType(Test2, "enum"); +AssertType(Test2.A, "string"); +AssertType(Test2.B, "string"); +AssertType(Test2.C, "string"); diff --git a/test/typeinfer/es2abc_feature/enum_expr/BUILD.gn b/test/typeinfer/es2abc_feature/enum_expr/BUILD.gn new file mode 100644 index 0000000000..384d262db0 --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum_expr/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_typeinfer_test_action("enum_expr") { + deps = [] + is_enable_global_typeinfer = true +} diff --git a/test/typeinfer/es2abc_feature/enum_expr/enum_expr.ts b/test/typeinfer/es2abc_feature/enum_expr/enum_expr.ts new file mode 100644 index 0000000000..57e9480516 --- /dev/null +++ b/test/typeinfer/es2abc_feature/enum_expr/enum_expr.ts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare function AssertType(value:any, type:string):void; + +enum Test1 { + A = 1 << 2, + B = 3 + 4 - 5 * 6, + C = "abc", + D = 123 | 456 & 789, +} + +AssertType(Test1, "enum"); +AssertType(Test1.A, "int"); +AssertType(Test1.B, "int"); +AssertType(Test1.C, "string"); +AssertType(Test1.D, "number"); + +enum Day { + SUNDAY = 0, + MONDAY = 1, + TUESDAY = 2, + WEDNESDAY = 3, + THURSDAY = 4, + FRIDAY = 5, + SATURDAY = 6, +} + +function foo(t:Day) { + switch (t) { + case Day.SUNDAY: { + AssertType(Day, "enum"); + AssertType(Day.SUNDAY, "int"); + } + case Day.MONDAY: { + AssertType(Day, "enum"); + AssertType(Day.MONDAY, "int"); + } + case Day.TUESDAY: { + AssertType(Day, "enum"); + AssertType(Day.TUESDAY, "int"); + } + case Day.WEDNESDAY: { + AssertType(Day, "enum"); + AssertType(Day.WEDNESDAY, "int"); + } + case Day.THURSDAY: { + AssertType(Day, "enum"); + AssertType(Day.THURSDAY, "int"); + } + case Day.FRIDAY: { + AssertType(Day, "enum"); + AssertType(Day.FRIDAY, "int"); + } + case Day.SATURDAY: { + AssertType(Day, "enum"); + AssertType(Day.SATURDAY, "int"); + } + default: { + AssertType(Day, "enum"); + } + } +} + +AssertType(Day, "enum"); +AssertType(Day.SUNDAY, "int"); +AssertType(Day.MONDAY, "int"); +AssertType(Day.TUESDAY, "int"); +AssertType(Day.WEDNESDAY, "int"); +AssertType(Day.THURSDAY, "int"); +AssertType(Day.FRIDAY, "int"); +AssertType(Day.SATURDAY, "int"); + +let t = Day.SUNDAY; +foo(t) -- Gitee