• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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