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