diff --git a/ecmascript/compiler/bytecode_info_collector.cpp b/ecmascript/compiler/bytecode_info_collector.cpp index 25a1f725852c2f7ac95b6b1e63aaca1bce631c6f..3342b87397f97ebe5179b31e11357fd34c53d3fe 100644 --- a/ecmascript/compiler/bytecode_info_collector.cpp +++ b/ecmascript/compiler/bytecode_info_collector.cpp @@ -581,7 +581,7 @@ bool BytecodeInfoCollector::CheckExportNameAndClassType(const CString &recordNam auto tsManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager(); 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 + for (uint32_t i = 0; i < length; i += TSTypeTable::EXPORT_TYPETABLE_ELEMENTS_LENGTH) { EcmaString *valueString = EcmaString::Cast(exportTypeTable->Get(i).GetTaggedObject()); if (!EcmaStringAccessor::StringsAreEqual(*exportStr, valueString)) { continue; diff --git a/ecmascript/ts_types/ts_manager.cpp b/ecmascript/ts_types/ts_manager.cpp index dee6cade6aa34dd4c589e6df81b4158d9e8fc922..1703cb7ce39faf9dfb8b8266c4cf69c871e128ea 100644 --- a/ecmascript/ts_types/ts_manager.cpp +++ b/ecmascript/ts_types/ts_manager.cpp @@ -1394,7 +1394,7 @@ JSHandle TSManager::GenerateExportTableFromLiteral(const JSPandaFil { bool isBuiltinTable = (std::strcmp(recordName.c_str(), TSTypeTable::BUILTINS_TABLE_NAME) == 0); ExportTypeTableExtractor exTableExtractor(jsPandaFile, recordName, isBuiltinTable); - uint32_t length = exTableExtractor.GetLength(); + uint32_t length = TSTypeTable::CalculateExportTypeTableLength(exTableExtractor.GetLength()); JSHandle typeOfExportedSymbols = factory_->NewOldSpaceTaggedArray(length); uint32_t index = 0; exTableExtractor.EnumerateModuleTypes( @@ -1402,6 +1402,7 @@ JSHandle TSManager::GenerateExportTableFromLiteral(const JSPandaFil JSHandle str = factory_->NewFromUtf8(name); typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue(str.GetTaggedValue())); typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue(typeId)); + typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue::False()); }); return typeOfExportedSymbols; } diff --git a/ecmascript/ts_types/ts_type_parser.cpp b/ecmascript/ts_types/ts_type_parser.cpp index 5ad7e3300f511b79164ad94e78b1613ed57bdb5e..ea39be5647ad5b41237de9fec7f51ef17745e069 100644 --- a/ecmascript/ts_types/ts_type_parser.cpp +++ b/ecmascript/ts_types/ts_type_parser.cpp @@ -57,7 +57,18 @@ GlobalTSTypeRef TSTypeParser::CreateGT(const JSPandaFile *jsPandaFile, const CSt if (tsManager_->HasCreatedGT(jsPandaFile, typeId)) { return tsManager_->GetGTFromOffset(jsPandaFile, typeId); } - return ParseType(jsPandaFile, recordName, typeId); + + IncreaseDepth(); + GlobalTSTypeRef gt; + if (LIKELY(!ReachMaxDepth())) { + gt = ParseType(jsPandaFile, recordName, typeId); + } else { + LOG_COMPILER(DEBUG) << "The maximum depth of recursive parsing TSTypes is reached." + << "The TSType with typeId " << typeId << " in the record " << recordName + << " will not be parsed and will be treated as any."; + } + DecreaseDepth(); + return gt; } GlobalTSTypeRef TSTypeParser::ParseBuiltinObjType(uint32_t typeId) @@ -531,11 +542,13 @@ JSHandle TSTypeParser::GenerateExportTableFromRecord(const JSPand JSHandle exportValeTable = TSTypeTable::GetExportValueTable(thread_, table); if (exportValeTable->IsUndefined()) { // Read export-data from annotation of the .abc File - JSHandle literalTable = tsManager_->GetExportTableFromLiteral(jsPandaFile, recordName); - ObjectFactory *factory = vm_->GetFactory(); - uint32_t length = literalTable->GetLength(); - JSHandle exportTable = factory->NewAndCopyTaggedArray(literalTable, length, length); - for (uint32_t i = 1; i < length; i += 2) { // 2: skip a pair of key and value + JSHandle exportTable = tsManager_->GetExportTableFromLiteral(jsPandaFile, recordName); + uint32_t length = exportTable->GetLength(); + for (uint32_t i = 1; i < length; i += TSTypeTable::EXPORT_TYPETABLE_ELEMENTS_LENGTH) { + if (exportTable->Get(i + 1).IsTrue()) { + continue; + } + exportTable->Set(thread_, i + 1, JSTaggedValue::True()); JSTaggedValue target = exportTable->Get(i); // Create GT based on typeId, and wrapped it into a JSTaggedValue uint32_t typeId = static_cast(target.GetInt()); @@ -576,7 +589,7 @@ GlobalTSTypeRef TSTypeParser::GetExportGTByName(JSHandle target, JSH uint32_t length = exportTable->GetLength(); // the exportTable is arranged as follows ["A", "101", "B", "102"] // get GT of a export type specified by its descriptor/name - for (uint32_t i = 0; i < length; i = i + 2) { // 2: symbol and symbolType + for (uint32_t i = 0; i < length; i += TSTypeTable::EXPORT_TYPETABLE_ELEMENTS_LENGTH) { EcmaString *valueString = EcmaString::Cast(exportTable->Get(i).GetTaggedObject()); if (EcmaStringAccessor::StringsAreEqual(*target, valueString)) { // Transform raw data of JSTaggedValue to GT diff --git a/ecmascript/ts_types/ts_type_parser.h b/ecmascript/ts_types/ts_type_parser.h index 21df7195dad03abae7a95702d3b1c02a976a1cf8..0a682ace77bbd2c29e5b9069a6adbceec93fe354 100644 --- a/ecmascript/ts_types/ts_type_parser.h +++ b/ecmascript/ts_types/ts_type_parser.h @@ -53,6 +53,7 @@ private: static constexpr size_t NUM_INDEX_SIG_INDEX = 1; static constexpr size_t NUM_GENERICS_PARA_INDEX = 1; static constexpr size_t GENERICS_PARA_OFFSET = BUILDIN_TYPE_OFFSET + 1; + static constexpr size_t MAX_DEPTH = 1U << 7; inline GlobalTSTypeRef GetAndStoreGT(const JSPandaFile *jsPandaFile, uint32_t typeId, const CString &recordName, uint32_t moduleId = 0, uint32_t localId = 0) @@ -227,12 +228,28 @@ private: GlobalTSTypeRef TryReplaceTypePara(GlobalTSTypeRef gt, const std::vector ¶s); + inline void IncreaseDepth() + { + depth_++; + } + + inline void DecreaseDepth() + { + depth_--; + } + + inline bool ReachMaxDepth() const + { + return depth_ >= MAX_DEPTH; + } + TSManager *tsManager_ {nullptr}; EcmaVM *vm_ {nullptr}; JSThread *thread_ {nullptr}; ObjectFactory *factory_ {nullptr}; TSTypeTableGenerator tableGenerator_; kungfu::BCInfo *bcInfo_ {nullptr}; + uint32_t depth_ {0}; }; struct ClassLiteralInfo { diff --git a/ecmascript/ts_types/ts_type_table.h b/ecmascript/ts_types/ts_type_table.h index 2dda98544fb376896a5665887150cab3fe54fd7f..f48d5620edafae9fe8298cfe2abe1cd791dd0ace 100644 --- a/ecmascript/ts_types/ts_type_table.h +++ b/ecmascript/ts_types/ts_type_table.h @@ -24,6 +24,7 @@ public: static constexpr size_t RESERVE_TABLE_LENGTH = 2; // for reserve length and exportTable static constexpr size_t NUMBER_OF_TYPES_INDEX = 0; static constexpr size_t INCREASE_CAPACITY_RATE = 2; + static constexpr size_t EXPORT_TYPETABLE_ELEMENTS_LENGTH = 3; // 3: key, type and parser status static constexpr const char* PRIMITIVE_TABLE_NAME = "primitiveTypes"; static constexpr const char* BUILTINS_TABLE_NAME = "lib_ark_builtins.d"; static constexpr const char* INFER_TABLE_NAME = "inferTypes"; @@ -53,6 +54,12 @@ public: static JSHandle PushBackTypeToTable(JSThread *thread, JSHandle &table, const JSHandle &type); + + static inline uint32_t CalculateExportTypeTableLength(const uint32_t length) + { + ASSERT((length % 2) == 0); // 2: even number + return (length / 2) * EXPORT_TYPETABLE_ELEMENTS_LENGTH; + } }; } // namespace panda::ecmascript diff --git a/test/typeinfer/module_test/BUILD.gn b/test/typeinfer/module_test/BUILD.gn index 316438d453585fab1b6040cc1a43a5a80f68f493..3f25b69dac367bb568dea53cc2eefb7864983c9c 100644 --- a/test/typeinfer/module_test/BUILD.gn +++ b/test/typeinfer/module_test/BUILD.gn @@ -15,6 +15,7 @@ group("ark_typeinfer_module_test") { testonly = true test_list = [ "module_class", + "module_circular_references", "module_function", "module_function_infer", "module_multi_import", diff --git a/test/typeinfer/module_test/module_circular_references/BUILD.gn b/test/typeinfer/module_test/module_circular_references/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..02e2ac443eaca6aa0464f396102de3491ea5898a --- /dev/null +++ b/test/typeinfer/module_test/module_circular_references/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("module_circular_references") { + deps = [] + is_multi_file_tests = true +} diff --git a/test/typeinfer/module_test/module_circular_references/export1.ts b/test/typeinfer/module_test/module_circular_references/export1.ts new file mode 100644 index 0000000000000000000000000000000000000000..623c3b404b90764a40e9eed62e1aac55fad3c66e --- /dev/null +++ b/test/typeinfer/module_test/module_circular_references/export1.ts @@ -0,0 +1,23 @@ +/* + * 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 class A { + value:string = "abc"; +} +let a:A = new A(); +AssertType(a, "A"); +AssertType(a.value, "string"); +export {B} from "./export2" diff --git a/test/typeinfer/module_test/module_circular_references/export2.ts b/test/typeinfer/module_test/module_circular_references/export2.ts new file mode 100644 index 0000000000000000000000000000000000000000..f348cb4ced8ebbf95a8b9de3bfe91f326b4556cc --- /dev/null +++ b/test/typeinfer/module_test/module_circular_references/export2.ts @@ -0,0 +1,23 @@ +/* + * 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 class B { + value:number = 123; +} +let b:B = new B(); +AssertType(b, "B"); +AssertType(b.value, "number"); +export {A} from "./export1" diff --git a/test/typeinfer/module_test/module_circular_references/module_circular_references.ts b/test/typeinfer/module_test/module_circular_references/module_circular_references.ts new file mode 100644 index 0000000000000000000000000000000000000000..493adabe1796cb77c305141556d37e17ac2be5b2 --- /dev/null +++ b/test/typeinfer/module_test/module_circular_references/module_circular_references.ts @@ -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. + */ + +declare function AssertType(value:any, type:string):void; +import {A} from "./export1" +let a:A = new A(); +AssertType(a, "A"); +AssertType(a.value, "string");