• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notDictionaryMode);
329     Bind(&notDictionaryMode);
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, &notHole);
346             Bind(&notHole);
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, &notHole);
394                     Bind(&notHole);
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, &notHole);
548                 Bind(&notHole);
549                 {
550                     Label isAccessor(env);
551                     Label notAccessor(env);
552                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
553                     Bind(&isAccessor);
554                     {
555                         value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
556                         // exception
557                         Label exception(env);
558                         Branch(HasPendingException(glue_), &exception, &notAccessor);
559                         Bind(&exception);
560                         {
561                             *result = Exception();
562                             Jump(funcExit);
563                         }
564                     }
565                     Bind(&notAccessor);
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, &notDictionaryMode);
602     Bind(&notDictionaryMode);
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, &notTwoArg); // 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(&notTwoArg);
689         Label threeArg(env);
690         Label notThreeArg(env);
691         Branch(Int64Equal(numArgs_, IntPtr(3)), &threeArg, &notThreeArg); // 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(&notThreeArg);
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, &notIndex);
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, &notDictionaryElement);
743                     Bind(&notDictionaryElement);
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), &notHole, exit);
753                             Bind(&notHole);
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)), &notNegtiveOne, exit);
765                         Bind(&notNegtiveOne);
766                         {
767                             *result = TaggedTrue();
768                             Jump(exit);
769                         }
770                     }
771                 }
772             }
773             Bind(&notIndex);
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, &notDicMode);
783                     Bind(&notDicMode);
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)), &notNegtiveOne, exit);
806                         Bind(&notNegtiveOne);
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, &notDictionary);
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(&notDictionary);
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, &notHasProps);
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, &notOnlyOwnKeys);
1098             Bind(&isOnlyOwnKeys);
1099             {
1100                 result = CopyFromEnumCache(glue, enumCache);
1101                 Jump(&exit);
1102             }
1103             Bind(&notOnlyOwnKeys);
1104             {
1105                 Label numNotZero(env);
1106                 Branch(Int32GreaterThan(numOfKeys, Int32(0)), &numNotZero, &notHasProps);
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(&notHasProps);
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, &notPrimitiveString);
1159         Bind(&isJSPrimitiveRef);
1160         GateRef value = Load(VariableType::JS_ANY(), obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
1161         Branch(TaggedIsString(value), &isPrimitiveString, &notPrimitiveString);
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, &notPrimitiveString);
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(&notPrimitiveString);
1186         GateRef elements = GetElementsArray(obj);
1187         Branch(IsDictionaryMode(elements), &isDictMode, &notDictMode);
1188         Bind(&notDictMode);
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, &notHole);
1204                     Bind(&notHole);
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