• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/subtyping_operator.h"
19 #include "ecmascript/jspandafile/js_pandafile_manager.h"
20 #include "ecmascript/module/js_module_manager.h"
21 #include "ecmascript/module/module_path_helper.h"
22 #include "ecmascript/jspandafile/program_object.h"
23 
24 namespace panda::ecmascript {
25 // For each property of one class, object or interface, it's name and typeIndex are recorded in order,
26 // and if it is a field, then accessFlag and readonly of this property will be additionally recorded.
27 static constexpr uint32_t FIELD_LENGTH = 4;
28 static constexpr uint32_t METHOD_LENGTH = 2;
29 static constexpr uint32_t INDEX_OCCUPIED_OFFSET = 1;
30 
TSTypeParser(TSManager * tsManager)31 TSTypeParser::TSTypeParser(TSManager *tsManager)
32     : tsManager_(tsManager), vm_(tsManager->GetEcmaVM()),
33       thread_(vm_->GetJSThread()), factory_(vm_->GetFactory()),
34       tableGenerator_(tsManager_)
35 {
36     auto bcInfoCollector = tsManager_->GetBytecodeInfoCollector();
37     if (bcInfoCollector != nullptr) {
38         bcInfo_ = bcInfoCollector->GetBytecodeInfoPtr();
39     }
40 }
41 
CreateGT(const JSPandaFile * jsPandaFile,const CString & recordName,uint32_t typeId)42 GlobalTSTypeRef TSTypeParser::CreateGT(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId)
43 {
44     if (typeId <= BUILDIN_TYPE_OFFSET) {
45         return GlobalTSTypeRef(static_cast<uint32_t>(ModuleTableIdx::PRIMITIVE), typeId);
46     }
47 
48     if (!IsUserDefinedType(typeId)) {
49         return ParseBuiltinObjType(typeId);
50     }
51 
52     // Negative numbers are used to represent type parameters in generics types.
53     if (static_cast<int32_t>(typeId) < 0) {
54         return EncodeParaType(typeId);
55     }
56 
57     GlobalTypeID gId(jsPandaFile, typeId);
58     if (tsManager_->HasCreatedGT(gId)) {
59         return tsManager_->GetGTByGlobalTypeID(gId);
60     }
61     return ParseType(jsPandaFile, recordName, typeId);
62 }
63 
ParseBuiltinObjType(uint32_t typeId)64 GlobalTSTypeRef TSTypeParser::ParseBuiltinObjType(uint32_t typeId)
65 {
66     if (!tsManager_->IsBuiltinsDTSEnabled()) {
67         return GlobalTSTypeRef(static_cast<uint32_t>(ModuleTableIdx::BUILTIN), typeId);
68     }
69     const JSPandaFile *builtinjsPandaFile = tsManager_->GetBuiltinPandaFile();
70     if (builtinjsPandaFile == nullptr) {
71         LOG_COMPILER(FATAL) << "load lib_ark_builtins.d.ts failed";
72     }
73     uint32_t offset = tsManager_->GetBuiltinOffset(typeId);
74     return CreateGT(builtinjsPandaFile, tsManager_->GetBuiltinRecordName(), offset);
75 }
76 
ParseType(const JSPandaFile * jsPandaFile,const CString & recordName,uint32_t typeId)77 GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId)
78 {
79     TypeLiteralExtractor typeLiteralExtractor(jsPandaFile, typeId);
80     if (!typeLiteralExtractor.IsVaildTypeLiteral()) {  // typeLiteral maybe hole in d.abc
81         return GlobalTSTypeRef::Default();
82     }
83 
84     if (TypeNeedResolve(&typeLiteralExtractor)) {
85         return ResolveType(jsPandaFile, recordName, &typeLiteralExtractor);
86     }
87 
88     uint32_t moduleId = tableGenerator_.TryGetModuleId(recordName);
89     if (UNLIKELY(!GlobalTSTypeRef::IsValidModuleId(moduleId))) {
90         LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the record "
91                             << recordName << " will not be parsed and will be treated as any.";
92         return GetAndStoreGT(jsPandaFile, typeId, recordName);
93     }
94 
95     JSHandle<TSTypeTable> table = tableGenerator_.GetOrGenerateTSTypeTable(jsPandaFile, recordName, moduleId);
96     uint32_t localId = tableGenerator_.TryGetLocalId(table);
97     if (UNLIKELY(!GlobalTSTypeRef::IsValidLocalId(localId))) {
98         LOG_COMPILER(DEBUG) << "The maximum number of TSTypes in TSTypeTable " << moduleId << " is reached. "
99                             << "The TSType with typeId " << typeId << " in the record " << recordName
100                             << " will not be parsed and will be treated as any.";
101         return GetAndStoreGT(jsPandaFile, typeId, recordName);
102     }
103 
104     table->SetNumberOfTypes(thread_, localId);
105     GlobalTSTypeRef gt = GetAndStoreGT(jsPandaFile, typeId, recordName, moduleId, localId);
106     JSHandle<JSTaggedValue> type = ParseNonImportType(jsPandaFile, recordName, &typeLiteralExtractor);
107     if (UNLIKELY(type->IsUndefined())) {
108         return GetAndStoreGT(jsPandaFile, typeId, recordName);
109     }
110 
111     SetTSType(table, type, gt);
112     if (typeLiteralExtractor.GetTypeKind() != TSTypeKind::GENERIC_INSTANCE) {
113         tsManager_->CollectGT(gt);  // collect types that need to generate hclasses
114     }
115     return gt;
116 }
117 
ResolveType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)118 GlobalTSTypeRef TSTypeParser::ResolveType(const JSPandaFile *jsPandaFile, const CString &recordName,
119                                           TypeLiteralExtractor *typeLiteralExtractor)
120 {
121     if (typeLiteralExtractor->IsGenerics()) {
122         return ParseGenericsType(jsPandaFile, recordName, typeLiteralExtractor);
123     }
124 
125     auto kind = typeLiteralExtractor->GetTypeKind();
126     switch (kind) {
127         case TSTypeKind::IMPORT: {
128             return ResolveImportType(jsPandaFile, recordName, typeLiteralExtractor);
129         }
130         case TSTypeKind::INDEXSIG: {
131             return ParseIndexSigType(jsPandaFile, recordName, typeLiteralExtractor);
132         }
133         default: {
134             return GlobalTSTypeRef::Default();
135         }
136     }
137 }
138 
ResolveImportType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)139 GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
140                                                 TypeLiteralExtractor *typeLiteralExtractor)
141 {
142     uint32_t typeId = typeLiteralExtractor->GetTypeOffset();
143     JSHandle<EcmaString> importVarNamePath =
144         factory_->NewFromUtf8(typeLiteralExtractor->GetStringValue(DEFAULT_INDEX));
145     JSHandle<EcmaString> relativePath = GenerateImportRelativePath(importVarNamePath);
146     CString cstringRelativePath = ConvertToString(*relativePath);
147     // skip @ohos:|@app:|@native: prefixed imports
148     if (ModulePathHelper::IsNativeModuleRequest(cstringRelativePath)) {
149         return GetAndStoreGT(jsPandaFile, typeId, recordName);
150     }
151 
152     CString baseFileName = jsPandaFile->GetJSPandaFileDesc();
153     CString entryPoint =
154         ModulePathHelper::ConcatFileNameWithMerge(thread_, jsPandaFile, baseFileName, recordName, cstringRelativePath);
155     if (entryPoint.empty()) {
156         LOG_COMPILER(DEBUG) << "EntryPoint is empty. Please check whether concating file name is correct or "
157                                "whether the module request recorded in the import-type literal is correct.";
158     }
159     // skip files without type information
160     if (UNLIKELY(!jsPandaFile->HasTypeSummaryOffset(entryPoint))) {
161         return GetAndStoreGT(jsPandaFile, typeId, recordName);
162     }
163 
164     uint32_t moduleId = tableGenerator_.TryGetModuleId(entryPoint);
165     if (UNLIKELY(!GlobalTSTypeRef::IsValidModuleId(moduleId))) {
166         LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the record "
167                             << entryPoint << " will not be parsed and will be treated as any.";
168         return GetAndStoreGT(jsPandaFile, typeId, recordName);
169     }
170 
171     JSHandle<TSTypeTable> table = tableGenerator_.GetOrGenerateTSTypeTable(jsPandaFile, entryPoint, moduleId);
172     JSHandle<JSTaggedValue> exportTable = GenerateExportTableFromRecord(jsPandaFile, entryPoint, table);
173     JSHandle<TaggedArray> arrayWithGT(exportTable);
174     JSHandle<EcmaString> targetVarName = GenerateImportVar(importVarNamePath);
175     std::unordered_set<CString> markSet;
176     GlobalTSTypeRef importedGT = GetExportGTByName(targetVarName, arrayWithGT, jsPandaFile, entryPoint, markSet);
177     return GetAndStoreImportGT(jsPandaFile, typeId, recordName, importedGT);
178 }
179 
ParseIndexSigType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)180 GlobalTSTypeRef TSTypeParser::ParseIndexSigType(const JSPandaFile *jsPandaFile, const CString &recordName,
181                                                 TypeLiteralExtractor *typeLiteralExtractor)
182 {
183     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INDEXSIG);
184     uint32_t length = typeLiteralExtractor->GetIntValue(NUM_INDEX_SIG_INDEX);
185     JSHandle<TSObjLayoutInfo> indexSignInfo = factory_->CreateTSObjLayoutInfo(length);
186     typeLiteralExtractor->EnumerateTypesWithIntKey(NUM_INDEX_SIG_INDEX,
187         [this, &jsPandaFile, &recordName, &indexSignInfo](const uint32_t literalTag, const uint32_t literalValue) {
188             auto keyGT = CreateGT(jsPandaFile, recordName, literalTag);
189             auto valueGT = CreateGT(jsPandaFile, recordName, literalValue);
190             indexSignInfo->AddProperty(thread_, JSTaggedValue(keyGT.GetType()), JSTaggedValue(valueGT.GetType()));
191         });
192 
193     uint32_t oriTypeId = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
194     auto oriGT = CreateGT(jsPandaFile, recordName, oriTypeId);
195     JSHandle<JSTaggedValue> type = tsManager_->GetTSType(oriGT);
196     if (type->IsTSClassType()) {
197         JSHandle<TSClassType> classType(type);
198         classType->SetIndexSigns(thread_, indexSignInfo);
199     } else if (type->IsTSObjectType()) {
200         JSHandle<TSObjectType> objectType(type);
201         objectType->SetIndexSigns(thread_, indexSignInfo);
202     } else if (type->IsTSInterfaceType()) {
203         JSHandle<TSInterfaceType> interfaceType(type);
204         interfaceType->SetIndexSigns(thread_, indexSignInfo);
205     } else {
206         LOG_COMPILER(DEBUG) << "Unsupport TSType with index signature: "
207                             << static_cast<uint32_t>(typeLiteralExtractor->GetTypeKind());
208     }
209     uint32_t typeId = typeLiteralExtractor->GetTypeOffset();
210     return GetAndStoreGT(jsPandaFile, typeId, recordName, oriGT.GetModuleId(), oriGT.GetLocalId());
211 }
212 
ParseNonImportType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)213 JSHandle<JSTaggedValue> TSTypeParser::ParseNonImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
214                                                          TypeLiteralExtractor *typeLiteralExtractor)
215 {
216     auto kind = typeLiteralExtractor->GetTypeKind();
217     switch (kind) {
218         case TSTypeKind::CLASS: {
219             JSHandle<TSClassType> classType = ParseClassType(jsPandaFile, recordName, typeLiteralExtractor);
220             return JSHandle<JSTaggedValue>(classType);
221         }
222         case TSTypeKind::CLASS_INSTANCE: {
223             JSHandle<TSClassInstanceType> classInstanceType =
224                 ParseClassInstanceType(jsPandaFile, recordName, typeLiteralExtractor);
225             return JSHandle<JSTaggedValue>(classInstanceType);
226         }
227         case TSTypeKind::INTERFACE: {
228             JSHandle<TSInterfaceType> interfaceType = ParseInterfaceType(jsPandaFile, recordName, typeLiteralExtractor);
229             return JSHandle<JSTaggedValue>(interfaceType);
230         }
231         case TSTypeKind::UNION: {
232             JSHandle<TSUnionType> unionType = ParseUnionType(jsPandaFile, recordName, typeLiteralExtractor);
233             return JSHandle<JSTaggedValue>(unionType);
234         }
235         case TSTypeKind::FUNCTION: {
236             JSHandle<TSFunctionType> functionType =
237                 ParseFunctionType(jsPandaFile, recordName, typeLiteralExtractor);
238             return JSHandle<JSTaggedValue>(functionType);
239         }
240         case TSTypeKind::ARRAY: {
241             JSHandle<TSArrayType> arrayType = ParseArrayType(jsPandaFile, recordName, typeLiteralExtractor);
242             return JSHandle<JSTaggedValue>(arrayType);
243         }
244         case TSTypeKind::OBJECT: {
245             JSHandle<TSObjectType> objectType = ParseObjectType(jsPandaFile, recordName, typeLiteralExtractor);
246             return JSHandle<JSTaggedValue>(objectType);
247         }
248         case TSTypeKind::BUILTIN_INSTANCE:
249         case TSTypeKind::GENERIC_INSTANCE: {
250             return ParseGenericsInstanceType(jsPandaFile, recordName, typeLiteralExtractor);
251         }
252         default: {
253             LOG_COMPILER(DEBUG) << "Do not support parse types with kind " << static_cast<uint32_t>(kind) << ". "
254                                 << "Please check whether the type literal " << typeLiteralExtractor->GetTypeOffset()
255                                 << " recorded in the record " << recordName << " is correct.";
256             return thread_->GlobalConstants()->GetHandledUndefined();
257         }
258     }
259 }
260 
ParseClassType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)261 JSHandle<TSClassType> TSTypeParser::ParseClassType(const JSPandaFile *jsPandaFile, const CString &recordName,
262                                                    TypeLiteralExtractor *typeLiteralExtractor)
263 {
264     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS);
265     ClassLiteralInfo classLitInfo(typeLiteralExtractor);
266     uint32_t numNonStaticFieldsIndex = classLitInfo.numNonStaticFieldsIndex;
267     uint32_t numNonStaticMethodsIndex = classLitInfo.numNonStaticMethodsIndex;
268     uint32_t numStaticFieldsIndex = classLitInfo.numStaticFieldsIndex;
269     uint32_t numStaticMethodsIndex = classLitInfo.numStaticMethodsIndex;
270 
271     JSHandle<TSClassType> classType = factory_->NewTSClassType();
272     SetClassName(classType, jsPandaFile, typeLiteralExtractor);
273     SetSuperClassType(classType, jsPandaFile, recordName, typeLiteralExtractor);
274 
275     // resolve instance type
276     uint32_t numFields = typeLiteralExtractor->GetIntValue(numNonStaticFieldsIndex);
277     JSHandle<TSObjectType> instanceType = factory_->NewTSObjectType(numFields);
278     FillPropTypes(jsPandaFile, recordName, instanceType, typeLiteralExtractor, numNonStaticFieldsIndex, FIELD_LENGTH);
279     classType->SetInstanceType(thread_, instanceType);
280 
281     // resolve prototype type
282     uint32_t numNonStatic = typeLiteralExtractor->GetIntValue(numNonStaticMethodsIndex);
283     JSHandle<TSObjectType> prototypeType = factory_->NewTSObjectType(numNonStatic);
284     FillPropTypes(jsPandaFile, recordName, prototypeType, typeLiteralExtractor,
285                   numNonStaticMethodsIndex, METHOD_LENGTH);
286     classType->SetPrototypeType(thread_, prototypeType);
287 
288     // resolve constructor type
289     uint32_t numStaticFields = typeLiteralExtractor->GetIntValue(numStaticFieldsIndex);
290     uint32_t numStaticMethods = typeLiteralExtractor->GetIntValue(numStaticMethodsIndex);
291     uint32_t numStatic = numStaticFields + numStaticMethods;
292     JSHandle<TSObjectType> constructorType = factory_->NewTSObjectType(numStatic);
293     FillPropTypes(jsPandaFile, recordName, constructorType, typeLiteralExtractor, numStaticFieldsIndex, FIELD_LENGTH);
294     FillPropTypes(jsPandaFile, recordName, constructorType, typeLiteralExtractor,
295                   numStaticMethodsIndex, METHOD_LENGTH);
296     classType->SetConstructorType(thread_, constructorType);
297     return classType;
298 }
299 
ParseClassInstanceType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)300 JSHandle<TSClassInstanceType> TSTypeParser::ParseClassInstanceType(const JSPandaFile *jsPandaFile,
301                                                                    const CString &recordName,
302                                                                    TypeLiteralExtractor *typeLiteralExtractor)
303 {
304     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS_INSTANCE);
305     JSHandle<TSClassInstanceType> classInstanceType = factory_->NewTSClassInstanceType();
306     // classTypeId is stored in the first position
307     uint32_t classTypeId = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
308     auto classGT = CreateGT(jsPandaFile, recordName, classTypeId);
309     classInstanceType->SetClassGT(classGT);
310     return classInstanceType;
311 }
312 
ParseInterfaceType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)313 JSHandle<TSInterfaceType> TSTypeParser::ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName,
314                                                            TypeLiteralExtractor *typeLiteralExtractor)
315 {
316     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INTERFACE);
317     JSHandle<TSInterfaceType> interfaceType = factory_->NewTSInterfaceType();
318     InterfaceLiteralInfo interfaceLitInfo(typeLiteralExtractor);
319     uint32_t numFieldsIndex = interfaceLitInfo.numFieldsIndex;
320     uint32_t numMethodsIndex = interfaceLitInfo.numMethodsIndex;
321 
322     // resolve extends of interface
323     uint32_t numExtends = typeLiteralExtractor->GetIntValue(InterfaceLiteralInfo::NUM_EXTENDS_INDEX);
324     JSHandle<TaggedArray> extendsId = factory_->NewTaggedArray(numExtends);
325     uint32_t extendsIndex = 0;
326     typeLiteralExtractor->EnumerateElements(InterfaceLiteralInfo::NUM_EXTENDS_INDEX,
327         [this, &jsPandaFile, &recordName, &extendsIndex, &extendsId](const uint32_t literalValue) {
328             auto extendGT = CreateGT(jsPandaFile, recordName, literalValue);
329             extendsId->Set(thread_, extendsIndex++, JSTaggedValue(extendGT.GetType()));
330         });
331     interfaceType->SetExtends(thread_, extendsId);
332 
333     uint32_t numFields = typeLiteralExtractor->GetIntValue(numFieldsIndex);
334     uint32_t numMethods = typeLiteralExtractor->GetIntValue(numMethodsIndex);
335     uint32_t totalFields = numFields + numMethods;
336     JSHandle<TSObjectType> fieldsType = factory_->NewTSObjectType(totalFields);
337     FillPropTypes(jsPandaFile, recordName, fieldsType, typeLiteralExtractor, numFieldsIndex, FIELD_LENGTH);
338     FillInterfaceMethodTypes(jsPandaFile, recordName, fieldsType, typeLiteralExtractor, numMethodsIndex);
339     interfaceType->SetFields(thread_, fieldsType);
340     return interfaceType;
341 }
342 
ParseUnionType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)343 JSHandle<TSUnionType> TSTypeParser::ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName,
344                                                    TypeLiteralExtractor *typeLiteralExtractor)
345 {
346     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::UNION);
347     // the number of union types is stored in the first position
348     uint32_t numOfUnionMembers = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
349     JSHandle<TSUnionType> unionType = factory_->NewTSUnionType(numOfUnionMembers);
350 
351     JSHandle<TaggedArray> components(thread_, unionType->GetComponents());
352     uint32_t index = 0;
353     typeLiteralExtractor->EnumerateElements(DEFAULT_INDEX,
354         [this, &jsPandaFile, &recordName, &index, &components](const uint32_t literalValue) {
355             auto componentGT = CreateGT(jsPandaFile, recordName, literalValue);
356             components->Set(thread_, index++, JSTaggedValue(componentGT.GetType()));
357         });
358     unionType->SetComponents(thread_, components);
359     return unionType;
360 }
361 
ParseFunctionType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)362 JSHandle<TSFunctionType> TSTypeParser::ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName,
363                                                          TypeLiteralExtractor *typeLiteralExtractor)
364 {
365     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::FUNCTION);
366     FunctionLiteralInfo functionLitInfo(typeLiteralExtractor);
367     uint32_t numParasIndex = functionLitInfo.numParasIndex;
368     uint32_t returnTypeIndex = functionLitInfo.returnTypeIndex;
369 
370     uint32_t length = typeLiteralExtractor->GetIntValue(numParasIndex);
371     JSHandle<TSFunctionType> functionType = factory_->NewTSFunctionType(length);
372 
373     SetFunctionThisType(functionType, jsPandaFile, recordName, typeLiteralExtractor);
374     JSHandle<TaggedArray> parameterTypes(thread_, functionType->GetParameterTypes());
375     uint32_t index = 0;
376     typeLiteralExtractor->EnumerateElements(numParasIndex,
377         [this, &jsPandaFile, &recordName, &index, &parameterTypes](const uint32_t literalValue) {
378             auto parameterGT = CreateGT(jsPandaFile, recordName, literalValue);
379             if (tsManager_->IsClassTypeKind(parameterGT)) {
380                 parameterGT = tsManager_->CreateClassInstanceType(parameterGT);
381             }
382             parameterTypes->Set(thread_, index++, JSTaggedValue(parameterGT.GetType()));
383         });
384     functionType->SetParameterTypes(thread_, parameterTypes);
385 
386     JSHandle<JSTaggedValue> functionName(
387         factory_->NewFromUtf8(typeLiteralExtractor->GetStringValue(FunctionLiteralInfo::NAME_INDEX)));
388     functionType->SetName(thread_, functionName);
389 
390     uint32_t returntypeId = typeLiteralExtractor->GetIntValue(returnTypeIndex);
391     auto returnGT = CreateGT(jsPandaFile, recordName, returntypeId);
392     functionType->SetReturnGT(returnGT);
393 
394     uint32_t bitField = typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::BITFIELD_INDEX);
395     functionType->SetBitField(bitField);
396 
397     StoreMethodOffset(functionType, typeLiteralExtractor);
398     return functionType;
399 }
400 
ParseArrayType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)401 JSHandle<TSArrayType> TSTypeParser::ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName,
402                                                    TypeLiteralExtractor *typeLiteralExtractor)
403 {
404     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::ARRAY);
405     JSHandle<TSArrayType> arrayType = factory_->NewTSArrayType();
406     // the type of elements of array is stored in the first position
407     auto elemetnGT = CreateGT(jsPandaFile, recordName, typeLiteralExtractor->GetIntValue(DEFAULT_INDEX));
408     if (tsManager_->IsClassTypeKind(elemetnGT)) {
409         elemetnGT = tsManager_->CreateClassInstanceType(elemetnGT);
410     }
411     arrayType->SetElementGT(elemetnGT);
412     return arrayType;
413 }
414 
ParseObjectType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)415 JSHandle<TSObjectType> TSTypeParser::ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName,
416                                                      TypeLiteralExtractor *typeLiteralExtractor)
417 {
418     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::OBJECT);
419     // the number of properties of object is stored in the first position
420     uint32_t length = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
421     JSHandle<TSObjectType> objectType = factory_->NewTSObjectType(length);
422     FillPropTypes(jsPandaFile, recordName, objectType, typeLiteralExtractor, DEFAULT_INDEX, METHOD_LENGTH);
423     return objectType;
424 }
425 
FillPropTypes(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TSObjectType> & objectType,TypeLiteralExtractor * typeLiteralExtractor,const uint32_t numOfFieldIndex,const uint32_t gap)426 void TSTypeParser::FillPropTypes(const JSPandaFile *jsPandaFile,
427                                  const CString &recordName,
428                                  const JSHandle<TSObjectType> &objectType,
429                                  TypeLiteralExtractor *typeLiteralExtractor,
430                                  const uint32_t numOfFieldIndex,
431                                  const uint32_t gap)
432 {
433     JSHandle<TSObjLayoutInfo> layout(thread_, objectType->GetObjLayoutInfo());
434     JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
435     typeLiteralExtractor->EnumerateProperties(numOfFieldIndex, gap,
436         [this, &key, &jsPandaFile, &recordName, &layout](const CString &literalKey, const uint32_t literalValue) {
437             JSHandle<JSTaggedValue> propName(factory_->NewFromUtf8(literalKey));
438             key.Update(propName.GetTaggedValue());
439             ASSERT(key->IsString());
440             auto gt = CreateGT(jsPandaFile, recordName, literalValue);
441             if (tsManager_->IsClassTypeKind(gt)) {
442                 gt = tsManager_->CreateClassInstanceType(gt);
443             }
444             layout->AddProperty(thread_, key.GetTaggedValue(), JSTaggedValue(gt.GetType()));
445         });
446 }
447 
FillInterfaceMethodTypes(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TSObjectType> & objectType,TypeLiteralExtractor * typeLiteralExtractor,const uint32_t numExtends)448 void TSTypeParser::FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile,
449                                             const CString &recordName,
450                                             const JSHandle<TSObjectType> &objectType,
451                                             TypeLiteralExtractor *typeLiteralExtractor,
452                                             const uint32_t numExtends)
453 {
454     JSHandle<TSObjLayoutInfo> layout(thread_, objectType->GetObjLayoutInfo());
455     JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
456     typeLiteralExtractor->EnumerateElements(numExtends,
457         [this, &jsPandaFile, &recordName, &layout, &key](const uint32_t literalValue) {
458             auto gt = CreateGT(jsPandaFile, recordName, literalValue);
459             if (tsManager_->IsFunctionTypeKind(gt)) {
460                 JSHandle<JSTaggedValue> tsType = tsManager_->GetTSType(gt);
461                 ASSERT(tsType->IsTSFunctionType());
462                 JSHandle<TSFunctionType> functionType(tsType);
463                 key.Update(functionType->GetName());
464             };
465             layout->AddProperty(thread_, key.GetTaggedValue(), JSTaggedValue(gt.GetType()));
466         });
467 }
468 
SetClassName(const JSHandle<TSClassType> & classType,const JSPandaFile * jsPandaFile,TypeLiteralExtractor * typeLiteralExtractor)469 void TSTypeParser::SetClassName(const JSHandle<TSClassType> &classType,
470                                 const JSPandaFile *jsPandaFile,
471                                 TypeLiteralExtractor *typeLiteralExtractor)
472 {
473     std::string className = tsManager_->GetClassNameByOffset(jsPandaFile, typeLiteralExtractor->GetTypeOffset());
474     JSHandle<EcmaString> classEcmaString = factory_->NewFromStdString(className);
475     classType->SetName(thread_, classEcmaString.GetTaggedValue());
476 }
477 
SetSuperClassType(const JSHandle<TSClassType> & classType,const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)478 void TSTypeParser::SetSuperClassType(const JSHandle<TSClassType> &classType,
479                                      const JSPandaFile *jsPandaFile,
480                                      const CString &recordName,
481                                      TypeLiteralExtractor *typeLiteralExtractor)
482 {
483     uint32_t extendsTypeId = typeLiteralExtractor->GetIntValue(ClassLiteralInfo::SUPER_CLASS_INDEX);
484     if (TSClassType::IsBaseClassType(extendsTypeId)) {
485         classType->SetHasLinked(true);
486     } else {
487         auto extensionGT = CreateGT(jsPandaFile, recordName, extendsTypeId);
488         classType->SetExtensionGT(extensionGT);
489         if (extensionGT.IsDefault()) {
490             classType->SetHasLinked(true);
491         }
492     }
493 }
494 
SetFunctionThisType(const JSHandle<TSFunctionType> & functionType,const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)495 void TSTypeParser::SetFunctionThisType(const JSHandle<TSFunctionType> &functionType,
496                                        const JSPandaFile *jsPandaFile,
497                                        const CString &recordName,
498                                        TypeLiteralExtractor *typeLiteralExtractor)
499 {
500     bool hasThisType = static_cast<bool>(typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::HAS_THIS_TYPE_INDEX));
501     if (hasThisType) {
502         // if hasThisType is true, then the next position will store typeId of this
503         uint32_t thisTypeId = typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::HAS_THIS_TYPE_INDEX + 1);
504         auto thisGT = CreateGT(jsPandaFile, recordName, thisTypeId);
505         functionType->SetThisGT(thisGT);
506     }
507 }
508 
StoreMethodOffset(const JSHandle<TSFunctionType> & functionType,TypeLiteralExtractor * typeLiteralExtractor)509 void TSTypeParser::StoreMethodOffset(const JSHandle<TSFunctionType> &functionType,
510                                      TypeLiteralExtractor *typeLiteralExtractor)
511 {
512     if (bcInfo_ != nullptr) {
513         uint32_t typeOffset = typeLiteralExtractor->GetTypeOffset();
514         uint32_t methodOffset = bcInfo_->IterateFunctionTypeIDAndMethodOffset(typeOffset);
515         if (methodOffset != 0) {
516             functionType->SetMethodOffset(methodOffset);
517             functionType->SetIsMethodOffsetVaild(true);
518             bool isVaild;
519             kungfu::FastCallInfo info = bcInfo_->IterateMethodOffsetToFastCallInfo(methodOffset, &isVaild);
520             functionType->SetIsFastCallVaild(isVaild);
521             functionType->SetIsFastCall(info.canFastCall_);
522             functionType->SetIsNoGC(info.isNoGC_);
523         } else {
524             functionType->SetIsMethodOffsetVaild(false);
525             functionType->SetIsFastCallVaild(false);
526         }
527     }
528 }
529 
GenerateExportTableFromRecord(const JSPandaFile * jsPandaFile,const CString & recordName,const JSHandle<TSTypeTable> & table)530 JSHandle<JSTaggedValue> TSTypeParser::GenerateExportTableFromRecord(const JSPandaFile *jsPandaFile,
531                                                                     const CString &recordName,
532                                                                     const JSHandle<TSTypeTable> &table)
533 {
534     JSHandle<JSTaggedValue> exportValeTable = TSTypeTable::GetExportValueTable(thread_, table);
535     if (exportValeTable->IsUndefined()) {
536         // Read export-data from annotation of the .abc File
537         JSHandle<TaggedArray> literalTable = tsManager_->GetExportTableFromLiteral(jsPandaFile, recordName);
538         ObjectFactory *factory = vm_->GetFactory();
539         uint32_t length = literalTable->GetLength();
540         JSHandle<TaggedArray> exportTable = factory->NewAndCopyTaggedArray(literalTable, length, length);
541         for (uint32_t i = 1; i < length; i += 2) {  // 2: skip a pair of key and value
542             JSTaggedValue target = exportTable->Get(i);
543             // Create GT based on typeId, and wrapped it into a JSTaggedValue
544             uint32_t typeId = static_cast<uint32_t>(target.GetInt());
545             GlobalTSTypeRef gt = CreateGT(jsPandaFile, recordName, typeId);
546             // Set the wrapped GT to exportTable
547             exportTable->Set(thread_, i, JSTaggedValue(gt.GetType()));
548         }
549         TSTypeTable::SetExportValueTable(thread_, table, exportTable);
550         return JSHandle<JSTaggedValue>(exportTable);
551     }
552     ASSERT(exportValeTable->IsTaggedArray());
553     return exportValeTable;
554 }
555 
GenerateImportRelativePath(JSHandle<EcmaString> importRel) const556 JSHandle<EcmaString> TSTypeParser::GenerateImportRelativePath(JSHandle<EcmaString> importRel) const
557 {
558     // importNamePath #A#./A
559     CString importNamePath = ConvertToString(importRel.GetTaggedValue());
560     auto lastPos = importNamePath.find_last_of('#');
561     CString path = importNamePath.substr(lastPos + 1, importNamePath.size() - lastPos - 1);
562     return factory_->NewFromUtf8(path); // #A#./A -> ./A
563 }
564 
GenerateImportVar(JSHandle<EcmaString> import) const565 JSHandle<EcmaString> TSTypeParser::GenerateImportVar(JSHandle<EcmaString> import) const
566 {
567     // importNamePath #A#./A
568     CString importVarNamePath = ConvertToString(import.GetTaggedValue());
569     auto firstPos = importVarNamePath.find_first_of('#');
570     auto lastPos = importVarNamePath.find_last_of('#');
571     CString target = importVarNamePath.substr(firstPos + 1, lastPos - firstPos - 1);
572     return factory_->NewFromUtf8(target); // #A#./A -> A
573 }
574 
GetExportGTByName(JSHandle<EcmaString> target,JSHandle<TaggedArray> & exportTable,const JSPandaFile * jsPandaFile,const CString & recordName,std::unordered_set<CString> & markSet)575 GlobalTSTypeRef TSTypeParser::GetExportGTByName(JSHandle<EcmaString> target, JSHandle<TaggedArray> &exportTable,
576                                                 const JSPandaFile *jsPandaFile, const CString &recordName,
577                                                 std::unordered_set<CString> &markSet)
578 {
579     uint32_t length = exportTable->GetLength();
580     // the exportTable is arranged as follows ["A", "101", "B", "102"]
581     // get GT of a export type specified by its descriptor/name
582     for (uint32_t i = 0; i < length; i = i + 2) {  // 2: symbol and symbolType
583         EcmaString *valueString = EcmaString::Cast(exportTable->Get(i).GetTaggedObject());
584         if (EcmaStringAccessor::StringsAreEqual(*target, valueString)) {
585             // Transform raw data of JSTaggedValue to GT
586             return GlobalTSTypeRef(exportTable->Get(i + 1).GetInt());
587         }
588     }
589     // if we can't find the exportName in exportTable of this record, we will try to search in its starExportRecords.
590     return IterateStarExport(target, jsPandaFile, recordName, markSet);
591 }
592 
IterateStarExport(JSHandle<EcmaString> target,const JSPandaFile * jsPandaFile,const CString & recordName,std::unordered_set<CString> & markSet)593 GlobalTSTypeRef TSTypeParser::IterateStarExport(JSHandle<EcmaString> target, const JSPandaFile *jsPandaFile,
594                                                 const CString &recordName, std::unordered_set<CString> &markSet)
595 {
596     if (bcInfo_->HasStarExportToRecord(recordName)) {
597         const auto &starRecords = bcInfo_->GetstarExportToRecord(recordName);
598         markSet.insert(recordName);
599         JSMutableHandle<TaggedArray> starTable(thread_, JSTaggedValue::Undefined());
600         for (const auto &star : starRecords) {
601             // use markSet to avoid circular import
602             if (markSet.find(star) != markSet.end()) {
603                 continue;
604             }
605             uint32_t starModuleId = tableGenerator_.TryGetModuleId(star);
606             if (UNLIKELY(!GlobalTSTypeRef::IsValidModuleId(starModuleId))) {
607                 continue;
608             }
609             JSHandle<TSTypeTable> table = tableGenerator_.GetOrGenerateTSTypeTable(jsPandaFile, star, starModuleId);
610             starTable.Update(GenerateExportTableFromRecord(jsPandaFile, star, table));
611             // the target name will be the same under retransmission.
612             auto gt = GetExportGTByName(target, starTable, jsPandaFile, star, markSet);
613             if (!gt.IsDefault()) {
614                 return gt;
615             }
616         }
617     }
618     return GlobalTSTypeRef::Default();
619 }
620 
ParseGenericsType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)621 GlobalTSTypeRef TSTypeParser::ParseGenericsType(const JSPandaFile *jsPandaFile, const CString &recordName,
622                                                 TypeLiteralExtractor *typeLiteralExtractor)
623 {
624     uint32_t typeId = typeLiteralExtractor->GetTypeOffset();
625     JSHandle<JSTaggedValue> type = ParseNonImportType(jsPandaFile, recordName, typeLiteralExtractor);
626     if (UNLIKELY(type->IsUndefined())) {
627         return GetAndStoreGT(jsPandaFile, typeId, recordName);
628     }
629     auto gt = tsManager_->AddTSTypeToGenericsTable(JSHandle<TSType>(type));
630     return GetAndStoreGT(jsPandaFile, typeId, recordName, gt.GetModuleId(), gt.GetLocalId());
631 }
632 
ParseGenericsInstanceType(const JSPandaFile * jsPandaFile,const CString & recordName,TypeLiteralExtractor * typeLiteralExtractor)633 JSHandle<JSTaggedValue> TSTypeParser::ParseGenericsInstanceType(const JSPandaFile *jsPandaFile,
634                                                                 const CString &recordName,
635                                                                 TypeLiteralExtractor *typeLiteralExtractor)
636 {
637     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::BUILTIN_INSTANCE ||
638            typeLiteralExtractor->GetTypeKind() == TSTypeKind::GENERIC_INSTANCE);
639     GlobalTSTypeRef genericsGT = CreateGT(jsPandaFile, recordName, typeLiteralExtractor->GetIntValue(DEFAULT_INDEX));
640     JSHandle<JSTaggedValue> genericsType = tsManager_->GetTSType(genericsGT);
641     std::vector<GlobalTSTypeRef> paras {};
642     typeLiteralExtractor->EnumerateElements(NUM_GENERICS_PARA_INDEX,
643         [this, &jsPandaFile, &recordName, &paras](const uint32_t literalValue) {
644             auto gt = CreateGT(jsPandaFile, recordName, literalValue);
645             paras.emplace_back(gt);
646         });
647     return InstantiateGenericsType(genericsType, paras);
648 }
649 
InstantiateGenericsType(const JSHandle<JSTaggedValue> & genericsType,const std::vector<GlobalTSTypeRef> & paras)650 JSHandle<JSTaggedValue> TSTypeParser::InstantiateGenericsType(const JSHandle<JSTaggedValue> &genericsType,
651                                                               const std::vector<GlobalTSTypeRef> &paras)
652 {
653     if (genericsType->IsTSClassType()) {
654         JSHandle<TSClassType> classType = InstantiateClassGenericsType(JSHandle<TSClassType>(genericsType), paras);
655         return JSHandle<JSTaggedValue>(classType);
656     } else if (genericsType->IsTSFunctionType()) {
657         JSHandle<TSFunctionType> funcType = InstantiateFuncGenericsType(JSHandle<TSFunctionType>(genericsType), paras);
658         return JSHandle<JSTaggedValue>(funcType);
659     } else if (genericsType->IsTSInterfaceType()) {
660         JSHandle<TSInterfaceType> interfaceType =
661             InstantiateInterfaceGenericsType(JSHandle<TSInterfaceType>(genericsType), paras);
662         return JSHandle<JSTaggedValue>(interfaceType);
663     } else if (genericsType->IsTSObjectType()) {
664         JSHandle<TSObjectType> objectType = InstantiateObjGenericsType(JSHandle<TSObjectType>(genericsType), paras);
665         return JSHandle<JSTaggedValue>(objectType);
666     }
667     LOG_COMPILER(DEBUG) << "Unsupport GenericsType Instantiate: "
668                         << static_cast<uint32_t>(genericsType->GetTaggedObject()->GetClass()->GetObjectType());
669     return genericsType;
670 }
671 
InstantiateFuncGenericsType(const JSHandle<TSFunctionType> & genericsType,const std::vector<GlobalTSTypeRef> & paras)672 JSHandle<TSFunctionType> TSTypeParser::InstantiateFuncGenericsType(const JSHandle<TSFunctionType> &genericsType,
673                                                                    const std::vector<GlobalTSTypeRef> &paras)
674 {
675     uint32_t length = genericsType->GetLength();
676     JSHandle<TSFunctionType> functionType = factory_->NewTSFunctionType(length);
677     functionType->SetBitField(genericsType->GetBitField());
678     functionType->SetName(thread_, genericsType->GetName());
679     GlobalTSTypeRef thisGT = genericsType->GetThisGT();
680     functionType->SetThisGT(TryReplaceTypePara(thisGT, paras));
681     GlobalTSTypeRef returnGT = genericsType->GetReturnGT();
682     functionType->SetReturnGT(TryReplaceTypePara(returnGT, paras));
683 
684     JSHandle<TaggedArray> argumentTypes(thread_, functionType->GetParameterTypes());
685     JSHandle<TaggedArray> parameterTypes(thread_, genericsType->GetParameterTypes());
686     for (uint32_t i = 0; i < length; ++i) {
687         GlobalTSTypeRef parameterGT(parameterTypes->Get(thread_, i).GetInt());
688         GlobalTSTypeRef argumentGT = TryReplaceTypePara(parameterGT, paras);
689         JSTaggedValue parameter(argumentGT.GetType());
690         argumentTypes->Set(thread_, i, parameter);
691     }
692     functionType->SetParameterTypes(thread_, argumentTypes);
693     return functionType;
694 }
695 
InstantiateClassGenericsType(const JSHandle<TSClassType> & genericsType,const std::vector<GlobalTSTypeRef> & paras)696 JSHandle<TSClassType> TSTypeParser::InstantiateClassGenericsType(const JSHandle<TSClassType> &genericsType,
697                                                                  const std::vector<GlobalTSTypeRef> &paras)
698 {
699     JSHandle<TSClassType> classType = factory_->NewTSClassType();
700     CopyClassName(genericsType, classType);
701     classType->SetExtensionGT(genericsType->GetExtensionGT());
702     classType->SetHasLinked(genericsType->GetHasLinked());
703 
704     JSHandle<TSObjectType> oldInstanceType(thread_, genericsType->GetInstanceType());
705     JSHandle<TSObjectType> newInstanceType = InstantiateObjGenericsType(oldInstanceType, paras);
706     classType->SetInstanceType(thread_, newInstanceType);
707 
708     JSHandle<TSObjectType> oldPrototypeType(thread_, genericsType->GetPrototypeType());
709     JSHandle<TSObjectType> newPrototypeType = InstantiateObjGenericsType(oldPrototypeType, paras);
710     classType->SetPrototypeType(thread_, newPrototypeType);
711 
712     JSHandle<TSObjectType> oldConstructorType(thread_, genericsType->GetConstructorType());
713     JSHandle<TSObjectType> newConstructorType = InstantiateObjGenericsType(oldConstructorType, paras);
714     classType->SetConstructorType(thread_, newConstructorType);
715     return classType;
716 }
717 
CopyClassName(const JSHandle<TSClassType> & genericsType,const JSHandle<TSClassType> & classType)718 void TSTypeParser::CopyClassName(const JSHandle<TSClassType> &genericsType, const JSHandle<TSClassType> &classType)
719 {
720     auto gt = genericsType->GetGT();
721     if (gt.IsBuiltinModule()) {
722         const std::string name = tsManager_->GetBuiltinsName(gt);
723         JSHandle<EcmaString> ecmaStr = factory_->NewFromStdString(name);
724         classType->SetName(thread_, ecmaStr);
725     } else {
726         classType->SetName(thread_, genericsType->GetName());
727     }
728 }
729 
InstantiateInterfaceGenericsType(const JSHandle<TSInterfaceType> & genericsType,const std::vector<GlobalTSTypeRef> & paras)730 JSHandle<TSInterfaceType> TSTypeParser::InstantiateInterfaceGenericsType(const JSHandle<TSInterfaceType> &genericsType,
731                                                                          const std::vector<GlobalTSTypeRef> &paras)
732 {
733     JSHandle<TSInterfaceType> interfaceType = factory_->NewTSInterfaceType();
734     JSHandle<TaggedArray> oldExtends(thread_, genericsType->GetExtends());
735     uint32_t numExtends = oldExtends->GetLength();
736     JSHandle<TaggedArray> extends = factory_->NewTaggedArray(numExtends);
737     for (uint32_t i = 0; i < numExtends; ++i) {
738         GlobalTSTypeRef parameterGT(oldExtends->Get(thread_, i).GetInt());
739         JSTaggedValue parameter(TryReplaceTypePara(parameterGT, paras).GetType());
740         extends->Set(thread_, i, parameter);
741     }
742 
743     JSHandle<TSObjectType> fields(thread_, genericsType->GetFields());
744     JSHandle<TSObjectType> newFields = InstantiateObjGenericsType(fields, paras);
745     interfaceType->SetFields(thread_, newFields);
746     return interfaceType;
747 }
748 
InstantiateObjGenericsType(const JSHandle<TSObjectType> & oldObjType,const std::vector<GlobalTSTypeRef> & paras)749 JSHandle<TSObjectType> TSTypeParser::InstantiateObjGenericsType(const JSHandle<TSObjectType> &oldObjType,
750                                                                 const std::vector<GlobalTSTypeRef> &paras)
751 {
752     JSHandle<TSObjLayoutInfo> oldLayout(thread_, oldObjType->GetObjLayoutInfo());
753     uint32_t numOfProps = static_cast<uint32_t>(oldLayout->GetNumOfProperties());
754 
755     JSHandle<TSObjectType> newObjType = factory_->NewTSObjectType(numOfProps);
756     JSHandle<TSObjLayoutInfo> newLayout(thread_, newObjType->GetObjLayoutInfo());
757     ASSERT(newLayout->GetPropertiesCapacity() == numOfProps);
758     for (uint32_t i = 0; i < numOfProps; ++i) {
759         GlobalTSTypeRef parameterGT(oldLayout->GetTypeId(i).GetInt());
760         JSTaggedValue parameter(TryReplaceTypePara(parameterGT, paras).GetType());
761         newLayout->AddProperty(thread_, oldLayout->GetKey(i), parameter);
762     }
763     return newObjType;
764 }
765 
TryReplaceTypePara(GlobalTSTypeRef gt,const std::vector<GlobalTSTypeRef> & paras)766 GlobalTSTypeRef TSTypeParser::TryReplaceTypePara(GlobalTSTypeRef gt, const std::vector<GlobalTSTypeRef> &paras)
767 {
768     // replace fields with types of templated
769     if (IsGenericsParaType(gt)) {
770         uint32_t paraTypeIndex = DecodePrarIndex(gt);
771         if (paraTypeIndex < paras.size()) {
772             return paras[paraTypeIndex];
773         }
774         return GlobalTSTypeRef::Default();
775     }
776 
777     // replace methods with signature that contains template type parameters
778     if (tsManager_->IsFunctionTypeKind(gt)) {
779         JSHandle<JSTaggedValue> tsType = tsManager_->GetTSType(gt);
780         ASSERT(tsType->IsTSFunctionType());
781         JSHandle<TSFunctionType> funcTSType(tsType);
782         JSHandle<TSFunctionType> funcInst = InstantiateFuncGenericsType(funcTSType, paras);
783         return tsManager_->AddTSTypeToInferredTable(JSHandle<TSType>(funcInst));
784     }
785     return gt;
786 }
787 
CreatePGOGT(PGOInfo info)788 GlobalTSTypeRef TSTypeParser::CreatePGOGT(PGOInfo info)
789 {
790     GlobalTypeID gId(info.jsPandaFile, info.pgoType);
791     if (tsManager_->HasCreatedGT(gId)) {
792         return tsManager_->GetGTByGlobalTypeID(gId);
793     }
794     return ParsePGOType(info);
795 }
796 
ParsePGOType(PGOInfo & info)797 GlobalTSTypeRef TSTypeParser::ParsePGOType(PGOInfo &info)
798 {
799     uint32_t moduleId = tableGenerator_.TryGetModuleId(info.recordName);
800     if (UNLIKELY(!GlobalTSTypeRef::IsValidModuleId(moduleId))) {
801         LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the record "
802                             << info.recordName << " will not be parsed and will be treated as any.";
803         return GetAndStoreGT(info.jsPandaFile, info.pgoType);
804     }
805 
806     JSHandle<TSTypeTable> table = tableGenerator_.GetOrGenerateTSTypeTable(info.jsPandaFile, info.recordName,
807                                                                            moduleId);
808     uint32_t localId = tableGenerator_.TryGetLocalId(table);
809     if (UNLIKELY(!GlobalTSTypeRef::IsValidLocalId(localId))) {
810         LOG_COMPILER(DEBUG) << "The maximum number of TSTypes in TSTypeTable " << moduleId << " is reached. "
811                             << "The objLiteral with constantpool index " << info.cpIdx << " in the record "
812                             << info.recordName << " will not be parsed and will be treated as any.";
813         return GetAndStoreGT(info.jsPandaFile, info.pgoType);
814     }
815 
816     table->SetNumberOfTypes(thread_, localId);
817     GlobalTSTypeRef gt = GetAndStoreGT(info.jsPandaFile, info.pgoType, moduleId, localId);
818     JSHandle<JSTaggedValue> parseType = ParseNonImportPGOType(gt, info);
819     if (UNLIKELY(parseType->IsUndefined())) {
820         return GetAndStoreGT(info.jsPandaFile, info.pgoType);
821     }
822     SetTSType(table, parseType, gt);
823     return gt;
824 }
825 
ParseNonImportPGOType(GlobalTSTypeRef gt,PGOInfo & info)826 JSHandle<JSTaggedValue> TSTypeParser::ParseNonImportPGOType(GlobalTSTypeRef gt, PGOInfo &info)
827 {
828     switch (info.type) {
829         case kungfu::PGOBCInfo::Type::OBJ_LITERAL: {
830             return ParseObjectPGOType(gt, info);
831         }
832         default:
833             LOG_COMPILER(DEBUG) << "Do not support parse extend types with kind " << static_cast<uint32_t>(info.type);
834             return thread_->GlobalConstants()->GetHandledUndefined();
835     }
836 }
837 
ParseObjectPGOType(GlobalTSTypeRef gt,PGOInfo & info)838 JSHandle<JSTaggedValue> TSTypeParser::ParseObjectPGOType(GlobalTSTypeRef gt, PGOInfo &info)
839 {
840     JSHandle<ConstantPool> constpoolHandle(tsManager_->GetConstantPool());
841     JSTaggedValue obj = ConstantPool::GetLiteralFromCache<ConstPoolType::OBJECT_LITERAL>(
842         thread_, constpoolHandle.GetTaggedValue(), info.cpIdx, info.recordName);
843     JSHandle<JSObject> objHandle(thread_, obj);
844 
845     if (info.enableOptTrackField) {
846         ASSERT(info.pgoType.IsClassType());
847         PGOHClassLayoutDesc *desc;
848         if (info.decoder->GetHClassLayoutDesc(info.pgoType, &desc)) {
849             if (!VerifyObjIhcPGOType(objHandle, *desc)) {
850                 LOG_COMPILER(DEBUG) << "Verify ihc type failed";
851                 return thread_->GlobalConstants()->GetHandledUndefined();
852             }
853         }
854     }
855 
856     JSHandle<JSHClass> oldHClass(thread_, objHandle->GetClass());
857     if (oldHClass->IsDictionaryMode()) {
858         return thread_->GlobalConstants()->GetHandledUndefined();
859     }
860     JSHandle<JSHClass> hclass = JSHClass::Clone(thread_, oldHClass);
861     ObjectFactory *factory = vm_->GetFactory();
862     JSHandle<LayoutInfo> newLayout = factory->CopyLayoutInfo(JSHandle<LayoutInfo>(thread_, hclass->GetLayout()));
863     hclass->SetLayout(thread_, newLayout);
864 
865     hclass->SetTS(true);
866     JSHandle<TSObjectType> objectType = factory_->NewTSObjectType(0);
867     tsManager_->AddInstanceTSHClass(gt, hclass);
868     return JSHandle<JSTaggedValue>(objectType);
869 }
870 
VerifyObjIhcPGOType(JSHandle<JSObject> obj,const PGOHClassLayoutDesc & desc)871 bool TSTypeParser::VerifyObjIhcPGOType(JSHandle<JSObject> obj, const PGOHClassLayoutDesc &desc)
872 {
873     auto hclass = obj->GetClass();
874     LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
875     int element = layoutInfo->NumberOfElements();
876     for (int i = 0; i < element; i++) {
877         auto key = layoutInfo->GetKey(i);
878         if (!key.IsString()) {
879             continue;
880         }
881 
882         auto attr = layoutInfo->GetAttr(i);
883         if (!attr.IsInlinedProps()) {
884             continue;
885         }
886         JSTaggedValue value = obj->GetPropertyInlinedProps(i);
887 
888         auto keyString = EcmaStringAccessor(key).ToCString();
889         PGOHandler newHandler;
890         if (!desc.FindDescWithKey(keyString, newHandler)) {
891             continue;
892         }
893         PropertyAttributes newAttr;
894         if (!newHandler.SetAttribute(newAttr)) {
895             continue;
896         }
897         if (newAttr.IsDoubleRep()) {
898             if (!value.IsNumber()) {
899                 return false;
900             }
901         } else if (newAttr.IsIntRep()) {
902             if (!value.IsInt()) {
903                 return false;
904             }
905         }
906     }
907     return true;
908 }
909 
CalculateNextNumIndex(const TypeLiteralExtractor * typeLiteralExtractor,uint32_t startIndex=0,uint32_t gap=1)910 static uint32_t CalculateNextNumIndex(const TypeLiteralExtractor *typeLiteralExtractor,
911                                       uint32_t startIndex = 0,
912                                       uint32_t gap = 1)
913 {
914     return startIndex + INDEX_OCCUPIED_OFFSET + (typeLiteralExtractor->GetIntValue(startIndex) * gap);
915 }
916 
ClassLiteralInfo(const TypeLiteralExtractor * typeLiteralExtractor)917 ClassLiteralInfo::ClassLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor)
918 {
919     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS);
920     numNonStaticFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, NUM_IMPLEMENTS_INDEX);
921     numNonStaticMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numNonStaticFieldsIndex, FIELD_LENGTH);
922     numStaticFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, numNonStaticMethodsIndex, METHOD_LENGTH);
923     numStaticMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numStaticFieldsIndex, FIELD_LENGTH);
924 }
925 
InterfaceLiteralInfo(const TypeLiteralExtractor * typeLiteralExtractor)926 InterfaceLiteralInfo::InterfaceLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor)
927 {
928     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INTERFACE);
929     numFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, NUM_EXTENDS_INDEX);
930     numMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numFieldsIndex, FIELD_LENGTH);
931 }
932 
FunctionLiteralInfo(const TypeLiteralExtractor * typeLiteralExtractor)933 FunctionLiteralInfo::FunctionLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor)
934 {
935     ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::FUNCTION);
936     numParasIndex = HAS_THIS_TYPE_INDEX + INDEX_OCCUPIED_OFFSET +
937                     typeLiteralExtractor->GetIntValue(HAS_THIS_TYPE_INDEX);
938     returnTypeIndex = CalculateNextNumIndex(typeLiteralExtractor, numParasIndex);
939 }
940 }  // namespace panda::ecmascript
941