1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/ts_types/ts_type_parser.h"
17
18 #include "ecmascript/base/path_helper.h"
19 #include "ecmascript/jspandafile/js_pandafile_manager.h"
20 #include "ecmascript/jspandafile/literal_data_extractor.h"
21 #include "ecmascript/module/js_module_manager.h"
22
23 #include "libpandafile/annotation_data_accessor.h"
24 #include "libpandafile/class_data_accessor-inl.h"
25
26 namespace panda::ecmascript {
CreateGT(const JSPandaFile * jsPandaFile,const CString & recordName,uint32_t typeId)27 GlobalTSTypeRef TSTypeParser::CreateGT(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId)
28 {
29 if (typeId <= BUILDIN_TYPE_OFFSET) {
30 return GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, typeId);
31 }
32
33 if (typeId <= USER_DEFINED_TYPE_OFFSET) {
34 return ParseBuiltinObjType(typeId);
35 }
36
37 if (tsManager_->HasCreatedGT(jsPandaFile, typeId)) {
38 return tsManager_->GetGTFromOffset(jsPandaFile, typeId);
39 }
40 return ParseType(jsPandaFile, recordName, typeId);
41 }
42
ParseBuiltinObjType(uint32_t typeId)43 GlobalTSTypeRef TSTypeParser::ParseBuiltinObjType(uint32_t typeId)
44 {
45 if (!tsManager_->IsBuiltinsDTSEnabled()) {
46 return GlobalTSTypeRef(TSModuleTable::BUILTINS_TABLE_ID, typeId);
47 }
48 const JSPandaFile *builtinjsPandaFile = tsManager_->GetBuiltinPandaFile();
49 if (builtinjsPandaFile == nullptr) {
50 LOG_COMPILER(FATAL) << "load lib_ark_builtins.d.ts failed";
51 }
52 uint32_t offset = tsManager_->GetBuiltinOffset(typeId);
53 return CreateGT(builtinjsPandaFile, tsManager_->GetBuiltinRecordName(), offset);
54 }
55
ParseType(const JSPandaFile * jsPandaFile,const CString & recordName,uint32_t typeId)56 GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId)
57 {
58 panda_file::File::EntityId offset(typeId);
59 JSHandle<TaggedArray> literal = LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, offset);
60 if (literal->GetLength() == 0) { // typeLiteral maybe hole in d.abc
61 return GetAndStoreGT(jsPandaFile, typeId, recordName);
62 }
63 TSTypeKind kind = static_cast<TSTypeKind>(literal->Get(TYPE_KIND_INDEX_IN_LITERAL).GetInt());
64 if (kind == TSTypeKind::IMPORT) {
65 return ResolveImportType(jsPandaFile, recordName, literal, typeId);
66 }
67
68 uint32_t moduleId = tableGenerator_.TryGetModuleId(recordName);
69 if (UNLIKELY(!GlobalTSTypeRef::IsVaildModuleId(moduleId))) {
70 LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the record "
71 << recordName << " will not be parsed and will be treated as any.";
72 return GetAndStoreGT(jsPandaFile, typeId, recordName);
73 }
74
75 JSHandle<TSTypeTable> table = tableGenerator_.GetOrGenerateTSTypeTable(jsPandaFile, recordName, moduleId);
76 uint32_t localId = tableGenerator_.TryGetLocalId(table);
77 if (UNLIKELY(!GlobalTSTypeRef::IsVaildLocalId(localId))) {
78 LOG_COMPILER(DEBUG) << "The maximum number of TSTypes in TSTypeTable " << moduleId << " is reached. "
79 << "The TSType with typeId " << typeId << " in the record " << recordName
80 << " will not be parsed and will be treated as any.";
81 return GetAndStoreGT(jsPandaFile, typeId, recordName);
82 }
83
84 table->SetNumberOfTypes(thread_, localId);
85 GlobalTSTypeRef gt = GetAndStoreGT(jsPandaFile, typeId, recordName, moduleId, localId);
86 JSHandle<JSTaggedValue> type = ParseNonImportType(jsPandaFile, recordName, literal, kind, typeId);
87 if (UNLIKELY(type->IsUndefined())) {
88 return GetAndStoreGT(jsPandaFile, typeId, recordName);
89 }
90
91 SetTSType(table, type, gt);
92 tsManager_->CollectTypeOffsets(gt); // collect types that need to generate hclasses
93 return gt;
94 }
95
ResolveImportType(const JSPandaFile * jsPandaFile,const CString & recordName,JSHandle<TaggedArray> literal,uint32_t typeId)96 GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
97 JSHandle<TaggedArray> literal, uint32_t typeId)
98 {
99 JSHandle<EcmaString> importVarNamePath(thread_, literal->Get(IMPORT_PATH_OFFSET_IN_LITERAL)); // #A#./A
100 JSHandle<EcmaString> relativePath = GenerateImportRelativePath(importVarNamePath);
101 CString cstringRelativePath = ConvertToString(*relativePath);
102 // skip @ohos:|@app:|@native: prefixed imports
103 auto [isNative, _] = ModuleManager::CheckNativeModule(cstringRelativePath);
104 if (isNative) {
105 return GetAndStoreGT(jsPandaFile, typeId, recordName);
106 }
107
108 CString baseFileName = jsPandaFile->GetJSPandaFileDesc();
109 CString entryPoint =
110 base::PathHelper::ConcatFileNameWithMerge(thread_, jsPandaFile, baseFileName, recordName, cstringRelativePath);
111 ASSERT_PRINT(!entryPoint.empty(),
112 "EntryPoint is empty. Please check whether concating file name is correct or "
113 "whether the module request recorded in the import-type literal is correct.");
114 // skip files without type information
115 if (UNLIKELY(!jsPandaFile->HasTypeSummaryOffset(entryPoint))) {
116 return GetAndStoreGT(jsPandaFile, typeId, recordName);
117 }
118
119 uint32_t moduleId = tableGenerator_.TryGetModuleId(entryPoint);
120 if (UNLIKELY(!GlobalTSTypeRef::IsVaildModuleId(moduleId))) {
121 LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the recored "
122 << entryPoint << " will not be parsed and will be treated as any.";
123 return GetAndStoreGT(jsPandaFile, typeId, recordName);
124 }
125
126 JSHandle<TSTypeTable> table = tableGenerator_.GetOrGenerateTSTypeTable(jsPandaFile, entryPoint, moduleId);
127 JSHandle<JSTaggedValue> exportTable = GenerateExportTableFromRecord(jsPandaFile, entryPoint, table);
128 JSHandle<TaggedArray> arrayWithGT(exportTable);
129 JSHandle<EcmaString> targetVarName = GenerateImportVar(importVarNamePath);
130 GlobalTSTypeRef importedGT = GetExportGTByName(targetVarName, arrayWithGT);
131 return GetAndStoreImportGT(jsPandaFile, typeId, recordName, importedGT);
132 }
133
ParseNonImportType(const JSPandaFile * jsPandaFile,const CString & recordName,JSHandle<TaggedArray> literal,TSTypeKind kind,uint32_t typeId)134 JSHandle<JSTaggedValue> TSTypeParser::ParseNonImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
135 JSHandle<TaggedArray> literal, TSTypeKind kind, uint32_t typeId)
136 {
137 switch (kind) {
138 case TSTypeKind::CLASS: {
139 JSHandle<TSClassType> classType = ParseClassType(jsPandaFile, recordName, literal, typeId);
140 return JSHandle<JSTaggedValue>(classType);
141 }
142 case TSTypeKind::CLASS_INSTANCE: {
143 JSHandle<TSClassInstanceType> classInstanceType = ParseClassInstanceType(jsPandaFile, recordName, literal);
144 return JSHandle<JSTaggedValue>(classInstanceType);
145 }
146 case TSTypeKind::INTERFACE_KIND: {
147 JSHandle<TSInterfaceType> interfaceType = ParseInterfaceType(jsPandaFile, recordName, literal);
148 return JSHandle<JSTaggedValue>(interfaceType);
149 }
150 case TSTypeKind::UNION: {
151 JSHandle<TSUnionType> unionType = ParseUnionType(jsPandaFile, recordName, literal);
152 return JSHandle<JSTaggedValue>(unionType);
153 }
154 case TSTypeKind::FUNCTION: {
155 JSHandle<TSFunctionType> functionType = ParseFunctionType(jsPandaFile, recordName, literal);
156 return JSHandle<JSTaggedValue>(functionType);
157 }
158 case TSTypeKind::ARRAY: {
159 JSHandle<TSArrayType> arrayType = ParseArrayType(jsPandaFile, recordName, literal);
160 return JSHandle<JSTaggedValue>(arrayType);
161 }
162 case TSTypeKind::OBJECT: {
163 JSHandle<TSObjectType> objectType = ParseObjectType(jsPandaFile, recordName, literal);
164 return JSHandle<JSTaggedValue>(objectType);
165 }
166 default: {
167 LOG_COMPILER(DEBUG) << "Do not support parse types with kind " << static_cast<uint32_t>(kind) << ". "
168 << "Please check whether the type literal " << typeId
169 << " recorded in the record " << recordName << " is correct.";
170 return thread_->GlobalConstants()->GetHandledUndefined();
171 }
172 }
173 }
174
ParseClassType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal,uint32_t typeId)175 JSHandle<TSClassType> TSTypeParser::ParseClassType(const JSPandaFile *jsPandaFile, const CString &recordName,
176 const JSHandle<TaggedArray> &literal, uint32_t typeId)
177 {
178 JSHandle<TSClassType> classType = factory_->NewTSClassType();
179
180 std::string className = tsManager_->GetClassNameByOffset(jsPandaFile, typeId);
181 JSHandle<EcmaString> classEcmaString = factory_->NewFromStdString(className);
182 classType->SetName(thread_, classEcmaString.GetTaggedValue());
183
184 uint32_t index = 0;
185 ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::CLASS);
186
187 const uint32_t ignoreLength = 2; // 2: ignore accessFlag and readonly
188 index += ignoreLength;
189 int extendsTypeId = literal->Get(index++).GetInt();
190 if (TSClassType::IsBaseClassType(extendsTypeId)) {
191 classType->SetHasLinked(true);
192 } else {
193 auto extensionGT = CreateGT(jsPandaFile, recordName, extendsTypeId);
194 classType->SetExtensionGT(extensionGT);
195 if (extensionGT == GlobalTSTypeRef::Default()) {
196 classType->SetHasLinked(true);
197 }
198 }
199
200 // ignore implement
201 uint32_t numImplement = literal->Get(index++).GetInt();
202 index += numImplement;
203
204 // resolve instance type
205 uint32_t numFields = static_cast<uint32_t>(literal->Get(index++).GetInt());
206
207 JSHandle<TSObjectType> instanceType = factory_->NewTSObjectType(numFields);
208 JSHandle<TSObjLayoutInfo> instanceTypeInfo(thread_, instanceType->GetObjLayoutInfo());
209 ASSERT(instanceTypeInfo->GetPropertiesCapacity() == numFields);
210 FillPropertyTypes(jsPandaFile, recordName, instanceTypeInfo, literal, 0, numFields, index, true);
211 classType->SetInstanceType(thread_, instanceType);
212
213 // resolve prototype type
214 uint32_t numNonStatic = literal->Get(index++).GetInt();
215 JSHandle<TSObjectType> prototypeType = factory_->NewTSObjectType(numNonStatic);
216
217 JSHandle<TSObjLayoutInfo> nonStaticTypeInfo(thread_, prototypeType->GetObjLayoutInfo());
218 ASSERT(nonStaticTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(numNonStatic));
219 FillPropertyTypes(jsPandaFile, recordName, nonStaticTypeInfo, literal, 0, numNonStatic, index, false);
220 classType->SetPrototypeType(thread_, prototypeType);
221
222 // resolve constructor type
223 // static include fields and methods, which the former takes up 4 spaces and the latter takes up 2 spaces.
224 uint32_t numStaticFields = literal->Get(index++).GetInt();
225 uint32_t numStaticMethods = literal->Get(index + numStaticFields * TSClassType::FIELD_LENGTH).GetInt();
226 uint32_t numStatic = numStaticFields + numStaticMethods;
227 // new function type when support it
228 JSHandle<TSObjectType> constructorType = factory_->NewTSObjectType(numStatic);
229
230 JSHandle<TSObjLayoutInfo> staticTypeInfo(thread_, constructorType->GetObjLayoutInfo());
231 ASSERT(staticTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(numStatic));
232 FillPropertyTypes(jsPandaFile, recordName, staticTypeInfo, literal, 0, numStaticFields, index, true);
233 index++; // jmp over numStaticMethods
234 // static methods
235 FillPropertyTypes(jsPandaFile, recordName, staticTypeInfo, literal, numStaticFields, numStatic, index, false);
236 classType->SetConstructorType(thread_, constructorType);
237 return classType;
238 }
239
ParseClassInstanceType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal)240 JSHandle<TSClassInstanceType> TSTypeParser::ParseClassInstanceType(const JSPandaFile *jsPandaFile,
241 const CString &recordName,
242 const JSHandle<TaggedArray> &literal)
243 {
244 ASSERT(static_cast<TSTypeKind>(literal->Get(TYPE_KIND_INDEX_IN_LITERAL).GetInt()) ==
245 TSTypeKind::CLASS_INSTANCE);
246 JSHandle<TSClassInstanceType> classInstanceType = factory_->NewTSClassInstanceType();
247 uint32_t classTypeId = static_cast<uint32_t>(literal->Get(TSClassInstanceType::CREATE_CLASS_OFFSET).GetInt());
248 auto classGT = CreateGT(jsPandaFile, recordName, classTypeId);
249 classInstanceType->SetClassGT(classGT);
250 return classInstanceType;
251 }
252
ParseInterfaceType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal)253 JSHandle<TSInterfaceType> TSTypeParser::ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName,
254 const JSHandle<TaggedArray> &literal)
255 {
256 uint32_t index = 0;
257 JSHandle<TSInterfaceType> interfaceType = factory_->NewTSInterfaceType();
258 ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::INTERFACE_KIND);
259
260 index++;
261 // resolve extends of interface
262 uint32_t numExtends = literal->Get(index++).GetInt();
263 JSHandle<TaggedArray> extendsId = factory_->NewTaggedArray(numExtends);
264 JSMutableHandle<JSTaggedValue> extendsType(thread_, JSTaggedValue::Undefined());
265 for (uint32_t extendsIndex = 0; extendsIndex < numExtends; extendsIndex++) {
266 auto typeId = literal->Get(index++).GetInt();
267 auto extendGT = CreateGT(jsPandaFile, recordName, typeId);
268 extendsType.Update(JSTaggedValue(extendGT.GetType()));
269 extendsId->Set(thread_, extendsIndex, extendsType);
270 }
271 interfaceType->SetExtends(thread_, extendsId);
272
273 // resolve fields and methods of interface
274 uint32_t numFields = literal->Get(index++).GetInt();
275 // field takes up 4 spaces and method takes up 2 spaces.
276 uint32_t numMethods = static_cast<uint32_t>(literal->Get(index +
277 numFields * TSInterfaceType::FIELD_LENGTH).GetInt());
278 uint32_t totalFields = numFields + numMethods;
279
280 JSHandle<TSObjectType> fieldsType = factory_->NewTSObjectType(totalFields);
281 JSHandle<TSObjLayoutInfo> fieldsTypeInfo(thread_, fieldsType->GetObjLayoutInfo());
282 ASSERT(fieldsTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(totalFields));
283 FillPropertyTypes(jsPandaFile, recordName, fieldsTypeInfo, literal, 0, numFields, index, true);
284 index++; // jmp over numMethod
285 FillInterfaceMethodTypes(jsPandaFile, recordName, fieldsTypeInfo, literal, numFields, totalFields, index);
286 interfaceType->SetFields(thread_, fieldsType);
287 return interfaceType;
288 }
289
ParseUnionType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal)290 JSHandle<TSUnionType> TSTypeParser::ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName,
291 const JSHandle<TaggedArray> &literal)
292 {
293 uint32_t literalIndex = 0;
294 ASSERT(static_cast<TSTypeKind>(literal->Get(literalIndex).GetInt()) == TSTypeKind::UNION);
295 literalIndex++;
296 uint32_t numOfUnionMembers = literal->Get(literalIndex++).GetInt();
297
298 JSHandle<TSUnionType> unionType = factory_->NewTSUnionType(numOfUnionMembers);
299 JSHandle<TaggedArray> components(thread_, unionType->GetComponents());
300 for (uint32_t index = 0; index < numOfUnionMembers; ++index) {
301 uint32_t componentTypeId = literal->Get(literalIndex++).GetInt();
302 auto componentGT = CreateGT(jsPandaFile, recordName, componentTypeId);
303 components->Set(thread_, index, JSTaggedValue(componentGT.GetType()));
304 }
305 unionType->SetComponents(thread_, components);
306 return unionType;
307 }
308
ParseFunctionType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal)309 JSHandle<TSFunctionType> TSTypeParser::ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName,
310 const JSHandle<TaggedArray> &literal)
311 {
312 uint32_t index = 0;
313 ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::FUNCTION);
314 index++;
315
316 int32_t bitField = literal->Get(index++).GetInt();
317
318 JSHandle<JSTaggedValue> functionName(thread_, literal->Get(index++));
319 bool hasThisType = static_cast<bool>(literal->Get(index++).GetInt());
320 int32_t thisTypeId = 0;
321 if (hasThisType) {
322 thisTypeId = literal->Get(index++).GetInt();
323 }
324
325 int32_t length = literal->Get(index++).GetInt();
326 JSHandle<TSFunctionType> functionType = factory_->NewTSFunctionType(length);
327 JSHandle<TaggedArray> parameterTypes(thread_, functionType->GetParameterTypes());
328 JSMutableHandle<JSTaggedValue> parameterTypeRef(thread_, JSTaggedValue::Undefined());
329 for (int32_t i = 0; i < length; ++i) {
330 auto typeId = literal->Get(index++).GetInt();
331 auto parameterGT = CreateGT(jsPandaFile, recordName, typeId);
332 if (tsManager_->IsClassTypeKind(parameterGT)) {
333 parameterGT = tsManager_->CreateClassInstanceType(parameterGT);
334 }
335 parameterTypeRef.Update(JSTaggedValue(parameterGT.GetType()));
336 parameterTypes->Set(thread_, i, parameterTypeRef);
337 }
338 int32_t returntypeId = literal->Get(index++).GetInt();
339
340 functionType->SetName(thread_, functionName);
341 if (hasThisType) {
342 auto thisGT = CreateGT(jsPandaFile, recordName, thisTypeId);
343 functionType->SetThisGT(thisGT);
344 }
345
346 functionType->SetParameterTypes(thread_, parameterTypes);
347 auto returnGT = CreateGT(jsPandaFile, recordName, returntypeId);
348 functionType->SetReturnGT(returnGT);
349 functionType->SetBitField(bitField);
350
351 return functionType;
352 }
353
ParseArrayType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal)354 JSHandle<TSArrayType> TSTypeParser::ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName,
355 const JSHandle<TaggedArray> &literal)
356 {
357 uint32_t index = 0;
358 ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::ARRAY);
359 index++;
360 JSHandle<JSTaggedValue> elementTypeId(thread_, literal->Get(index++));
361 ASSERT(elementTypeId->IsInt());
362 JSHandle<TSArrayType> arrayType = factory_->NewTSArrayType();
363 auto elemetnGT = CreateGT(jsPandaFile, recordName, elementTypeId->GetInt());
364 if (tsManager_->IsClassTypeKind(elemetnGT)) {
365 elemetnGT = tsManager_->CreateClassInstanceType(elemetnGT);
366 }
367 arrayType->SetElementGT(elemetnGT);
368 return arrayType;
369 }
370
ParseObjectType(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TaggedArray> & literal)371 JSHandle<TSObjectType> TSTypeParser::ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName,
372 const JSHandle<TaggedArray> &literal)
373 {
374 uint32_t index = 0;
375 ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::OBJECT);
376 index++;
377 uint32_t length = literal->Get(index++).GetInt();
378 JSHandle<TSObjectType> objectType = factory_->NewTSObjectType(length);
379 JSHandle<TSObjLayoutInfo> propertyTypeInfo(thread_, objectType->GetObjLayoutInfo());
380 ASSERT(propertyTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(length));
381 FillPropertyTypes(jsPandaFile, recordName, propertyTypeInfo, literal, 0, length, index, false);
382 objectType->SetObjLayoutInfo(thread_, propertyTypeInfo);
383 return objectType;
384 }
385
FillPropertyTypes(const JSPandaFile * jsPandaFile,const CString & recordName,JSHandle<TSObjLayoutInfo> & layout,const JSHandle<TaggedArray> & literal,uint32_t startIndex,uint32_t lastIndex,uint32_t & index,bool isField)386 void TSTypeParser::FillPropertyTypes(const JSPandaFile *jsPandaFile, const CString &recordName,
387 JSHandle<TSObjLayoutInfo> &layout, const JSHandle<TaggedArray> &literal,
388 uint32_t startIndex, uint32_t lastIndex, uint32_t &index, bool isField)
389 {
390 JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
391 JSMutableHandle<JSTaggedValue> value(thread_, JSTaggedValue::Undefined());
392 for (uint32_t fieldIndex = startIndex; fieldIndex < lastIndex; ++fieldIndex) {
393 key.Update(literal->Get(index++));
394 ASSERT(key->IsString());
395 auto gt = CreateGT(jsPandaFile, recordName, literal->Get(index++).GetInt());
396 if (tsManager_->IsClassTypeKind(gt)) {
397 gt = tsManager_->CreateClassInstanceType(gt);
398 }
399 value.Update(JSTaggedValue(gt.GetType()));
400 layout->AddKeyAndType(thread_, key.GetTaggedValue(), value.GetTaggedValue());
401 if (isField) {
402 index += 2; // 2: ignore accessFlag and readonly
403 }
404 }
405 }
406
FillInterfaceMethodTypes(const JSPandaFile * jsPandaFile,const CString & recordName,JSHandle<TSObjLayoutInfo> & layout,const JSHandle<TaggedArray> & literal,uint32_t startIndex,uint32_t lastIndex,uint32_t & index)407 void TSTypeParser::FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile, const CString &recordName,
408 JSHandle<TSObjLayoutInfo> &layout, const JSHandle<TaggedArray> &literal,
409 uint32_t startIndex, uint32_t lastIndex, uint32_t &index)
410 {
411 JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
412 JSMutableHandle<JSTaggedValue> value(thread_, JSTaggedValue::Undefined());
413 for (uint32_t methodIndex = startIndex; methodIndex < lastIndex; ++methodIndex) {
414 auto gt = CreateGT(jsPandaFile, recordName, literal->Get(index++).GetInt());
415 value.Update(JSTaggedValue(gt.GetType()));
416
417 if (tsManager_->IsFunctionTypeKind(gt)) {
418 JSHandle<JSTaggedValue> tsType = tsManager_->GetTSType(gt);
419 ASSERT(tsType->IsTSFunctionType());
420
421 JSHandle<TSFunctionType> functionType(tsType);
422 key.Update(functionType->GetName());
423 };
424
425 layout->AddKeyAndType(thread_, key.GetTaggedValue(), value.GetTaggedValue());
426 }
427 }
428
GetExportDataFromRecord(const JSPandaFile * jsPandaFile,const CString & recordName)429 JSHandle<TaggedArray> TSTypeParser::GetExportDataFromRecord(const JSPandaFile *jsPandaFile,
430 const CString &recordName)
431 {
432 const panda_file::File &pf = *jsPandaFile->GetPandaFile();
433 panda_file::File::EntityId methodId(jsPandaFile->GetMainMethodIndex(recordName));
434 panda_file::MethodDataAccessor mda(pf, methodId);
435
436 const char *symbolTypes;
437 auto *fileName = pf.GetFilename().c_str();
438 if (::strcmp(TSTypeTable::BUILTINS_TABLE_NAME, fileName) == 0) {
439 symbolTypes = DECLARED_SYMBOL_TYPES;
440 } else {
441 symbolTypes = EXPORTED_SYMBOL_TYPES;
442 }
443
444 JSHandle<TaggedArray> typeOfExportedSymbols(thread_, thread_->GlobalConstants()->GetEmptyArray());
445 mda.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) {
446 panda_file::AnnotationDataAccessor ada(pf, annotation_id);
447 auto *annotationName = reinterpret_cast<const char *>(pf.GetStringData(ada.GetClassId()).data);
448 ASSERT(annotationName != nullptr);
449 if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) {
450 return;
451 }
452 uint32_t length = ada.GetCount();
453 for (uint32_t i = 0; i < length; i++) {
454 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
455 auto *elemName = reinterpret_cast<const char *>(pf.GetStringData(adae.GetNameId()).data);
456 ASSERT(elemName != nullptr);
457
458 if (::strcmp(symbolTypes, elemName) != 0) {
459 continue;
460 }
461
462 panda_file::ScalarValue sv = adae.GetScalarValue();
463 panda_file::File::EntityId literalOffset(sv.GetValue());
464 typeOfExportedSymbols = LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, literalOffset);
465 // typeOfExprotedSymbols: "symbol0", "type0", "symbol1", "type1" ...
466 }
467 });
468
469 return typeOfExportedSymbols;
470 }
471
GenerateExportTableFromRecord(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TSTypeTable> & table)472 JSHandle<JSTaggedValue> TSTypeParser::GenerateExportTableFromRecord(const JSPandaFile *jsPandaFile,
473 const CString &recordName,
474 const JSHandle<TSTypeTable> &table)
475 {
476 JSHandle<JSTaggedValue> exportValeTable = TSTypeTable::GetExportValueTable(thread_, table);
477 if (exportValeTable->IsUndefined()) {
478 // Read export-data from annotation of the .abc File
479 JSHandle<TaggedArray> exportTable = GetExportDataFromRecord(jsPandaFile, recordName);
480 uint32_t length = exportTable->GetLength();
481
482 // Replace typeIds with GT
483 JSTaggedValue target;
484 for (uint32_t i = 1; i < length; i += 2) { // 2: skip a pair of key and value
485 target = exportTable->Get(i);
486 // Create GT based on typeId, and wrapped it into a JSTaggedValue
487 uint32_t typeId = static_cast<uint32_t>(target.GetInt());
488 GlobalTSTypeRef typeGT = CreateGT(jsPandaFile, recordName, typeId);
489 // Set the wrapped GT to exportTable
490 exportTable->Set(thread_, i, JSTaggedValue(typeGT.GetType()));
491 }
492 TSTypeTable::SetExportValueTable(thread_, table, exportTable);
493 return JSHandle<JSTaggedValue>(exportTable);
494 }
495 ASSERT(exportValeTable->IsTaggedArray());
496 return exportValeTable;
497 }
498
GenerateImportRelativePath(JSHandle<EcmaString> importRel) const499 JSHandle<EcmaString> TSTypeParser::GenerateImportRelativePath(JSHandle<EcmaString> importRel) const
500 {
501 // importNamePath #A#./A
502 CString importNamePath = ConvertToString(importRel.GetTaggedValue());
503 auto lastPos = importNamePath.find_last_of('#');
504 CString path = importNamePath.substr(lastPos + 1, importNamePath.size() - lastPos - 1);
505 return factory_->NewFromUtf8(path); // #A#./A -> ./A
506 }
507
GenerateImportVar(JSHandle<EcmaString> import) const508 JSHandle<EcmaString> TSTypeParser::GenerateImportVar(JSHandle<EcmaString> import) const
509 {
510 // importNamePath #A#./A
511 CString importVarNamePath = ConvertToString(import.GetTaggedValue());
512 auto firstPos = importVarNamePath.find_first_of('#');
513 auto lastPos = importVarNamePath.find_last_of('#');
514 CString target = importVarNamePath.substr(firstPos + 1, lastPos - firstPos - 1);
515 return factory_->NewFromUtf8(target); // #A#./A -> A
516 }
517
GetExportGTByName(JSHandle<EcmaString> target,JSHandle<TaggedArray> & exportTable) const518 GlobalTSTypeRef TSTypeParser::GetExportGTByName(JSHandle<EcmaString> target, JSHandle<TaggedArray> &exportTable) const
519 {
520 uint32_t length = exportTable->GetLength();
521 // the exportTable is arranged as follows ["A", "101", "B", "102"]
522 // get GT of a export type specified by its descriptor/name
523 for (uint32_t i = 0; i < length; i = i + 2) { // 2: symbol and symbolType
524 EcmaString *valueString = EcmaString::Cast(exportTable->Get(i).GetTaggedObject());
525 if (EcmaStringAccessor::StringsAreEqual(*target, valueString)) {
526 // Transform raw data of JSTaggedValue to GT
527 return GlobalTSTypeRef(exportTable->Get(i + 1).GetInt());
528 }
529 }
530 return GlobalTSTypeRef::Default();
531 }
532 } // namespace panda::ecmascript
533