1 /*
2 * Copyright (c) 2023 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/compiler/builtins/builtins_object_stub_builder.h"
17
18 #include "ecmascript/compiler/circuit_builder_helper.h"
19 #include "ecmascript/compiler/new_object_stub_builder.h"
20 #include "ecmascript/compiler/stub_builder-inl.h"
21 #include "ecmascript/compiler/typed_array_stub_builder.h"
22 #include "ecmascript/js_arguments.h"
23 #include "ecmascript/js_primitive_ref.h"
24 #include "ecmascript/message_string.h"
25 #include "ecmascript/tagged_dictionary.h"
26
27 namespace panda::ecmascript::kungfu {
CreateListFromArrayLike(GateRef glue,GateRef arrayObj)28 GateRef BuiltinsObjectStubBuilder::CreateListFromArrayLike(GateRef glue, GateRef arrayObj)
29 {
30 auto env = GetEnvironment();
31 Label entry(env);
32 env->SubCfgEntry(&entry);
33 DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
34 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
35 Label exit(env);
36
37 // 3. If Type(obj) is Object, throw a TypeError exception.
38 Label targetIsHeapObject(env);
39 Label targetIsEcmaObject(env);
40 Label targetNotEcmaObject(env);
41 Branch(TaggedIsHeapObject(arrayObj), &targetIsHeapObject, &targetNotEcmaObject);
42 Bind(&targetIsHeapObject);
43 Branch(TaggedObjectIsEcmaObject(arrayObj), &targetIsEcmaObject, &targetNotEcmaObject);
44 Bind(&targetNotEcmaObject);
45 {
46 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
47 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
48 Jump(&exit);
49 }
50 Bind(&targetIsEcmaObject);
51 {
52 // 4. Let len be ToLength(Get(obj, "length")).
53 GateRef lengthString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
54 ConstantIndex::LENGTH_STRING_INDEX);
55 GateRef value = FastGetPropertyByName(glue, arrayObj, lengthString, ProfileOperation());
56 GateRef number = ToLength(glue, value);
57 // 5. ReturnIfAbrupt(len).
58 Label isPendingException1(env);
59 Label noPendingException1(env);
60 Branch(HasPendingException(glue), &isPendingException1, &noPendingException1);
61 Bind(&isPendingException1);
62 {
63 Jump(&exit);
64 }
65 Bind(&noPendingException1);
66 {
67 Label indexInRange(env);
68 Label indexOutRange(env);
69
70 GateRef doubleLen = GetDoubleOfTNumber(number);
71 Branch(DoubleGreaterThan(doubleLen, Double(JSObject::MAX_ELEMENT_INDEX)), &indexOutRange, &indexInRange);
72 Bind(&indexOutRange);
73 {
74 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(LenGreaterThanMax));
75 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
76 Jump(&exit);
77 }
78 Bind(&indexInRange);
79 {
80 GateRef int32Len = DoubleToInt(glue, doubleLen);
81 // 6. Let list be an empty List.
82 NewObjectStubBuilder newBuilder(this);
83 GateRef array = newBuilder.NewTaggedArray(glue, int32Len);
84 Label targetIsTypeArray(env);
85 Label targetNotTypeArray(env);
86 Branch(IsTypedArray(arrayObj), &targetIsTypeArray, &targetNotTypeArray);
87 Bind(&targetIsTypeArray);
88 {
89 TypedArrayStubBuilder arrayStubBuilder(this);
90 arrayStubBuilder.FastCopyElementToArray(glue, arrayObj, array);
91 // c. ReturnIfAbrupt(next).
92 Label isPendingException2(env);
93 Label noPendingException2(env);
94 Branch(HasPendingException(glue), &isPendingException2, &noPendingException2);
95 Bind(&isPendingException2);
96 {
97 Jump(&exit);
98 }
99 Bind(&noPendingException2);
100 {
101 res = array;
102 Jump(&exit);
103 }
104 }
105 Bind(&targetNotTypeArray);
106 // 8. Repeat while index < len
107 Label loopHead(env);
108 Label loopEnd(env);
109 Label afterLoop(env);
110 Label isPendingException3(env);
111 Label noPendingException3(env);
112 Label storeValue(env);
113 Jump(&loopHead);
114 LoopBegin(&loopHead);
115 {
116 Branch(Int32UnsignedLessThan(*index, int32Len), &storeValue, &afterLoop);
117 Bind(&storeValue);
118 {
119 GateRef next = FastGetPropertyByIndex(glue, arrayObj, *index, ProfileOperation());
120 // c. ReturnIfAbrupt(next).
121 Branch(HasPendingException(glue), &isPendingException3, &noPendingException3);
122 Bind(&isPendingException3);
123 {
124 Jump(&exit);
125 }
126 Bind(&noPendingException3);
127 SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, next);
128 index = Int32Add(*index, Int32(1));
129 Jump(&loopEnd);
130 }
131 }
132 Bind(&loopEnd);
133 LoopEnd(&loopHead);
134 Bind(&afterLoop);
135 {
136 res = array;
137 Jump(&exit);
138 }
139 }
140 }
141 }
142 Bind(&exit);
143 GateRef ret = *res;
144 env->SubCfgExit();
145 return ret;
146 }
147
CreateArrayFromList(GateRef glue,GateRef elements)148 GateRef BuiltinsObjectStubBuilder::CreateArrayFromList(GateRef glue, GateRef elements)
149 {
150 auto env = GetEnvironment();
151 DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
152 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
153 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
154 auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
155 GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
156 GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
157 NewObjectStubBuilder newBuilder(this);
158 newBuilder.SetParameters(glue, 0);
159 GateRef len = GetLengthOfTaggedArray(elements);
160 result = newBuilder.NewJSObject(glue, intialHClass);
161 SetPropertyInlinedProps(glue, *result, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
162 SetArrayLength(glue, *result, len);
163 SetExtensibleToBitfield(glue, *result, true);
164 SetElementsArray(VariableType::JS_POINTER(), glue_, *result, elements);
165 auto res = *result;
166 return res;
167 }
168
ToString(Variable * result,Label * exit,Label * slowPath)169 void BuiltinsObjectStubBuilder::ToString(Variable *result, Label *exit, Label *slowPath)
170 {
171 auto env = GetEnvironment();
172 Label ecmaObj(env);
173 // undefined
174 Label undefined(env);
175 Label checknull(env);
176 Branch(TaggedIsUndefined(thisValue_), &undefined, &checknull);
177 Bind(&undefined);
178 {
179 *result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::UNDEFINED_TO_STRING_INDEX);
180 Jump(exit);
181 }
182 // null
183 Bind(&checknull);
184 Label null(env);
185 Label checkObject(env);
186 Branch(TaggedIsUndefined(thisValue_), &null, &checkObject);
187 Bind(&null);
188 {
189 *result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::NULL_TO_STRING_INDEX);
190 Jump(exit);
191 }
192
193 Bind(&checkObject);
194 Branch(IsEcmaObject(thisValue_), &ecmaObj, slowPath);
195 Bind(&ecmaObj);
196 {
197 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
198 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
199 GateRef toStringTagSymbol = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
200 GlobalEnv::TOSTRINGTAG_SYMBOL_INDEX);
201 GateRef tag = FastGetPropertyByName(glue_, thisValue_, toStringTagSymbol, ProfileOperation());
202
203 Label defaultToString(env);
204 Branch(TaggedIsString(tag), slowPath, &defaultToString);
205 Bind(&defaultToString);
206 {
207 // default object
208 Label objectTag(env);
209 Branch(IsJSObjectType(thisValue_, JSType::JS_OBJECT), &objectTag, slowPath);
210 Bind(&objectTag);
211 {
212 // [object object]
213 *result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
214 ConstantIndex::OBJECT_TO_STRING_INDEX);
215 Jump(exit);
216 }
217 }
218 }
219 }
220
TransProtoWithoutLayout(GateRef hClass,GateRef proto)221 GateRef BuiltinsObjectStubBuilder::TransProtoWithoutLayout(GateRef hClass, GateRef proto)
222 {
223 auto env = GetEnvironment();
224 Label entry(env);
225 env->SubCfgEntry(&entry);
226 Label exit(env);
227 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
228
229 GateRef key = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
230 ConstantIndex::PROTOTYPE_STRING_INDEX);
231 GateRef newClass = CallNGCRuntime(glue_, RTSTUB_ID(JSHClassFindProtoTransitions), { hClass, key, proto });
232 Label undef(env);
233 Label find(env);
234 Branch(IntPtrEqual(TaggedCastToIntPtr(newClass), IntPtr(0)), &undef, &find);
235 Bind(&find);
236 {
237 result = newClass;
238 Jump(&exit);
239 }
240 Bind(&undef);
241 {
242 result = CallRuntime(glue_, RTSTUB_ID(HClassCloneWithAddProto), { hClass, key, proto });
243 Jump(&exit);
244 }
245 Bind(&exit);
246 auto ret = *result;
247 env->SubCfgExit();
248 return ret;
249 }
250
OrdinaryNewJSObjectCreate(GateRef proto)251 GateRef BuiltinsObjectStubBuilder::OrdinaryNewJSObjectCreate(GateRef proto)
252 {
253 auto env = GetEnvironment();
254 Label entry(env);
255 env->SubCfgEntry(&entry);
256 Label exit(env);
257 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
258
259 GateRef hClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
260 ConstantIndex::OBJECT_HCLASS_INDEX);
261 GateRef newClass = TransProtoWithoutLayout(hClass, proto);
262 Label exception(env);
263 Label noexception(env);
264 Branch(TaggedIsException(newClass), &exception, &noexception);
265 Bind(&exception);
266 {
267 result = Exception();
268 Jump(&exit);
269 }
270 Bind(&noexception);
271 NewObjectStubBuilder newBuilder(this);
272 GateRef newObj = newBuilder.NewJSObject(glue_, newClass);
273 Label exceptionNewObj(env);
274 Label noexceptionNewObj(env);
275 Branch(TaggedIsException(newObj), &exceptionNewObj, &noexceptionNewObj);
276 Bind(&exceptionNewObj);
277 {
278 result = Exception();
279 Jump(&exit);
280 }
281 Bind(&noexceptionNewObj);
282 {
283 SetExtensibleToBitfield(glue_, newObj, True());
284 result = newObj;
285 Jump(&exit);
286 }
287 Bind(&exit);
288 auto ret = *result;
289 env->SubCfgExit();
290 return ret;
291 }
292
Create(Variable * result,Label * exit,Label * slowPath)293 void BuiltinsObjectStubBuilder::Create(Variable *result, Label *exit, Label *slowPath)
294 {
295 auto env = GetEnvironment();
296 Label newObject(env);
297
298 GateRef proto = GetCallArg0(numArgs_);
299 GateRef protoIsNull = TaggedIsNull(proto);
300 GateRef protoIsEcmaObj = IsEcmaObject(proto);
301 GateRef protoIsJSShared = TaggedIsShared(proto);
302 Branch(BoolOr(BoolAnd(BoolNot(protoIsEcmaObj), BoolNot(protoIsNull)), protoIsJSShared), slowPath, &newObject);
303 Bind(&newObject);
304 {
305 Label noProperties(env);
306 GateRef propertiesObject = GetCallArg1(numArgs_);
307 Branch(TaggedIsUndefined(propertiesObject), &noProperties, slowPath);
308 Bind(&noProperties);
309 {
310 // OrdinaryNewJSObjectCreate
311 *result = OrdinaryNewJSObjectCreate(proto);
312 Jump(exit);
313 }
314 }
315 }
316
AssignEnumElementProperty(Variable * result,Label * funcExit,GateRef toAssign,GateRef source)317 void BuiltinsObjectStubBuilder::AssignEnumElementProperty(Variable *result, Label *funcExit,
318 GateRef toAssign, GateRef source)
319 {
320 auto env = GetEnvironment();
321 Label entryLabel(env);
322 env->SubCfgEntry(&entryLabel);
323 Label exit(env);
324
325 GateRef elements = GetElementsArray(source);
326 Label dictionaryMode(env);
327 Label notDictionaryMode(env);
328 Branch(IsDictionaryMode(elements), &dictionaryMode, ¬DictionaryMode);
329 Bind(¬DictionaryMode);
330 {
331 GateRef len = GetLengthOfTaggedArray(elements);
332 DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
333 Label loopHead(env);
334 Label loopEnd(env);
335 Label next(env);
336 Label loopExit(env);
337
338 Jump(&loopHead);
339 LoopBegin(&loopHead);
340 {
341 Branch(Int32LessThan(*idx, len), &next, &loopExit);
342 Bind(&next);
343 GateRef value = GetValueFromTaggedArray(elements, *idx);
344 Label notHole(env);
345 Branch(TaggedIsHole(value), &loopEnd, ¬Hole);
346 Bind(¬Hole);
347 {
348 // key, value
349 FastSetPropertyByIndex(glue_, toAssign, *idx, value);
350 Label exception(env);
351 Branch(HasPendingException(glue_), &exception, &loopEnd);
352 Bind(&exception);
353 {
354 *result = Exception();
355 Jump(funcExit);
356 }
357 }
358 }
359 Bind(&loopEnd);
360 idx = Int32Add(*idx, Int32(1));
361 LoopEnd(&loopHead);
362 Bind(&loopExit);
363 Jump(&exit);
364 }
365 Bind(&dictionaryMode);
366 {
367 // NumberDictionary::VisitAllEnumProperty
368 GateRef sizeIndex = Int32(TaggedHashTable<NumberDictionary>::SIZE_INDEX);
369 GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(elements, sizeIndex));
370 DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
371 Label loopHead(env);
372 Label loopEnd(env);
373 Label next(env);
374 Label loopExit(env);
375
376 Jump(&loopHead);
377 LoopBegin(&loopHead);
378 {
379 Branch(Int32LessThan(*idx, size), &next, &loopExit);
380 Bind(&next);
381 GateRef key = GetKeyFromDictionary<NumberDictionary>(elements, *idx);
382 Label checkEnumerable(env);
383 Branch(BoolOr(TaggedIsUndefined(key), TaggedIsHole(key)), &loopEnd, &checkEnumerable);
384 Bind(&checkEnumerable);
385 {
386 GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, *idx);
387 Label enumerable(env);
388 Branch(IsEnumerable(attr), &enumerable, &loopEnd);
389 Bind(&enumerable);
390 {
391 GateRef value = GetValueFromDictionary<NumberDictionary>(elements, *idx);
392 Label notHole(env);
393 Branch(TaggedIsHole(value), &loopEnd, ¬Hole);
394 Bind(¬Hole);
395 {
396 // value
397 FastSetPropertyByIndex(glue_, toAssign, *idx, value);
398 Label exception(env);
399 Branch(HasPendingException(glue_), &exception, &loopEnd);
400 Bind(&exception);
401 {
402 *result = Exception();
403 Jump(funcExit);
404 }
405 }
406 }
407 }
408 }
409 Bind(&loopEnd);
410 idx = Int32Add(*idx, Int32(1));
411 LoopEnd(&loopHead);
412 Bind(&loopExit);
413 Jump(&exit);
414 }
415 Bind(&exit);
416 env->SubCfgExit();
417 }
418
LayoutInfoAssignAllEnumProperty(Variable * result,Label * funcExit,GateRef toAssign,GateRef source)419 void BuiltinsObjectStubBuilder::LayoutInfoAssignAllEnumProperty(Variable *result, Label *funcExit,
420 GateRef toAssign, GateRef source)
421 {
422 auto env = GetEnvironment();
423 Label entryLabel(env);
424 env->SubCfgEntry(&entryLabel);
425 Label exit(env);
426
427 // LayoutInfo::VisitAllEnumProperty
428 GateRef cls = LoadHClass(source);
429 GateRef num = GetNumberOfPropsFromHClass(cls);
430 GateRef layout = GetLayoutFromHClass(cls);
431 DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
432 Label loopHead(env);
433 Label loopEnd(env);
434 Label next(env);
435 Label loopExit(env);
436
437 Jump(&loopHead);
438 LoopBegin(&loopHead);
439 {
440 Branch(Int32LessThan(*idx, num), &next, &loopExit);
441 Bind(&next);
442
443 GateRef key = GetKeyFromLayoutInfo(layout, *idx);
444 GateRef attr = TruncInt64ToInt32(GetPropAttrFromLayoutInfo(layout, *idx));
445 Label stringKey(env);
446 Branch(TaggedIsString(key), &stringKey, &loopEnd);
447 Bind(&stringKey);
448 {
449 Label enumerable(env);
450 Branch(IsEnumerable(attr), &enumerable, &loopEnd);
451 Bind(&enumerable);
452 {
453 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
454 value = JSObjectGetProperty(source, cls, attr);
455 // exception
456 Label exception0(env);
457 Label noexception0(env);
458 Branch(HasPendingException(glue_), &exception0, &noexception0);
459 Bind(&exception0);
460 {
461 *result = Exception();
462 Jump(funcExit);
463 }
464 Bind(&noexception0);
465 Label propertyBox(env);
466 Label checkAccessor(env);
467 Label setValue(env);
468 Branch(TaggedIsPropertyBox(*value), &propertyBox, &checkAccessor);
469 Bind(&propertyBox);
470 {
471 value = GetValueFromPropertyBox(*value);
472 Jump(&setValue);
473 }
474 Bind(&checkAccessor);
475 Label isAccessor(env);
476 Branch(IsAccessor(attr), &isAccessor, &setValue);
477 Bind(&isAccessor);
478 {
479 value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
480 Label exception(env);
481 Branch(HasPendingException(glue_), &exception, &setValue);
482 Bind(&exception);
483 {
484 *result = Exception();
485 Jump(funcExit);
486 }
487 }
488 Bind(&setValue);
489 {
490 FastSetPropertyByName(glue_, toAssign, key, *value);
491 Label exception(env);
492 Branch(HasPendingException(glue_), &exception, &loopEnd);
493 Bind(&exception);
494 {
495 *result = Exception();
496 Jump(funcExit);
497 }
498 }
499 }
500 }
501 }
502 Bind(&loopEnd);
503 idx = Int32Add(*idx, Int32(1));
504 LoopEnd(&loopHead);
505 Bind(&loopExit);
506 Jump(&exit);
507
508 Bind(&exit);
509 env->SubCfgExit();
510 }
511
NameDictionaryAssignAllEnumProperty(Variable * result,Label * funcExit,GateRef toAssign,GateRef source,GateRef properties)512 void BuiltinsObjectStubBuilder::NameDictionaryAssignAllEnumProperty(Variable *result, Label *funcExit,
513 GateRef toAssign, GateRef source, GateRef properties)
514 {
515 // NameDictionary::VisitAllEnumProperty
516 auto env = GetEnvironment();
517 Label entryLabel(env);
518 env->SubCfgEntry(&entryLabel);
519 Label exit(env);
520
521 GateRef sizeIndex = Int32(TaggedHashTable<NameDictionary>::SIZE_INDEX);
522 GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(properties, sizeIndex));
523 DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
524 Label loopHead(env);
525 Label loopEnd(env);
526 Label next(env);
527 Label loopExit(env);
528
529 Jump(&loopHead);
530 LoopBegin(&loopHead);
531 {
532 Branch(Int32LessThan(*idx, size), &next, &loopExit);
533 Bind(&next);
534 GateRef key = GetKeyFromDictionary<NameDictionary>(properties, *idx);
535 Label stringKey(env);
536 Branch(TaggedIsString(key), &stringKey, &loopEnd);
537 Bind(&stringKey);
538 {
539 GateRef attr = GetAttributesFromDictionary<NameDictionary>(properties, *idx);
540 Label enumerable(env);
541 Branch(IsEnumerable(attr), &enumerable, &loopEnd);
542 Bind(&enumerable);
543 {
544 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
545 value = GetValueFromDictionary<NameDictionary>(properties, *idx);
546 Label notHole(env);
547 Branch(TaggedIsHole(*value), &loopEnd, ¬Hole);
548 Bind(¬Hole);
549 {
550 Label isAccessor(env);
551 Label notAccessor(env);
552 Branch(IsAccessor(attr), &isAccessor, ¬Accessor);
553 Bind(&isAccessor);
554 {
555 value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
556 // exception
557 Label exception(env);
558 Branch(HasPendingException(glue_), &exception, ¬Accessor);
559 Bind(&exception);
560 {
561 *result = Exception();
562 Jump(funcExit);
563 }
564 }
565 Bind(¬Accessor);
566 {
567 FastSetPropertyByName(glue_, toAssign, key, *value);
568 Label exception(env);
569 Branch(HasPendingException(glue_), &exception, &loopEnd);
570 Bind(&exception);
571 {
572 *result = Exception();
573 Jump(funcExit);
574 }
575 }
576 }
577 }
578 }
579 }
580 Bind(&loopEnd);
581 idx = Int32Add(*idx, Int32(1));
582 LoopEnd(&loopHead);
583 Bind(&loopExit);
584 Jump(&exit);
585
586 Bind(&exit);
587 env->SubCfgExit();
588 }
589
AssignAllEnumProperty(Variable * res,Label * funcExit,GateRef toAssign,GateRef source)590 void BuiltinsObjectStubBuilder::AssignAllEnumProperty(Variable *res, Label *funcExit,
591 GateRef toAssign, GateRef source)
592 {
593 auto env = GetEnvironment();
594 Label entryLabel(env);
595 env->SubCfgEntry(&entryLabel);
596 Label exit(env);
597
598 GateRef properties = GetPropertiesArray(source);
599 Label dictionaryMode(env);
600 Label notDictionaryMode(env);
601 Branch(IsDictionaryMode(properties), &dictionaryMode, ¬DictionaryMode);
602 Bind(¬DictionaryMode);
603 {
604 LayoutInfoAssignAllEnumProperty(res, funcExit, toAssign, source);
605 Jump(&exit);
606 }
607 Bind(&dictionaryMode);
608 {
609 NameDictionaryAssignAllEnumProperty(res, funcExit, toAssign, source, properties);
610 Jump(&exit);
611 }
612 Bind(&exit);
613 env->SubCfgExit();
614 }
615
SlowAssign(Variable * result,Label * funcExit,GateRef toAssign,GateRef source)616 void BuiltinsObjectStubBuilder::SlowAssign(Variable *result, Label *funcExit, GateRef toAssign, GateRef source)
617 {
618 auto env = GetEnvironment();
619 Label entryLabel(env);
620 env->SubCfgEntry(&entryLabel);
621 Label exit(env);
622 CallRuntime(glue_, RTSTUB_ID(ObjectSlowAssign), { toAssign, source });
623
624 Label exception(env);
625 Branch(HasPendingException(glue_), &exception, &exit);
626 Bind(&exception);
627 {
628 *result = Exception();
629 Jump(funcExit);
630 }
631 Bind(&exit);
632 env->SubCfgExit();
633 }
634
FastAssign(Variable * res,Label * funcExit,GateRef toAssign,GateRef source)635 void BuiltinsObjectStubBuilder::FastAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source)
636 {
637 // visit elements
638 AssignEnumElementProperty(res, funcExit, toAssign, source);
639 AssignAllEnumProperty(res, funcExit, toAssign, source);
640 }
641
Assign(Variable * res,Label * nextIt,Label * funcExit,GateRef toAssign,GateRef source)642 void BuiltinsObjectStubBuilder::Assign(Variable *res, Label *nextIt, Label *funcExit,
643 GateRef toAssign, GateRef source)
644 {
645 auto env = GetEnvironment();
646 Label checkJsObj(env);
647 Branch(BoolOr(TaggedIsNull(source), TaggedIsUndefined(source)), nextIt, &checkJsObj);
648 Bind(&checkJsObj);
649 {
650 Label fastAssign(env);
651 Label slowAssign(env);
652 Branch(IsJSObjectType(source, JSType::JS_OBJECT), &fastAssign, &slowAssign);
653 Bind(&fastAssign);
654 {
655 FastAssign(res, funcExit, toAssign, source);
656 Jump(nextIt);
657 }
658 Bind(&slowAssign);
659 {
660 SlowAssign(res, funcExit, toAssign, source);
661 Jump(nextIt);
662 }
663 }
664 }
665
Assign(Variable * result,Label * exit,Label * slowPath)666 void BuiltinsObjectStubBuilder::Assign(Variable *result, Label *exit, Label *slowPath)
667 {
668 auto env = GetEnvironment();
669 Label thisCollectionObj(env);
670
671 GateRef target = GetCallArg0(numArgs_);
672 *result = target;
673 Label jsObject(env);
674 Branch(IsJSObjectType(target, JSType::JS_OBJECT), &jsObject, slowPath);
675 Bind(&jsObject);
676 {
677 Label twoArg(env);
678 Label notTwoArg(env);
679 Branch(Int64Equal(numArgs_, IntPtr(2)), &twoArg, ¬TwoArg); // 2 : two args
680 Bind(&twoArg);
681 {
682 GateRef source = GetCallArg1(numArgs_);
683 Label next(env);
684 Assign(result, &next, exit, target, source);
685 Bind(&next);
686 Jump(exit);
687 }
688 Bind(¬TwoArg);
689 Label threeArg(env);
690 Label notThreeArg(env);
691 Branch(Int64Equal(numArgs_, IntPtr(3)), &threeArg, ¬ThreeArg); // 3 : three args
692 Bind(&threeArg);
693 {
694 Label nextArg(env);
695 GateRef source = GetCallArg1(numArgs_);
696 Label next(env);
697 Assign(result, &next, exit, target, source);
698 Bind(&next);
699 Label next1(env);
700 GateRef source1 = GetCallArg2(numArgs_);
701 Assign(result, &next1, exit, target, source1);
702 Bind(&next1);
703 Jump(exit);
704 }
705 Bind(¬ThreeArg);
706 {
707 Jump(slowPath);
708 }
709 }
710 }
711
HasOwnProperty(Variable * result,Label * exit,Label * slowPath)712 void BuiltinsObjectStubBuilder::HasOwnProperty(Variable *result, Label *exit, Label *slowPath)
713 {
714 auto env = GetEnvironment();
715 Label keyIsString(env);
716 Label valid(env);
717 Label isHeapObject(env);
718 GateRef prop = GetCallArg0(numArgs_);
719 Branch(TaggedIsHeapObject(thisValue_), &isHeapObject, slowPath);
720 Bind(&isHeapObject);
721 Branch(TaggedIsRegularObject(thisValue_), &valid, slowPath);
722 Bind(&valid);
723 {
724 Label isIndex(env);
725 Label notIndex(env);
726 Branch(TaggedIsString(prop), &keyIsString, slowPath); // 2 : two args
727 Bind(&keyIsString);
728 {
729 GateRef res = CallNGCRuntime(glue_, RTSTUB_ID(TryToElementsIndexOrFindInStringTable), { glue_, prop });
730 Branch(TaggedIsNumber(res), &isIndex, ¬Index);
731 Bind(&isIndex);
732 {
733 GateRef index = NumberGetInt(glue_, res);
734 Label findByIndex(env);
735 GateRef elements = GetElementsArray(thisValue_);
736 GateRef len = GetLengthOfTaggedArray(elements);
737 Branch(Int32Equal(len, Int32(0)), exit, &findByIndex);
738 Bind(&findByIndex);
739 {
740 Label isDictionaryElement(env);
741 Label notDictionaryElement(env);
742 Branch(IsDictionaryMode(elements), &isDictionaryElement, ¬DictionaryElement);
743 Bind(¬DictionaryElement);
744 {
745 Label lessThanLength(env);
746 Label notLessThanLength(env);
747 Branch(Int32UnsignedLessThanOrEqual(len, index), exit, &lessThanLength);
748 Bind(&lessThanLength);
749 {
750 Label notHole(env);
751 GateRef value = GetValueFromTaggedArray(elements, index);
752 Branch(TaggedIsNotHole(value), ¬Hole, exit);
753 Bind(¬Hole);
754 {
755 *result = TaggedTrue();
756 Jump(exit);
757 }
758 }
759 }
760 Bind(&isDictionaryElement);
761 {
762 GateRef entryA = FindElementFromNumberDictionary(glue_, elements, index);
763 Label notNegtiveOne(env);
764 Branch(Int32NotEqual(entryA, Int32(-1)), ¬NegtiveOne, exit);
765 Bind(¬NegtiveOne);
766 {
767 *result = TaggedTrue();
768 Jump(exit);
769 }
770 }
771 }
772 }
773 Bind(¬Index);
774 {
775 Label findInStringTabel(env);
776 Branch(TaggedIsHole(res), exit, &findInStringTabel);
777 Bind(&findInStringTabel);
778 {
779 Label isDicMode(env);
780 Label notDicMode(env);
781 GateRef hclass = LoadHClass(thisValue_);
782 Branch(IsDictionaryModeByHClass(hclass), &isDicMode, ¬DicMode);
783 Bind(¬DicMode);
784 {
785 GateRef layOutInfo = GetLayoutFromHClass(hclass);
786 GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
787 // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
788 GateRef entryA = FindElementWithCache(glue_, layOutInfo, hclass, res, propsNum);
789 Label hasEntry(env);
790 // if branch condition : entry != -1
791 Branch(Int32NotEqual(entryA, Int32(-1)), &hasEntry, exit);
792 Bind(&hasEntry);
793 {
794 *result = TaggedTrue();
795 Jump(exit);
796 }
797 }
798 Bind(&isDicMode);
799 {
800 GateRef array = GetPropertiesArray(thisValue_);
801 // int entry = dict->FindEntry(key)
802 GateRef entryB = FindEntryFromNameDictionary(glue_, array, res);
803 Label notNegtiveOne(env);
804 // if branch condition : entry != -1
805 Branch(Int32NotEqual(entryB, Int32(-1)), ¬NegtiveOne, exit);
806 Bind(¬NegtiveOne);
807 {
808 *result = TaggedTrue();
809 Jump(exit);
810 }
811 }
812 }
813 }
814 }
815 }
816 }
817
GetNumKeysFromLayoutInfo(GateRef object,GateRef end,GateRef layoutInfo)818 GateRef BuiltinsObjectStubBuilder::GetNumKeysFromLayoutInfo(GateRef object, GateRef end, GateRef layoutInfo)
819 {
820 auto env = GetEnvironment();
821 Label entry(env);
822 env->SubCfgEntry(&entry);
823 Label exit(env);
824 DEFVARIABLE(result, VariableType::INT32(), Int32(0));
825 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
826
827 Label loopHead(env);
828 Label loopEnd(env);
829 Label iLessEnd(env);
830 Label isString(env);
831 Label initializedProp(env);
832 Label isEnumerable(env);
833 Jump(&loopHead);
834 LoopBegin(&loopHead);
835 {
836 Branch(Int32UnsignedLessThan(*i, end), &iLessEnd, &exit);
837 Bind(&iLessEnd);
838 {
839 GateRef key = GetKey(layoutInfo, *i);
840 Branch(TaggedIsString(key), &isString, &loopEnd);
841 Bind(&isString);
842 Branch(IsUninitializedProperty(object, *i, layoutInfo), &loopEnd, &initializedProp);
843 Bind(&initializedProp);
844 Branch(IsEnumerable(GetAttr(layoutInfo, *i)), &isEnumerable, &loopEnd);
845 Bind(&isEnumerable);
846 result = Int32Add(*result, Int32(1));
847 Jump(&loopEnd);
848 }
849 Bind(&loopEnd);
850 i = Int32Add(*i, Int32(1));
851 LoopEnd(&loopHead);
852 }
853 Bind(&exit);
854 auto ret = *result;
855 env->SubCfgExit();
856 return ret;
857 }
858
IsUninitializedProperty(GateRef object,GateRef index,GateRef layoutInfo)859 GateRef BuiltinsObjectStubBuilder::IsUninitializedProperty(GateRef object, GateRef index, GateRef layoutInfo)
860 {
861 auto env = GetEnvironment();
862 Label entry(env);
863 env->SubCfgEntry(&entry);
864 Label exit(env);
865 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
866 DEFVARIABLE(result, VariableType::BOOL(), False());
867
868 Label inlinedProp(env);
869 GateRef attr = GetAttr(layoutInfo, index);
870 GateRef rep = GetRepInPropAttr(attr);
871 GateRef hclass = LoadHClass(object);
872 Branch(IsInlinedProperty(attr), &inlinedProp, &exit);
873 Bind(&inlinedProp);
874 {
875 value = GetPropertyInlinedProps(object, hclass, index);
876 result = TaggedIsHole(*value);
877 Label nonDoubleToTagged(env);
878 Label doubleToTagged(env);
879 Branch(IsDoubleRepInPropAttr(rep), &doubleToTagged, &nonDoubleToTagged);
880 Bind(&doubleToTagged);
881 {
882 value = TaggedPtrToTaggedDoublePtr(*value);
883 result = TaggedIsHole(*value);
884 Jump(&exit);
885 }
886 Bind(&nonDoubleToTagged);
887 {
888 Label intToTagged(env);
889 Branch(IsIntRepInPropAttr(rep), &intToTagged, &exit);
890 Bind(&intToTagged);
891 {
892 value = TaggedPtrToTaggedIntPtr(*value);
893 result = TaggedIsHole(*value);
894 Jump(&exit);
895 }
896 }
897 }
898
899 Bind(&exit);
900 auto ret = *result;
901 env->SubCfgExit();
902 return ret;
903 }
904
GetNumKeysFromDictionary(GateRef array)905 GateRef BuiltinsObjectStubBuilder::GetNumKeysFromDictionary(GateRef array)
906 {
907 auto env = GetEnvironment();
908 Label entry(env);
909 env->SubCfgEntry(&entry);
910 Label exit(env);
911
912 GateRef sizeIndex = Int32(TaggedHashTable<NameDictionary>::SIZE_INDEX);
913 GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(array, sizeIndex));
914 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
915 DEFVARIABLE(result, VariableType::INT32(), Int32(0));
916
917 Label loopHead(env);
918 Label loopEnd(env);
919 Label afterLoop(env);
920 Label iLessSize(env);
921 Label isString(env);
922 Label initializedProp(env);
923 Label isEnumerable(env);
924
925 Jump(&loopHead);
926 LoopBegin(&loopHead);
927 {
928 Branch(Int32UnsignedLessThan(*i, size), &iLessSize, &afterLoop);
929 Bind(&iLessSize);
930 {
931 GateRef key = GetKeyFromDictionary<NameDictionary>(array, *i);
932 Branch(TaggedIsString(key), &isString, &loopEnd);
933 Bind(&isString);
934 GateRef attr = GetAttributesFromDictionary<NameDictionary>(array, *i);
935 Branch(IsEnumerable(attr), &isEnumerable, &loopEnd);
936 Bind(&isEnumerable);
937 result = Int32Add(*result, Int32(1));
938 Jump(&loopEnd);
939 }
940 Bind(&loopEnd);
941 i = Int32Add(*i, Int32(1));
942 LoopEnd(&loopHead);
943 }
944 Bind(&afterLoop);
945 Jump(&exit);
946
947 Bind(&exit);
948 auto ret = *result;
949 env->SubCfgExit();
950 return ret;
951 }
952
LayoutInfoGetAllEnumKeys(GateRef end,GateRef offset,GateRef array,GateRef object,GateRef layoutInfo)953 void BuiltinsObjectStubBuilder::LayoutInfoGetAllEnumKeys(GateRef end, GateRef offset,
954 GateRef array, GateRef object, GateRef layoutInfo)
955 {
956 auto env = GetEnvironment();
957 Label entry(env);
958 env->SubCfgEntry(&entry);
959 Label exit(env);
960 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
961 DEFVARIABLE(enumKeys, VariableType::INT32(), Int32(0));
962 Label loopHead(env);
963 Label loopEnd(env);
964 Label afterLoop(env);
965 Label iLessEnd(env);
966 Label isEnumerable(env);
967 Label initializedProp(env);
968 Jump(&loopHead);
969 LoopBegin(&loopHead);
970 {
971 Branch(Int32UnsignedLessThan(*i, end), &iLessEnd, &afterLoop);
972 Bind(&iLessEnd);
973 {
974 GateRef key = GetKey(layoutInfo, *i);
975 Branch(BoolAnd(TaggedIsString(key), IsEnumerable(GetAttr(layoutInfo, *i))), &isEnumerable, &loopEnd);
976 Bind(&isEnumerable);
977 Branch(IsUninitializedProperty(object, *i, layoutInfo), &loopEnd, &initializedProp);
978 Bind(&initializedProp);
979 SetValueToTaggedArray(VariableType::JS_ANY(), glue_, array, Int32Add(*enumKeys, offset), key);
980 enumKeys = Int32Add(*enumKeys, Int32(1));
981 Jump(&loopEnd);
982 }
983 Bind(&loopEnd);
984 i = Int32Add(*i, Int32(1));
985 LoopEnd(&loopHead);
986 }
987 Bind(&afterLoop);
988 Jump(&exit);
989 Bind(&exit);
990 env->SubCfgExit();
991 }
992
CopyFromEnumCache(GateRef glue,GateRef elements)993 GateRef BuiltinsObjectStubBuilder::CopyFromEnumCache(GateRef glue, GateRef elements)
994 {
995 auto env = GetEnvironment();
996 Label subEntry(env);
997 env->SubCfgEntry(&subEntry);
998 Label exit(env);
999 DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1000 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
1001 DEFVARIABLE(newLen, VariableType::INT32(), Int32(0));
1002 NewObjectStubBuilder newBuilder(this);
1003
1004 Label lenIsZero(env);
1005 Label lenNotZero(env);
1006 Label afterLenCon(env);
1007 GateRef oldLen = GetLengthOfTaggedArray(elements);
1008 Branch(Int32Equal(oldLen, Int32(0)), &lenIsZero, &lenNotZero);
1009 {
1010 Bind(&lenIsZero);
1011 {
1012 newLen = Int32(0);
1013 Jump(&afterLenCon);
1014 }
1015 Bind(&lenNotZero);
1016 newLen = Int32Sub(oldLen, Int32(EnumCache::ENUM_CACHE_HEADER_SIZE));
1017 Jump(&afterLenCon);
1018 }
1019 Bind(&afterLenCon);
1020 GateRef array = newBuilder.NewTaggedArray(glue, *newLen);
1021 Store(VariableType::INT32(), glue, array, IntPtr(TaggedArray::LENGTH_OFFSET), *newLen);
1022 GateRef oldExtractLen = GetExtractLengthOfTaggedArray(elements);
1023 Store(VariableType::INT32(), glue, array, IntPtr(TaggedArray::EXTRA_LENGTH_OFFSET), oldExtractLen);
1024 Label loopHead(env);
1025 Label loopEnd(env);
1026 Label afterLoop(env);
1027 Label storeValue(env);
1028 Jump(&loopHead);
1029 LoopBegin(&loopHead);
1030 {
1031 Branch(Int32UnsignedLessThan(*index, *newLen), &storeValue, &afterLoop);
1032 Bind(&storeValue);
1033 {
1034 GateRef value = GetValueFromTaggedArray(elements, Int32Add(*index,
1035 Int32(EnumCache::ENUM_CACHE_HEADER_SIZE)));
1036 SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, value);
1037 index = Int32Add(*index, Int32(1));
1038 Jump(&loopEnd);
1039 }
1040 }
1041 Bind(&loopEnd);
1042 LoopEnd(&loopHead);
1043 Bind(&afterLoop);
1044 {
1045 result = array;
1046 Jump(&exit);
1047 }
1048 Bind(&exit);
1049 auto ret = *result;
1050 env->SubCfgExit();
1051 return ret;
1052 }
1053
GetAllEnumKeys(GateRef glue,GateRef obj)1054 GateRef BuiltinsObjectStubBuilder::GetAllEnumKeys(GateRef glue, GateRef obj)
1055 {
1056 auto env = GetEnvironment();
1057 Label subEntry(env);
1058 env->SubCfgEntry(&subEntry);
1059 Label exit(env);
1060 Label isDictionary(env);
1061 Label notDictionary(env);
1062 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1063 GateRef array = GetPropertiesArray(obj);
1064 Branch(IsDictionaryMode(array), &isDictionary, ¬Dictionary);
1065 Bind(&isDictionary);
1066 {
1067 Label propsNotZero(env);
1068 Label propsIsZero(env);
1069 GateRef numOfKeys = GetNumKeysFromDictionary(array);
1070 Branch(Int32GreaterThan(numOfKeys, Int32(0)), &propsNotZero, &propsIsZero);
1071 Bind(&propsNotZero);
1072 result = CallRuntime(glue, RTSTUB_ID(NameDictionaryGetAllEnumKeys), { obj, IntToTaggedInt(numOfKeys) });
1073 Jump(&exit);
1074 Bind(&propsIsZero);
1075 GateRef emptyArray = GetEmptyArray(glue);
1076 result = emptyArray;
1077 Jump(&exit);
1078 }
1079 Bind(¬Dictionary);
1080 {
1081 Label hasProps(env);
1082 Label notHasProps(env);
1083 GateRef hclass = LoadHClass(obj);
1084 // JSObject::GetNumberOfEnumKeys()
1085 GateRef num = GetNumberOfPropsFromHClass(hclass);
1086 Branch(Int32GreaterThan(num, Int32(0)), &hasProps, ¬HasProps);
1087 Bind(&hasProps);
1088 {
1089 Label isOnlyOwnKeys(env);
1090 Label notOnlyOwnKeys(env);
1091 GateRef layout = GetLayoutFromHClass(hclass);
1092 GateRef numOfKeys = GetNumKeysFromLayoutInfo(obj, num, layout);
1093 // JSObject::GetAllEnumKeys
1094 GateRef enumCache = GetEnumCacheFromHClass(hclass);
1095 GateRef kind = GetEnumCacheKind(glue, enumCache);
1096 Branch(Int32Equal(kind, Int32(static_cast<int32_t>(EnumCacheKind::ONLY_OWN_KEYS))),
1097 &isOnlyOwnKeys, ¬OnlyOwnKeys);
1098 Bind(&isOnlyOwnKeys);
1099 {
1100 result = CopyFromEnumCache(glue, enumCache);
1101 Jump(&exit);
1102 }
1103 Bind(¬OnlyOwnKeys);
1104 {
1105 Label numNotZero(env);
1106 Branch(Int32GreaterThan(numOfKeys, Int32(0)), &numNotZero, ¬HasProps);
1107 Bind(&numNotZero);
1108 NewObjectStubBuilder newBuilder(this);
1109 GateRef keyArray = newBuilder.NewTaggedArray(glue,
1110 Int32Add(numOfKeys, Int32(static_cast<int32_t>(EnumCache::ENUM_CACHE_HEADER_SIZE))));
1111 LayoutInfoGetAllEnumKeys(num, Int32(EnumCache::ENUM_CACHE_HEADER_SIZE), keyArray, obj, layout);
1112 SetValueToTaggedArray(VariableType::JS_ANY(), glue, keyArray,
1113 Int32(EnumCache::ENUM_CACHE_KIND_OFFSET),
1114 IntToTaggedInt(Int32(static_cast<int32_t>(EnumCacheKind::ONLY_OWN_KEYS))));
1115 SetEnumCacheToHClass(VariableType::JS_ANY(), glue, hclass, keyArray);
1116 result = CopyFromEnumCache(glue, keyArray);
1117 Jump(&exit);
1118 }
1119 }
1120 Bind(¬HasProps);
1121 {
1122 GateRef emptyArray = GetEmptyArray(glue);
1123 result = emptyArray;
1124 Jump(&exit);
1125 }
1126 }
1127 Bind(&exit);
1128 auto ret = *result;
1129 env->SubCfgExit();
1130 return ret;
1131 }
1132
GetEnumElementKeys(GateRef glue,GateRef obj)1133 GateRef BuiltinsObjectStubBuilder::GetEnumElementKeys(GateRef glue, GateRef obj)
1134 {
1135 auto env = GetEnvironment();
1136 Label subEntry(env);
1137 env->SubCfgEntry(&subEntry);
1138 Label exit(env);
1139 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1140 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1141 DEFVARIABLE(j, VariableType::INT32(), Int32(0));
1142 DEFVARIABLE(elementIndex, VariableType::INT32(), Int32(0));
1143
1144 Label propsNotZero(env);
1145 Label propsIsZero(env);
1146 GateRef numOfElements = GetNumberOfElements(obj);
1147 Branch(Int32GreaterThan(numOfElements, Int32(0)), &propsNotZero, &propsIsZero);
1148 Bind(&propsNotZero);
1149 {
1150 Label isJSPrimitiveRef(env);
1151 Label isPrimitiveString(env);
1152 Label notPrimitiveString(env);
1153 Label isDictMode(env);
1154 Label notDictMode(env);
1155
1156 NewObjectStubBuilder newBuilder(this);
1157 GateRef elementArray = newBuilder.NewTaggedArray(glue, numOfElements);
1158 Branch(IsJSPrimitiveRef(obj), &isJSPrimitiveRef, ¬PrimitiveString);
1159 Bind(&isJSPrimitiveRef);
1160 GateRef value = Load(VariableType::JS_ANY(), obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
1161 Branch(TaggedIsString(value), &isPrimitiveString, ¬PrimitiveString);
1162 Bind(&isPrimitiveString);
1163 {
1164 Label loopHead(env);
1165 Label loopEnd(env);
1166 Label iLessLength(env);
1167 GateRef strLen = GetLengthFromString(value);
1168 Jump(&loopHead);
1169 LoopBegin(&loopHead);
1170 {
1171 Branch(Int32UnsignedLessThan(*i, strLen), &iLessLength, ¬PrimitiveString);
1172 Bind(&iLessLength);
1173 {
1174 GateRef str = IntToEcmaString(glue, *i);
1175 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elementArray,
1176 *elementIndex, str);
1177 elementIndex = Int32Add(*elementIndex, Int32(1));
1178 Jump(&loopEnd);
1179 }
1180 Bind(&loopEnd);
1181 i = Int32Add(*i, Int32(1));
1182 LoopEnd(&loopHead);
1183 }
1184 }
1185 Bind(¬PrimitiveString);
1186 GateRef elements = GetElementsArray(obj);
1187 Branch(IsDictionaryMode(elements), &isDictMode, ¬DictMode);
1188 Bind(¬DictMode);
1189 {
1190 Label loopHead(env);
1191 Label loopEnd(env);
1192 Label iLessLength(env);
1193 Label notHole(env);
1194 Label afterLoop(env);
1195 GateRef elementsLen = GetLengthOfTaggedArray(elements);
1196 Jump(&loopHead);
1197 LoopBegin(&loopHead);
1198 {
1199 Branch(Int32UnsignedLessThan(*j, elementsLen), &iLessLength, &afterLoop);
1200 Bind(&iLessLength);
1201 {
1202 GateRef element = GetValueFromTaggedArray(elements, *j);
1203 Branch(TaggedIsHole(element), &loopEnd, ¬Hole);
1204 Bind(¬Hole);
1205 GateRef str = IntToEcmaString(glue, *j);
1206 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elementArray,
1207 *elementIndex, str);
1208 elementIndex = Int32Add(*elementIndex, Int32(1));
1209 Jump(&loopEnd);
1210 }
1211 Bind(&loopEnd);
1212 j = Int32Add(*j, Int32(1));
1213 LoopEnd(&loopHead);
1214 Bind(&afterLoop);
1215 {
1216 Store(VariableType::INT32(), glue_,
1217 elementArray, IntPtr(TaggedArray::LENGTH_OFFSET), *elementIndex);
1218 result = elementArray;
1219 Jump(&exit);
1220 }
1221 }
1222 }
1223 Bind(&isDictMode);
1224 {
1225 CallRuntime(glue, RTSTUB_ID(NumberDictionaryGetAllEnumKeys),
1226 { elements, elementArray, IntToTaggedInt(*elementIndex) });
1227 result = elementArray;
1228 Jump(&exit);
1229 }
1230 }
1231 Bind(&propsIsZero);
1232 {
1233 GateRef emptyArray = GetEmptyArray(glue);
1234 result = emptyArray;
1235 Jump(&exit);
1236 }
1237 Bind(&exit);
1238 auto ret = *result;
1239 env->SubCfgExit();
1240 return ret;
1241 }
1242
Keys(Variable * result,Label * exit,Label * slowPath)1243 void BuiltinsObjectStubBuilder::Keys(Variable *result, Label *exit, Label *slowPath)
1244 {
1245 auto env = GetEnvironment();
1246 GateRef msg = GetCallArg0(numArgs_);
1247 // 1. Let obj be ToObject(O).
1248 GateRef obj = ToObject(glue_, msg);
1249 Label isPendingException(env);
1250 Label noPendingException(env);
1251 Branch(HasPendingException(glue_), &isPendingException, &noPendingException);
1252 Bind(&isPendingException);
1253 Jump(exit);
1254 Bind(&noPendingException);
1255 Label isFast(env);
1256 // EnumerableOwnNames(obj)
1257 GateRef isSpecialKey = BoolOr(IsTypedArray(obj), IsModuleNamespace(obj));
1258 GateRef notSlowObjectKey = BoolNot(BoolOr(isSpecialKey, IsJSGlobalObject(obj)));
1259 Branch(BoolAnd(IsJSObject(obj), notSlowObjectKey), &isFast, slowPath);
1260 Bind(&isFast);
1261 {
1262 Label hasKeyAndEle(env);
1263 Label nonKeyAndEle(env);
1264 GateRef elementArray = GetEnumElementKeys(glue_, obj);
1265 GateRef keyArray = GetAllEnumKeys(glue_, obj);
1266 GateRef lengthOfKeys = GetLengthOfTaggedArray(keyArray);
1267 GateRef lengthOfElements = GetLengthOfTaggedArray(elementArray);
1268 GateRef KeyAndEle = BoolAnd(Int32NotEqual(lengthOfElements, Int32(0)), Int32NotEqual(lengthOfKeys, Int32(0)));
1269 Branch(KeyAndEle, &hasKeyAndEle, &nonKeyAndEle);
1270 Bind(&hasKeyAndEle);
1271 {
1272 GateRef allKeys = AppendSkipHole(glue_, elementArray, keyArray, Int32Add(lengthOfKeys, lengthOfElements));
1273 *result = CreateArrayFromList(glue_, allKeys);
1274 Jump(exit);
1275 }
1276 Bind(&nonKeyAndEle);
1277 {
1278 Label hasKey(env);
1279 Label nonKey(env);
1280 Branch(Int32NotEqual(lengthOfKeys, Int32(0)), &hasKey, &nonKey);
1281 Bind(&hasKey);
1282 {
1283 *result = CreateArrayFromList(glue_, keyArray);
1284 Jump(exit);
1285 }
1286 Bind(&nonKey);
1287 {
1288 Label hasEle(env);
1289 Label nonEle(env);
1290 Branch(Int32NotEqual(lengthOfElements, Int32(0)), &hasEle, &nonEle);
1291 Bind(&hasEle);
1292 {
1293 *result = CreateArrayFromList(glue_, elementArray);
1294 Jump(exit);
1295 }
1296 Bind(&nonEle);
1297 {
1298 GateRef emptyArray = GetEmptyArray(glue_);
1299 *result = CreateArrayFromList(glue_, emptyArray);
1300 Jump(exit);
1301 }
1302 }
1303 }
1304 }
1305 }
1306
1307 } // namespace panda::ecmascript::kungfu
1308