• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 
18 #include "ecmascript/js_object-inl.h"
19 #include "ecmascript/jspandafile/program_object.h"
20 #include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
21 #include "ecmascript/shared_objects/js_shared_map.h"
22 #include "ecmascript/object_fast_operator-inl.h"
23 
24 namespace panda::ecmascript {
BuildClassInfoExtractorFromLiteral(JSThread * thread,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<TaggedArray> & literal,uint32_t length,ClassKind kind)25 void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor,
26                                                             const JSHandle<TaggedArray> &literal,
27                                                             uint32_t length,
28                                                             ClassKind kind)
29 {
30     [[maybe_unused]] EcmaHandleScope handleScope(thread);
31     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
32     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33 
34     ASSERT(length <= literal->GetLength());
35     // non static properties number is hidden in the last index of Literal buffer
36     uint32_t nonStaticNum = 0;
37     if (length != 0) {
38         nonStaticNum = static_cast<uint32_t>(literal->Get(thread, length - 1).GetInt());
39     }
40 
41     // Reserve sufficient length to prevent frequent creation.
42     JSHandle<TaggedArray> nonStaticKeys;
43     JSHandle<TaggedArray> nonStaticProperties;
44     if (kind == ClassKind::SENDABLE) {
45         nonStaticKeys = factory->NewSOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
46         nonStaticProperties =
47             factory->NewSOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
48     } else {
49         nonStaticKeys = factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
50         nonStaticProperties =
51             factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH);
52     }
53 
54     nonStaticKeys->Set(thread, CONSTRUCTOR_INDEX, globalConst->GetConstructorString());
55     Method *method = Method::Cast(extractor->GetConstructorMethod().GetTaggedObject());
56     MethodLiteral *methodLiteral = method->GetMethodLiteral();
57     const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
58     EntityId methodId = method->GetMethodId();
59     if (nonStaticNum) {
60         ExtractContentsDetail nonStaticDetail {0, nonStaticNum * 2, NON_STATIC_RESERVED_LENGTH, nullptr};
61 
62         JSHandle<TaggedArray> nonStaticElements = factory->EmptyArray();
63         if (UNLIKELY(ExtractAndReturnWhetherWithElements(thread, literal, nonStaticDetail, nonStaticKeys,
64                                                          nonStaticProperties, nonStaticElements, jsPandaFile))) {
65             extractor->SetNonStaticWithElements(true);
66             extractor->SetNonStaticElements(thread, nonStaticElements);
67         }
68     }
69 
70     extractor->SetNonStaticKeys(thread, nonStaticKeys);
71     extractor->SetNonStaticProperties(thread, nonStaticProperties);
72 
73     uint32_t staticNum = length == 0 ? 0 : (length - 1) / 2 - nonStaticNum;
74 
75     // Reserve sufficient length to prevent frequent creation.
76     JSHandle<TaggedArray> staticKeys;
77     JSHandle<TaggedArray> staticProperties;
78     if (kind == ClassKind::SENDABLE) {
79         staticKeys = factory->NewSOldSpaceTaggedArray(staticNum + SENDABLE_STATIC_RESERVED_LENGTH);
80         staticProperties = factory->NewSOldSpaceTaggedArray(staticNum + SENDABLE_STATIC_RESERVED_LENGTH);
81     } else {
82         staticKeys = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH);
83         staticProperties = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH);
84     }
85 
86     staticKeys->Set(thread, LENGTH_INDEX, globalConst->GetLengthString());
87     staticKeys->Set(thread, NAME_INDEX, globalConst->GetNameString());
88     staticKeys->Set(thread, PROTOTYPE_INDEX, globalConst->GetPrototypeString());
89     if (kind == ClassKind::SENDABLE) {
90         staticKeys->Set(thread, SENDABLE_ELEMENTS_INDEX, globalConst->GetSendableElementsSymbol());
91     }
92 
93     JSHandle<TaggedArray> staticElements = factory->EmptyArray();
94 
95     if (staticNum) {
96         ExtractContentsDetail staticDetail {};
97 
98         if (kind == ClassKind::SENDABLE) {
99             staticDetail = { nonStaticNum * 2, length - 1, SENDABLE_STATIC_RESERVED_LENGTH, methodLiteral };
100         } else {
101             staticDetail = { nonStaticNum * 2, length - 1, STATIC_RESERVED_LENGTH, methodLiteral };
102         }
103 
104         if (UNLIKELY(ExtractAndReturnWhetherWithElements(thread, literal, staticDetail, staticKeys,
105                                                          staticProperties, staticElements, jsPandaFile))) {
106             extractor->SetStaticWithElements(true);
107             extractor->SetStaticElements(thread, staticElements);
108         }
109     } else {
110         // without static properties, set class name
111         std::string clsName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
112         JSHandle<EcmaString> clsNameHandle = factory->NewFromStdString(clsName);
113         staticProperties->Set(thread, NAME_INDEX, clsNameHandle);
114     }
115 
116     // set prototype internal accessor
117     JSHandle<JSTaggedValue> prototypeAccessor = globalConst->GetHandledFunctionPrototypeAccessor();
118     staticProperties->Set(thread, PROTOTYPE_INDEX, prototypeAccessor);
119     if (kind == ClassKind::SENDABLE) {
120         staticProperties->Set(thread, SENDABLE_ELEMENTS_INDEX, JSTaggedValue::Undefined());
121     }
122 
123     extractor->SetStaticKeys(thread, staticKeys);
124     extractor->SetStaticProperties(thread, staticProperties);
125 }
126 
ExtractAndReturnWhetherWithElements(JSThread * thread,const JSHandle<TaggedArray> & literal,const ExtractContentsDetail & detail,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties,JSHandle<TaggedArray> & elements,const JSPandaFile * jsPandaFile)127 bool ClassInfoExtractor::ExtractAndReturnWhetherWithElements(JSThread *thread, const JSHandle<TaggedArray> &literal,
128                                                              const ExtractContentsDetail &detail,
129                                                              JSHandle<TaggedArray> &keys,
130                                                              JSHandle<TaggedArray> &properties,
131                                                              JSHandle<TaggedArray> &elements,
132                                                              const JSPandaFile *jsPandaFile)
133 {
134     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
135 
136     ASSERT(keys->GetLength() == properties->GetLength() && elements->GetLength() == 0);
137 
138     uint32_t pos = detail.fillStartLoc;
139     bool withElementsFlag = false;
140     bool isStaticFlag = (detail.methodLiteral != nullptr);
141     bool keysHasNameFlag = false;
142 
143     JSHandle<JSTaggedValue> nameString = globalConst->GetHandledNameString();
144     JSMutableHandle<JSTaggedValue> firstValue(thread, JSTaggedValue::Undefined());
145     JSMutableHandle<JSTaggedValue> secondValue(thread, JSTaggedValue::Undefined());
146     for (uint32_t index = detail.extractBegin; index < detail.extractEnd; index += 2) {  // 2: key-value pair
147         firstValue.Update(literal->Get(index));
148         secondValue.Update(literal->Get(index + 1));
149         ASSERT_PRINT(JSTaggedValue::IsPropertyKey(firstValue), "Key is not a property key");
150 
151         if (LIKELY(firstValue->IsString())) {
152             if (isStaticFlag && !keysHasNameFlag && JSTaggedValue::SameValue(firstValue, nameString)) {
153                 properties->Set(thread, NAME_INDEX, secondValue);
154                 keysHasNameFlag = true;
155                 continue;
156             }
157 
158             // front-end can do better: write index in class literal directly.
159             uint32_t elementIndex = 0;
160             if (JSTaggedValue::StringToElementIndex(firstValue.GetTaggedValue(), &elementIndex)) {
161                 ASSERT(elementIndex < JSObject::MAX_ELEMENT_INDEX);
162                 uint32_t elementsLength = elements->GetLength();
163                 elements =
164                     TaggedArray::SetCapacityInOldSpace(thread, elements, elementsLength + 2); // 2: key-value pair
165                 elements->Set(thread, elementsLength, firstValue);
166                 elements->Set(thread, elementsLength + 1, secondValue);
167                 withElementsFlag = true;
168                 continue;
169             }
170         }
171 
172         keys->Set(thread, pos, firstValue);
173         properties->Set(thread, pos, secondValue);
174         pos++;
175     }
176 
177     if (isStaticFlag) {
178         if (LIKELY(!keysHasNameFlag)) {
179             [[maybe_unused]] EcmaHandleScope handleScope(thread);
180             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
181             EntityId methodId = detail.methodLiteral->GetMethodId();
182             std::string clsName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
183             JSHandle<EcmaString> clsNameHandle = factory->NewFromStdString(clsName);
184             properties->Set(thread, NAME_INDEX, clsNameHandle);
185         } else {
186             // class has static name property, reserved length bigger 1 than actual, need trim
187             uint32_t trimOneLength = keys->GetLength() - 1;
188             keys->Trim(thread, trimOneLength);
189             properties->Trim(thread, trimOneLength);
190         }
191     }
192 
193     if (UNLIKELY(withElementsFlag)) {
194         ASSERT(pos + elements->GetLength() / 2 == properties->GetLength());  // 2: half
195         keys->Trim(thread, pos);
196         properties->Trim(thread, pos);
197     }
198 
199     return withElementsFlag;
200 }
201 
CreatePrototypeHClass(JSThread * thread,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties)202 JSHandle<JSHClass> ClassInfoExtractor::CreatePrototypeHClass(JSThread *thread,
203                                                              JSHandle<TaggedArray> &keys,
204                                                              JSHandle<TaggedArray> &properties)
205 {
206     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
207 
208     uint32_t length = keys->GetLength();
209     JSHandle<JSHClass> hclass;
210     if (LIKELY(length <= PropertyAttributes::MAX_FAST_PROPS_CAPACITY)) {
211         JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
212         JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(length, MemSpaceType::OLD_SPACE, GrowMode::KEEP);
213         for (uint32_t index = 0; index < length; ++index) {
214             key.Update(keys->Get(index));
215             ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
216             PropertyAttributes attributes = PropertyAttributes::Default(true, false, true);  // non-enumerable
217 
218             if (UNLIKELY(properties->Get(index).IsAccessor())) {
219                 attributes.SetIsAccessor(true);
220             }
221 
222             attributes.SetIsInlinedProps(true);
223             attributes.SetRepresentation(Representation::TAGGED);
224             attributes.SetOffset(index);
225             layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
226         }
227 
228         hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, length);
229         // Not need set proto here
230         hclass->SetLayout(thread, layout);
231         hclass->SetNumberOfProps(length);
232     } else {
233         // dictionary mode
234         hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, 0);  // without in-obj
235         hclass->SetIsDictionaryMode(true);
236         hclass->SetNumberOfProps(0);
237     }
238 
239     hclass->SetClassPrototype(true);
240     hclass->SetIsPrototype(true);
241     return hclass;
242 }
243 
CreateConstructorHClass(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties)244 JSHandle<JSHClass> ClassInfoExtractor::CreateConstructorHClass(JSThread *thread, const JSHandle<JSTaggedValue> &base,
245                                                                JSHandle<TaggedArray> &keys,
246                                                                JSHandle<TaggedArray> &properties)
247 {
248     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
249 
250     uint32_t length = keys->GetLength();
251     if (!thread->GetEcmaVM()->IsEnablePGOProfiler()) {
252         // The class constructor of AOT is not shared, and PGO collect cannot be shared.
253         if (length == ClassInfoExtractor::STATIC_RESERVED_LENGTH && base->IsHole() &&
254             properties->Get(NAME_INDEX).IsString()) {
255             const GlobalEnvConstants *globalConst = thread->GlobalConstants();
256             return JSHandle<JSHClass>(globalConst->GetHandledClassConstructorClass());
257         }
258     }
259     JSHandle<JSHClass> hclass;
260     if (LIKELY(length <= PropertyAttributes::MAX_FAST_PROPS_CAPACITY)) {
261         JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
262         JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(length, MemSpaceType::OLD_SPACE, GrowMode::KEEP);
263         for (uint32_t index = 0; index < length; ++index) {
264             key.Update(keys->Get(index));
265             ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
266             PropertyAttributes attributes;
267             switch (index) {
268                 case LENGTH_INDEX:
269                     attributes = PropertyAttributes::Default(false, false, true);
270                     break;
271                 case NAME_INDEX:
272                     if (LIKELY(properties->Get(NAME_INDEX).IsString())) {
273                         attributes = PropertyAttributes::Default(false, false, true);
274                     } else {
275                         ASSERT(properties->Get(NAME_INDEX).IsFunctionTemplate());
276                         attributes = PropertyAttributes::Default(true, false, true);
277                     }
278                     break;
279                 case PROTOTYPE_INDEX:
280                     attributes = PropertyAttributes::DefaultAccessor(false, false, false);
281                     break;
282                 default:
283                     attributes = PropertyAttributes::Default(true, false, true);
284                     break;
285             }
286 
287             if (UNLIKELY(properties->Get(index).IsAccessor())) {
288                 attributes.SetIsAccessor(true);
289             }
290 
291             attributes.SetIsInlinedProps(true);
292             attributes.SetRepresentation(Representation::TAGGED);
293             attributes.SetOffset(index);
294             layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
295         }
296 
297         hclass = factory->NewEcmaHClass(JSFunction::SIZE, JSType::JS_FUNCTION, length);
298         // Not need set proto here
299         hclass->SetLayout(thread, layout);
300         hclass->SetNumberOfProps(length);
301     } else {
302         // dictionary mode
303         hclass = factory->NewEcmaHClass(JSFunction::SIZE, JSType::JS_FUNCTION, 0);  // without in-obj
304         hclass->SetIsDictionaryMode(true);
305         hclass->SetNumberOfProps(0);
306     }
307 
308     hclass->SetClassConstructor(true);
309     hclass->SetConstructor(true);
310 
311     return hclass;
312 }
313 
CorrectConstructorHClass(JSThread * thread,JSHandle<TaggedArray> & properties,JSHClass * constructorHClass)314 void ClassInfoExtractor::CorrectConstructorHClass(JSThread *thread,
315                                                   JSHandle<TaggedArray> &properties,
316                                                   JSHClass *constructorHClass)
317 {
318     if (constructorHClass->IsDictionaryMode()) {
319         return;
320     }
321     JSHandle<LayoutInfo> layout(thread, constructorHClass->GetLayout());
322     for (uint32_t index = 0; index < ClassInfoExtractor::STATIC_RESERVED_LENGTH; ++index) {
323         if (index == NAME_INDEX) {
324             if (UNLIKELY(properties->Get(NAME_INDEX).IsFunctionTemplate())) {
325                 PropertyAttributes attr = layout->GetAttr(index);
326                 attr.SetWritable(true);
327                 layout->SetNormalAttr(thread, index, attr);
328             }
329             if (UNLIKELY(properties->Get(index).IsAccessor())) {
330                 PropertyAttributes attr = layout->GetAttr(index);
331                 attr.SetIsAccessor(true);
332                 layout->SetNormalAttr(thread, index, attr);
333             }
334         } else {
335             if (UNLIKELY(properties->Get(index).IsAccessor())) {
336                 PropertyAttributes attr = layout->GetAttr(index);
337                 attr.SetIsAccessor(true);
338                 layout->SetNormalAttr(thread, index, attr);
339             }
340         }
341     }
342 }
343 
CreateSendableHClass(JSThread * thread,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties,bool isProtoClass,uint32_t extraLength)344 JSHandle<JSHClass> ClassInfoExtractor::CreateSendableHClass(JSThread *thread, JSHandle<TaggedArray> &keys,
345                                                             JSHandle<TaggedArray> &properties, bool isProtoClass,
346                                                             uint32_t extraLength)
347 {
348     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
349     uint32_t length = keys->GetLength();
350     JSHandle<JSHClass> hclass;
351     uint32_t maxInline = isProtoClass ? JSSharedObject::MAX_INLINE : JSSharedFunction::MAX_INLINE;
352     if (LIKELY(length + extraLength <= maxInline)) {
353         JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
354         JSHandle<LayoutInfo> layout = factory->CreateSLayoutInfo(length + extraLength);
355         for (uint32_t index = 0; index < length; ++index) {
356             key.Update(keys->Get(index));
357             ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
358             PropertyAttributes attributes = PropertyAttributes::Default(false, false, false);
359             if (UNLIKELY(properties->Get(index).IsAccessor())) {
360                 attributes.SetIsAccessor(true);
361             }
362             attributes.SetIsInlinedProps(true);
363             attributes.SetRepresentation(Representation::TAGGED);
364             attributes.SetOffset(index);
365             layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
366         }
367         hclass = isProtoClass ? factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, length) :
368             factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, length + extraLength);
369         hclass->SetLayout(thread, layout);
370         hclass->SetNumberOfProps(length);
371     } else {
372         // dictionary mode
373         hclass = isProtoClass ? factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0) :
374             factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, 0);
375         hclass->SetIsDictionaryMode(true);
376         hclass->SetNumberOfProps(0);
377     }
378     if (isProtoClass) {
379         hclass->SetClassPrototype(true);
380         hclass->SetIsPrototype(true);
381     } else {
382         hclass->SetClassConstructor(true);
383         hclass->SetConstructor(true);
384     }
385     return hclass;
386 }
387 
DefineClassFromExtractor(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<JSTaggedValue> & lexenv)388 JSHandle<JSFunction> ClassHelper::DefineClassFromExtractor(JSThread *thread, const JSHandle<JSTaggedValue> &base,
389                                                            JSHandle<ClassInfoExtractor> &extractor,
390                                                            const JSHandle<JSTaggedValue> &lexenv)
391 {
392     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
393     JSHandle<TaggedArray> staticKeys(thread, extractor->GetStaticKeys());
394     JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
395 
396     JSHandle<TaggedArray> nonStaticKeys(thread, extractor->GetNonStaticKeys());
397     JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
398     JSHandle<JSHClass> prototypeHClass = ClassInfoExtractor::CreatePrototypeHClass(thread, nonStaticKeys,
399                                                                                    nonStaticProperties);
400 
401     JSHandle<JSObject> prototype = factory->NewOldSpaceJSObject(prototypeHClass);
402     JSHandle<Method> method(thread, Method::Cast(extractor->GetConstructorMethod().GetTaggedObject()));
403     JSHandle<JSHClass> constructorHClass = ClassInfoExtractor::CreateConstructorHClass(thread, base, staticKeys,
404                                                                                        staticProperties);
405     // Allocate to non-movable space for PGO
406     JSHandle<JSFunction> constructor = factory->NewJSFunctionByHClass(method, constructorHClass,
407         MemSpaceType::NON_MOVABLE);
408 
409     // non-static
410     nonStaticProperties->Set(thread, 0, constructor);
411 
412     uint32_t nonStaticLength = nonStaticProperties->GetLength();
413     JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
414 
415     if (LIKELY(!prototypeHClass->IsDictionaryMode())) {
416         for (uint32_t index = 0; index < nonStaticLength; ++index) {
417             propValue.Update(nonStaticProperties->Get(index));
418             if (propValue->IsFunctionTemplate()) {
419                 auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
420                 propValue.Update(CreateJSFunctionFromTemplate(thread, literalFunc, prototype, lexenv));
421             }
422             prototype->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
423         }
424     } else {
425         JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, prototype, nonStaticKeys, nonStaticProperties,
426                                                                   ClassPropertyType::NON_STATIC, lexenv);
427         prototype->SetProperties(thread, dict);
428     }
429 
430     // non-static elements
431     if (UNLIKELY(extractor->GetNonStaticWithElements())) {
432         JSHandle<TaggedArray> nonStaticElements(thread, extractor->GetNonStaticElements());
433         ClassHelper::HandleElementsProperties(thread, prototype, lexenv, nonStaticElements);
434     }
435 
436     // static
437     uint32_t staticLength = staticProperties->GetLength();
438 
439     if (LIKELY(!constructorHClass->IsDictionaryMode())) {
440         for (uint32_t index = 0; index < staticLength; ++index) {
441             propValue.Update(staticProperties->Get(index));
442             if (propValue->IsFunctionTemplate()) {
443                 auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
444                 propValue.Update(
445                     CreateJSFunctionFromTemplate(thread, literalFunc, JSHandle<JSObject>(constructor), lexenv));
446             }
447             JSHandle<JSObject>::Cast(constructor)->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
448         }
449     } else {
450         JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, JSHandle<JSObject>(constructor), staticKeys,
451                                                                   staticProperties, ClassPropertyType::STATIC, lexenv);
452         constructor->SetProperties(thread, dict);
453     }
454 
455     // static elements
456     if (UNLIKELY(extractor->GetStaticWithElements())) {
457         JSHandle<TaggedArray> staticElements(thread, extractor->GetStaticElements());
458         ClassHelper::HandleElementsProperties(thread, JSHandle<JSObject>(constructor), lexenv, staticElements);
459     }
460 
461     PropertyDescriptor ctorDesc(thread, JSHandle<JSTaggedValue>(constructor), true, false, true);
462     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
463     JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(prototype),
464                                          globalConst->GetHandledConstructorString(), ctorDesc);
465     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSFunction, thread);
466     constructor->SetHomeObject(thread, prototype);
467     constructor->SetProtoOrHClass(thread, prototype);
468     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
469         thread->GetEcmaVM()->GetPGOProfiler()->ProfileDefineClass(constructor.GetTaggedType());
470     }
471     return constructor;
472 }
473 
DefineClassWithIHClass(JSThread * thread,const JSHandle<JSTaggedValue> & base,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<JSTaggedValue> & lexenv,const JSHandle<JSTaggedValue> & prototypeOrHClassVal,const JSHandle<JSTaggedValue> & constructorHClassVal)474 JSHandle<JSFunction> ClassHelper::DefineClassWithIHClass(JSThread *thread, const JSHandle<JSTaggedValue> &base,
475                                                          JSHandle<ClassInfoExtractor> &extractor,
476                                                          const JSHandle<JSTaggedValue> &lexenv,
477                                                          const JSHandle<JSTaggedValue> &prototypeOrHClassVal,
478                                                          const JSHandle<JSTaggedValue> &constructorHClassVal)
479 {
480     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
481     JSHandle<TaggedArray> staticKeys(thread, extractor->GetStaticKeys());
482     JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
483     JSHandle<JSHClass> constructorHClass;
484     // When constructorHClassVal is undefined, it means that AOT has not generated the corresponding hclass (chc),
485     // then chc will be created through the interpreter.
486     if (constructorHClassVal->IsUndefined()) {
487         constructorHClass = ClassInfoExtractor::CreateConstructorHClass(thread, base, staticKeys, staticProperties);
488     } else {
489         constructorHClass = JSHandle<JSHClass>(constructorHClassVal);
490         ClassInfoExtractor::CorrectConstructorHClass(thread, staticProperties, *constructorHClass);
491     }
492 
493     JSHandle<TaggedArray> nonStaticKeys(thread, extractor->GetNonStaticKeys());
494     JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
495     JSHandle<JSObject> prototype;
496     JSHandle<JSTaggedValue> prototypeOrHClass = prototypeOrHClassVal;
497     // When prototypeOrHClassVal is undefined, it means that AOT has not generated the corresponding hclass or
498     // prototype, then prototype will be created through the interpreter.
499     if (prototypeOrHClassVal->IsUndefined()) {
500         JSHandle<JSHClass> prototypeHClass = ClassInfoExtractor::CreatePrototypeHClass(thread, nonStaticKeys,
501                                                                                        nonStaticProperties);
502         prototype = factory->NewOldSpaceJSObject(prototypeHClass);
503         prototypeOrHClass = JSHandle<JSTaggedValue>(prototype);
504     } else if (prototypeOrHClassVal->IsJSHClass()) {
505         JSHandle<JSHClass> ihclass(prototypeOrHClassVal);
506         prototype = JSHandle<JSObject>(thread, ihclass->GetProto());
507     } else {
508         prototype = JSHandle<JSObject>(prototypeOrHClassVal);
509     }
510 
511     JSHandle<Method> method(thread, Method::Cast(extractor->GetConstructorMethod().GetTaggedObject()));
512     JSHandle<JSFunction> constructor = factory->NewJSFunctionByHClass(method, constructorHClass,
513         MemSpaceType::NON_MOVABLE);
514 
515     // non-static
516     nonStaticProperties->Set(thread, 0, constructor);
517 
518     uint32_t nonStaticLength = nonStaticProperties->GetLength();
519     JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
520 
521     if (LIKELY(!prototype->GetJSHClass()->IsDictionaryMode())) {
522         for (uint32_t index = 0; index < nonStaticLength; ++index) {
523             propValue.Update(nonStaticProperties->Get(index));
524             if (propValue->IsFunctionTemplate()) {
525                 auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
526                 propValue.Update(CreateJSFunctionFromTemplate(thread, literalFunc, prototype, lexenv));
527             }
528             prototype->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
529         }
530     } else {
531         JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, prototype, nonStaticKeys, nonStaticProperties,
532                                                                   ClassPropertyType::NON_STATIC, lexenv);
533         prototype->SetProperties(thread, dict);
534     }
535 
536     // non-static elements
537     if (UNLIKELY(extractor->GetNonStaticWithElements())) {
538         JSHandle<TaggedArray> nonStaticElements(thread, extractor->GetNonStaticElements());
539         ClassHelper::HandleElementsProperties(thread, prototype, lexenv, nonStaticElements);
540     }
541 
542     // static
543     uint32_t staticLength = staticProperties->GetLength();
544     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
545     int correntIndex = 0;
546     if (LIKELY(!constructorHClass->IsDictionaryMode())) {
547         for (uint32_t index = 0; index < staticLength; ++index) {
548             propValue.Update(staticProperties->Get(index));
549             if (propValue->IsFunctionTemplate()) {
550                 auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
551                 propValue.Update(
552                     CreateJSFunctionFromTemplate(thread, literalFunc, JSHandle<JSObject>(constructor), lexenv));
553             }
554             bool needCorrentIndex = index >= ClassInfoExtractor::STATIC_RESERVED_LENGTH;
555             if (needCorrentIndex) {
556                 key.Update(staticKeys->Get(index));
557                 correntIndex = JSHClass::FindPropertyEntry(thread, *constructorHClass, key.GetTaggedValue());
558             }
559             JSHandle<JSObject>::Cast(constructor)->SetPropertyInlinedProps(thread,
560                 needCorrentIndex ? static_cast<uint32_t>(correntIndex) : index, propValue.GetTaggedValue());
561         }
562     } else {
563         JSHandle<NameDictionary> dict = BuildDictionaryProperties(thread, JSHandle<JSObject>(constructor), staticKeys,
564                                                                   staticProperties, ClassPropertyType::STATIC, lexenv);
565         constructor->SetProperties(thread, dict);
566     }
567 
568     // static elements
569     if (UNLIKELY(extractor->GetStaticWithElements())) {
570         JSHandle<TaggedArray> staticElements(thread, extractor->GetStaticElements());
571         ClassHelper::HandleElementsProperties(thread, JSHandle<JSObject>(constructor), lexenv, staticElements);
572     }
573 
574     PropertyDescriptor ctorDesc(thread, JSHandle<JSTaggedValue>(constructor), true, false, true);
575     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
576     JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(prototype),
577                                          globalConst->GetHandledConstructorString(), ctorDesc);
578     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSFunction, thread);
579     constructor->SetHomeObject(thread, prototype);
580     constructor->SetProtoOrHClass(thread, prototypeOrHClass);
581 
582     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
583         thread->GetEcmaVM()->GetPGOProfiler()->ProfileDefineClass(constructor.GetTaggedType());
584     }
585     return constructor;
586 }
587 
CreateJSFunctionFromTemplate(JSThread * thread,const JSHandle<FunctionTemplate> & funcTemp,const JSHandle<JSObject> & homeObject,const JSHandle<JSTaggedValue> & lexenv)588 JSHandle<JSFunction> ClassHelper::CreateJSFunctionFromTemplate(JSThread *thread,
589                                                                const JSHandle<FunctionTemplate> &funcTemp,
590                                                                const JSHandle<JSObject> &homeObject,
591                                                                const JSHandle<JSTaggedValue> &lexenv)
592 {
593     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
594     JSHandle<JSFunction> propFunc = factory->CreateJSFunctionFromTemplate(funcTemp);
595     JSFunction::UpdateProfileTypeInfoCell(thread, funcTemp, propFunc);
596     propFunc->SetHomeObject(thread, homeObject);
597     propFunc->SetLexicalEnv(thread, lexenv);
598     return propFunc;
599 }
600 
BuildDictionaryProperties(JSThread * thread,const JSHandle<JSObject> & object,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties,ClassPropertyType type,const JSHandle<JSTaggedValue> & lexenv)601 JSHandle<NameDictionary> ClassHelper::BuildDictionaryProperties(JSThread *thread, const JSHandle<JSObject> &object,
602                                                                 JSHandle<TaggedArray> &keys,
603                                                                 JSHandle<TaggedArray> &properties,
604                                                                 ClassPropertyType type,
605                                                                 const JSHandle<JSTaggedValue> &lexenv)
606 {
607     uint32_t length = keys->GetLength();
608     ASSERT(length > PropertyAttributes::MAX_FAST_PROPS_CAPACITY);
609     ASSERT(keys->GetLength() == properties->GetLength());
610 
611     JSMutableHandle<NameDictionary> dict(
612         thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(length)));
613     JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
614     JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
615     for (uint32_t index = 0; index < length; index++) {
616         PropertyAttributes attributes;
617         if (type == ClassPropertyType::STATIC) {
618             switch (index) {
619                 case ClassInfoExtractor::LENGTH_INDEX:
620                     attributes = PropertyAttributes::Default(false, false, true);
621                     break;
622                 case ClassInfoExtractor::NAME_INDEX:
623                     if (LIKELY(properties->Get(ClassInfoExtractor::NAME_INDEX).IsString())) {
624                         attributes = PropertyAttributes::Default(false, false, true);
625                     } else {
626                         ASSERT(properties->Get(ClassInfoExtractor::NAME_INDEX).IsFunctionTemplate());
627                         attributes = PropertyAttributes::Default(true, false, true);
628                     }
629                     break;
630                 case ClassInfoExtractor::PROTOTYPE_INDEX:
631                     attributes = PropertyAttributes::DefaultAccessor(false, false, false);
632                     break;
633                 default:
634                     attributes = PropertyAttributes::Default(true, false, true);
635                     break;
636             }
637         } else {
638             attributes = PropertyAttributes::Default(true, false, true);  // non-enumerable
639         }
640         propKey.Update(keys->Get(index));
641         propValue.Update(properties->Get(index));
642         if (propValue->IsFunctionTemplate()) {
643             auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
644             propValue.Update(CreateJSFunctionFromTemplate(thread, literalFunc, object, lexenv));
645         }
646         JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attributes);
647         dict.Update(newDict);
648     }
649     return dict;
650 }
651 
MatchFieldType(SharedFieldType fieldType,JSTaggedValue value)652 bool ClassHelper::MatchFieldType(SharedFieldType fieldType, JSTaggedValue value)
653 {
654     // all sendable types can be set to undefined
655     if (value.IsUndefined()) {
656         return true;
657     }
658     uint32_t sharedFieldType = static_cast<uint32_t>(fieldType);
659     if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::NUMBER)) != 0 && value.IsNumber()) {
660         return true;
661     } else if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::BOOLEAN)) != 0 && value.IsBoolean()) {
662         return true;
663     } else if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::STRING)) != 0 &&
664         (value.IsString() || value.IsNull())) {
665         return true;
666     } else if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::BIG_INT)) != 0 && value.IsBigInt()) {
667         return true;
668     } else if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::SENDABLE)) != 0 &&
669         (value.IsJSShared() || value.IsNull())) {
670         return true;
671     } else if ((sharedFieldType == static_cast<uint32_t>(SharedFieldType::NONE) ||
672         (sharedFieldType & static_cast<uint32_t>(SharedFieldType::GENERIC)) != 0) &&
673         (value.IsJSShared() || !value.IsHeapObject())) {
674         // (none || generic) && (jsShared || !heapObject)
675         return true;
676     } else if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::NULL_TYPE)) != 0 && value.IsNull()) {
677         return true;
678     } else if ((sharedFieldType & static_cast<uint32_t>(SharedFieldType::UNDEFINED)) != 0 && value.IsUndefined()) {
679         return true;
680     }
681     std::stringstream oss;
682     value.DumpTaggedValueType(oss);
683     LOG_ECMA(ERROR) << "Sendable obj Match field type fail. expected type: " <<
684         StaticFieldTypeToString(sharedFieldType) << ", actual type: " << oss.str();
685     return false;
686 }
687 
StaticFieldTypeToString(uint32_t fieldType)688 CString ClassHelper::StaticFieldTypeToString(uint32_t fieldType)
689 {
690     switch (fieldType) {
691         case static_cast<uint32_t>(SharedFieldType::NONE):
692             return "[None]";
693         case static_cast<uint32_t>(SharedFieldType::NUMBER):
694             return "[Number]";
695         case static_cast<uint32_t>(SharedFieldType::STRING):
696             return "[String]";
697         case static_cast<uint32_t>(SharedFieldType::BOOLEAN):
698             return "[Boolean]";
699         case static_cast<uint32_t>(SharedFieldType::SENDABLE):
700             return "[Sendable Object]";
701         case static_cast<uint32_t>(SharedFieldType::BIG_INT):
702             return "[BigInt]";
703         case static_cast<uint32_t>(SharedFieldType::GENERIC):
704             return "[Generic]";
705         case static_cast<uint32_t>(SharedFieldType::NULL_TYPE):
706             return "[Null]";
707         case static_cast<uint32_t>(SharedFieldType::UNDEFINED):
708             return "[Undefined]";
709         default: {
710             CString ret = "unknown type ";
711             return ret.append(std::to_string(fieldType));
712         }
713     }
714 }
715 
HandleElementsProperties(JSThread * thread,const JSHandle<JSObject> & object,const JSHandle<JSTaggedValue> & lexenv,JSHandle<TaggedArray> & elements)716 void ClassHelper::HandleElementsProperties(JSThread *thread, const JSHandle<JSObject> &object,
717                                            const JSHandle<JSTaggedValue> &lexenv, JSHandle<TaggedArray> &elements)
718 {
719     JSMutableHandle<JSTaggedValue> elementsKey(thread, JSTaggedValue::Undefined());
720     JSMutableHandle<JSTaggedValue> elementsValue(thread, JSTaggedValue::Undefined());
721     for (uint32_t index = 0; index < elements->GetLength(); index += 2) {  // 2: key-value pair
722         elementsKey.Update(elements->Get(index));
723         elementsValue.Update(elements->Get(index + 1));
724         if (elementsValue->IsFunctionTemplate()) {
725             auto literalFunc = JSHandle<FunctionTemplate>::Cast(elementsValue);
726             elementsValue.Update(CreateJSFunctionFromTemplate(thread, literalFunc, object, lexenv));
727         }
728 
729         // class property attribute is not default, will transition to dictionary directly.
730         JSObject::DefinePropertyByLiteral(thread, object, elementsKey, elementsValue, true);
731     }
732 }
733 
DefineSendableClassFromExtractor(JSThread * thread,JSHandle<ClassInfoExtractor> & extractor,const JSHandle<TaggedArray> & staticFieldArray)734 JSHandle<JSFunction> SendableClassDefiner::DefineSendableClassFromExtractor(JSThread *thread,
735     JSHandle<ClassInfoExtractor> &extractor, const JSHandle<TaggedArray> &staticFieldArray)
736 {
737     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
738     JSHandle<TaggedArray> staticKeys(thread, extractor->GetStaticKeys());
739     JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
740     SendableClassDefiner::FilterDuplicatedKeys(thread, staticKeys, staticProperties);
741 
742     JSHandle<TaggedArray> nonStaticKeys(thread, extractor->GetNonStaticKeys());
743     JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
744     SendableClassDefiner::FilterDuplicatedKeys(thread, nonStaticKeys, nonStaticProperties);
745     JSHandle<JSHClass> prototypeHClass = ClassInfoExtractor::CreateSendableHClass(thread, nonStaticKeys,
746                                                                                   nonStaticProperties, true);
747     JSHandle<JSObject> prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass);
748     uint32_t length = staticFieldArray->GetLength();
749     uint32_t staticFields =  length / 2; // 2: key-type
750     JSHandle<JSHClass> constructorHClass =
751         ClassInfoExtractor::CreateSendableHClass(thread, staticKeys, staticProperties, false, staticFields);
752     JSHandle<Method> method(thread, Method::Cast(extractor->GetConstructorMethod().GetTaggedObject()));
753     /*
754     * Method::SetFunctionKind can't be called here, because method will set kind when set inheritance relationship,
755     * so there is a multi-threading problem with multi-threads define sendable DERIVED class at the same time.
756     * Scenario:
757     *    A thread: define DERIVED class X [X's kind = DEFAULT --> BASE CLASS --> DERIVED CLASS], new X()
758     *    B thread: define DERIVED class X [X's kind = DEFAULT --> BASE CLASS --> DERIVED CLASS], new X()
759     * Issue:
760     *     When A thread new DERIVED class X, X's kind maybe set to BASE CLASS at B thread,
761     *     and A thread will throw error when call super().
762     */
763 
764     JSHandle<NumberDictionary> elementsDic = NumberDictionary::CreateInSharedHeap(thread);
765     bool hasElement = false;
766     if (!constructorHClass->IsDictionaryMode() && staticFields > 0) {
767         auto layout = JSHandle<LayoutInfo>(thread, constructorHClass->GetLayout());
768         AddFieldTypeToHClass(
769             thread, staticFieldArray, length, layout, constructorHClass, elementsDic, hasElement, ~0U);
770     }
771 
772     JSHandle<JSFunction> constructor = factory->NewSFunctionByHClass(method, constructorHClass);
773 
774     // non-static
775     nonStaticProperties->Set(thread, 0, constructor);
776 
777     uint32_t nonStaticLength = nonStaticProperties->GetLength();
778     JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
779 
780     if (LIKELY(!prototypeHClass->IsDictionaryMode())) {
781         for (uint32_t index = 0; index < nonStaticLength; ++index) {
782             propValue.Update(nonStaticProperties->Get(index));
783             // constructor don't need to clone
784             if (propValue->IsFunctionTemplate() && index != ClassInfoExtractor::CONSTRUCTOR_INDEX) {
785                 auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
786                 propValue.Update(
787                     CreateSFunctionFromTemplate(thread, literalFunc, prototype, JSHandle<JSTaggedValue>(constructor)));
788             } else if (propValue->IsAccessorData()) {
789                 UpdateAccessorFunction(thread, propValue, JSHandle<JSTaggedValue>(prototype), constructor);
790             }
791             prototype->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
792         }
793     } else {
794         JSHandle<NameDictionary> dict = BuildSendableDictionaryProperties(thread, prototype, nonStaticKeys,
795             nonStaticProperties, ClassPropertyType::NON_STATIC, constructor);
796         prototype->SetProperties(thread, dict);
797     }
798 
799     // non-static elements
800     if (UNLIKELY(extractor->GetNonStaticWithElements())) {
801         THROW_TYPE_ERROR_AND_RETURN(thread, "Concurrent class don't support members with numerical key",
802             JSHandle<JSFunction>(thread, JSTaggedValue::Exception()));
803     }
804 
805     // static
806     uint32_t staticLength = staticProperties->GetLength();
807     if (LIKELY(!constructorHClass->IsDictionaryMode())) {
808         for (uint32_t index = 0; index < staticLength; ++index) {
809             propValue.Update(staticProperties->Get(index));
810             if (propValue->IsFunctionTemplate()) {
811                 auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
812                 propValue.Update(CreateSFunctionFromTemplate(
813                     thread, literalFunc, JSHandle<JSObject>(constructor), JSHandle<JSTaggedValue>(constructor)));
814             } else if (propValue->IsAccessorData()) {
815                 UpdateAccessorFunction(thread, propValue, JSHandle<JSTaggedValue>(constructor), constructor);
816             }
817             JSHandle<JSObject>::Cast(constructor)->SetPropertyInlinedProps(thread, index, propValue.GetTaggedValue());
818         }
819     } else {
820         JSHandle<NameDictionary> dict =
821             BuildSendableDictionaryProperties(thread, JSHandle<JSObject>(constructor), staticKeys,
822                                               staticProperties, ClassPropertyType::STATIC, constructor);
823         JSMutableHandle<NameDictionary> nameDict(thread, dict);
824         if (staticFields > 0) {
825             AddFieldTypeToDict(thread, staticFieldArray, length, nameDict, elementsDic, hasElement,
826                                PropertyAttributes::Default(true, true, false));
827         }
828         constructor->SetProperties(thread, nameDict);
829     }
830     if (hasElement) {
831         constructor->SetElements(thread, elementsDic);
832         constructorHClass->SetIsDictionaryElement(true);
833     }
834 
835     // static elements
836     if (UNLIKELY(extractor->GetStaticWithElements())) {
837         THROW_TYPE_ERROR_AND_RETURN(thread, "Concurrent class don't support static members with numerical key",
838             JSHandle<JSFunction>(thread, JSTaggedValue::Exception()));
839     }
840     prototype->GetJSHClass()->SetExtensible(false);
841     constructor->SetHomeObject(thread, prototype);
842     constructor->SetProtoOrHClass(thread, prototype);
843     constructor->SetLexicalEnv(thread, constructor);
844     return constructor;
845 }
846 
847 // Process duplicated key due to getter/setter.
FilterDuplicatedKeys(JSThread * thread,const JSHandle<TaggedArray> & keys,const JSHandle<TaggedArray> & properties)848 void SendableClassDefiner::FilterDuplicatedKeys(JSThread *thread, const JSHandle<TaggedArray> &keys,
849                                                 const JSHandle<TaggedArray> &properties)
850 {
851     auto attr = PropertyAttributes::Default();
852     uint32_t length = keys->GetLength();
853     uint32_t left = 0;
854     uint32_t right = 0;
855     JSMutableHandle<NameDictionary> dict(
856         thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(length)));
857     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
858     JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
859     JSMutableHandle<JSTaggedValue> existValue(thread, JSTaggedValue::Undefined());
860     JSMutableHandle<JSTaggedValue> index(thread, JSTaggedValue::Undefined());
861     for (; right < length; right++) {
862         key.Update(keys->Get(right));
863         value.Update(properties->Get(right));
864         int entry = dict->FindEntry(key.GetTaggedValue());
865         if (entry == -1) {
866             TryUpdateValue(thread, value);
867             index.Update(JSTaggedValue(left));
868             JSHandle<NameDictionary> newDict =
869                 NameDictionary::PutIfAbsent(thread, dict, key, index, attr);
870             dict.Update(newDict);
871             if (left < right) {
872                 keys->Set(thread, left, key);
873             }
874             properties->Set(thread, left, value);
875             left++;
876             continue;
877         }
878         auto existIndex = static_cast<uint32_t>(dict->GetValue(entry).GetNumber());
879         existValue.Update(properties->Get(existIndex));
880         bool needUpdateValue = TryUpdateExistValue(thread, existValue, value);
881         if (needUpdateValue) {
882             properties->Set(thread, existIndex, value);
883         }
884     }
885     if (left < right) {
886         keys->Trim(thread, left);
887         properties->Trim(thread, left);
888     }
889 }
890 
BuildSendableDictionaryProperties(JSThread * thread,const JSHandle<JSObject> & object,JSHandle<TaggedArray> & keys,JSHandle<TaggedArray> & properties,ClassPropertyType type,const JSHandle<JSFunction> & ctor)891 JSHandle<NameDictionary> SendableClassDefiner::BuildSendableDictionaryProperties(JSThread *thread,
892     const JSHandle<JSObject> &object, JSHandle<TaggedArray> &keys, JSHandle<TaggedArray> &properties,
893     ClassPropertyType type, const JSHandle<JSFunction> &ctor)
894 {
895     uint32_t length = keys->GetLength();
896     ASSERT(keys->GetLength() == properties->GetLength());
897 
898     JSMutableHandle<NameDictionary> dict(
899         thread, NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(length)));
900     JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
901     JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
902     for (uint32_t index = 0; index < length; index++) {
903         PropertyAttributes attributes = PropertyAttributes::Default(false, false, false);
904         if (UNLIKELY(properties->Get(index).IsAccessor())) {
905             attributes.SetIsAccessor(true);
906         }
907         propKey.Update(keys->Get(index));
908         propValue.Update(properties->Get(index));
909         // constructor don't need to clone
910         if (index == ClassInfoExtractor::CONSTRUCTOR_INDEX && type == ClassPropertyType::NON_STATIC) {
911             JSHandle<NameDictionary> newDict =
912                 NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attributes);
913             dict.Update(newDict);
914             continue;
915         }
916         if (propValue->IsFunctionTemplate()) {
917             auto literalFunc = JSHandle<FunctionTemplate>::Cast(propValue);
918             propValue.Update(CreateSFunctionFromTemplate(thread, literalFunc, object, JSHandle<JSTaggedValue>(ctor)));
919         } else if (propValue->IsAccessorData()) {
920             UpdateAccessorFunction(thread, propValue, JSHandle<JSTaggedValue>(object), ctor);
921         }
922         JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attributes);
923         dict.Update(newDict);
924     }
925     return dict;
926 }
927 
CreateSFunctionFromTemplate(JSThread * thread,const JSHandle<FunctionTemplate> & funcTemp,const JSHandle<JSObject> & homeObject,const JSHandle<JSTaggedValue> & lexenv)928 JSHandle<JSFunction> SendableClassDefiner::CreateSFunctionFromTemplate(JSThread *thread,
929                                                                        const JSHandle<FunctionTemplate> &funcTemp,
930                                                                        const JSHandle<JSObject> &homeObject,
931                                                                        const JSHandle<JSTaggedValue> &lexenv)
932 {
933     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
934     JSHandle<JSFunction> propFunc = factory->CreateSFunctionFromTemplate(funcTemp);
935     propFunc->SetHomeObject(thread, homeObject);
936     propFunc->SetLexicalEnv(thread, lexenv);
937     ASSERT(!propFunc->GetClass()->IsExtensible());
938     return propFunc;
939 }
940 
AddFieldTypeToDict(JSThread * thread,const JSHandle<TaggedArray> & fieldTypeArray,uint32_t length,JSMutableHandle<NameDictionary> & dict,JSHandle<NumberDictionary> & elementsDic,bool & hasElement,PropertyAttributes attributes)941 void SendableClassDefiner::AddFieldTypeToDict(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray,
942                                               uint32_t length, JSMutableHandle<NameDictionary> &dict,
943                                               JSHandle<NumberDictionary> &elementsDic, bool &hasElement,
944                                               PropertyAttributes attributes)
945 {
946     ASSERT(length <= fieldTypeArray->GetLength());
947     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
948     auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
949     JSHandle<JSTaggedValue> value = globalConst->GetHandledUndefined();
950 
951     JSMutableHandle<NumberDictionary> elementsDicUpdate(thread, elementsDic);
952     JSHandle<JSTaggedValue> undefinedVal = thread->GlobalConstants()->GetHandledUndefined();
953     JSMutableHandle<JSTaggedValue> eleIndexKey(thread, JSTaggedValue::Undefined());
954 
955     for (uint32_t i = 0; i < length; i += 2) { // 2: key-value pair;
956         key.Update(fieldTypeArray->Get(i));
957         ASSERT(key->IsString());
958         SharedFieldType type = FromFieldType(FieldType(fieldTypeArray->Get(i + 1).GetInt()));
959         attributes.SetSharedFieldType(type);
960         attributes.SetBoxType(PropertyBoxType::UNDEFINED);
961         int64_t eleIndex = ObjectFastOperator::TryToElementsIndex(key.GetTaggedValue());
962         if (eleIndex >= 0) {
963             eleIndexKey.Update(JSTaggedValue(eleIndex));
964             JSHandle<NumberDictionary> newElementsDic = NumberDictionary::Put(
965                 thread, elementsDic, eleIndexKey, undefinedVal, attributes);
966             elementsDicUpdate.Update(newElementsDic);
967             if (!hasElement) {
968                 hasElement = true;
969             }
970         } else {
971             JSHandle<NameDictionary> newDict = NameDictionary::Put(thread, dict, key, value, attributes);
972             dict.Update(newDict);
973         }
974     }
975 }
976 
AddFieldTypeToHClass(JSThread * thread,const JSHandle<TaggedArray> & fieldTypeArray,uint32_t length,const JSHandle<LayoutInfo> & layout,const JSHandle<JSHClass> & hclass,JSHandle<NumberDictionary> & elementsDic,bool & hasElement,size_t start,std::vector<JSHandle<JSTaggedValue>> && propertyList)977 void SendableClassDefiner::AddFieldTypeToHClass(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray,
978                                                 uint32_t length, const JSHandle<LayoutInfo> &layout,
979                                                 const JSHandle<JSHClass> &hclass,
980                                                 JSHandle<NumberDictionary> &elementsDic,
981                                                 bool &hasElement, size_t start,
982                                                 std::vector<JSHandle<JSTaggedValue>> &&propertyList)
983 {
984     ASSERT(length <= fieldTypeArray->GetLength());
985     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
986     uint32_t index = static_cast<uint32_t>(layout->NumberOfElements());
987 
988     JSMutableHandle<NumberDictionary> elementsDicUpdate(thread, elementsDic);
989     JSHandle<JSTaggedValue> undefinedVal = thread->GlobalConstants()->GetHandledUndefined();
990     JSMutableHandle<JSTaggedValue> eleIndexKey(thread, JSTaggedValue::Undefined());
991     for (uint32_t i = 0; i < length; i += 2) { // 2: key-value pair;
992         PropertyAttributes attributes = PropertyAttributes::Default(true, true, false);
993         key.Update(fieldTypeArray->Get(i));
994         ASSERT(key->IsString());
995         SharedFieldType type = FromFieldType(FieldType(fieldTypeArray->Get(i + 1).GetInt()));
996         int entry = layout->FindElementWithCache(thread, *hclass, key.GetTaggedValue(), index);
997         if (entry != -1) {
998             attributes = layout->GetAttr(entry);
999             attributes.SetSharedFieldType(type);
1000             layout->SetNormalAttr(thread, entry, attributes);
1001             if (start != ~0U && propertyList.size() > 0) {
1002                 propertyList[start + (static_cast<uint32_t>(entry) << 1)] = propertyList[start + i];
1003                 propertyList[start + (static_cast<uint32_t>(entry) << 1) + 1] = propertyList[start + i + 1];
1004             }
1005         } else {
1006             int64_t eleIndex = ObjectFastOperator::TryToElementsIndex(key.GetTaggedValue());
1007             if (eleIndex < 0 && start != ~0U && propertyList.size() > 0) {
1008                 propertyList[start + (index << 1)] = propertyList[start + i];
1009                 propertyList[start + (index << 1) + 1] = propertyList[start + i + 1];
1010             }
1011             attributes.SetIsInlinedProps(true);
1012             attributes.SetRepresentation(Representation::TAGGED);
1013             attributes.SetSharedFieldType(type);
1014             attributes.SetOffset(index);
1015             if (eleIndex >= 0) {
1016                 if (propertyList.size() > 0) {
1017                     undefinedVal = propertyList[start + i + 1];
1018                 }
1019                 eleIndexKey.Update(JSTaggedValue(eleIndex));
1020                 JSHandle<NumberDictionary> newElementsDic = NumberDictionary::Put(
1021                     thread, elementsDic, eleIndexKey, undefinedVal, attributes);
1022                 elementsDicUpdate.Update(newElementsDic);
1023                 if (!hasElement) {
1024                     hasElement = true;
1025                 }
1026             } else {
1027                 layout->AddKey(thread, index++, key.GetTaggedValue(), attributes);
1028             }
1029         }
1030     }
1031     hclass->SetLayout(thread, layout);
1032     hclass->SetNumberOfProps(index);
1033     auto inlinedProps = hclass->GetInlinedProperties();
1034     if (inlinedProps > index) {
1035         // resize hclass due to duplicated key.
1036         uint32_t duplicatedSize = (inlinedProps - index) * JSTaggedValue::TaggedTypeSize();
1037         hclass->SetObjectSize(hclass->GetObjectSize() - duplicatedSize);
1038     }
1039 }
1040 
AddFieldTypeToHClass(JSThread * thread,const JSHandle<TaggedArray> & fieldTypeArray,uint32_t length,const JSHandle<NameDictionary> & nameDict,const JSHandle<JSHClass> & hclass,JSHandle<NumberDictionary> & elementsDic,bool & hasElement)1041 void SendableClassDefiner::AddFieldTypeToHClass(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray,
1042                                                 uint32_t length, const JSHandle<NameDictionary> &nameDict,
1043                                                 const JSHandle<JSHClass> &hclass,
1044                                                 JSHandle<NumberDictionary> &elementsDic,
1045                                                 bool &hasElement)
1046 {
1047     JSMutableHandle<NameDictionary> dict(thread, nameDict);
1048     AddFieldTypeToDict(thread, fieldTypeArray, length, dict, elementsDic, hasElement);
1049     hclass->SetLayout(thread, dict);
1050     hclass->SetNumberOfProps(0);
1051     hclass->SetIsDictionaryMode(true);
1052 }
1053 
DefineSendableInstanceHClass(JSThread * thread,const JSHandle<TaggedArray> & fieldTypeArray,uint32_t length,const JSHandle<JSFunction> & ctor,const JSHandle<JSTaggedValue> & base)1054 void SendableClassDefiner::DefineSendableInstanceHClass(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray,
1055     uint32_t length, const JSHandle<JSFunction> &ctor, const JSHandle<JSTaggedValue> &base)
1056 {
1057     ASSERT(ctor->GetClass()->IsJSSharedFunction());
1058     JSHandle<JSObject> clsPrototype(thread, JSHandle<JSFunction>(ctor)->GetFunctionPrototype());
1059     ASSERT(clsPrototype->GetClass()->IsJSSharedObject());
1060     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1061     ASSERT(length <= fieldTypeArray->GetLength());
1062     uint32_t fieldNum = length / 2; // 2: key-value pair;
1063     JSHandle<JSHClass> iHClass;
1064     JSHandle<NumberDictionary> elementsDic = NumberDictionary::CreateInSharedHeap(thread);
1065     bool hasElement = false;
1066     if (base->IsHole() || base->IsNull()) {
1067         if (fieldNum == 0) {
1068             iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum);
1069         } else if (LIKELY(fieldNum <= JSSharedObject::MAX_INLINE)) {
1070             iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum);
1071             JSHandle<LayoutInfo> layout = factory->CreateSLayoutInfo(fieldNum);
1072             AddFieldTypeToHClass(thread, fieldTypeArray, length, layout, iHClass, elementsDic, hasElement, ~0U);
1073         } else {
1074             iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0);
1075             JSHandle<NameDictionary> dict =
1076                 NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(fieldNum));
1077             AddFieldTypeToHClass(thread, fieldTypeArray, length, dict, iHClass, elementsDic, hasElement);
1078         }
1079     } else {
1080         ASSERT(base->IsJSSharedFunction());
1081         JSHandle<JSFunction> baseCtor = JSHandle<JSFunction>::Cast(base);
1082         JSHandle<JSHClass> baseIHClass(thread, baseCtor->GetProtoOrHClass());
1083         ASSERT(baseIHClass->IsJSShared());
1084         JSType baseType = baseIHClass->GetObjectType();
1085         const auto [baseSize, baseMaxInlineSize] = GetSizeAndMaxInlineByType(baseType);
1086         if (LIKELY(!baseIHClass->IsDictionaryMode())) {
1087             auto baseLength = baseIHClass->NumberOfProps();
1088             JSHandle<LayoutInfo> baseLayout(thread, baseIHClass->GetLayout());
1089             auto newLength = baseLength + fieldNum;
1090             if (newLength == 0) {
1091                 iHClass = factory->NewSEcmaHClass(baseSize, baseType, 0);
1092             } else if (LIKELY(newLength <= baseMaxInlineSize)) {
1093                 iHClass = factory->NewSEcmaHClass(baseSize, baseType, newLength);
1094                 JSHandle<LayoutInfo> layout = factory->CopyAndReSortSLayoutInfo(baseLayout, baseLength, newLength);
1095                 AddFieldTypeToHClass(thread, fieldTypeArray, length, layout, iHClass, elementsDic, hasElement, ~0U);
1096             } else {
1097                 iHClass = factory->NewSEcmaHClass(baseSize, baseType, 0);
1098                 JSHandle<NameDictionary> dict =
1099                     NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(newLength));
1100                 auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
1101                 JSHandle<JSTaggedValue> value = globalConst->GetHandledUndefined();
1102                 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1103                 for (uint32_t i = 0; i < baseLength; i++) {
1104                     key.Update(baseLayout->GetKey(i));
1105                     PropertyAttributes attr = baseLayout->GetAttr(i);
1106                     attr.SetIsInlinedProps(false);
1107                     attr.SetBoxType(PropertyBoxType::UNDEFINED);
1108                     dict = NameDictionary::Put(thread, dict, key, value, attr);
1109                 }
1110                 AddFieldTypeToHClass(thread, fieldTypeArray, length, dict, iHClass, elementsDic, hasElement);
1111             }
1112         } else {
1113             JSHandle<NameDictionary> baseDict(thread, baseIHClass->GetLayout());
1114             auto baseLength = baseDict->EntriesCount();
1115             auto newLength = fieldNum + static_cast<uint32_t>(baseLength);
1116             JSHandle<NameDictionary> dict =
1117                 NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(newLength));
1118             baseDict->Rehash(thread, *dict);
1119             dict->SetNextEnumerationIndex(thread, baseDict->GetNextEnumerationIndex());
1120             iHClass = factory->NewSEcmaHClass(baseSize, baseType, 0);
1121             AddFieldTypeToHClass(thread, fieldTypeArray, length, dict, iHClass, elementsDic, hasElement);
1122         }
1123     }
1124     if (hasElement) {
1125         JSHandle<JSObject>::Cast(ctor)->SetPropertyInlinedProps(
1126             thread, ClassInfoExtractor::SENDABLE_ELEMENTS_INDEX, elementsDic.GetTaggedValue());
1127     }
1128     iHClass->SetPrototype(thread, JSHandle<JSTaggedValue>(clsPrototype));
1129     iHClass->SetExtensible(false);
1130     ctor->SetProtoOrHClass(thread, iHClass);
1131     ctor->GetJSHClass()->SetExtensible(false);
1132 }
1133 
ExtractStaticFieldTypeArray(JSThread * thread,const JSHandle<TaggedArray> & fieldTypeArray)1134 JSHandle<TaggedArray> SendableClassDefiner::ExtractStaticFieldTypeArray(JSThread *thread,
1135     const JSHandle<TaggedArray> &fieldTypeArray)
1136 {
1137     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1138     uint32_t arrayLength = fieldTypeArray->GetLength();
1139     ASSERT(arrayLength > 0);
1140     auto instanceFieldNums = static_cast<uint32_t>(fieldTypeArray->Get(arrayLength - 1).GetInt());
1141     uint32_t staticFieldBegin = instanceFieldNums * 2; // 2: key-type
1142     if (staticFieldBegin >= arrayLength) {
1143         LOG_ECMA(ERROR) << "ExtractStaticFieldTypeArray Failed, staticFieldBegin:" << staticFieldBegin
1144                         << " should be less than totalLength:" << arrayLength;
1145         return factory->EmptyArray();
1146     }
1147     uint32_t staticFieldLength = arrayLength - staticFieldBegin - 1;
1148     JSHandle<TaggedArray> staticFieldArray = factory->NewTaggedArray(staticFieldLength);
1149     for (uint32_t i = 0; i < staticFieldLength; i += 2) {  // 2: key-type
1150         staticFieldArray->Set(thread, i, fieldTypeArray->Get(staticFieldBegin + i));
1151         staticFieldArray->Set(thread, i + 1, fieldTypeArray->Get(staticFieldBegin + i + 1));
1152     }
1153     return staticFieldArray;
1154 }
1155 
UpdateAccessorFunction(JSThread * thread,const JSMutableHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & homeObject,const JSHandle<JSFunction> & ctor)1156 void SendableClassDefiner::UpdateAccessorFunction(JSThread *thread, const JSMutableHandle<JSTaggedValue> &value,
1157     const JSHandle<JSTaggedValue> &homeObject, const JSHandle<JSFunction> &ctor)
1158 {
1159     ASSERT(value->IsAccessorData());
1160     JSHandle<AccessorData> accessor(value);
1161     auto getter = accessor->GetGetter();
1162     if (getter.IsFunctionTemplate()) {
1163         auto funcTemp = JSHandle<FunctionTemplate>(thread, getter);
1164         auto propFunc = CreateSFunctionFromTemplate(
1165             thread, funcTemp, JSHandle<JSObject>(homeObject), JSHandle<JSTaggedValue>(ctor));
1166         accessor->SetGetter(thread, propFunc);
1167     }
1168     auto setter = accessor->GetSetter();
1169     if (setter.IsFunctionTemplate()) {
1170         auto funcTemp = JSHandle<FunctionTemplate>(thread, setter);
1171         auto propFunc = CreateSFunctionFromTemplate(
1172             thread, funcTemp, JSHandle<JSObject>(homeObject), JSHandle<JSTaggedValue>(ctor));
1173         accessor->SetSetter(thread, propFunc);
1174     }
1175 }
1176 
TryUpdateExistValue(JSThread * thread,JSMutableHandle<JSTaggedValue> & existValue,JSMutableHandle<JSTaggedValue> & value)1177 bool SendableClassDefiner::TryUpdateExistValue(JSThread *thread, JSMutableHandle<JSTaggedValue> &existValue,
1178                                                JSMutableHandle<JSTaggedValue> &value)
1179 {
1180     bool needUpdateValue = true;
1181     if (existValue->IsAccessorData()) {
1182         if (value->IsFunctionTemplate() && JSHandle<FunctionTemplate>(value)->IsGetterOrSetter()) {
1183             JSHandle<AccessorData> accessor(existValue);
1184             UpdateValueToAccessor(thread, value, accessor);
1185             needUpdateValue = false;
1186         }
1187     } else {
1188         if (value->IsFunctionTemplate() && JSHandle<FunctionTemplate>(value)->IsGetterOrSetter()) {
1189             JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData();
1190             UpdateValueToAccessor(thread, value, accessor);
1191         }
1192     }
1193     return needUpdateValue;
1194 }
1195 
TryUpdateValue(JSThread * thread,JSMutableHandle<JSTaggedValue> & value)1196 void SendableClassDefiner::TryUpdateValue(JSThread *thread, JSMutableHandle<JSTaggedValue> &value)
1197 {
1198     if (value->IsFunctionTemplate() && JSHandle<FunctionTemplate>(value)->IsGetterOrSetter()) {
1199         JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData();
1200         UpdateValueToAccessor(thread, value, accessor);
1201     }
1202 }
1203 
UpdateValueToAccessor(JSThread * thread,JSMutableHandle<JSTaggedValue> & value,JSHandle<AccessorData> & accessor)1204 void SendableClassDefiner::UpdateValueToAccessor(JSThread *thread, JSMutableHandle<JSTaggedValue> &value,
1205                                                  JSHandle<AccessorData> &accessor)
1206 {
1207     ASSERT(value->IsFunctionTemplate() && JSHandle<FunctionTemplate>(value)->IsGetterOrSetter());
1208     if (JSHandle<FunctionTemplate>(value)->IsGetter()) {
1209         accessor->SetGetter(thread, value);
1210     } else {
1211         accessor->SetSetter(thread, value);
1212     }
1213     value.Update(accessor);
1214 }
1215 
GetSizeAndMaxInlineByType(JSType type)1216 std::pair<uint32_t, uint32_t> SendableClassDefiner::GetSizeAndMaxInlineByType(JSType type)
1217 {
1218     switch (type) {
1219         case JSType::JS_SHARED_OBJECT:
1220             return { JSSharedObject::SIZE, JSSharedObject::MAX_INLINE };
1221         case JSType::JS_SHARED_ARRAY:
1222             return { JSSharedArray::SIZE, JSSharedArray::MAX_INLINE };
1223         case JSType::JS_SHARED_MAP:
1224             return { JSSharedMap::SIZE, JSSharedMap::MAX_INLINE };
1225         case JSType::JS_SHARED_SET:
1226             return { JSSharedSet::SIZE, JSSharedSet::MAX_INLINE };
1227         case JSType::JS_SENDABLE_ARRAY_BUFFER:
1228             return { JSSendableArrayBuffer::SIZE, JSSendableArrayBuffer::MAX_INLINE };
1229         case JSType::JS_API_BITVECTOR:
1230             return { JSAPIBitVector::SIZE, JSAPIBitVector::MAX_INLINE };
1231         default:
1232             if (JSType::JS_SHARED_TYPED_ARRAY_FIRST < type && type <= JSType::JS_SHARED_TYPED_ARRAY_LAST) {
1233                 return { JSSharedTypedArray::SIZE, JSSharedTypedArray::MAX_INLINE };
1234             }
1235             LOG_ECMA(FATAL) << "this branch is unreachable, cannot get size for type: " << static_cast<uint32_t>(type);
1236             UNREACHABLE();
1237             return {};
1238     }
1239 }
1240 }  // namespace panda::ecmascript
1241