From 34ddc4792258b6dfdf40c8735e1fa8f0ae9f956b Mon Sep 17 00:00:00 2001 From: huoqingyi Date: Wed, 12 Apr 2023 10:41:30 +0800 Subject: [PATCH] Support typeinfer for generic types [PART_1] In order to support typeinfer for generic types, we first need to refactor the process of extracting types and parsing types to handling negative numbers, which represent formal parameters of generic types recorded in type literals in abc files. Issus: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6UYLQ Tests: test262, typeinfer test, aot test Signed-off-by: huoqingyi Change-Id: I8197a93c81cc2b2335a418b0307b23880a0799e4 --- BUILD.gn | 1 + .../compiler/bytecode_info_collector.cpp | 124 +--- ecmascript/compiler/bytecode_info_collector.h | 7 +- ecmascript/compiler/type_recorder.cpp | 72 +-- ecmascript/jspandafile/js_pandafile.h | 2 +- .../jspandafile/literal_data_extractor.cpp | 43 -- .../jspandafile/literal_data_extractor.h | 5 +- .../jspandafile/panda_file_translator.cpp | 5 +- .../jspandafile/panda_file_translator.h | 4 +- .../jspandafile/type_literal_extractor.cpp | 248 +++++++ .../jspandafile/type_literal_extractor.h | 207 ++++++ ecmascript/ts_types/global_ts_type_ref.h | 19 +- ecmascript/ts_types/ts_manager.cpp | 46 +- ecmascript/ts_types/ts_manager.h | 21 +- ecmascript/ts_types/ts_type.h | 4 - ecmascript/ts_types/ts_type_parser.cpp | 611 +++++++++--------- ecmascript/ts_types/ts_type_parser.h | 96 ++- .../ts_types/ts_type_table_generator.cpp | 12 +- 18 files changed, 946 insertions(+), 581 deletions(-) create mode 100644 ecmascript/jspandafile/type_literal_extractor.cpp create mode 100644 ecmascript/jspandafile/type_literal_extractor.h diff --git a/BUILD.gn b/BUILD.gn index 3c721e1772..d4a040a959 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -625,6 +625,7 @@ ecma_source = [ "ecmascript/jspandafile/class_info_extractor.cpp", "ecmascript/jspandafile/debug_info_extractor.cpp", "ecmascript/jspandafile/literal_data_extractor.cpp", + "ecmascript/jspandafile/type_literal_extractor.cpp", "ecmascript/jspandafile/accessor/module_data_accessor.cpp", "ecmascript/jspandafile/panda_file_translator.cpp", "ecmascript/jspandafile/js_pandafile_executor.cpp", diff --git a/ecmascript/compiler/bytecode_info_collector.cpp b/ecmascript/compiler/bytecode_info_collector.cpp index 35bb73f305..925879ffe8 100644 --- a/ecmascript/compiler/bytecode_info_collector.cpp +++ b/ecmascript/compiler/bytecode_info_collector.cpp @@ -18,6 +18,7 @@ #include "ecmascript/base/path_helper.h" #include "ecmascript/compiler/type_recorder.h" #include "ecmascript/interpreter/interpreter-inl.h" +#include "ecmascript/jspandafile/type_literal_extractor.h" #include "ecmascript/ts_types/ts_type_parser.h" #include "libpandafile/code_data_accessor.h" @@ -79,7 +80,7 @@ void BytecodeInfoCollector::ProcessClasses() cda.EnumerateMethods([this, methods, &methodIdx, pf, &processedInsns, &recordNames, &methodPcInfos, &recordName] (panda_file::MethodDataAccessor &mda) { auto methodId = mda.GetMethodId(); - CollectFunctionTypeId(vm_->GetJSThread(), methodId); + CollectFunctionTypeId(methodId); // Generate all constpool vm_->FindOrCreateConstPool(jsPandaFile_, methodId); @@ -142,99 +143,50 @@ void BytecodeInfoCollector::CollectClassLiteralInfo(const MethodLiteral *method, } } -void BytecodeInfoCollector::CollectFunctionTypeId(JSThread *thread, panda_file::File::EntityId fieldId) +void BytecodeInfoCollector::CollectFunctionTypeId(panda_file::File::EntityId fieldId) { - const panda_file::File *pf = jsPandaFile_->GetPandaFile(); - panda_file::MethodDataAccessor mda(*pf, fieldId); - mda.EnumerateAnnotations([this, fieldId, pf, thread] (panda_file::File::EntityId annotationId) { - panda_file::AnnotationDataAccessor ada(*pf, annotationId); - auto *annotationName = reinterpret_cast(jsPandaFile_->GetStringData(ada.GetClassId()).data); - ASSERT(annotationName != nullptr); - if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) { - return; - } - uint32_t length = ada.GetCount(); - for (uint32_t i = 0; i < length; i++) { - panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); - auto *elemName = reinterpret_cast(jsPandaFile_->GetStringData(adae.GetNameId()).data); - ASSERT(elemName != nullptr); - if (::strcmp("_TypeOfInstruction", elemName) != 0) { - continue; + uint32_t offset = fieldId.GetOffset(); + TypeAnnotationExtractor annoExtractor(jsPandaFile_, offset); + annoExtractor.EnumerateInstsAndTypes( + [this, offset](const int32_t bcOffset, const uint32_t typeId) { + if (bcOffset == TypeRecorder::METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) { + bytecodeInfo_.SetFunctionTypeIDAndMethodOffset(typeId, offset); + return; } - - panda_file::ScalarValue sv = adae.GetScalarValue(); - panda_file::File::EntityId literalOffset(sv.GetValue()); - JSHandle typeOfInstruction = - LiteralDataExtractor::GetTypeLiteral(thread, jsPandaFile_, literalOffset); - - for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) { // + 2 means bcOffset and typeId - int32_t bcOffset = typeOfInstruction->Get(j).GetInt(); - uint32_t typeId = static_cast(typeOfInstruction->Get(j + 1).GetInt()); - if (bcOffset == TypeRecorder::METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) { - bytecodeInfo_.SetFunctionTypeIDAndMethodOffset(typeId, fieldId.GetOffset()); - return; - } - } - } - }); + }); } void BytecodeInfoCollector::IterateLiteral(const MethodLiteral *method, std::vector &classOffsetVector) { - const panda_file::File *pf = jsPandaFile_->GetPandaFile(); panda_file::File::EntityId fieldId = method->GetMethodId(); uint32_t defineMethodOffset = fieldId.GetOffset(); - panda_file::MethodDataAccessor methodDataAccessor(*pf, fieldId); - - methodDataAccessor.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) { - panda_file::AnnotationDataAccessor ada(*pf, annotation_id); - std::string annotationName = std::string(utf::Mutf8AsCString(pf->GetStringData(ada.GetClassId()).data)); - if (annotationName.compare("L_ESTypeAnnotation;") != 0) { - return; - } - uint32_t length = ada.GetCount(); - for (uint32_t i = 0; i < length; i++) { - panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); - std::string elemName = std::string(utf::Mutf8AsCString(pf->GetStringData(adae.GetNameId()).data)); - if (elemName.compare("_TypeOfInstruction") != 0) { - continue; + TypeAnnotationExtractor annoExtractor(jsPandaFile_, defineMethodOffset); + std::map offsetTypeMap; + annoExtractor.EnumerateInstsAndTypes( + [this, &offsetTypeMap, defineMethodOffset](const int32_t bcOffset, const uint32_t typeOffset) { + if (classDefBCIndexes_.find(bcOffset) != classDefBCIndexes_.end() || + classDefBCIndexes_.find(bcOffset - 1) != classDefBCIndexes_.end()) { // for getter setter + bytecodeInfo_.SetClassTypeOffsetAndDefMethod(typeOffset, defineMethodOffset); } - - panda_file::ScalarValue sv = adae.GetScalarValue(); - panda_file::File::EntityId literalOffset(sv.GetValue()); - JSHandle typeOfInstruction = - LiteralDataExtractor::GetTypeLiteral(vm_->GetJSThread(), jsPandaFile_, literalOffset); - std::map offsetTypeMap; - for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) { // 2: Two parsing once - int32_t bcOffset = typeOfInstruction->Get(j).GetInt(); - uint32_t typeOffset = static_cast(typeOfInstruction->Get(j + 1).GetInt()); - if (classDefBCIndexes_.find(bcOffset) != classDefBCIndexes_.end() || - classDefBCIndexes_.find(bcOffset - 1) != classDefBCIndexes_.end()) { // for getter setter - bytecodeInfo_.SetClassTypeOffsetAndDefMethod(typeOffset, defineMethodOffset); - } - if (bcOffset != TypeRecorder::METHOD_ANNOTATION_THIS_TYPE_OFFSET && - typeOffset > TSTypeParser::USER_DEFINED_TYPE_OFFSET) { - offsetTypeMap.insert(std::make_pair(bcOffset, typeOffset)); - } + if (bcOffset != TypeRecorder::METHOD_ANNOTATION_THIS_TYPE_OFFSET && + typeOffset > TSTypeParser::USER_DEFINED_TYPE_OFFSET) { + offsetTypeMap.insert(std::make_pair(bcOffset, typeOffset)); } + }); + + for (auto item : offsetTypeMap) { + uint32_t typeOffset = item.second; + StoreClassTypeOffset(typeOffset, classOffsetVector); + } - for (auto item : offsetTypeMap) { - uint32_t typeOffset = item.second; - StoreClassTypeOffset(typeOffset, classOffsetVector); - } - } - }); classDefBCIndexes_.clear(); } void BytecodeInfoCollector::StoreClassTypeOffset(const uint32_t typeOffset, std::vector &classOffsetVector) { - panda_file::File::EntityId offset(typeOffset); - JSHandle literal = - LiteralDataExtractor::GetTypeLiteral(vm_->GetJSThread(), jsPandaFile_, offset); - int typeKind = literal->Get(0).GetInt(); - if (typeKind != static_cast(TSTypeKind::CLASS)) { + TypeLiteralExtractor typeLiteralExtractor(jsPandaFile_, typeOffset); + if (typeLiteralExtractor.GetTypeKind() != TSTypeKind::CLASS) { return; } @@ -566,26 +518,12 @@ void BytecodeInfoCollector::CollectExportIndexs(const CString &recordName, uint3 bool BytecodeInfoCollector::CheckExportName(const CString &recordName, const JSHandle &exportStr) { auto tsManager = vm_->GetTSManager(); - // To compare with the exportTable, we need to parse the literalbuffer in abc TypeAnnotation. - // If the exportTable already exist, we will use it directly. OtherWise, we will parse and store it. - // In type system parser at a later stage, we will also use these arrays to avoid duplicate parsing. - if (tsManager->HasResolvedExportTable(jsPandaFile_, recordName)) { - JSTaggedValue exportTypeTable = tsManager->GetResolvedExportTable(jsPandaFile_, recordName); - JSHandle table(vm_->GetJSThread(), exportTypeTable); - return IsEffectiveExportName(exportStr, table); - } - JSHandle newResolvedTable = tsManager->GenerateExportTableFromLiteral(jsPandaFile_, recordName); - return IsEffectiveExportName(exportStr, newResolvedTable); -} - -bool BytecodeInfoCollector::IsEffectiveExportName(const JSHandle &exportNameStr, - const JSHandle &exportTypeTable) -{ + JSHandle exportTypeTable = tsManager->GetExportTableFromLiteral(jsPandaFile_, recordName); uint32_t length = exportTypeTable->GetLength(); for (uint32_t i = 0; i < length; i = i + 2) { // 2: skip a pair of key and value EcmaString *valueString = EcmaString::Cast(exportTypeTable->Get(i).GetTaggedObject()); uint32_t typeId = static_cast(exportTypeTable->Get(i + 1).GetInt()); - if (EcmaStringAccessor::StringsAreEqual(*exportNameStr, valueString) && typeId != 0) { + if (EcmaStringAccessor::StringsAreEqual(*exportStr, valueString) && typeId != 0) { return true; } } diff --git a/ecmascript/compiler/bytecode_info_collector.h b/ecmascript/compiler/bytecode_info_collector.h index 585d3a7fec..dd57eaf0a9 100644 --- a/ecmascript/compiler/bytecode_info_collector.h +++ b/ecmascript/compiler/bytecode_info_collector.h @@ -715,13 +715,10 @@ private: void IterateLiteral(const MethodLiteral *method, std::vector &classOffsetVector); void StoreClassTypeOffset(const uint32_t typeOffset, std::vector &classOffsetVector); void CollectClassLiteralInfo(const MethodLiteral *method, const std::vector &classNameVec); - void CollectFunctionTypeId(JSThread *thread, panda_file::File::EntityId fieldId); + void CollectFunctionTypeId(panda_file::File::EntityId fieldId); void CollectImportIndexs(uint32_t methodOffset, uint32_t index); void CollectExportIndexs(const CString &recordName, uint32_t index); - bool CheckExportName(const CString &recordName, - const JSHandle &exportStr); - bool IsEffectiveExportName(const JSHandle &exportNameStr, - const JSHandle &exportTypeTable); + bool CheckExportName(const CString &recordName, const JSHandle &exportStr); void CollectRecordReferenceREL(); void CollectRecordImportInfo(const CString &recordName); void CollectRecordExportInfo(const CString &recordName); diff --git a/ecmascript/compiler/type_recorder.cpp b/ecmascript/compiler/type_recorder.cpp index 9c46ef2739..de646680d1 100644 --- a/ecmascript/compiler/type_recorder.cpp +++ b/ecmascript/compiler/type_recorder.cpp @@ -15,12 +15,10 @@ #include "ecmascript/compiler/type_recorder.h" -#include "ecmascript/jspandafile/literal_data_extractor.h" +#include "ecmascript/jspandafile/type_literal_extractor.h" #include "ecmascript/pgo_profiler/pgo_profiler_loader.h" #include "ecmascript/ts_types/ts_type_parser.h" -#include "libpandafile/method_data_accessor-inl.h" - namespace panda::ecmascript::kungfu { TypeRecorder::TypeRecorder(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral, TSManager *tsManager, const CString &recordName, PGOProfilerLoader *loader) @@ -38,60 +36,34 @@ TypeRecorder::TypeRecorder(const JSPandaFile *jsPandaFile, const MethodLiteral * void TypeRecorder::LoadTypes(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral, TSManager *tsManager, const CString &recordName) { - JSThread *thread = tsManager->GetThread(); TSTypeParser typeParser(tsManager); - const panda_file::File *pf = jsPandaFile->GetPandaFile(); panda_file::File::EntityId fieldId = methodLiteral->GetMethodId(); - panda_file::MethodDataAccessor mda(*pf, fieldId); - mda.EnumerateAnnotations([&](panda_file::File::EntityId annotationId) { - panda_file::AnnotationDataAccessor ada(*pf, annotationId); - auto *annotationName = reinterpret_cast(jsPandaFile->GetStringData(ada.GetClassId()).data); - ASSERT(annotationName != nullptr); - if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) { + TypeAnnotationExtractor annoExtractor(jsPandaFile, fieldId.GetOffset()); + GlobalTSTypeRef thisGT; + GlobalTSTypeRef funcGT; + annoExtractor.EnumerateInstsAndTypes([this, &typeParser, &jsPandaFile, &recordName, &thisGT, + &funcGT](const int32_t bcOffset, const uint32_t typeId) { + GlobalTSTypeRef gt = typeParser.CreateGT(jsPandaFile, recordName, typeId); + if (gt.IsDefault()) { return; } - uint32_t length = ada.GetCount(); - for (uint32_t i = 0; i < length; i++) { - panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); - auto *elemName = reinterpret_cast(jsPandaFile->GetStringData(adae.GetNameId()).data); - ASSERT(elemName != nullptr); - if (::strcmp("_TypeOfInstruction", elemName) != 0) { - continue; - } - panda_file::ScalarValue sv = adae.GetScalarValue(); - panda_file::File::EntityId literalOffset(sv.GetValue()); - JSHandle typeOfInstruction = - LiteralDataExtractor::GetTypeLiteral(thread, jsPandaFile, literalOffset); - - GlobalTSTypeRef thisGT = GlobalTSTypeRef::Default(); - GlobalTSTypeRef funcGT = GlobalTSTypeRef::Default(); - for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) { // + 2 means bcOffset and typeId - int32_t bcOffset = typeOfInstruction->Get(j).GetInt(); - uint32_t typeId = static_cast(typeOfInstruction->Get(j + 1).GetInt()); - GlobalTSTypeRef gt = typeParser.CreateGT(jsPandaFile, recordName, typeId); - if (gt.IsDefault()) { - continue; - } - - // The type of a function is recorded as (-1, funcTypeId). If the function is a member of a class, - // the type of the class or its instance is is recorded as (-2, classTypeId). If it is a static - // member, the type id refers to the type of the class; otherwise, it links to the type of the - // instances of the class. - if (bcOffset == METHOD_ANNOTATION_THIS_TYPE_OFFSET) { - thisGT = gt; - continue; - } - if (bcOffset == METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) { - funcGT = gt; - continue; - } - auto type = GateType(gt); - bcOffsetGtMap_.emplace(bcOffset, type); - } - LoadArgTypes(tsManager, funcGT, thisGT); + // The type of a function is recorded as (-1, funcTypeId). If the function is a member of a class, + // the type of the class or its instance is is recorded as (-2, classTypeId). If it is a static + // member, the type id refers to the type of the class; otherwise, it links to the type of the + // instances of the class. + if (bcOffset == METHOD_ANNOTATION_THIS_TYPE_OFFSET) { + thisGT = gt; + return; } + if (bcOffset == METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) { + funcGT = gt; + return; + } + auto type = GateType(gt); + bcOffsetGtMap_.emplace(bcOffset, type); }); + LoadArgTypes(tsManager, funcGT, thisGT); } void TypeRecorder::LoadTypesFromPGO(const MethodLiteral *methodLiteral, const CString &recordName) diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index f4a44f8075..3d649268ca 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -22,7 +22,7 @@ #include "ecmascript/jspandafile/method_literal.h" #include "ecmascript/mem/c_containers.h" -#include "libpandafile/file.h" +#include "libpandafile/file-inl.h" #include "libpandafile/file_items.h" #include "libpandafile/literal_data_accessor.h" diff --git a/ecmascript/jspandafile/literal_data_extractor.cpp b/ecmascript/jspandafile/literal_data_extractor.cpp index ac3ea481d4..ee72dd4116 100644 --- a/ecmascript/jspandafile/literal_data_extractor.cpp +++ b/ecmascript/jspandafile/literal_data_extractor.cpp @@ -19,7 +19,6 @@ #include "ecmascript/ecma_string.h" #include "ecmascript/global_env.h" #include "ecmascript/js_thread.h" -#include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/patch/quick_fix_manager.h" #include "ecmascript/tagged_array-inl.h" @@ -445,46 +444,4 @@ JSHandle LiteralDataExtractor::GetDatasIgnoreType(JSThread *thread, }); return literals; } - -// use for parsing specific literal which record TS type info -JSHandle LiteralDataExtractor::GetTypeLiteral(JSThread *thread, const JSPandaFile *jsPandaFile, - EntityId offset) -{ - LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor(); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - uint32_t num = lda.GetLiteralValsNum(offset) / 2; // 2: half - JSHandle literals = factory->NewOldSpaceTaggedArray(num); - uint32_t pos = 0; - lda.EnumerateLiteralVals( - offset, [literals, &pos, factory, thread, jsPandaFile](const LiteralValue &value, const LiteralTag &tag) { - JSTaggedValue jt = JSTaggedValue::Null(); - switch (tag) { - case LiteralTag::INTEGER: { - jt = JSTaggedValue(base::bit_cast(std::get(value))); - break; - } - case LiteralTag::LITERALARRAY: { - ASSERT(std::get(value) > LITERALARRAY_VALUE_LOW_BOUNDARY); - jt = JSTaggedValue(std::get(value)); - break; - } - case LiteralTag::BUILTINTYPEINDEX: { - jt = JSTaggedValue(std::get(value)); - break; - } - case LiteralTag::STRING: { - StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); - EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::OLD_SPACE); - jt = JSTaggedValue(str); - break; - } - default: { - LOG_FULL(FATAL) << "type literal should not exist LiteralTag: " << static_cast(tag); - break; - } - } - literals->Set(thread, pos++, jt); - }); - return literals; -} } // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/literal_data_extractor.h b/ecmascript/jspandafile/literal_data_extractor.h index 245fb3858a..dad558ae60 100644 --- a/ecmascript/jspandafile/literal_data_extractor.h +++ b/ecmascript/jspandafile/literal_data_extractor.h @@ -16,7 +16,7 @@ #ifndef ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H #define ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H -#include "ecmascript/jspandafile/panda_file_translator.h" +#include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/js_tagged_value-inl.h" #include "libpandafile/literal_data_accessor-inl.h" @@ -57,9 +57,6 @@ public: static void PUBLIC_API GetMethodOffsets(const JSPandaFile *jsPandaFile, EntityId id, std::vector &methodOffsets); - - static JSHandle PUBLIC_API GetTypeLiteral(JSThread *thread, const JSPandaFile *jsPandaFile, - EntityId offset); private: static JSHandle EnumerateLiteralVals(JSThread *thread, panda_file::LiteralDataAccessor &lda, const JSPandaFile *jsPandaFile, size_t index, JSHandle constpool, diff --git a/ecmascript/jspandafile/panda_file_translator.cpp b/ecmascript/jspandafile/panda_file_translator.cpp index 0ec156676b..9f5f6aec5b 100644 --- a/ecmascript/jspandafile/panda_file_translator.cpp +++ b/ecmascript/jspandafile/panda_file_translator.cpp @@ -26,10 +26,9 @@ #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" -#include "ecmascript/ts_types/ts_manager.h" -#include "ecmascript/ts_types/ts_type_table.h" -#include "libpandabase/utils/utf.h" + #include "libpandafile/class_data_accessor-inl.h" +#include "libpandabase/utils/utf.h" namespace panda::ecmascript { template diff --git a/ecmascript/jspandafile/panda_file_translator.h b/ecmascript/jspandafile/panda_file_translator.h index 0e03704d92..acc812babf 100644 --- a/ecmascript/jspandafile/panda_file_translator.h +++ b/ecmascript/jspandafile/panda_file_translator.h @@ -17,14 +17,12 @@ #define ECMASCRIPT_JSPANDAFILE_PANDA_FILE_TRANSLATOR_H #include "ecmascript/ecma_vm.h" +#include "ecmascript/jspandafile/bytecode_inst/old_instruction.h" #include "ecmascript/jspandafile/constpool_value.h" #include "ecmascript/jspandafile/js_pandafile.h" #include "libpandabase/utils/bit_field.h" #include "libpandafile/code_data_accessor-inl.h" -#include "libpandafile/file-inl.h" - -#include "ecmascript/jspandafile/bytecode_inst/old_instruction.h" namespace panda::ecmascript { class Program; diff --git a/ecmascript/jspandafile/type_literal_extractor.cpp b/ecmascript/jspandafile/type_literal_extractor.cpp new file mode 100644 index 0000000000..28acbae8da --- /dev/null +++ b/ecmascript/jspandafile/type_literal_extractor.cpp @@ -0,0 +1,248 @@ +/* + * 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. + */ + +#include "ecmascript/jspandafile/type_literal_extractor.h" + +#include "libpandafile/literal_data_accessor-inl.h" +#include "libpandafile/method_data_accessor-inl.h" + +namespace panda::ecmascript { +using LiteralTag = panda_file::LiteralTag; +using LiteralValue = panda_file::LiteralDataAccessor::LiteralValue; +using StringData = panda_file::StringData; +using EntityId = panda_file::File::EntityId; +using LiteralDataAccessor = panda_file::LiteralDataAccessor; + +static constexpr const char *TYPE_ANNO_RECORD_NAME = "L_ESTypeAnnotation;"; + +static bool IsLegalOffset(uint32_t offset) +{ + return offset != 0U; +} + +static uint32_t GetMethodAnnoOffset(const JSPandaFile *jsPandaFile, uint32_t methodOffset, const char *annoName) +{ + const panda_file::File &pf = *jsPandaFile->GetPandaFile(); + EntityId methodId(methodOffset); + panda_file::MethodDataAccessor mda(pf, methodId); + + uint32_t annoOffset = 0; + mda.EnumerateAnnotations([&jsPandaFile, &annoName, &pf, &annoOffset](EntityId annotationId) { + panda_file::AnnotationDataAccessor ada(pf, annotationId); + auto *annotationName = reinterpret_cast(jsPandaFile->GetStringData(ada.GetClassId()).data); + ASSERT(annotationName != nullptr); + if (::strcmp(TYPE_ANNO_RECORD_NAME, annotationName) != 0) { + return; + } + uint32_t length = ada.GetCount(); + for (uint32_t i = 0; i < length; i++) { + panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); + auto *elemName = reinterpret_cast(jsPandaFile->GetStringData(adae.GetNameId()).data); + ASSERT(elemName != nullptr); + + if (::strcmp(annoName, elemName) != 0) { + continue; + } + + panda_file::ScalarValue sv = adae.GetScalarValue(); + annoOffset = sv.GetValue(); + } + }); + return annoOffset; +} + +TypeLiteralExtractor::TypeLiteralExtractor(const JSPandaFile *jsPandaFile, const uint32_t typeOffset) + : typeOffset_(typeOffset) +{ + ProcessTypeLiteral(jsPandaFile, typeOffset); +} + +void TypeLiteralExtractor::ProcessTypeLiteral(const JSPandaFile *jsPandaFile, const uint32_t typeOffset) +{ + EntityId literalId(typeOffset); + LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor(); + bool isFirst = true; + lda.EnumerateLiteralVals(literalId, + [this, &jsPandaFile, &isFirst](const LiteralValue &value, const LiteralTag &tag) { + if (isFirst) { + uint32_t kindValue = std::get(value); + if (UNLIKELY(!IsVaildKind(kindValue))) { + LOG_COMPILER(FATAL) << "Load type literal failure."; + return; + } + kind_ = static_cast(std::get(value)); + isFirst = false; + return; + } + switch (tag) { + case LiteralTag::INTEGER: { + uint32_t valueValue = std::get(value); + if (static_cast(valueValue) < 0) { + isGenerics_ = true; + } + array_.emplace_back(valueValue); + break; + } + case LiteralTag::LITERALARRAY: { + array_.emplace_back(std::get(value)); + break; + } + case LiteralTag::BUILTINTYPEINDEX: { + array_.emplace_back(static_cast(std::get(value))); + break; + } + case LiteralTag::STRING: { + StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); + CString stringValue = utf::Mutf8AsCString(sd.data); + array_.emplace_back(stringValue); + break; + } + default: { + LOG_COMPILER(FATAL) << "TypeLiteral should not exist LiteralTag: " << static_cast(tag); + break; + } + } + }); +} + +TypeSummaryExtractor::TypeSummaryExtractor(const JSPandaFile *jsPandaFile, const CString &recordName) +{ + ProcessTypeSummary(jsPandaFile, jsPandaFile->GetTypeSummaryOffset(recordName)); +} + +void TypeSummaryExtractor::ProcessTypeSummary(const JSPandaFile *jsPandaFile, const uint32_t summaryOffset) +{ + EntityId summaryId(summaryOffset); + LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor(); + bool isFirstIndex = true; + lda.EnumerateLiteralVals(summaryId, + [this, &isFirstIndex, &jsPandaFile](const LiteralValue &value, const LiteralTag &tag) { + switch (tag) { + case LiteralTag::LITERALARRAY: { + typeOffsets_.emplace_back(std::get(value)); + break; + } + case LiteralTag::BUILTINTYPEINDEX: { + typeOffsets_.emplace_back(static_cast(std::get(value))); + break; + } + case LiteralTag::INTEGER: { + if (isFirstIndex) { + numOfTypes_ = std::get(value); + typeOffsets_.emplace_back(numOfTypes_); + isFirstIndex = false; + } else { + numOfRedirects_ = std::get(value); + } + break; + } + case LiteralTag::STRING: { + StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); + CString stringValue = utf::Mutf8AsCString(sd.data); + reDirects_.emplace_back(stringValue); + break; + } + default: { + LOG_COMPILER(FATAL) << "TypeSummary should not exist LiteralTag: " << static_cast(tag); + break; + } + } + }); + ASSERT(typeOffsets_.size() == numOfTypes_ + 1); + ASSERT(reDirects_.size() == numOfRedirects_); +} + +TypeAnnotationExtractor::TypeAnnotationExtractor(const JSPandaFile *jsPandaFile, const uint32_t methodOffset) +{ + ProcessTypeAnnotation(jsPandaFile, methodOffset); +} + +void TypeAnnotationExtractor::ProcessTypeAnnotation(const JSPandaFile *jsPandaFile, const uint32_t methodOffset) +{ + uint32_t annoOffset = GetMethodAnnoOffset(jsPandaFile, methodOffset, TYPE_ANNO_ELEMENT_NAME); + if (!IsLegalOffset(annoOffset)) { + return; + } + + EntityId annoId(annoOffset); + LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor(); + lda.EnumerateLiteralVals(annoId, [this](const LiteralValue &value, const LiteralTag &tag) { + switch (tag) { + case LiteralTag::INTEGER: { + int32_t valueValue = base::bit_cast(std::get(value)); + bcOffsets_.emplace_back(valueValue); + break; + } + case LiteralTag::LITERALARRAY: { + typeIds_.emplace_back(std::get(value)); + break; + } + case LiteralTag::BUILTINTYPEINDEX: { + typeIds_.emplace_back(static_cast(std::get(value))); + break; + } + default: { + LOG_COMPILER(FATAL) << "TypeAnnotation should not exist LiteralTag: " << static_cast(tag); + break; + } + } + }); + ASSERT(bcOffsets_.size() == typeIds_.size()); +} + +ExportTypeTableExtractor::ExportTypeTableExtractor(const JSPandaFile *jsPandaFile, + const CString &recordName, + bool isBuiltinTable) +{ + ProcessExportTable(jsPandaFile, recordName, isBuiltinTable); +} + +void ExportTypeTableExtractor::ProcessExportTable(const JSPandaFile *jsPandaFile, + const CString &recordName, + bool isBuiltinTable) +{ + const char *name = isBuiltinTable ? DECLARED_SYMBOL_TYPES : EXPORTED_SYMBOL_TYPES; + uint32_t methodOffset = jsPandaFile->GetMainMethodIndex(recordName); + uint32_t annoOffset = GetMethodAnnoOffset(jsPandaFile, methodOffset, name); + if (!IsLegalOffset(annoOffset)) { + return; + } + + EntityId annoId(annoOffset); + LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor(); + lda.EnumerateLiteralVals(annoId, [this, &jsPandaFile](const LiteralValue &value, const LiteralTag &tag) { + switch (tag) { + case LiteralTag::LITERALARRAY: { + typeIds_.emplace_back(std::get(value)); + break; + } + case LiteralTag::BUILTINTYPEINDEX: { + typeIds_.emplace_back(static_cast(std::get(value))); + break; + } + case LiteralTag::STRING: { + StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); + exportVars_.emplace_back(utf::Mutf8AsCString(sd.data)); + break; + } + default: { + LOG_COMPILER(FATAL) << "TypeExportTable should not exist LiteralTag: " << static_cast(tag); + break; + } + } + }); + ASSERT(exportVars_.size() == typeIds_.size()); +} +} // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/type_literal_extractor.h b/ecmascript/jspandafile/type_literal_extractor.h new file mode 100644 index 0000000000..f8560cd6e2 --- /dev/null +++ b/ecmascript/jspandafile/type_literal_extractor.h @@ -0,0 +1,207 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_JSPANDAFILE_TYPE_LITERAL_EXTRACTOR_H +#define ECMASCRIPT_JSPANDAFILE_TYPE_LITERAL_EXTRACTOR_H + +#include "ecmascript/jspandafile/js_pandafile.h" + +namespace panda::ecmascript { +class TypeLiteralExtractor { +using TypeLiteralValue = std::variant; + +public: + explicit TypeLiteralExtractor(const JSPandaFile *jsPandaFile, const uint32_t typeOffset); + ~TypeLiteralExtractor() = default; + NO_COPY_SEMANTIC(TypeLiteralExtractor); + NO_MOVE_SEMANTIC(TypeLiteralExtractor); + + inline bool IsVaildTypeLiteral() const + { + return !array_.empty(); + } + + inline TSTypeKind GetTypeKind() const + { + return kind_; + } + + inline bool IsGenerics() const + { + return isGenerics_; + } + + inline void SetGenerics() + { + isGenerics_ = true; + } + + inline uint32_t GetIntValue(const uint32_t index) const + { + ASSERT(index < array_.size()); + auto t = array_[index]; + ASSERT(std::holds_alternative(t)); + return std::get(t); + } + + inline const CString &GetStringValue(const uint32_t index) const + { + ASSERT(index < array_.size()); + const auto &t = array_[index]; + ASSERT(std::holds_alternative(t)); + return std::get(t); + } + + inline uint32_t GetTypeOffset() const + { + return typeOffset_; + } + + template + void EnumerateElements(const uint32_t numIndex, const Callback &callback) + { + ASSERT(numIndex < array_.size()); + uint32_t length = std::get(array_[numIndex]); + ASSERT(numIndex + length < array_.size()); + for (uint32_t i = 1; i <= length; i++) { + uint32_t value = GetIntValue(numIndex + i); + callback(value); + } + } + + template + void EnumerateProperties(const uint32_t numIndex, const uint32_t gap, const Callback &callback) + { + ASSERT(numIndex < array_.size()); + ASSERT(gap >= VALUE_OFFSET); + uint32_t length = std::get(array_[numIndex]); + ASSERT(numIndex + length * gap < array_.size()); + for (uint32_t i = 0; i < length; i++) { + uint32_t keyIndex = numIndex + i * gap + KEY_OFFSET; + uint32_t valueIndex = numIndex + i * gap + VALUE_OFFSET; + const CString &key = GetStringValue(keyIndex); + uint32_t value = GetIntValue(valueIndex); + callback(key, value); + } + } + +private: + static constexpr uint32_t KEY_OFFSET = 1; + static constexpr uint32_t VALUE_OFFSET = 2; + + inline bool IsVaildKind(const uint32_t kindValue) const + { + return (static_cast(TSTypeKind::TYPEKIND_FIRST) <= kindValue) && + (kindValue <= static_cast(TSTypeKind::TYPEKIND_LAST)); + } + + void ProcessTypeLiteral(const JSPandaFile *jsPandaFile, const uint32_t typeOffset); + + std::vector array_; + uint32_t typeOffset_ { 0 }; + TSTypeKind kind_ { TSTypeKind::UNKNOWN }; + bool isGenerics_ { false }; +}; + +class TypeSummaryExtractor { +public: + explicit TypeSummaryExtractor(const JSPandaFile *jsPandaFile, const CString &recordName); + ~TypeSummaryExtractor() = default; + NO_COPY_SEMANTIC(TypeSummaryExtractor); + NO_MOVE_SEMANTIC(TypeSummaryExtractor); + + template + void EnumerateTypeOffsets(const uint32_t lastIndex, const Callback &callback) + { + ASSERT(lastIndex < typeOffsets_.size()); + for (uint32_t i = 0; i <= lastIndex; i++) { + callback(typeOffsets_[i]); + } + } + + inline uint32_t GetNumOfTypes() const + { + return numOfTypes_; + } + +private: + void ProcessTypeSummary(const JSPandaFile *jsPandaFile, const uint32_t summaryOffset); + + std::vector typeOffsets_ {}; + std::vector reDirects_ {}; + uint32_t numOfTypes_ { 0 }; + uint32_t numOfRedirects_ { 0 }; +}; + +class TypeAnnotationExtractor { +public: + explicit TypeAnnotationExtractor(const JSPandaFile *jsPandaFile, const uint32_t methodOffset); + ~TypeAnnotationExtractor() = default; + NO_COPY_SEMANTIC(TypeAnnotationExtractor); + NO_MOVE_SEMANTIC(TypeAnnotationExtractor); + + template + void EnumerateInstsAndTypes(const Callback &callback) + { + ASSERT(bcOffsets_.size() == typeIds_.size()); + uint32_t length = bcOffsets_.size(); + for (uint32_t i = 0; i < length; i++) { + callback(bcOffsets_[i], typeIds_[i]); + } + } + +private: + static constexpr const char *TYPE_ANNO_ELEMENT_NAME = "_TypeOfInstruction"; + + void ProcessTypeAnnotation(const JSPandaFile *jsPandaFile, const uint32_t methodOffset); + + std::vector bcOffsets_ {}; + std::vector typeIds_ {}; +}; + +class ExportTypeTableExtractor { +public: + explicit ExportTypeTableExtractor(const JSPandaFile *jsPandaFile, const CString &recordName, bool isBuiltinTable); + ~ExportTypeTableExtractor() = default; + NO_COPY_SEMANTIC(ExportTypeTableExtractor); + NO_MOVE_SEMANTIC(ExportTypeTableExtractor); + + inline uint32_t GetLength() const + { + ASSERT(exportVars_.size() == typeIds_.size()); + return exportVars_.size() + typeIds_.size(); + } + + template + void EnumerateModuleTypes(const Callback &callback) + { + ASSERT(exportVars_.size() == typeIds_.size()); + uint32_t length = exportVars_.size(); + for (uint32_t i = 0; i < length; i++) { + callback(exportVars_[i], typeIds_[i]); + } + } + +private: + static constexpr const char *DECLARED_SYMBOL_TYPES = "declaredSymbolTypes"; + static constexpr const char *EXPORTED_SYMBOL_TYPES = "exportedSymbolTypes"; + + void ProcessExportTable(const JSPandaFile *jsPandaFile, const CString &recordName, bool isBuiltinTable); + + std::vector exportVars_ {}; + std::vector typeIds_ {}; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_JSPANDAFILE_TYPE_LITERAL_EXTRACTOR_H diff --git a/ecmascript/ts_types/global_ts_type_ref.h b/ecmascript/ts_types/global_ts_type_ref.h index 8a6a54da9c..a785bc414b 100644 --- a/ecmascript/ts_types/global_ts_type_ref.h +++ b/ecmascript/ts_types/global_ts_type_ref.h @@ -20,12 +20,9 @@ #include "libpandabase/utils/bit_field.h" namespace panda::ecmascript { -/* - * To maintain consistency with the frontend, ITERATOR_INSTANCE should always be at - * the end of TSTypeKind, because there is no ITERATOR_INSTANCE in the frontend. - */ -enum class TSTypeKind : int { +enum class TSTypeKind : uint8_t { PRIMITIVE = 0, + // the following typekinds are recorded in abc files and are consistent with the corresponding values CLASS, CLASS_INSTANCE, FUNCTION, @@ -33,9 +30,17 @@ enum class TSTypeKind : int { ARRAY, OBJECT, IMPORT, - INTERFACE_KIND, + INTERFACE, + BUILTININST, + GENERICINST, + INDEXSIG, + + // the following typekinds are not recorded in abc files and will be created at compile time ITERATOR_INSTANCE, - UNKNOWN + UNKNOWN, + + TYPEKIND_FIRST = CLASS, + TYPEKIND_LAST = INDEXSIG, }; enum class TSPrimitiveType : int { diff --git a/ecmascript/ts_types/ts_manager.cpp b/ecmascript/ts_types/ts_manager.cpp index f38f3729b6..5ea8f6b084 100644 --- a/ecmascript/ts_types/ts_manager.cpp +++ b/ecmascript/ts_types/ts_manager.cpp @@ -20,7 +20,6 @@ #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/subtyping_operator.h" -#include "ecmascript/ts_types/ts_type_parser.h" #include "ecmascript/ts_types/ts_type_table_generator.h" #include "ecmascript/vtable.h" @@ -235,7 +234,7 @@ TSTypeKind TSManager::GetTypeKind(const GlobalTSTypeRef >) const case JSType::TS_OBJECT_TYPE: return TSTypeKind::OBJECT; case JSType::TS_INTERFACE_TYPE: - return TSTypeKind::INTERFACE_KIND; + return TSTypeKind::INTERFACE; case JSType::TS_ITERATOR_INSTANCE_TYPE: return TSTypeKind::ITERATOR_INSTANCE; default: @@ -909,7 +908,7 @@ std::string TSManager::GetTypeStr(kungfu::GateType gateType) const return "object"; case TSTypeKind::IMPORT: return "import"; - case TSTypeKind::INTERFACE_KIND: + case TSTypeKind::INTERFACE: return "interface"; case TSTypeKind::ITERATOR_INSTANCE: return "iterator_instance"; @@ -1220,12 +1219,36 @@ kungfu::GateType TSManager::TryNarrowUnionType(kungfu::GateType gateType) return gateType; } +JSHandle TSManager::GetExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName) +{ + // To compare with the exportTable, we need to parse the literalbuffer in abc TypeAnnotation. + // If the exportTable already exist, we will use it directly. OtherWise, we will parse and store it. + // In type system parser at a later stage, we will also use these arrays to avoid duplicate parsing. + if (HasResolvedExportTable(jsPandaFile, recordName)) { + JSTaggedValue exportTypeTable = GetResolvedExportTable(jsPandaFile, recordName); + JSHandle table(vm_->GetJSThread(), exportTypeTable); + return table; + } + + JSHandle typeOfExportedSymbols = GenerateExportTableFromLiteral(jsPandaFile, recordName); + AddResolvedExportTable(jsPandaFile, recordName, typeOfExportedSymbols.GetTaggedValue()); + return typeOfExportedSymbols; +} + JSHandle TSManager::GenerateExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName) { - TSTypeParser parser(this); - JSHandle typeOfExportedSymbols = parser.GetExportDataFromRecord(jsPandaFile, recordName); - AddResolvedExportTable(jsPandaFile, recordName, typeOfExportedSymbols.GetTaggedValue()); + bool isBuiltinTable = (std::strcmp(recordName.c_str(), TSTypeTable::BUILTINS_TABLE_NAME) == 0); + ExportTypeTableExtractor exTableExtractor(jsPandaFile, recordName, isBuiltinTable); + uint32_t length = exTableExtractor.GetLength(); + JSHandle typeOfExportedSymbols = factory_->NewOldSpaceTaggedArray(length); + uint32_t index = 0; + exTableExtractor.EnumerateModuleTypes( + [this, &typeOfExportedSymbols, &index](const CString &name, const uint32_t typeId) { + JSHandle str = factory_->NewFromUtf8(name); + typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue(str.GetTaggedValue())); + typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue(typeId)); + }); return typeOfExportedSymbols; } @@ -1285,12 +1308,11 @@ void TSManager::GenerateBuiltinSummary() SetBuiltinPandaFile(jsPandaFile.get()); CString builtinsRecordName(TSTypeTable::BUILTINS_TABLE_NAME); SetBuiltinRecordName(builtinsRecordName); - panda_file::File::EntityId summaryOffset(jsPandaFile->GetTypeSummaryOffset(builtinsRecordName)); - JSHandle builtinOffsets = - LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile.get(), summaryOffset); - for (uint32_t i = 0; i <= static_cast(BuiltinTypeId::NUM_OF_BUILTIN_TYPES); i++) { - builtinOffsets_.emplace_back(static_cast(builtinOffsets->Get(i).GetInt())); - } + TypeSummaryExtractor summExtractor(jsPandaFile.get(), builtinsRecordName); + summExtractor.EnumerateTypeOffsets(static_cast(BuiltinTypeId::NUM_OF_BUILTIN_TYPES), + [this](const uint32_t typeOffset) { + builtinOffsets_.emplace_back(typeOffset); + }); } void TSManager::PrintNumOfTypes() const diff --git a/ecmascript/ts_types/ts_manager.h b/ecmascript/ts_types/ts_manager.h index 48d684b325..5704d8fd49 100644 --- a/ecmascript/ts_types/ts_manager.h +++ b/ecmascript/ts_types/ts_manager.h @@ -16,12 +16,13 @@ #ifndef ECMASCRIPT_TS_TYPES_TS_MANAGER_H #define ECMASCRIPT_TS_TYPES_TS_MANAGER_H -#include "ecmascript/js_handle.h" -#include "ecmascript/js_tagged_value-inl.h" -#include "ecmascript/ts_types/global_ts_type_ref.h" -#include "ecmascript/ts_types/ts_obj_layout_info.h" #include "ecmascript/compiler/bytecode_info_collector.h" #include "ecmascript/compiler/compilation_driver.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/jspandafile/type_literal_extractor.h" +#include "ecmascript/ts_types/global_ts_type_ref.h" +#include "ecmascript/ts_types/ts_obj_layout_info.h" namespace panda::ecmascript { enum class MTableIdx : uint8_t { @@ -411,7 +412,7 @@ public: V(Array, TSTypeKind::ARRAY) \ V(Object, TSTypeKind::OBJECT) \ V(Import, TSTypeKind::IMPORT) \ - V(Interface, TSTypeKind::INTERFACE_KIND) \ + V(Interface, TSTypeKind::INTERFACE) \ V(IteratorInstance, TSTypeKind::ITERATOR_INSTANCE) \ #define IS_TSTYPEKIND(NAME, TSTYPEKIND) \ @@ -440,7 +441,11 @@ public: bool isImportType = false) { auto key = std::make_pair(jsPandaFile, offset); - literalOffsetGTMap_.emplace(key, gt); + if (literalOffsetGTMap_.find(key) != literalOffsetGTMap_.end()) { + literalOffsetGTMap_[key] = gt; + } else { + literalOffsetGTMap_.emplace(key, gt); + } if (!isImportType) { auto value = std::make_pair(recordName, offset); gtLiteralOffsetMap_.emplace(gt, value); @@ -693,7 +698,7 @@ public: kungfu::GateType TryNarrowUnionType(kungfu::GateType gateType); - JSHandle GenerateExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName); + JSHandle GetExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName); private: NO_COPY_SEMANTIC(TSManager); @@ -701,6 +706,8 @@ private: GlobalTSTypeRef AddTSTypeToTypeTable(const JSHandle &type, int tableId) const; + JSHandle GenerateExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName); + GlobalTSTypeRef FindUnionInTypeTable(JSHandle table, JSHandle unionType) const; GlobalTSTypeRef FindIteratorInstanceInInferTable(GlobalTSTypeRef kindGt, GlobalTSTypeRef elementGt) const; diff --git a/ecmascript/ts_types/ts_type.h b/ecmascript/ts_types/ts_type.h index 71ee1edc1a..18624cc533 100644 --- a/ecmascript/ts_types/ts_type.h +++ b/ecmascript/ts_types/ts_type.h @@ -77,7 +77,6 @@ class TSClassType : public TSType { public: CAST_CHECK(TSClassType, IsTSClassType); - static constexpr size_t FIELD_LENGTH = 4; // every field record name, typeIndex, accessFlag, readonly static constexpr size_t INSTANCE_TYPE_OFFSET = TSType::SIZE; static GlobalTSTypeRef GetPropTypeGT(JSThread *thread, JSHandle classType, @@ -149,9 +148,6 @@ class TSInterfaceType : public TSType { public: CAST_CHECK(TSInterfaceType, IsTSInterfaceType); - // every field record name, typeIndex, accessFlag, readonly - static constexpr size_t FIELD_LENGTH = 4; - static GlobalTSTypeRef GetPropTypeGT(JSThread *thread, JSHandle classInstanceType, JSHandle propName); diff --git a/ecmascript/ts_types/ts_type_parser.cpp b/ecmascript/ts_types/ts_type_parser.cpp index dd1d5acd27..70f2d7560a 100644 --- a/ecmascript/ts_types/ts_type_parser.cpp +++ b/ecmascript/ts_types/ts_type_parser.cpp @@ -17,13 +17,16 @@ #include "ecmascript/base/path_helper.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/jspandafile/literal_data_extractor.h" +#include "ecmascript/jspandafile/type_literal_extractor.h" #include "ecmascript/module/js_module_manager.h" -#include "libpandafile/annotation_data_accessor.h" -#include "libpandafile/class_data_accessor-inl.h" - namespace panda::ecmascript { +// For each property of one class, object or interface, it's name and typeIndex are recorded in order, +// and if it is a field, then accessFlag and readonly of this property will be additionally recorded. +static constexpr uint32_t FIELD_LENGTH = 4; +static constexpr uint32_t METHOD_LENGTH = 2; +static constexpr uint32_t INDEX_OCCUPIED_OFFSET = 1; + TSTypeParser::TSTypeParser(TSManager *tsManager) : tsManager_(tsManager), vm_(tsManager->GetEcmaVM()), thread_(vm_->GetJSThread()), factory_(vm_->GetFactory()), @@ -72,14 +75,13 @@ GlobalTSTypeRef TSTypeParser::ParseBuiltinObjType(uint32_t typeId) GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId) { - panda_file::File::EntityId offset(typeId); - JSHandle literal = LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, offset); - if (literal->GetLength() == 0) { // typeLiteral maybe hole in d.abc - return GetAndStoreGT(jsPandaFile, typeId, recordName); + TypeLiteralExtractor typeLiteralExtractor(jsPandaFile, typeId); + if (!typeLiteralExtractor.IsVaildTypeLiteral()) { // typeLiteral maybe hole in d.abc + return GlobalTSTypeRef::Default(); } - TSTypeKind kind = static_cast(literal->Get(TYPE_KIND_INDEX_IN_LITERAL).GetInt()); - if (kind == TSTypeKind::IMPORT) { - return ResolveImportType(jsPandaFile, recordName, literal, typeId); + + if (typeLiteralExtractor.GetTypeKind() == TSTypeKind::IMPORT) { + return ResolveImportType(jsPandaFile, recordName, &typeLiteralExtractor); } uint32_t moduleId = tableGenerator_.TryGetModuleId(recordName); @@ -100,7 +102,7 @@ GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CS table->SetNumberOfTypes(thread_, localId); GlobalTSTypeRef gt = GetAndStoreGT(jsPandaFile, typeId, recordName, moduleId, localId); - JSHandle type = ParseNonImportType(jsPandaFile, recordName, literal, kind, typeId); + JSHandle type = ParseNonImportType(jsPandaFile, recordName, &typeLiteralExtractor); if (UNLIKELY(type->IsUndefined())) { return GetAndStoreGT(jsPandaFile, typeId, recordName); } @@ -111,9 +113,11 @@ GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CS } GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle literal, uint32_t typeId) + TypeLiteralExtractor *typeLiteralExtractor) { - JSHandle importVarNamePath(thread_, literal->Get(IMPORT_PATH_OFFSET_IN_LITERAL)); // #A#./A + uint32_t typeId = typeLiteralExtractor->GetTypeOffset(); + JSHandle importVarNamePath = + factory_->NewFromUtf8(typeLiteralExtractor->GetStringValue(DEFAULT_INDEX)); JSHandle relativePath = GenerateImportRelativePath(importVarNamePath); CString cstringRelativePath = ConvertToString(*relativePath); // skip @ohos:|@app:|@native: prefixed imports @@ -135,7 +139,7 @@ GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, uint32_t moduleId = tableGenerator_.TryGetModuleId(entryPoint); if (UNLIKELY(!GlobalTSTypeRef::IsVaildModuleId(moduleId))) { - LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the recored " + LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the record " << entryPoint << " will not be parsed and will be treated as any."; return GetAndStoreGT(jsPandaFile, typeId, recordName); } @@ -150,40 +154,43 @@ GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, } JSHandle TSTypeParser::ParseNonImportType(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle literal, TSTypeKind kind, uint32_t typeId) + TypeLiteralExtractor *typeLiteralExtractor) { + auto kind = typeLiteralExtractor->GetTypeKind(); switch (kind) { case TSTypeKind::CLASS: { - JSHandle classType = ParseClassType(jsPandaFile, recordName, literal, typeId); + JSHandle classType = ParseClassType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(classType); } case TSTypeKind::CLASS_INSTANCE: { - JSHandle classInstanceType = ParseClassInstanceType(jsPandaFile, recordName, literal); + JSHandle classInstanceType = + ParseClassInstanceType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(classInstanceType); } - case TSTypeKind::INTERFACE_KIND: { - JSHandle interfaceType = ParseInterfaceType(jsPandaFile, recordName, literal); + case TSTypeKind::INTERFACE: { + JSHandle interfaceType = ParseInterfaceType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(interfaceType); } case TSTypeKind::UNION: { - JSHandle unionType = ParseUnionType(jsPandaFile, recordName, literal); + JSHandle unionType = ParseUnionType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(unionType); } case TSTypeKind::FUNCTION: { - JSHandle functionType = ParseFunctionType(jsPandaFile, recordName, literal, typeId); + JSHandle functionType = + ParseFunctionType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(functionType); } case TSTypeKind::ARRAY: { - JSHandle arrayType = ParseArrayType(jsPandaFile, recordName, literal); + JSHandle arrayType = ParseArrayType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(arrayType); } case TSTypeKind::OBJECT: { - JSHandle objectType = ParseObjectType(jsPandaFile, recordName, literal); + JSHandle objectType = ParseObjectType(jsPandaFile, recordName, typeLiteralExtractor); return JSHandle(objectType); } default: { LOG_COMPILER(DEBUG) << "Do not support parse types with kind " << static_cast(kind) << ". " - << "Please check whether the type literal " << typeId + << "Please check whether the type literal " << typeLiteralExtractor->GetTypeOffset() << " recorded in the record " << recordName << " is correct."; return thread_->GlobalConstants()->GetHandledUndefined(); } @@ -191,20 +198,228 @@ JSHandle TSTypeParser::ParseNonImportType(const JSPandaFile *jsPa } JSHandle TSTypeParser::ParseClassType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal, uint32_t typeId) + TypeLiteralExtractor *typeLiteralExtractor) { - JSHandle classType = factory_->NewTSClassType(); + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS); + ClassLiteralInfo classLitInfo(typeLiteralExtractor); + uint32_t numNonStaticFieldsIndex = classLitInfo.numNonStaticFieldsIndex; + uint32_t numNonStaticMethodsIndex = classLitInfo.numNonStaticMethodsIndex; + uint32_t numStaticFieldsIndex = classLitInfo.numStaticFieldsIndex; + uint32_t numStaticMethodsIndex = classLitInfo.numStaticMethodsIndex; - std::string className = tsManager_->GetClassNameByOffset(jsPandaFile, typeId); + JSHandle classType = factory_->NewTSClassType(); + SetClassName(classType, jsPandaFile, typeLiteralExtractor); + SetSuperClassType(classType, jsPandaFile, recordName, typeLiteralExtractor); + + // resolve instance type + uint32_t numFields = typeLiteralExtractor->GetIntValue(numNonStaticFieldsIndex); + JSHandle instanceType = factory_->NewTSObjectType(numFields); + FillPropTypes(jsPandaFile, recordName, instanceType, typeLiteralExtractor, numNonStaticFieldsIndex, FIELD_LENGTH); + classType->SetInstanceType(thread_, instanceType); + + // resolve prototype type + uint32_t numNonStatic = typeLiteralExtractor->GetIntValue(numNonStaticMethodsIndex); + JSHandle prototypeType = factory_->NewTSObjectType(numNonStatic); + FillPropTypes(jsPandaFile, recordName, prototypeType, typeLiteralExtractor, + numNonStaticMethodsIndex, METHOD_LENGTH); + classType->SetPrototypeType(thread_, prototypeType); + + // resolve constructor type + uint32_t numStaticFields = typeLiteralExtractor->GetIntValue(numStaticFieldsIndex); + uint32_t numStaticMethods = typeLiteralExtractor->GetIntValue(numStaticMethodsIndex); + uint32_t numStatic = numStaticFields + numStaticMethods; + JSHandle constructorType = factory_->NewTSObjectType(numStatic); + FillPropTypes(jsPandaFile, recordName, constructorType, typeLiteralExtractor, numStaticFieldsIndex, FIELD_LENGTH); + FillPropTypes(jsPandaFile, recordName, constructorType, typeLiteralExtractor, + numStaticMethodsIndex, METHOD_LENGTH); + classType->SetConstructorType(thread_, constructorType); + return classType; +} + +JSHandle TSTypeParser::ParseClassInstanceType(const JSPandaFile *jsPandaFile, + const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS_INSTANCE); + JSHandle classInstanceType = factory_->NewTSClassInstanceType(); + // classTypeId is stored in the first position + uint32_t classTypeId = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX); + auto classGT = CreateGT(jsPandaFile, recordName, classTypeId); + classInstanceType->SetClassGT(classGT); + return classInstanceType; +} + +JSHandle TSTypeParser::ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INTERFACE); + JSHandle interfaceType = factory_->NewTSInterfaceType(); + InterfaceLiteralInfo interfaceLitInfo(typeLiteralExtractor); + uint32_t numFieldsIndex = interfaceLitInfo.numFieldsIndex; + uint32_t numMethodsIndex = interfaceLitInfo.numMethodsIndex; + + // resolve extends of interface + uint32_t numExtends = typeLiteralExtractor->GetIntValue(InterfaceLiteralInfo::NUM_EXTENDS_INDEX); + JSHandle extendsId = factory_->NewTaggedArray(numExtends); + uint32_t extendsIndex = 0; + typeLiteralExtractor->EnumerateElements(InterfaceLiteralInfo::NUM_EXTENDS_INDEX, + [this, &jsPandaFile, &recordName, &extendsIndex, &extendsId](const uint32_t literalValue) { + auto extendGT = CreateGT(jsPandaFile, recordName, literalValue); + extendsId->Set(thread_, extendsIndex++, JSTaggedValue(extendGT.GetType())); + }); + interfaceType->SetExtends(thread_, extendsId); + + uint32_t numFields = typeLiteralExtractor->GetIntValue(numFieldsIndex); + uint32_t numMethods = typeLiteralExtractor->GetIntValue(numMethodsIndex); + uint32_t totalFields = numFields + numMethods; + JSHandle fieldsType = factory_->NewTSObjectType(totalFields); + FillPropTypes(jsPandaFile, recordName, fieldsType, typeLiteralExtractor, numFieldsIndex, FIELD_LENGTH); + FillInterfaceMethodTypes(jsPandaFile, recordName, fieldsType, typeLiteralExtractor, numMethodsIndex); + interfaceType->SetFields(thread_, fieldsType); + return interfaceType; +} + +JSHandle TSTypeParser::ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::UNION); + // the number of union types is stored in the first position + uint32_t numOfUnionMembers = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX); + JSHandle unionType = factory_->NewTSUnionType(numOfUnionMembers); + + JSHandle components(thread_, unionType->GetComponents()); + uint32_t index = 0; + typeLiteralExtractor->EnumerateElements(DEFAULT_INDEX, + [this, &jsPandaFile, &recordName, &index, &components](const uint32_t literalValue) { + auto componentGT = CreateGT(jsPandaFile, recordName, literalValue); + components->Set(thread_, index++, JSTaggedValue(componentGT.GetType())); + }); + unionType->SetComponents(thread_, components); + return unionType; +} + +JSHandle TSTypeParser::ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::FUNCTION); + FunctionLiteralInfo functionLitInfo(typeLiteralExtractor); + uint32_t numParasIndex = functionLitInfo.numParasIndex; + uint32_t returnTypeIndex = functionLitInfo.returnTypeIndex; + + uint32_t length = typeLiteralExtractor->GetIntValue(numParasIndex); + JSHandle functionType = factory_->NewTSFunctionType(length); + + SetFunctionThisType(functionType, jsPandaFile, recordName, typeLiteralExtractor); + JSHandle parameterTypes(thread_, functionType->GetParameterTypes()); + uint32_t index = 0; + typeLiteralExtractor->EnumerateElements(numParasIndex, + [this, &jsPandaFile, &recordName, &index, ¶meterTypes](const uint32_t literalValue) { + auto parameterGT = CreateGT(jsPandaFile, recordName, literalValue); + if (tsManager_->IsClassTypeKind(parameterGT)) { + parameterGT = tsManager_->CreateClassInstanceType(parameterGT); + } + parameterTypes->Set(thread_, index++, JSTaggedValue(parameterGT.GetType())); + }); + functionType->SetParameterTypes(thread_, parameterTypes); + + JSHandle functionName( + factory_->NewFromUtf8(typeLiteralExtractor->GetStringValue(FunctionLiteralInfo::NAME_INDEX))); + functionType->SetName(thread_, functionName); + + uint32_t returntypeId = typeLiteralExtractor->GetIntValue(returnTypeIndex); + auto returnGT = CreateGT(jsPandaFile, recordName, returntypeId); + functionType->SetReturnGT(returnGT); + + uint32_t bitField = typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::BITFIELD_INDEX); + functionType->SetBitField(bitField); + + StoreMethodOffset(functionType, typeLiteralExtractor); + return functionType; +} + +JSHandle TSTypeParser::ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::ARRAY); + JSHandle arrayType = factory_->NewTSArrayType(); + // the type of elements of array is stored in the first position + auto elemetnGT = CreateGT(jsPandaFile, recordName, typeLiteralExtractor->GetIntValue(DEFAULT_INDEX)); + if (tsManager_->IsClassTypeKind(elemetnGT)) { + elemetnGT = tsManager_->CreateClassInstanceType(elemetnGT); + } + arrayType->SetElementGT(elemetnGT); + return arrayType; +} + +JSHandle TSTypeParser::ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::OBJECT); + // the number of properties of object is stored in the first position + uint32_t length = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX); + JSHandle objectType = factory_->NewTSObjectType(length); + FillPropTypes(jsPandaFile, recordName, objectType, typeLiteralExtractor, DEFAULT_INDEX, METHOD_LENGTH); + return objectType; +} + +void TSTypeParser::FillPropTypes(const JSPandaFile *jsPandaFile, + const CString &recordName, + const JSHandle &objectType, + TypeLiteralExtractor *typeLiteralExtractor, + const uint32_t numOfFieldIndex, + const uint32_t gap) +{ + JSHandle layout(thread_, objectType->GetObjLayoutInfo()); + JSMutableHandle key(thread_, JSTaggedValue::Undefined()); + typeLiteralExtractor->EnumerateProperties(numOfFieldIndex, gap, + [this, &key, &jsPandaFile, &recordName, &layout](const CString &literalKey, const uint32_t literalValue) { + JSHandle propName(factory_->NewFromUtf8(literalKey)); + key.Update(propName.GetTaggedValue()); + ASSERT(key->IsString()); + auto gt = CreateGT(jsPandaFile, recordName, literalValue); + if (tsManager_->IsClassTypeKind(gt)) { + gt = tsManager_->CreateClassInstanceType(gt); + } + layout->AddKeyAndType(thread_, key.GetTaggedValue(), JSTaggedValue(gt.GetType())); + }); +} + +void TSTypeParser::FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile, + const CString &recordName, + const JSHandle &objectType, + TypeLiteralExtractor *typeLiteralExtractor, + const uint32_t numExtends) +{ + JSHandle layout(thread_, objectType->GetObjLayoutInfo()); + JSMutableHandle key(thread_, JSTaggedValue::Undefined()); + typeLiteralExtractor->EnumerateElements(numExtends, + [this, &jsPandaFile, &recordName, &layout, &key](const uint32_t literalValue) { + auto gt = CreateGT(jsPandaFile, recordName, literalValue); + if (tsManager_->IsFunctionTypeKind(gt)) { + JSHandle tsType = tsManager_->GetTSType(gt); + ASSERT(tsType->IsTSFunctionType()); + JSHandle functionType(tsType); + key.Update(functionType->GetName()); + }; + layout->AddKeyAndType(thread_, key.GetTaggedValue(), JSTaggedValue(gt.GetType())); + }); +} + +void TSTypeParser::SetClassName(const JSHandle &classType, + const JSPandaFile *jsPandaFile, + TypeLiteralExtractor *typeLiteralExtractor) +{ + std::string className = tsManager_->GetClassNameByOffset(jsPandaFile, typeLiteralExtractor->GetTypeOffset()); JSHandle classEcmaString = factory_->NewFromStdString(className); classType->SetName(thread_, classEcmaString.GetTaggedValue()); +} - uint32_t index = 0; - ASSERT(static_cast(literal->Get(index).GetInt()) == TSTypeKind::CLASS); - - const uint32_t ignoreLength = 2; // 2: ignore accessFlag and readonly - index += ignoreLength; - int extendsTypeId = literal->Get(index++).GetInt(); +void TSTypeParser::SetSuperClassType(const JSHandle &classType, + const JSPandaFile *jsPandaFile, + const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) +{ + uint32_t extendsTypeId = typeLiteralExtractor->GetIntValue(ClassLiteralInfo::SUPER_CLASS_INDEX); if (TSClassType::IsBaseClassType(extendsTypeId)) { classType->SetHasLinked(true); } else { @@ -214,284 +429,32 @@ JSHandle TSTypeParser::ParseClassType(const JSPandaFile *jsPandaFil classType->SetHasLinked(true); } } - - // ignore implement - uint32_t numImplement = literal->Get(index++).GetInt(); - index += numImplement; - - // resolve instance type - uint32_t numFields = static_cast(literal->Get(index++).GetInt()); - - JSHandle instanceType = factory_->NewTSObjectType(numFields); - JSHandle instanceTypeInfo(thread_, instanceType->GetObjLayoutInfo()); - ASSERT(instanceTypeInfo->GetPropertiesCapacity() == numFields); - FillPropertyTypes(jsPandaFile, recordName, instanceTypeInfo, literal, 0, numFields, index, true); - classType->SetInstanceType(thread_, instanceType); - - // resolve prototype type - uint32_t numNonStatic = literal->Get(index++).GetInt(); - JSHandle prototypeType = factory_->NewTSObjectType(numNonStatic); - - JSHandle nonStaticTypeInfo(thread_, prototypeType->GetObjLayoutInfo()); - ASSERT(nonStaticTypeInfo->GetPropertiesCapacity() == static_cast(numNonStatic)); - FillPropertyTypes(jsPandaFile, recordName, nonStaticTypeInfo, literal, 0, numNonStatic, index, false); - classType->SetPrototypeType(thread_, prototypeType); - - // resolve constructor type - // static include fields and methods, which the former takes up 4 spaces and the latter takes up 2 spaces. - uint32_t numStaticFields = literal->Get(index++).GetInt(); - uint32_t numStaticMethods = literal->Get(index + numStaticFields * TSClassType::FIELD_LENGTH).GetInt(); - uint32_t numStatic = numStaticFields + numStaticMethods; - // new function type when support it - JSHandle constructorType = factory_->NewTSObjectType(numStatic); - - JSHandle staticTypeInfo(thread_, constructorType->GetObjLayoutInfo()); - ASSERT(staticTypeInfo->GetPropertiesCapacity() == static_cast(numStatic)); - FillPropertyTypes(jsPandaFile, recordName, staticTypeInfo, literal, 0, numStaticFields, index, true); - index++; // jmp over numStaticMethods - // static methods - FillPropertyTypes(jsPandaFile, recordName, staticTypeInfo, literal, numStaticFields, numStatic, index, false); - classType->SetConstructorType(thread_, constructorType); - return classType; } -JSHandle TSTypeParser::ParseClassInstanceType(const JSPandaFile *jsPandaFile, - const CString &recordName, - const JSHandle &literal) +void TSTypeParser::SetFunctionThisType(const JSHandle &functionType, + const JSPandaFile *jsPandaFile, + const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor) { - ASSERT(static_cast(literal->Get(TYPE_KIND_INDEX_IN_LITERAL).GetInt()) == - TSTypeKind::CLASS_INSTANCE); - JSHandle classInstanceType = factory_->NewTSClassInstanceType(); - uint32_t classTypeId = static_cast(literal->Get(TSClassInstanceType::CREATE_CLASS_OFFSET).GetInt()); - auto classGT = CreateGT(jsPandaFile, recordName, classTypeId); - classInstanceType->SetClassGT(classGT); - return classInstanceType; -} - -JSHandle TSTypeParser::ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal) -{ - uint32_t index = 0; - JSHandle interfaceType = factory_->NewTSInterfaceType(); - ASSERT(static_cast(literal->Get(index).GetInt()) == TSTypeKind::INTERFACE_KIND); - - index++; - // resolve extends of interface - uint32_t numExtends = literal->Get(index++).GetInt(); - JSHandle extendsId = factory_->NewTaggedArray(numExtends); - JSMutableHandle extendsType(thread_, JSTaggedValue::Undefined()); - for (uint32_t extendsIndex = 0; extendsIndex < numExtends; extendsIndex++) { - auto typeId = literal->Get(index++).GetInt(); - auto extendGT = CreateGT(jsPandaFile, recordName, typeId); - extendsType.Update(JSTaggedValue(extendGT.GetType())); - extendsId->Set(thread_, extendsIndex, extendsType); - } - interfaceType->SetExtends(thread_, extendsId); - - // resolve fields and methods of interface - uint32_t numFields = static_cast(literal->Get(index++).GetInt()); - // field takes up 4 spaces and method takes up 2 spaces. - uint32_t numMethods = static_cast(literal->Get(index + - numFields * TSInterfaceType::FIELD_LENGTH).GetInt()); - uint32_t totalFields = numFields + numMethods; - - JSHandle fieldsType = factory_->NewTSObjectType(totalFields); - JSHandle fieldsTypeInfo(thread_, fieldsType->GetObjLayoutInfo()); - ASSERT(fieldsTypeInfo->GetPropertiesCapacity() == static_cast(totalFields)); - FillPropertyTypes(jsPandaFile, recordName, fieldsTypeInfo, literal, 0, numFields, index, true); - index++; // jmp over numMethod - FillInterfaceMethodTypes(jsPandaFile, recordName, fieldsTypeInfo, literal, numFields, totalFields, index); - interfaceType->SetFields(thread_, fieldsType); - return interfaceType; -} - -JSHandle TSTypeParser::ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal) -{ - uint32_t literalIndex = 0; - ASSERT(static_cast(literal->Get(literalIndex).GetInt()) == TSTypeKind::UNION); - literalIndex++; - uint32_t numOfUnionMembers = literal->Get(literalIndex++).GetInt(); - - JSHandle unionType = factory_->NewTSUnionType(numOfUnionMembers); - JSHandle components(thread_, unionType->GetComponents()); - for (uint32_t index = 0; index < numOfUnionMembers; ++index) { - uint32_t componentTypeId = literal->Get(literalIndex++).GetInt(); - auto componentGT = CreateGT(jsPandaFile, recordName, componentTypeId); - components->Set(thread_, index, JSTaggedValue(componentGT.GetType())); - } - unionType->SetComponents(thread_, components); - return unionType; -} - -JSHandle TSTypeParser::ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal, uint32_t functionId) -{ - uint32_t index = 0; - ASSERT(static_cast(literal->Get(index).GetInt()) == TSTypeKind::FUNCTION); - index++; - - int32_t bitField = literal->Get(index++).GetInt(); - - JSHandle functionName(thread_, literal->Get(index++)); - bool hasThisType = static_cast(literal->Get(index++).GetInt()); - int32_t thisTypeId = 0; - if (hasThisType) { - thisTypeId = literal->Get(index++).GetInt(); - } - - int32_t length = literal->Get(index++).GetInt(); - JSHandle functionType = factory_->NewTSFunctionType(length); - JSHandle parameterTypes(thread_, functionType->GetParameterTypes()); - JSMutableHandle parameterTypeRef(thread_, JSTaggedValue::Undefined()); - for (int32_t i = 0; i < length; ++i) { - auto typeId = literal->Get(index++).GetInt(); - auto parameterGT = CreateGT(jsPandaFile, recordName, typeId); - if (tsManager_->IsClassTypeKind(parameterGT)) { - parameterGT = tsManager_->CreateClassInstanceType(parameterGT); - } - parameterTypeRef.Update(JSTaggedValue(parameterGT.GetType())); - parameterTypes->Set(thread_, i, parameterTypeRef); - } - int32_t returntypeId = literal->Get(index++).GetInt(); - - functionType->SetName(thread_, functionName); + bool hasThisType = static_cast(typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::HAS_THIS_TYPE_INDEX)); if (hasThisType) { + // if hasThisType is true, then the next position will store typeId of this + uint32_t thisTypeId = typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::HAS_THIS_TYPE_INDEX + 1); auto thisGT = CreateGT(jsPandaFile, recordName, thisTypeId); functionType->SetThisGT(thisGT); } +} - functionType->SetParameterTypes(thread_, parameterTypes); - auto returnGT = CreateGT(jsPandaFile, recordName, returntypeId); - functionType->SetReturnGT(returnGT); - functionType->SetBitField(bitField); - auto bcInfoCollector = tsManager_->GetBytecodeInfoCollector(); - if (bcInfoCollector != nullptr) { - auto &bcInfo = bcInfoCollector->GetBytecodeInfo(); - uint32_t methodOffset = bcInfo.IterateFunctionTypeIDAndMethodOffset(functionId); +void TSTypeParser::StoreMethodOffset(const JSHandle &functionType, + TypeLiteralExtractor *typeLiteralExtractor) +{ + if (bcInfo_ != nullptr) { + uint32_t typeOffset = typeLiteralExtractor->GetTypeOffset(); + uint32_t methodOffset = bcInfo_->IterateFunctionTypeIDAndMethodOffset(typeOffset); if (methodOffset != 0) { functionType->SetMethodOffset(methodOffset); } } - return functionType; -} - -JSHandle TSTypeParser::ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal) -{ - uint32_t index = 0; - ASSERT(static_cast(literal->Get(index).GetInt()) == TSTypeKind::ARRAY); - index++; - JSHandle elementTypeId(thread_, literal->Get(index++)); - ASSERT(elementTypeId->IsInt()); - JSHandle arrayType = factory_->NewTSArrayType(); - auto elemetnGT = CreateGT(jsPandaFile, recordName, elementTypeId->GetInt()); - if (tsManager_->IsClassTypeKind(elemetnGT)) { - elemetnGT = tsManager_->CreateClassInstanceType(elemetnGT); - } - arrayType->SetElementGT(elemetnGT); - return arrayType; -} - -JSHandle TSTypeParser::ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal) -{ - uint32_t index = 0; - ASSERT(static_cast(literal->Get(index).GetInt()) == TSTypeKind::OBJECT); - index++; - uint32_t length = literal->Get(index++).GetInt(); - JSHandle objectType = factory_->NewTSObjectType(length); - JSHandle propertyTypeInfo(thread_, objectType->GetObjLayoutInfo()); - ASSERT(propertyTypeInfo->GetPropertiesCapacity() == static_cast(length)); - FillPropertyTypes(jsPandaFile, recordName, propertyTypeInfo, literal, 0, length, index, false); - objectType->SetObjLayoutInfo(thread_, propertyTypeInfo); - return objectType; -} - -void TSTypeParser::FillPropertyTypes(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle &layout, const JSHandle &literal, - uint32_t startIndex, uint32_t lastIndex, uint32_t &index, bool isField) -{ - JSMutableHandle key(thread_, JSTaggedValue::Undefined()); - JSMutableHandle value(thread_, JSTaggedValue::Undefined()); - for (uint32_t fieldIndex = startIndex; fieldIndex < lastIndex; ++fieldIndex) { - key.Update(literal->Get(index++)); - ASSERT(key->IsString()); - auto gt = CreateGT(jsPandaFile, recordName, literal->Get(index++).GetInt()); - if (tsManager_->IsClassTypeKind(gt)) { - gt = tsManager_->CreateClassInstanceType(gt); - } - value.Update(JSTaggedValue(gt.GetType())); - layout->AddKeyAndType(thread_, key.GetTaggedValue(), value.GetTaggedValue()); - if (isField) { - index += 2; // 2: ignore accessFlag and readonly - } - } -} - -void TSTypeParser::FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle &layout, const JSHandle &literal, - uint32_t startIndex, uint32_t lastIndex, uint32_t &index) -{ - JSMutableHandle key(thread_, JSTaggedValue::Undefined()); - JSMutableHandle value(thread_, JSTaggedValue::Undefined()); - for (uint32_t methodIndex = startIndex; methodIndex < lastIndex; ++methodIndex) { - auto gt = CreateGT(jsPandaFile, recordName, literal->Get(index++).GetInt()); - value.Update(JSTaggedValue(gt.GetType())); - - if (tsManager_->IsFunctionTypeKind(gt)) { - JSHandle tsType = tsManager_->GetTSType(gt); - ASSERT(tsType->IsTSFunctionType()); - - JSHandle functionType(tsType); - key.Update(functionType->GetName()); - }; - - layout->AddKeyAndType(thread_, key.GetTaggedValue(), value.GetTaggedValue()); - } -} - -JSHandle TSTypeParser::GetExportDataFromRecord(const JSPandaFile *jsPandaFile, - const CString &recordName) -{ - const panda_file::File &pf = *jsPandaFile->GetPandaFile(); - panda_file::File::EntityId methodId(jsPandaFile->GetMainMethodIndex(recordName)); - panda_file::MethodDataAccessor mda(pf, methodId); - - const char *symbolTypes; - auto *fileName = pf.GetFilename().c_str(); - if (::strcmp(TSTypeTable::BUILTINS_TABLE_NAME, fileName) == 0) { - symbolTypes = DECLARED_SYMBOL_TYPES; - } else { - symbolTypes = EXPORTED_SYMBOL_TYPES; - } - - JSHandle typeOfExportedSymbols(thread_, thread_->GlobalConstants()->GetEmptyArray()); - mda.EnumerateAnnotations([&](panda_file::File::EntityId annotationId) { - panda_file::AnnotationDataAccessor ada(pf, annotationId); - auto *annotationName = reinterpret_cast(jsPandaFile->GetStringData(ada.GetClassId()).data); - ASSERT(annotationName != nullptr); - if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) { - return; - } - uint32_t length = ada.GetCount(); - for (uint32_t i = 0; i < length; i++) { - panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); - auto *elemName = reinterpret_cast(jsPandaFile->GetStringData(adae.GetNameId()).data); - ASSERT(elemName != nullptr); - - if (::strcmp(symbolTypes, elemName) != 0) { - continue; - } - - panda_file::ScalarValue sv = adae.GetScalarValue(); - panda_file::File::EntityId literalOffset(sv.GetValue()); - typeOfExportedSymbols = LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, literalOffset); - // typeOfExprotedSymbols: "symbol0", "type0", "symbol1", "type1" ... - } - }); - - return typeOfExportedSymbols; } JSHandle TSTypeParser::GenerateExportTableFromRecord(const JSPandaFile *jsPandaFile, @@ -501,24 +464,15 @@ JSHandle TSTypeParser::GenerateExportTableFromRecord(const JSPand JSHandle exportValeTable = TSTypeTable::GetExportValueTable(thread_, table); if (exportValeTable->IsUndefined()) { // Read export-data from annotation of the .abc File - JSHandle exportTable; - if (tsManager_->HasResolvedExportTable(jsPandaFile, recordName)) { - JSTaggedValue resolvedTable = tsManager_->GetResolvedExportTable(jsPandaFile, recordName); - exportTable = JSHandle::Cast(JSHandle(thread_, resolvedTable)); - } else { - exportTable = GetExportDataFromRecord(jsPandaFile, recordName); - } + JSHandle exportTable = tsManager_->GetExportTableFromLiteral(jsPandaFile, recordName); uint32_t length = exportTable->GetLength(); - - // Replace typeIds with GT - JSTaggedValue target; for (uint32_t i = 1; i < length; i += 2) { // 2: skip a pair of key and value - target = exportTable->Get(i); + JSTaggedValue target = exportTable->Get(i); // Create GT based on typeId, and wrapped it into a JSTaggedValue uint32_t typeId = static_cast(target.GetInt()); - GlobalTSTypeRef typeGT = CreateGT(jsPandaFile, recordName, typeId); + GlobalTSTypeRef gt = CreateGT(jsPandaFile, recordName, typeId); // Set the wrapped GT to exportTable - exportTable->Set(thread_, i, JSTaggedValue(typeGT.GetType())); + exportTable->Set(thread_, i, JSTaggedValue(gt.GetType())); } TSTypeTable::SetExportValueTable(thread_, table, exportTable); return JSHandle(exportTable); @@ -591,4 +545,35 @@ GlobalTSTypeRef TSTypeParser::IterateStarExport(JSHandle target, con } return GlobalTSTypeRef::Default(); } + +static uint32_t CalculateNextNumIndex(const TypeLiteralExtractor *typeLiteralExtractor, + uint32_t startIndex = 0, + uint32_t gap = 1) +{ + return startIndex + INDEX_OCCUPIED_OFFSET + (typeLiteralExtractor->GetIntValue(startIndex) * gap); +} + +ClassLiteralInfo::ClassLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS); + numNonStaticFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, NUM_IMPLEMENTS_INDEX); + numNonStaticMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numNonStaticFieldsIndex, FIELD_LENGTH); + numStaticFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, numNonStaticMethodsIndex, METHOD_LENGTH); + numStaticMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numStaticFieldsIndex, FIELD_LENGTH); +} + +InterfaceLiteralInfo::InterfaceLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INTERFACE); + numFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, NUM_EXTENDS_INDEX); + numMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numFieldsIndex, FIELD_LENGTH); +} + +FunctionLiteralInfo::FunctionLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor) +{ + ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::FUNCTION); + numParasIndex = HAS_THIS_TYPE_INDEX + INDEX_OCCUPIED_OFFSET + + typeLiteralExtractor->GetIntValue(HAS_THIS_TYPE_INDEX); + returnTypeIndex = CalculateNextNumIndex(typeLiteralExtractor, numParasIndex); +} } // namespace panda::ecmascript diff --git a/ecmascript/ts_types/ts_type_parser.h b/ecmascript/ts_types/ts_type_parser.h index 41105245b3..bb66765434 100644 --- a/ecmascript/ts_types/ts_type_parser.h +++ b/ecmascript/ts_types/ts_type_parser.h @@ -36,17 +36,11 @@ public: GlobalTSTypeRef PUBLIC_API CreateGT(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId); - JSHandle GetExportDataFromRecord(const JSPandaFile *jsPandaFile, const CString &recordName); - static constexpr size_t USER_DEFINED_TYPE_OFFSET = 100; private: - static constexpr size_t TYPE_KIND_INDEX_IN_LITERAL = 0; static constexpr size_t BUILDIN_TYPE_OFFSET = 20; - static constexpr size_t IMPORT_PATH_OFFSET_IN_LITERAL = 1; - - static constexpr const char* DECLARED_SYMBOL_TYPES = "declaredSymbolTypes"; - static constexpr const char* EXPORTED_SYMBOL_TYPES = "exportedSymbolTypes"; + static constexpr size_t DEFAULT_INDEX = 0; inline GlobalTSTypeRef GetAndStoreGT(const JSPandaFile *jsPandaFile, uint32_t typeId, const CString &recordName, uint32_t moduleId = 0, uint32_t localId = 0) @@ -76,45 +70,60 @@ private: GlobalTSTypeRef ParseBuiltinObjType(uint32_t typeId); GlobalTSTypeRef ResolveImportType(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle literal, uint32_t typeId); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseNonImportType(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle literal, TSTypeKind kind, uint32_t typeId); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseClassType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal, uint32_t typeId); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseClassInstanceType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal, uint32_t functionId); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal); + TypeLiteralExtractor *typeLiteralExtractor); JSHandle ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName, - const JSHandle &literal); + TypeLiteralExtractor *typeLiteralExtractor); - void FillPropertyTypes(const JSPandaFile *jsPandaFile, - const CString &recordName, - JSHandle &layout, - const JSHandle &literal, - uint32_t startIndex, uint32_t lastIndex, - uint32_t &index, bool isField); + void FillPropTypes(const JSPandaFile *jsPandaFile, + const CString &recordName, + const JSHandle &objectType, + TypeLiteralExtractor *typeLiteralExtractor, + const uint32_t numOfFieldIndex, + const uint32_t gap); void FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile, const CString &recordName, - JSHandle &layout, - const JSHandle &literal, - uint32_t startIndex, uint32_t lastIndex, - uint32_t &index); + const JSHandle &objectType, + TypeLiteralExtractor *typeLiteralExtractor, + const uint32_t numExtends); + + void SetClassName(const JSHandle &classType, + const JSPandaFile *jsPandaFile, + TypeLiteralExtractor *typeLiteralExtractor); + + void SetSuperClassType(const JSHandle &classType, + const JSPandaFile *jsPandaFile, + const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor); + + void SetFunctionThisType(const JSHandle &functionType, + const JSPandaFile *jsPandaFile, + const CString &recordName, + TypeLiteralExtractor *typeLiteralExtractor); + + void StoreMethodOffset(const JSHandle &functionType, TypeLiteralExtractor *typeLiteralExtractor); JSHandle GenerateExportTableFromRecord(const JSPandaFile *jsPandaFile, const CString &recordName, const JSHandle &table); @@ -137,5 +146,40 @@ private: TSTypeTableGenerator tableGenerator_; kungfu::BCInfo *bcInfo_ {nullptr}; }; + +struct ClassLiteralInfo { + explicit ClassLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor); + ~ClassLiteralInfo() = default; + + static constexpr uint32_t SUPER_CLASS_INDEX = 1; + static constexpr uint32_t NUM_IMPLEMENTS_INDEX = 2; + + uint32_t numNonStaticFieldsIndex {0}; + uint32_t numNonStaticMethodsIndex {0}; + uint32_t numStaticFieldsIndex {0}; + uint32_t numStaticMethodsIndex {0}; +}; + +struct InterfaceLiteralInfo { + explicit InterfaceLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor); + ~InterfaceLiteralInfo() = default; + + static constexpr uint32_t NUM_EXTENDS_INDEX = 0; + + uint32_t numFieldsIndex {0}; + uint32_t numMethodsIndex {0}; +}; + +struct FunctionLiteralInfo { + explicit FunctionLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor); + ~FunctionLiteralInfo() = default; + + static constexpr uint32_t BITFIELD_INDEX = 0; + static constexpr uint32_t NAME_INDEX = 1; + static constexpr uint32_t HAS_THIS_TYPE_INDEX = 2; + + uint32_t numParasIndex {0}; + uint32_t returnTypeIndex {0}; +}; } // panda::ecmascript #endif // ECMASCRIPT_TS_TYPES_TS_TYPE_PARSER_H diff --git a/ecmascript/ts_types/ts_type_table_generator.cpp b/ecmascript/ts_types/ts_type_table_generator.cpp index 2777dda9c7..d609ee57a4 100644 --- a/ecmascript/ts_types/ts_type_table_generator.cpp +++ b/ecmascript/ts_types/ts_type_table_generator.cpp @@ -55,16 +55,8 @@ JSHandle TSTypeTableGenerator::GetOrGenerateTSTypeTable(const JSPan return tsManager_->GetTSTypeTable(moduleId); } JSHandle recordNameStr = factory_->NewFromUtf8(recordName); - // read type summary literal - // struct of summaryLiteral: {numTypes, literalOffset0, literalOffset1, ...} - panda_file::File::EntityId summaryOffset(jsPandaFile->GetTypeSummaryOffset(recordName)); - JSHandle summaryLiteral = - LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, summaryOffset); - uint32_t numIdx = static_cast(BuiltinTypeId::NUM_INDEX_IN_SUMMARY); - uint32_t numTypes = static_cast(summaryLiteral->Get(numIdx).GetInt()); - - // Initialize a empty TSTypeTable with length of (numTypes + RESERVE_TABLE_LENGTH) - JSHandle table = AddTypeTable(recordNameStr, numTypes); + TypeSummaryExtractor summExtractor(jsPandaFile, recordName); + JSHandle table = AddTypeTable(recordNameStr, summExtractor.GetNumOfTypes()); return table; }