1 /*
2 * Copyright (c) 2021-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/jspandafile/class_info_extractor.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/js_function.h"
19 #include "ecmascript/jspandafile/program_object.h"
20 #include "ecmascript/jspandafile/method_literal.h"
21 #include "ecmascript/tagged_dictionary.h"
22
23 namespace panda::ecmascript {
BuildClassInfoExtractorFromLiteral(JSThread * thread,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<TaggedArray> & literal)24 void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor,
25 const JSHandle<TaggedArray> &literal)
26 {
27 [[maybe_unused]] EcmaHandleScope handleScope(thread);
28 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
29 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
30
31 uint32_t literalBufferLength = literal->GetLength();
32 // non static properties number is hidden in the last index of Literal buffer
33 uint32_t nonStaticNum = 0;
34 if (literalBufferLength != 0) {
35 nonStaticNum = static_cast<uint32_t>(literal->Get(thread, literalBufferLength - 1).GetInt());
36 }
37
38 // Reserve sufficient length to prevent frequent creation.
39 JSHandle<TaggedArray> nonStaticKeys = factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
40 JSHandle<TaggedArray> nonStaticProperties =
41 factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
42
43 nonStaticKeys->Set(thread, CONSTRUCTOR_INDEX, globalConst->GetConstructorString());
44 Method *method = Method::Cast(extractor->GetConstructorMethod().GetTaggedObject());
45 MethodLiteral *methodLiteral = method->GetMethodLiteral();
46 const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
47 EntityId methodId = method->GetMethodId();
48 if (nonStaticNum) {
49 ExtractContentsDetail nonStaticDetail {0, nonStaticNum * 2, NON_STATIC_RESERVED_LENGTH, nullptr};
50
51 JSHandle<TaggedArray> nonStaticElements = factory->EmptyArray();
52 if (UNLIKELY(ExtractAndReturnWhetherWithElements(thread, literal, nonStaticDetail, nonStaticKeys,
53 nonStaticProperties, nonStaticElements, jsPandaFile))) {
54 extractor->SetNonStaticWithElements(true);
55 extractor->SetNonStaticElements(thread, nonStaticElements);
56 }
57 }
58
59 extractor->SetNonStaticKeys(thread, nonStaticKeys);
60 extractor->SetNonStaticProperties(thread, nonStaticProperties);
61
62 uint32_t staticNum = literalBufferLength == 0 ? 0 : (literalBufferLength - 1) / 2 - nonStaticNum;
63
64 // Reserve sufficient length to prevent frequent creation.
65 JSHandle<TaggedArray> staticKeys = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH);
66 JSHandle<TaggedArray> staticProperties = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH);
67
68 staticKeys->Set(thread, LENGTH_INDEX, globalConst->GetLengthString());
69 staticKeys->Set(thread, NAME_INDEX, globalConst->GetNameString());
70 staticKeys->Set(thread, PROTOTYPE_INDEX, globalConst->GetPrototypeString());
71
72 JSHandle<TaggedArray> staticElements = factory->EmptyArray();
73
74 if (staticNum) {
75 ExtractContentsDetail staticDetail {
76 nonStaticNum * 2,
77 literalBufferLength - 1,
78 STATIC_RESERVED_LENGTH,
79 methodLiteral
80 };
81 if (UNLIKELY(ExtractAndReturnWhetherWithElements(thread, literal, staticDetail, staticKeys,
82 staticProperties, staticElements, jsPandaFile))) {
83 extractor->SetStaticWithElements(true);
84 extractor->SetStaticElements(thread, staticElements);
85 }
86 } else {
87 // without static properties, set class name
88 std::string clsName = methodLiteral->ParseFunctionName(jsPandaFile, methodId);
89 JSHandle<EcmaString> clsNameHandle = factory->NewFromStdString(clsName);
90 staticProperties->Set(thread, NAME_INDEX, clsNameHandle);
91 }
92
93 // set prototype internal accessor
94 JSHandle<JSTaggedValue> prototypeAccessor = globalConst->GetHandledFunctionPrototypeAccessor();
95 staticProperties->Set(thread, PROTOTYPE_INDEX, prototypeAccessor);
96
97 extractor->SetStaticKeys(thread, staticKeys);
98 extractor->SetStaticProperties(thread, staticProperties);
99 }
100
ExtractAndReturnWhetherWithElements(JSThread * thread,const JSHandle<TaggedArray> & literal,const ExtractContentsDetail & detail,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties,JSHandle<TaggedArray> & elements,const JSPandaFile * jsPandaFile)101 bool ClassInfoExtractor::ExtractAndReturnWhetherWithElements(JSThread *thread, const JSHandle<TaggedArray> &literal,
102 const ExtractContentsDetail &detail,
103 JSHandle<TaggedArray> &keys,
104 JSHandle<TaggedArray> &properties,
105 JSHandle<TaggedArray> &elements,
106 const JSPandaFile *jsPandaFile)
107 {
108 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
109
110 ASSERT(keys->GetLength() == properties->GetLength() && elements->GetLength() == 0);
111
112 uint32_t pos = detail.fillStartLoc;
113 bool withElementsFlag = false;
114 bool isStaticFlag = detail.methodLiteral ? true : false;
115 bool keysHasNameFlag = false;
116
117 JSHandle<JSTaggedValue> nameString = globalConst->GetHandledNameString();
118 JSMutableHandle<JSTaggedValue> firstValue(thread, JSTaggedValue::Undefined());
119 JSMutableHandle<JSTaggedValue> secondValue(thread, JSTaggedValue::Undefined());
120 for (uint32_t index = detail.extractBegin; index < detail.extractEnd; index += 2) { // 2: key-value pair
121 firstValue.Update(literal->Get(index));
122 secondValue.Update(literal->Get(index + 1));
123 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(firstValue), "Key is not a property key");
124
125 if (LIKELY(firstValue->IsString())) {
126 if (isStaticFlag && !keysHasNameFlag && JSTaggedValue::SameValue(firstValue, nameString)) {
127 properties->Set(thread, NAME_INDEX, secondValue);
128 keysHasNameFlag = true;
129 continue;
130 }
131
132 // front-end can do better: write index in class literal directly.
133 uint32_t elementIndex = 0;
134 if (JSTaggedValue::StringToElementIndex(firstValue.GetTaggedValue(), &elementIndex)) {
135 ASSERT(elementIndex < JSObject::MAX_ELEMENT_INDEX);
136 uint32_t elementsLength = elements->GetLength();
137 elements =
138 TaggedArray::SetCapacityInOldSpace(thread, elements, elementsLength + 2); // 2: key-value pair
139 elements->Set(thread, elementsLength, firstValue);
140 elements->Set(thread, elementsLength + 1, secondValue);
141 withElementsFlag = true;
142 continue;
143 }
144 }
145
146 keys->Set(thread, pos, firstValue);
147 properties->Set(thread, pos, secondValue);
148 pos++;
149 }
150
151 if (isStaticFlag) {
152 if (LIKELY(!keysHasNameFlag)) {
153 [[maybe_unused]] EcmaHandleScope handleScope(thread);
154 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
155 EntityId methodId = detail.methodLiteral->GetMethodId();
156 std::string clsName = detail.methodLiteral->ParseFunctionName(jsPandaFile, methodId);
157 JSHandle<EcmaString> clsNameHandle = factory->NewFromStdString(clsName);
158 properties->Set(thread, NAME_INDEX, clsNameHandle);
159 } else {
160 // class has static name property, reserved length bigger 1 than actual, need trim
161 uint32_t trimOneLength = keys->GetLength() - 1;
162 keys->Trim(thread, trimOneLength);
163 properties->Trim(thread, trimOneLength);
164 }
165 }
166
167 if (UNLIKELY(withElementsFlag)) {
168 ASSERT(pos + elements->GetLength() / 2 == properties->GetLength()); // 2: half
169 keys->Trim(thread, pos);
170 properties->Trim(thread, pos);
171 }
172
173 return withElementsFlag;
174 }
175
CreatePrototypeHClass(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties)176 JSHandle<JSHClass> ClassInfoExtractor::CreatePrototypeHClass(JSThread *thread, const JSHandle<JSTaggedValue> &base,
177 JSHandle<TaggedArray> &keys,
178 JSHandle<TaggedArray> &properties)
179 {
180 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
181
182 uint32_t length = keys->GetLength();
183 if (length == ClassInfoExtractor::NON_STATIC_RESERVED_LENGTH && base->IsHole()) {
184 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
185 return JSHandle<JSHClass>(globalConst->GetHandledClassPrototypeClass());
186 }
187 JSHandle<JSHClass> hclass;
188 if (LIKELY(length <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)) {
189 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
190 JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(length, MemSpaceType::OLD_SPACE, GrowMode::KEEP);
191 for (uint32_t index = 0; index < length; ++index) {
192 key.Update(keys->Get(index));
193 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
194 PropertyAttributes attributes = PropertyAttributes::Default(true, false, true); // non-enumerable
195
196 if (UNLIKELY(properties->Get(index).IsAccessor())) {
197 attributes.SetIsAccessor(true);
198 }
199
200 attributes.SetIsInlinedProps(true);
201 attributes.SetRepresentation(Representation::MIXED);
202 attributes.SetOffset(index);
203 layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
204 }
205
206 hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, length);
207 // Not need set proto here
208 hclass->SetLayout(thread, layout);
209 hclass->SetNumberOfProps(length);
210 } else {
211 // dictionary mode
212 hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, 0); // without in-obj
213 hclass->SetIsDictionaryMode(true);
214 hclass->SetNumberOfProps(0);
215 }
216
217 hclass->SetClassPrototype(true);
218 hclass->SetIsPrototype(true);
219 return hclass;
220 }
221
CreateConstructorHClass(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties)222 JSHandle<JSHClass> ClassInfoExtractor::CreateConstructorHClass(JSThread *thread, const JSHandle<JSTaggedValue> &base,
223 JSHandle<TaggedArray> &keys,
224 JSHandle<TaggedArray> &properties)
225 {
226 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
227
228 uint32_t length = keys->GetLength();
229 if (length == ClassInfoExtractor::STATIC_RESERVED_LENGTH && base->IsHole() &&
230 properties->Get(NAME_INDEX).IsString()) {
231 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
232 return JSHandle<JSHClass>(globalConst->GetHandledClassConstructorClass());
233 }
234 JSHandle<JSHClass> hclass;
235 if (LIKELY(length <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)) {
236 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
237 JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(length, MemSpaceType::OLD_SPACE, GrowMode::KEEP);
238 for (uint32_t index = 0; index < length; ++index) {
239 key.Update(keys->Get(index));
240 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
241 PropertyAttributes attributes;
242 switch (index) {
243 case LENGTH_INDEX:
244 attributes = PropertyAttributes::Default(false, false, true);
245 break;
246 case NAME_INDEX:
247 if (LIKELY(properties->Get(NAME_INDEX).IsString())) {
248 attributes = PropertyAttributes::Default(false, false, true);
249 } else {
250 ASSERT(properties->Get(NAME_INDEX).IsJSFunction());
251 attributes = PropertyAttributes::Default(true, false, true);
252 }
253 break;
254 case PROTOTYPE_INDEX:
255 attributes = PropertyAttributes::DefaultAccessor(false, false, false);
256 break;
257 default:
258 attributes = PropertyAttributes::Default(true, false, true);
259 break;
260 }
261
262 if (UNLIKELY(properties->Get(index).IsAccessor())) {
263 attributes.SetIsAccessor(true);
264 }
265
266 attributes.SetIsInlinedProps(true);
267 attributes.SetRepresentation(Representation::MIXED);
268 attributes.SetOffset(index);
269 layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
270 }
271
272 hclass = factory->NewEcmaHClass(JSFunction::SIZE, JSType::JS_FUNCTION, length);
273 // Not need set proto here
274 hclass->SetLayout(thread, layout);
275 hclass->SetNumberOfProps(length);
276 } else {
277 // dictionary mode
278 hclass = factory->NewEcmaHClass(JSFunction::SIZE, JSType::JS_FUNCTION, 0); // without in-obj
279 hclass->SetIsDictionaryMode(true);
280 hclass->SetNumberOfProps(0);
281 }
282
283 hclass->SetClassConstructor(true);
284 hclass->SetConstructor(true);
285
286 return hclass;
287 }
288
DefineClassFromExtractor(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<JSTaggedValue> & lexenv)289 JSHandle<JSFunction> ClassHelper::DefineClassFromExtractor(JSThread *thread, const JSHandle<JSTaggedValue> &base,
290 JSHandle<ClassInfoExtractor> &extractor,
291 const JSHandle<JSTaggedValue> &lexenv)
292 {
293 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
294 JSHandle<TaggedArray> staticKeys(thread, extractor->GetStaticKeys());
295 JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
296 JSHandle<JSHClass> constructorHClass = ClassInfoExtractor::CreateConstructorHClass(thread, base, staticKeys,
297 staticProperties);
298
299 JSHandle<TaggedArray> nonStaticKeys(thread, extractor->GetNonStaticKeys());
300 JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
301 JSHandle<JSHClass> prototypeHClass = ClassInfoExtractor::CreatePrototypeHClass(thread, base, nonStaticKeys,
302 nonStaticProperties);
303
304 JSHandle<JSObject> prototype = factory->NewOldSpaceJSObject(prototypeHClass);
305
306 JSHandle<Method> method(thread, Method::Cast(extractor->GetConstructorMethod().GetTaggedObject()));
307 JSHandle<JSFunction> constructor = factory->NewJSFunctionByHClass(method, constructorHClass);
308
309 // non-static
310 nonStaticProperties->Set(thread, 0, constructor);
311
312 uint32_t nonStaticLength = nonStaticProperties->GetLength();
313 JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
314
315 if (LIKELY(!prototypeHClass->IsDictionaryMode())) {
316 for (uint32_t index = 0; index < nonStaticLength; ++index) {
317 propValue.Update(nonStaticProperties->Get(index));
318 if (propValue->IsJSFunction()) {
319 JSHandle<JSFunction> propFunc = factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue));
320 propFunc->SetHomeObject(thread, prototype);
321 propFunc->SetLexicalEnv(thread, lexenv);
322 propValue.Update(propFunc);
323 }
324 prototype->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
325 }
326 } else {
327 JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, prototype, nonStaticKeys, nonStaticProperties,
328 ClassPropertyType::NON_STATIC, lexenv);
329 prototype->SetProperties(thread, dict);
330 }
331
332 // non-static elements
333 if (UNLIKELY(extractor->GetNonStaticWithElements())) {
334 JSHandle<TaggedArray> nonStaticElements(thread, extractor->GetNonStaticElements());
335 ClassHelper::HandleElementsProperties(thread, prototype, nonStaticElements);
336 }
337
338 // static
339 uint32_t staticLength = staticProperties->GetLength();
340
341 if (LIKELY(!constructorHClass->IsDictionaryMode())) {
342 for (uint32_t index = 0; index < staticLength; ++index) {
343 propValue.Update(staticProperties->Get(index));
344 if (propValue->IsJSFunction()) {
345 JSHandle<JSFunction> propFunc = factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue));
346 propFunc->SetHomeObject(thread, constructor);
347 propFunc->SetLexicalEnv(thread, lexenv);
348 propValue.Update(propFunc);
349 }
350 JSHandle<JSObject>::Cast(constructor)->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
351 }
352 } else {
353 JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, JSHandle<JSObject>(constructor), staticKeys,
354 staticProperties, ClassPropertyType::STATIC, lexenv);
355 constructor->SetProperties(thread, dict);
356 }
357
358 // static elements
359 if (UNLIKELY(extractor->GetStaticWithElements())) {
360 JSHandle<TaggedArray> staticElements(thread, extractor->GetStaticElements());
361 ClassHelper::HandleElementsProperties(thread, JSHandle<JSObject>(constructor), staticElements);
362 }
363
364 PropertyDescriptor ctorDesc(thread, JSHandle<JSTaggedValue>(constructor), true, false, true);
365 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
366 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(prototype),
367 globalConst->GetHandledConstructorString(), ctorDesc);
368
369 constructor->SetHomeObject(thread, prototype);
370 constructor->SetProtoOrHClass(thread, prototype);
371
372 return constructor;
373 }
374
DefineClassWithIHClass(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<JSTaggedValue> & lexenv,const JSHandle<JSHClass> & ihclass)375 JSHandle<JSFunction> ClassHelper::DefineClassWithIHClass(JSThread *thread, const JSHandle<JSTaggedValue> &base,
376 JSHandle<ClassInfoExtractor> &extractor,
377 const JSHandle<JSTaggedValue> &lexenv,
378 const JSHandle<JSHClass> &ihclass)
379 {
380 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
381 JSHandle<TaggedArray> staticKeys(thread, extractor->GetStaticKeys());
382 JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
383 JSHandle<JSHClass> constructorHClass = ClassInfoExtractor::CreateConstructorHClass(thread, base, staticKeys,
384 staticProperties);
385
386 JSHandle<TaggedArray> nonStaticKeys(thread, extractor->GetNonStaticKeys());
387 JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
388 JSHandle<JSObject> prototype(thread, ihclass->GetProto());
389
390 JSHandle<Method> method(thread, Method::Cast(extractor->GetConstructorMethod().GetTaggedObject()));
391 JSHandle<JSFunction> constructor = factory->NewJSFunctionByHClass(method, constructorHClass);
392
393 // non-static
394 nonStaticProperties->Set(thread, 0, constructor);
395
396 uint32_t nonStaticLength = nonStaticProperties->GetLength();
397 JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
398
399 if (LIKELY(!prototype->GetJSHClass()->IsDictionaryMode())) {
400 for (uint32_t index = 0; index < nonStaticLength; ++index) {
401 propValue.Update(nonStaticProperties->Get(index));
402 if (propValue->IsJSFunction()) {
403 JSHandle<JSFunction> propFunc = factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue));
404 propFunc->SetHomeObject(thread, prototype);
405 propFunc->SetLexicalEnv(thread, lexenv);
406 propValue.Update(propFunc);
407 }
408 prototype->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
409 }
410 } else {
411 JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, prototype, nonStaticKeys, nonStaticProperties,
412 ClassPropertyType::NON_STATIC, lexenv);
413 prototype->SetProperties(thread, dict);
414 }
415
416 // non-static elements
417 if (UNLIKELY(extractor->GetNonStaticWithElements())) {
418 JSHandle<TaggedArray> nonStaticElements(thread, extractor->GetNonStaticElements());
419 ClassHelper::HandleElementsProperties(thread, prototype, nonStaticElements);
420 }
421
422 // static
423 uint32_t staticLength = staticProperties->GetLength();
424
425 if (LIKELY(!constructorHClass->IsDictionaryMode())) {
426 for (uint32_t index = 0; index < staticLength; ++index) {
427 propValue.Update(staticProperties->Get(index));
428 if (propValue->IsJSFunction()) {
429 JSHandle<JSFunction> propFunc = factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue));
430 propFunc->SetHomeObject(thread, constructor);
431 propFunc->SetLexicalEnv(thread, lexenv);
432 propValue.Update(propFunc);
433 }
434 JSHandle<JSObject>::Cast(constructor)->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
435 }
436 } else {
437 JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, JSHandle<JSObject>(constructor), staticKeys,
438 staticProperties, ClassPropertyType::STATIC, lexenv);
439 constructor->SetProperties(thread, dict);
440 }
441
442 // static elements
443 if (UNLIKELY(extractor->GetStaticWithElements())) {
444 JSHandle<TaggedArray> staticElements(thread, extractor->GetStaticElements());
445 ClassHelper::HandleElementsProperties(thread, JSHandle<JSObject>(constructor), staticElements);
446 }
447
448 PropertyDescriptor ctorDesc(thread, JSHandle<JSTaggedValue>(constructor), true, false, true);
449 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
450 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(prototype),
451 globalConst->GetHandledConstructorString(), ctorDesc);
452
453 constructor->SetHomeObject(thread, prototype);
454 constructor->SetProtoOrHClass(thread, ihclass);
455
456 return constructor;
457 }
458
BuildDictionaryProperties(JSThread * thread,const JSHandle<JSObject> & object,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties,ClassPropertyType type,const JSHandle<JSTaggedValue> & lexenv)459 JSHandle<NameDictionary> ClassHelper::BuildDictionaryProperties(JSThread *thread, const JSHandle<JSObject> &object,
460 JSHandle<TaggedArray> &keys,
461 JSHandle<TaggedArray> &properties,
462 ClassPropertyType type,
463 const JSHandle<JSTaggedValue> &lexenv)
464 {
465 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
466 uint32_t length = keys->GetLength();
467 ASSERT(length > PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES);
468 ASSERT(keys->GetLength() == properties->GetLength());
469
470 JSMutableHandle<NameDictionary> dict(
471 thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(length)));
472 JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
473 JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
474 for (uint32_t index = 0; index < length; index++) {
475 PropertyAttributes attributes;
476 if (type == ClassPropertyType::STATIC) {
477 switch (index) {
478 case ClassInfoExtractor::LENGTH_INDEX:
479 attributes = PropertyAttributes::Default(false, false, true);
480 break;
481 case ClassInfoExtractor::NAME_INDEX:
482 if (LIKELY(properties->Get(ClassInfoExtractor::NAME_INDEX).IsString())) {
483 attributes = PropertyAttributes::Default(false, false, true);
484 } else {
485 ASSERT(properties->Get(ClassInfoExtractor::NAME_INDEX).IsJSFunction());
486 attributes = PropertyAttributes::Default(true, false, true);
487 }
488 break;
489 case ClassInfoExtractor::PROTOTYPE_INDEX:
490 attributes = PropertyAttributes::DefaultAccessor(false, false, false);
491 break;
492 default:
493 attributes = PropertyAttributes::Default(true, false, true);
494 break;
495 }
496 } else {
497 attributes = PropertyAttributes::Default(true, false, true); // non-enumerable
498 }
499 propKey.Update(keys->Get(index));
500 propValue.Update(properties->Get(index));
501 if (propValue->IsJSFunction()) {
502 JSHandle<JSFunction> propFunc = factory->CloneJSFuction(JSHandle<JSFunction>::Cast(propValue));
503 propFunc->SetHomeObject(thread, object);
504 propFunc->SetLexicalEnv(thread, lexenv);
505 propValue.Update(propFunc);
506 }
507 JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attributes);
508 dict.Update(newDict);
509 }
510 return dict;
511 }
512
HandleElementsProperties(JSThread * thread,const JSHandle<JSObject> & object,JSHandle<TaggedArray> & elements)513 void ClassHelper::HandleElementsProperties(JSThread *thread, const JSHandle<JSObject> &object,
514 JSHandle<TaggedArray> &elements)
515 {
516 JSMutableHandle<JSTaggedValue> elementsKey(thread, JSTaggedValue::Undefined());
517 JSMutableHandle<JSTaggedValue> elementsValue(thread, JSTaggedValue::Undefined());
518 for (uint32_t index = 0; index < elements->GetLength(); index += 2) { // 2: key-value pair
519 elementsKey.Update(elements->Get(index));
520 elementsValue.Update(elements->Get(index + 1));
521 // class property attribute is not default, will transition to dictionary directly.
522 JSObject::DefinePropertyByLiteral(thread, object, elementsKey, elementsValue, true);
523
524 if (elementsValue->IsJSFunction()) {
525 JSHandle<JSFunction> elementsFunc = JSHandle<JSFunction>::Cast(elementsValue);
526 elementsFunc->SetHomeObject(thread, object);
527 }
528 }
529 }
530 } // namespace panda::ecmascript
531