• 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/compiler/type_recorder.h"
17 
18 #include "ecmascript/jspandafile/literal_data_extractor.h"
19 #include "ecmascript/ts_types/ts_type_parser.h"
20 
21 #include "libpandafile/method_data_accessor-inl.h"
22 
23 namespace panda::ecmascript::kungfu {
TypeRecorder(const JSPandaFile * jsPandaFile,const MethodLiteral * methodLiteral,TSManager * tsManager,const CString & recordName)24 TypeRecorder::TypeRecorder(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral,
25                            TSManager *tsManager, const CString &recordName)
26     : argTypes_(methodLiteral->GetNumArgsWithCallField() + static_cast<size_t>(TypedArgIdx::NUM_OF_TYPED_ARGS),
27                 GateType::AnyType())
28 {
29     if (!jsPandaFile->HasTSTypes(recordName)) {
30         return;
31     }
32     LoadTypes(jsPandaFile, methodLiteral, tsManager, recordName);
33     tsManager->GenerateTSHClasses();
34 }
35 
LoadTypes(const JSPandaFile * jsPandaFile,const MethodLiteral * methodLiteral,TSManager * tsManager,const CString & recordName)36 void TypeRecorder::LoadTypes(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral,
37                              TSManager *tsManager, const CString &recordName)
38 {
39     JSThread *thread = tsManager->GetThread();
40     TSTypeParser typeParser(tsManager);
41     const panda_file::File *pf = jsPandaFile->GetPandaFile();
42     panda_file::File::EntityId fieldId = methodLiteral->GetMethodId();
43     panda_file::MethodDataAccessor mda(*pf, fieldId);
44     mda.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) {
45         panda_file::AnnotationDataAccessor ada(*pf, annotation_id);
46         auto *annotationName = reinterpret_cast<const char *>(pf->GetStringData(ada.GetClassId()).data);
47         ASSERT(annotationName != nullptr);
48         if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) {
49             return;
50         }
51         uint32_t length = ada.GetCount();
52         for (uint32_t i = 0; i < length; i++) {
53             panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
54             auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data);
55             ASSERT(elemName != nullptr);
56             if (::strcmp("_TypeOfInstruction", elemName) != 0) {
57                 continue;
58             }
59 
60             panda_file::ScalarValue sv = adae.GetScalarValue();
61             panda_file::File::EntityId literalOffset(sv.GetValue());
62             JSHandle<TaggedArray> typeOfInstruction =
63                 LiteralDataExtractor::GetTypeLiteral(thread, jsPandaFile, literalOffset);
64 
65             GlobalTSTypeRef thisGT = GlobalTSTypeRef::Default();
66             GlobalTSTypeRef funcGT = GlobalTSTypeRef::Default();
67             for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) {  // + 2 means bcOffset and typeId
68                 int32_t bcOffset = typeOfInstruction->Get(j).GetInt();
69                 uint32_t typeId =  static_cast<uint32_t>(typeOfInstruction->Get(j + 1).GetInt());
70                 GlobalTSTypeRef gt = typeParser.CreateGT(jsPandaFile, recordName, typeId);
71                 if (gt.IsDefault()) {
72                     continue;
73                 }
74 
75                 // The type of a function is recorded as (-1, funcTypeId). If the function is a member of a class,
76                 // the type of the class or its instance is is recorded as (-2, classTypeId). If it is a static
77                 // member, the type id refers to the type of the class; otherwise, it links to the type of the
78                 // instances of the class.
79                 if (bcOffset == METHOD_ANNOTATION_THIS_TYPE_OFFSET) {
80                     thisGT = gt;
81                     continue;
82                 }
83                 if (bcOffset == METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) {
84                     tsManager->SetFuncMethodOffset(gt, methodLiteral->GetMethodId().GetOffset());
85                     funcGT = gt;
86                     continue;
87                 }
88                 auto type = GateType(gt);
89                 bcOffsetGtMap_.emplace(bcOffset, type);
90             }
91             LoadArgTypes(tsManager, funcGT, thisGT);
92         }
93     });
94 }
95 
LoadArgTypes(const TSManager * tsManager,GlobalTSTypeRef funcGT,GlobalTSTypeRef thisGT)96 void TypeRecorder::LoadArgTypes(const TSManager *tsManager, GlobalTSTypeRef funcGT, GlobalTSTypeRef thisGT)
97 {
98     argTypes_[static_cast<size_t>(TypedArgIdx::FUNC)] = TryGetFuncType(funcGT);
99     argTypes_[static_cast<size_t>(TypedArgIdx::NEW_TARGET)] = TryGetNewTargetType(tsManager, thisGT);
100     argTypes_[static_cast<size_t>(TypedArgIdx::THIS_OBJECT)] = TryGetThisType(tsManager, funcGT, thisGT);
101 
102     if (funcGT.IsDefault()) {
103         return;
104     }
105     size_t extraParasNum = static_cast<size_t>(TypedArgIdx::NUM_OF_TYPED_ARGS);
106     uint32_t numExplicitArgs = tsManager->GetFunctionTypeLength(funcGT);
107     for (uint32_t explicitArgId = 0; explicitArgId < numExplicitArgs; explicitArgId++) {
108         argTypes_[extraParasNum++] = GateType(tsManager->GetFuncParameterTypeGT(funcGT, explicitArgId));
109     }
110 }
111 
TryGetThisType(const TSManager * tsManager,GlobalTSTypeRef funcGT,GlobalTSTypeRef thisGT) const112 GateType TypeRecorder::TryGetThisType(const TSManager *tsManager, GlobalTSTypeRef funcGT, GlobalTSTypeRef thisGT) const
113 {
114     // The parameter 'this' may be declared explicitly, e.g. foo(this: Person, num: number). In this case, the type
115     // of 'this' is recorded in the type of the function. And this type is preferred over the type derived from
116     // 'thisGT' if both are given.
117     if (!funcGT.IsDefault()) {
118         auto gt = tsManager->GetFuncThisGT(funcGT);
119         if (!gt.IsDefault()) {
120             return GateType(gt);
121         }
122     }
123     return GateType(thisGT);
124 }
125 
TryGetNewTargetType(const TSManager * tsManager,GlobalTSTypeRef thisGT) const126 GateType TypeRecorder::TryGetNewTargetType(const TSManager *tsManager, GlobalTSTypeRef thisGT) const
127 {
128     if (thisGT.IsDefault()) {
129         return GateType::AnyType();
130     }
131 
132     GateType thisType(thisGT);
133     if (tsManager->IsClassInstanceTypeKind(thisType)) {
134         return GateType(tsManager->GetClassType(thisGT));
135     } else {
136         return thisType;
137     }
138 }
139 
TryGetFuncType(GlobalTSTypeRef funcGT) const140 GateType TypeRecorder::TryGetFuncType(GlobalTSTypeRef funcGT) const
141 {
142     if (funcGT.IsDefault()) {
143         return GateType::AnyType();
144     }
145     return GateType(funcGT);
146 }
147 
GetType(const int32_t offset) const148 GateType TypeRecorder::GetType(const int32_t offset) const
149 {
150     if (bcOffsetGtMap_.find(offset) != bcOffsetGtMap_.end()) {
151         return bcOffsetGtMap_.at(offset);
152     }
153     return GateType::AnyType();
154 }
155 
GetArgType(const uint32_t argIndex) const156 GateType TypeRecorder::GetArgType(const uint32_t argIndex) const
157 {
158     ASSERT(argIndex < argTypes_.size());
159     return argTypes_[argIndex];
160 }
161 
UpdateType(const int32_t offset,const GateType & type) const162 GateType TypeRecorder::UpdateType(const int32_t offset, const GateType &type) const
163 {
164     auto tempType = GetType(offset);
165     if (!tempType.IsAnyType()) {
166         ASSERT(type.IsAnyType());
167         return tempType;
168     }
169     return type;
170 }
171 }  // namespace panda::ecmascript
172