1 /*
2 * Copyright (c) 2021 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 #include "ecmascript/ts_types/ts_type.h"
16
17 #include "ecmascript/js_function.h"
18 #include "ecmascript/object_factory.h"
19
20 namespace panda::ecmascript {
GetOrCreateHClass(JSThread * thread,JSHandle<TSObjectType> objectType,TSObjectTypeKind kind)21 JSHClass *TSObjectType::GetOrCreateHClass(JSThread *thread, JSHandle<TSObjectType> objectType, TSObjectTypeKind kind)
22 {
23 JSTaggedValue mayBeHClass = objectType->GetHClass();
24 if (mayBeHClass.IsJSHClass()) {
25 return JSHClass::Cast(mayBeHClass.GetTaggedObject());
26 }
27 JSHandle<TSObjLayoutInfo> propTypeInfo(thread, objectType->GetObjLayoutInfo());
28 JSHClass *hclass = nullptr;
29
30 switch (kind) {
31 case TSObjectTypeKind::INSTANCE: {
32 hclass = objectType->CreateHClassByProps(thread, propTypeInfo);
33 break;
34 }
35 case TSObjectTypeKind::PROTOTYPE: {
36 hclass = objectType->CreatePrototypeHClassByProps(thread, propTypeInfo);
37 break;
38 }
39 default:
40 UNREACHABLE();
41 }
42
43 objectType->SetHClass(thread, JSTaggedValue(hclass));
44 return hclass;
45 }
46
CreateHClassByProps(JSThread * thread,JSHandle<TSObjLayoutInfo> propType) const47 JSHClass *TSObjectType::CreateHClassByProps(JSThread *thread, JSHandle<TSObjLayoutInfo> propType) const
48 {
49 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
50
51 uint32_t numOfProps = propType->GetNumOfProperties();
52 JSHandle<JSHClass> hclass;
53 if (LIKELY(numOfProps <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)) {
54 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
55 JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(numOfProps);
56 for (uint32_t index = 0; index < numOfProps; ++index) {
57 JSTaggedValue tsPropKey = propType->GetKey(index);
58 key.Update(tsPropKey);
59 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
60 PropertyAttributes attributes = PropertyAttributes::Default();
61 attributes.SetIsInlinedProps(true);
62 attributes.SetRepresentation(Representation::MIXED);
63 attributes.SetOffset(index);
64 layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
65 }
66 hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, numOfProps);
67 hclass->SetLayout(thread, layout);
68 hclass->SetNumberOfProps(numOfProps);
69 } else {
70 // dictionary mode
71 hclass = factory->NewEcmaHClass(JSFunction::SIZE, JSType::JS_OBJECT, 0); // without in-obj
72 hclass->SetIsDictionaryMode(true);
73 hclass->SetNumberOfProps(0);
74 }
75
76 hclass->SetTS(true);
77
78 return *hclass;
79 }
80
CreatePrototypeHClassByProps(JSThread * thread,JSHandle<TSObjLayoutInfo> propType) const81 JSHClass *TSObjectType::CreatePrototypeHClassByProps(JSThread *thread, JSHandle<TSObjLayoutInfo> propType) const
82 {
83 [[maybe_unused]] EcmaHandleScope scope(thread);
84
85 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
86 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
87
88 uint32_t numOfProps = propType->GetNumOfProperties();
89 JSHandle<JSHClass> hclass;
90 if (LIKELY(numOfProps <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)) {
91 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
92 JSHandle<JSTaggedValue> ctor = globalConst->GetHandledConstructorString();
93 CVector<std::pair<JSHandle<JSTaggedValue>, GlobalTSTypeRef>> sortedPrototype {{ctor, GlobalTSTypeRef()}};
94 CVector<std::pair<JSHandle<JSTaggedValue>, GlobalTSTypeRef>> signatureVec {};
95 for (uint32_t index = 0; index < numOfProps; ++index) {
96 JSHandle<JSTaggedValue> key(thread, propType->GetKey(index));
97 auto value = GlobalTSTypeRef(propType->GetTypeId(index).GetInt());
98 // Usually, abstract methods in abstract class have no specific implementation,
99 // and method signatures will be added after class scope.
100 // Strategy: ignore abstract method, and rearrange the order of method signature to be at the end.
101 bool isSame = JSTaggedValue::SameValue(key, ctor);
102 bool isAbs = tsManager->IsAbstractMethod(value);
103 if (!isSame && !isAbs) {
104 bool isSign = tsManager->IsMethodSignature(value);
105 if (LIKELY(!isSign)) {
106 sortedPrototype.emplace_back(std::make_pair(key, value));
107 } else {
108 signatureVec.emplace_back(std::make_pair(key, value));
109 }
110 }
111 }
112
113 if (!signatureVec.empty()) {
114 sortedPrototype.insert(sortedPrototype.end(), signatureVec.begin(), signatureVec.end());
115 }
116
117 uint32_t keysLen = sortedPrototype.size();
118 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
119 JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(keysLen);
120
121 for (uint32_t index = 0; index < keysLen; ++index) {
122 key.Update(sortedPrototype[index].first);
123 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
124 PropertyAttributes attributes = PropertyAttributes::Default(true, false, true);
125 if (tsManager->IsGetterSetterFunc(sortedPrototype[index].second)) {
126 attributes.SetIsAccessor(true);
127 }
128 attributes.SetIsInlinedProps(true);
129 attributes.SetRepresentation(Representation::MIXED);
130 attributes.SetOffset(index);
131 layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
132 }
133 hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, keysLen);
134 hclass->SetLayout(thread, layout);
135 hclass->SetNumberOfProps(keysLen);
136 } else {
137 // dictionary mode
138 hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, 0); // without in-obj
139 hclass->SetIsDictionaryMode(true);
140 hclass->SetNumberOfProps(0);
141 }
142
143 hclass->SetTS(true);
144 hclass->SetClassPrototype(true);
145 hclass->SetIsPrototype(true);
146
147 return *hclass;
148 }
149
IsEqual(JSHandle<TSUnionType> unionB)150 bool TSUnionType::IsEqual(JSHandle<TSUnionType> unionB)
151 {
152 DISALLOW_GARBAGE_COLLECTION;
153 ASSERT(unionB->GetComponents().IsTaggedArray());
154
155 TaggedArray *unionArrayA = TaggedArray::Cast(TSUnionType::GetComponents().GetTaggedObject());
156 TaggedArray *unionArrayB = TaggedArray::Cast(unionB->GetComponents().GetTaggedObject());
157 uint32_t unionALength = unionArrayA->GetLength();
158 uint32_t unionBLength = unionArrayB->GetLength();
159 if (unionALength != unionBLength) {
160 return false;
161 }
162 for (uint32_t unionAIndex = 0; unionAIndex < unionALength; unionAIndex++) {
163 int argUnionA = unionArrayA->Get(unionAIndex).GetNumber();
164 bool findArgTag = false;
165 for (uint32_t unionBIndex = 0; unionBIndex < unionBLength; unionBIndex++) {
166 int argUnionB = unionArrayB->Get(unionBIndex).GetNumber();
167 if (argUnionA == argUnionB) {
168 findArgTag = true;
169 break;
170 }
171 }
172 if (!findArgTag) {
173 return false;
174 }
175 }
176 return true;
177 }
178
GetPropTypeGT(JSThread * thread,JSHandle<TSClassType> classType,JSHandle<EcmaString> propName)179 GlobalTSTypeRef TSClassType::GetPropTypeGT(JSThread *thread, JSHandle<TSClassType> classType,
180 JSHandle<EcmaString> propName)
181 {
182 DISALLOW_GARBAGE_COLLECTION;
183 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
184 JSMutableHandle<TSClassType> mutableClassType(thread, classType.GetTaggedValue());
185 JSMutableHandle<TSObjectType> mutableConstructorType(thread, mutableClassType->GetConstructorType());
186 GlobalTSTypeRef propTypeGT = GlobalTSTypeRef::Default();
187
188 while (propTypeGT.IsDefault()) { // not find
189 propTypeGT = TSObjectType::GetPropTypeGT(mutableConstructorType, propName);
190 GlobalTSTypeRef classTypeGT = mutableClassType->GetExtensionGT();
191 if (classTypeGT.IsDefault()) { // end of prototype chain
192 break;
193 }
194
195 JSTaggedValue tmpType = tsManager->GetTSType(classTypeGT).GetTaggedValue();
196 if (tmpType.IsUndefined()) {
197 return GlobalTSTypeRef::Default();
198 }
199 mutableClassType.Update(tmpType);
200 mutableConstructorType.Update(mutableClassType->GetConstructorType());
201 }
202 return propTypeGT;
203 }
204
GetSuperPropTypeGT(JSThread * thread,JSHandle<TSClassType> classType,JSHandle<EcmaString> propName,PropertyType propType)205 GlobalTSTypeRef TSClassType::GetSuperPropTypeGT(JSThread *thread, JSHandle<TSClassType> classType,
206 JSHandle<EcmaString> propName, PropertyType propType)
207 {
208 DISALLOW_GARBAGE_COLLECTION;
209 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
210 JSMutableHandle<TSClassType> mutableClassType(thread, classType.GetTaggedValue());
211 GlobalTSTypeRef propTypeGT = GlobalTSTypeRef::Default();
212 GlobalTSTypeRef notExistPropGt = kungfu::GateType::UndefinedType().GetGTRef();
213 GlobalTSTypeRef superClassTypeGT = mutableClassType->GetExtensionGT();
214 if (superClassTypeGT.IsDefault()) { // end of prototype chain
215 return notExistPropGt;
216 }
217 ASSERT(propType != PropertyType::OTHERS);
218 bool isStatic = propType == PropertyType::STATIC;
219 mutableClassType.Update(tsManager->GetTSType(superClassTypeGT).GetTaggedValue());
220 JSMutableHandle<TSObjectType> mutablePropTypes(thread, isStatic ?
221 mutableClassType->GetConstructorType() : mutableClassType->GetPrototypeType());
222 while (propTypeGT.IsDefault()) {
223 propTypeGT = TSObjectType::GetPropTypeGT(mutablePropTypes, propName);
224 GlobalTSTypeRef classTypeGT = mutableClassType->GetExtensionGT();
225 if (classTypeGT.IsDefault()) { // end of prototype chain
226 break;
227 }
228 JSTaggedValue tmpType = tsManager->GetTSType(classTypeGT).GetTaggedValue();
229 if (tmpType.IsUndefined()) { // this is for builtin.d.abc
230 return GlobalTSTypeRef::Default();
231 }
232 mutableClassType.Update(tmpType);
233 mutablePropTypes.Update(isStatic ?
234 mutableClassType->GetConstructorType() : mutableClassType->GetPrototypeType());
235 }
236 return propTypeGT.IsDefault() ? notExistPropGt : propTypeGT;
237 }
238
GetNonStaticPropTypeGT(JSThread * thread,JSHandle<TSClassType> classType,JSHandle<EcmaString> propName)239 GlobalTSTypeRef TSClassType::GetNonStaticPropTypeGT(JSThread *thread, JSHandle<TSClassType> classType,
240 JSHandle<EcmaString> propName)
241 {
242 DISALLOW_GARBAGE_COLLECTION;
243 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
244
245 JSHandle<TSObjectType> instanceType(thread, classType->GetInstanceType());
246
247 GlobalTSTypeRef propTypeGT = TSObjectType::GetPropTypeGT(instanceType, propName);
248 if (!propTypeGT.IsDefault()) {
249 return propTypeGT;
250 }
251
252 // search on prototype chain
253 JSMutableHandle<TSClassType> mutableClassType(thread, classType.GetTaggedValue());
254 JSMutableHandle<TSObjectType> mutablePrototypeType(thread, classType->GetPrototypeType());
255 while (propTypeGT.IsDefault()) { // not find
256 propTypeGT = TSObjectType::GetPropTypeGT(mutablePrototypeType, propName);
257 GlobalTSTypeRef classTypeGT = mutableClassType->GetExtensionGT();
258 if (classTypeGT.IsDefault()) { // end of prototype chain
259 break;
260 }
261
262 JSTaggedValue tmpType = tsManager->GetTSType(classTypeGT).GetTaggedValue();
263 if (tmpType.IsUndefined()) {
264 return GlobalTSTypeRef::Default();
265 }
266 mutableClassType.Update(tmpType);
267 mutablePrototypeType.Update(mutableClassType->GetPrototypeType());
268 }
269 return propTypeGT;
270 }
271
GetPropTypeGT(JSThread * thread,JSHandle<TSClassInstanceType> classInstanceType,JSHandle<EcmaString> propName)272 GlobalTSTypeRef TSClassInstanceType::GetPropTypeGT(JSThread *thread, JSHandle<TSClassInstanceType> classInstanceType,
273 JSHandle<EcmaString> propName)
274 {
275 DISALLOW_GARBAGE_COLLECTION;
276 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
277 GlobalTSTypeRef classTypeGT = classInstanceType->GetClassGT();
278 JSHandle<JSTaggedValue> type = tsManager->GetTSType(classTypeGT);
279
280 if (type->IsUndefined()) {
281 return GlobalTSTypeRef::Default();
282 }
283
284 ASSERT(type->IsTSClassType());
285 JSHandle<TSClassType> classType(type);
286 GlobalTSTypeRef propTypeGT = TSClassType::GetNonStaticPropTypeGT(thread, classType, propName);
287 return propTypeGT;
288 }
289
GetPropTypeGT(JSHandle<TSObjectType> objectType,JSHandle<EcmaString> propName)290 GlobalTSTypeRef TSObjectType::GetPropTypeGT(JSHandle<TSObjectType> objectType, JSHandle<EcmaString> propName)
291 {
292 DISALLOW_GARBAGE_COLLECTION;
293 TSObjLayoutInfo *layout = TSObjLayoutInfo::Cast(objectType->GetObjLayoutInfo().GetTaggedObject());
294 uint32_t numOfProps = layout->GetNumOfProperties();
295 for (uint32_t i = 0; i < numOfProps; ++i) {
296 EcmaString* propKey = EcmaString::Cast(layout->GetKey(i).GetTaggedObject());
297 if (!EcmaStringAccessor::StringsAreEqual(propKey, *propName)) {
298 continue;
299 }
300
301 uint32_t gtRawData = static_cast<uint32_t>(layout->GetTypeId(i).GetInt());
302 return GlobalTSTypeRef(gtRawData);
303 }
304
305 return GlobalTSTypeRef::Default();
306 }
307
GetParameterTypeGT(int index) const308 GlobalTSTypeRef TSFunctionType::GetParameterTypeGT(int index) const
309 {
310 DISALLOW_GARBAGE_COLLECTION;
311 TaggedArray* functionParametersArray = TaggedArray::Cast(GetParameterTypes().GetTaggedObject());
312 JSTaggedValue parameterType = functionParametersArray->Get(index);
313 ASSERT(parameterType.IsInt());
314 uint32_t parameterGTRawData = parameterType.GetInt();
315 return GlobalTSTypeRef(parameterGTRawData);
316 }
317
GetPropTypeGT(JSThread * thread,JSHandle<TSIteratorInstanceType> iteratorInstanceType,JSHandle<EcmaString> propName)318 GlobalTSTypeRef TSIteratorInstanceType::GetPropTypeGT(JSThread *thread,
319 JSHandle<TSIteratorInstanceType> iteratorInstanceType, JSHandle<EcmaString> propName)
320 {
321 DISALLOW_GARBAGE_COLLECTION;
322 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
323 GlobalTSTypeRef kindGt = iteratorInstanceType->GetKindGT();
324 GlobalTSTypeRef elementGt = iteratorInstanceType->GetElementGT();
325
326 JSHandle<JSTaggedValue> tsType = tsManager->GetTSType(kindGt);
327 JSHandle<TSObjectType> objType(tsType);
328 GlobalTSTypeRef propGt = TSObjectType::GetPropTypeGT(objType, propName);
329 if (tsManager->IsTSIterator(kindGt)) {
330 GlobalTSTypeRef iteratorFunctionInstance =
331 tsManager->GetOrCreateTSIteratorInstanceType(static_cast<TSRuntimeType>(propGt.GetLocalId()), elementGt);
332 return iteratorFunctionInstance;
333 }
334
335 if (tsManager->IsTSIteratorResult(kindGt)) {
336 if (propGt.IsDefault()) {
337 #ifndef NDEBUG
338 JSHandle<JSTaggedValue> valueString = thread->GlobalConstants()->GetHandledValueString();
339 ASSERT(EcmaStringAccessor::StringsAreEqual(*propName, EcmaString::Cast(
340 valueString.GetTaggedValue().GetTaggedObject())));
341 #endif
342 propGt = elementGt;
343 }
344 return propGt;
345 }
346 return GlobalTSTypeRef::Default();
347 }
348
GetPropTypeGT(JSThread * thread,JSHandle<TSInterfaceType> interfaceType,JSHandle<EcmaString> propName)349 GlobalTSTypeRef TSInterfaceType::GetPropTypeGT(JSThread *thread, JSHandle<TSInterfaceType> interfaceType,
350 JSHandle<EcmaString> propName)
351 {
352 DISALLOW_GARBAGE_COLLECTION;
353 TSManager *tsManager = thread->GetEcmaVM()->GetTSManager();
354
355 JSMutableHandle<TSInterfaceType> mutableInterfaceType(thread, interfaceType.GetTaggedValue());
356 JSMutableHandle<TSObjectType> mutableFieldsType(thread, mutableInterfaceType->GetFields());
357 GlobalTSTypeRef propTypeGT = GlobalTSTypeRef::Default();
358 propTypeGT = TSObjectType::GetPropTypeGT(mutableFieldsType, propName);
359
360 TaggedArray* extendsArray = TaggedArray::Cast(mutableInterfaceType->GetExtends().GetTaggedObject());
361 uint32_t extendsLength = extendsArray->GetLength();
362
363 for (uint32_t index = 0; index < extendsLength; index++) {
364 if (!propTypeGT.IsDefault()) {
365 return propTypeGT;
366 }
367
368 JSTaggedValue extendsValue = extendsArray->Get(index);
369 ASSERT(extendsValue.IsInt());
370 uint32_t gtRawData = static_cast<uint32_t>(extendsValue.GetInt());
371 GlobalTSTypeRef extendsGT = GlobalTSTypeRef(gtRawData);
372 JSHandle<JSTaggedValue> extendsType = tsManager->GetTSType(extendsGT);
373 if (extendsType->IsUndefined()) {
374 return GlobalTSTypeRef::Default();
375 }
376 ASSERT(extendsType->IsTSType());
377
378 if (extendsType->IsTSClassType()) {
379 JSHandle<TSClassType> innerClassType(extendsType);
380 propTypeGT = TSClassType::GetNonStaticPropTypeGT(thread, innerClassType, propName);
381 } else if (extendsType->IsTSInterfaceType()) {
382 JSHandle<TSInterfaceType> extendsInterfaceType(extendsType);
383 propTypeGT = TSInterfaceType::GetPropTypeGT(thread, extendsInterfaceType, propName);
384 }
385 }
386
387 return propTypeGT;
388 }
389 } // namespace panda::ecmascript
390