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