• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/stub_builder-inl.h"
17 
18 #include "ecmascript/compiler/assembler_module.h"
19 #include "ecmascript/compiler/llvm_ir_builder.h"
20 #include "ecmascript/compiler/rt_call_signature.h"
21 #include "ecmascript/js_api/js_api_arraylist.h"
22 #include "ecmascript/js_api/js_api_vector.h"
23 #include "ecmascript/js_object.h"
24 #include "ecmascript/mem/remembered_set.h"
25 #include "ecmascript/message_string.h"
26 #include "ecmascript/tagged_dictionary.h"
27 #include "ecmascript/tagged_hash_table.h"
28 
29 namespace panda::ecmascript::kungfu {
Jump(Label * label)30 void StubBuilder::Jump(Label *label)
31 {
32     ASSERT(label);
33     auto currentLabel = env_->GetCurrentLabel();
34     auto currentControl = currentLabel->GetControl();
35     auto jump = env_->GetBuilder()->Goto(currentControl);
36     currentLabel->SetControl(jump);
37     label->AppendPredecessor(currentLabel);
38     label->MergeControl(currentLabel->GetControl());
39     env_->SetCurrentLabel(nullptr);
40 }
41 
Branch(GateRef condition,Label * trueLabel,Label * falseLabel)42 void StubBuilder::Branch(GateRef condition, Label *trueLabel, Label *falseLabel)
43 {
44     auto currentLabel = env_->GetCurrentLabel();
45     auto currentControl = currentLabel->GetControl();
46     GateRef ifBranch = env_->GetBuilder()->Branch(currentControl, condition);
47     currentLabel->SetControl(ifBranch);
48     GateRef ifTrue = env_->GetBuilder()->IfTrue(ifBranch);
49     trueLabel->AppendPredecessor(env_->GetCurrentLabel());
50     trueLabel->MergeControl(ifTrue);
51     GateRef ifFalse = env_->GetBuilder()->IfFalse(ifBranch);
52     falseLabel->AppendPredecessor(env_->GetCurrentLabel());
53     falseLabel->MergeControl(ifFalse);
54     env_->SetCurrentLabel(nullptr);
55 }
56 
Switch(GateRef index,Label * defaultLabel,int64_t * keysValue,Label * keysLabel,int numberOfKeys)57 void StubBuilder::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys)
58 {
59     auto currentLabel = env_->GetCurrentLabel();
60     auto currentControl = currentLabel->GetControl();
61     GateRef switchBranch = env_->GetBuilder()->SwitchBranch(currentControl, index, numberOfKeys);
62     currentLabel->SetControl(switchBranch);
63     for (int i = 0; i < numberOfKeys; i++) {
64         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
65         GateRef switchCase = env_->GetBuilder()->SwitchCase(switchBranch, keysValue[i]);
66         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
67         keysLabel[i].AppendPredecessor(currentLabel);
68         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
69         keysLabel[i].MergeControl(switchCase);
70     }
71 
72     GateRef defaultCase = env_->GetBuilder()->DefaultCase(switchBranch);
73     defaultLabel->AppendPredecessor(currentLabel);
74     defaultLabel->MergeControl(defaultCase);
75     env_->SetCurrentLabel(nullptr);
76 }
77 
LoopBegin(Label * loopHead)78 void StubBuilder::LoopBegin(Label *loopHead)
79 {
80     ASSERT(loopHead);
81     auto loopControl = env_->GetBuilder()->LoopBegin(loopHead->GetControl());
82     loopHead->SetControl(loopControl);
83     loopHead->SetPreControl(loopControl);
84     loopHead->Bind();
85     env_->SetCurrentLabel(loopHead);
86 }
87 
LoopEnd(Label * loopHead)88 void StubBuilder::LoopEnd(Label *loopHead)
89 {
90     ASSERT(loopHead);
91     auto currentLabel = env_->GetCurrentLabel();
92     auto currentControl = currentLabel->GetControl();
93     auto loopend = env_->GetBuilder()->LoopEnd(currentControl);
94     currentLabel->SetControl(loopend);
95     loopHead->AppendPredecessor(currentLabel);
96     loopHead->MergeControl(loopend);
97     loopHead->Seal();
98     loopHead->MergeAllControl();
99     loopHead->MergeAllDepend();
100     env_->SetCurrentLabel(nullptr);
101 }
102 
103 // FindElementWithCache in ecmascript/layout_info-inl.h
FindElementWithCache(GateRef glue,GateRef layoutInfo,GateRef hclass,GateRef key,GateRef propsNum)104 GateRef StubBuilder::FindElementWithCache(GateRef glue, GateRef layoutInfo, GateRef hclass,
105     GateRef key, GateRef propsNum)
106 {
107     auto env = GetEnvironment();
108     Label subEntry(env);
109     env->SubCfgEntry(&subEntry);
110     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
111     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
112     Label exit(env);
113     Label notExceedUpper(env);
114     Label exceedUpper(env);
115     Label afterExceedCon(env);
116     // 9 : Builtins Object properties number is nine
117     Branch(Int32LessThanOrEqual(propsNum, Int32(9)), &notExceedUpper, &exceedUpper);
118     {
119         Bind(&notExceedUpper);
120             Label loopHead(env);
121             Label loopEnd(env);
122             Label afterLoop(env);
123             Jump(&loopHead);
124             LoopBegin(&loopHead);
125             {
126                 Label propsNumIsZero(env);
127                 Label propsNumNotZero(env);
128                 Branch(Int32Equal(propsNum, Int32(0)), &propsNumIsZero, &propsNumNotZero);
129                 Bind(&propsNumIsZero);
130                 Jump(&afterLoop);
131                 Bind(&propsNumNotZero);
132                 GateRef elementAddr = GetPropertiesAddrFromLayoutInfo(layoutInfo);
133                 GateRef keyInProperty = Load(VariableType::JS_ANY(),
134                                              elementAddr,
135                                              PtrMul(ZExtInt32ToPtr(*i),
136                                                     IntPtr(sizeof(panda::ecmascript::Properties))));
137                 Label equal(env);
138                 Label notEqual(env);
139                 Label afterEqualCon(env);
140                 Branch(Equal(keyInProperty, key), &equal, &notEqual);
141                 Bind(&equal);
142                 result = *i;
143                 Jump(&exit);
144                 Bind(&notEqual);
145                 Jump(&afterEqualCon);
146                 Bind(&afterEqualCon);
147                 i = Int32Add(*i, Int32(1));
148                 Branch(Int32UnsignedLessThan(*i, propsNum), &loopEnd, &afterLoop);
149                 Bind(&loopEnd);
150                 LoopEnd(&loopHead);
151             }
152             Bind(&afterLoop);
153             result = Int32(-1);
154             Jump(&exit);
155         Bind(&exceedUpper);
156         Jump(&afterExceedCon);
157     }
158     Bind(&afterExceedCon);
159     result = CallNGCRuntime(glue, RTSTUB_ID(FindElementWithCache), { glue, hclass, key, propsNum });
160     Jump(&exit);
161     Bind(&exit);
162     auto ret = *result;
163     env->SubCfgExit();
164     return ret;
165 }
166 
FindElementFromNumberDictionary(GateRef glue,GateRef elements,GateRef index)167 GateRef StubBuilder::FindElementFromNumberDictionary(GateRef glue, GateRef elements, GateRef index)
168 {
169     auto env = GetEnvironment();
170     Label subentry(env);
171     env->SubCfgEntry(&subentry);
172     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
173     Label exit(env);
174     GateRef capcityoffset =
175         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
176                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
177     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
178     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
179                                            PtrAdd(dataoffset, capcityoffset)));
180     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
181     GateRef len = Int32(sizeof(int) / sizeof(uint8_t));
182     GateRef hash = CallRuntime(glue, RTSTUB_ID(GetHash32),
183         { IntToTaggedInt(index), IntToTaggedInt(len) });
184     DEFVARIABLE(entry, VariableType::INT32(),
185         Int32And(TruncInt64ToInt32(ChangeTaggedPointerToInt64(hash)), Int32Sub(capacity, Int32(1))));
186     Label loopHead(env);
187     Label loopEnd(env);
188     Label afterLoop(env);
189     Jump(&loopHead);
190     LoopBegin(&loopHead);
191     GateRef element = GetKeyFromDictionary<NumberDictionary>(elements, *entry);
192     Label isHole(env);
193     Label notHole(env);
194     Branch(TaggedIsHole(element), &isHole, &notHole);
195     Bind(&isHole);
196     Jump(&loopEnd);
197     Bind(&notHole);
198     Label isUndefined(env);
199     Label notUndefined(env);
200     Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
201     Bind(&isUndefined);
202     result = Int32(-1);
203     Jump(&exit);
204     Bind(&notUndefined);
205     Label isMatch(env);
206     Label notMatch(env);
207     Branch(Int32Equal(index, GetInt32OfTInt(element)), &isMatch, &notMatch);
208     Bind(&isMatch);
209     result = *entry;
210     Jump(&exit);
211     Bind(&notMatch);
212     Jump(&loopEnd);
213     Bind(&loopEnd);
214     entry = GetNextPositionForHash(*entry, *count, capacity);
215     count = Int32Add(*count, Int32(1));
216     LoopEnd(&loopHead);
217     Bind(&exit);
218     auto ret = *result;
219     env->SubCfgExit();
220     return ret;
221 }
222 
223 // int TaggedHashTable<Derived>::FindEntry(const JSTaggedValue &key) in tagged_hash_table.h
FindEntryFromNameDictionary(GateRef glue,GateRef elements,GateRef key)224 GateRef StubBuilder::FindEntryFromNameDictionary(GateRef glue, GateRef elements, GateRef key)
225 {
226     auto env = GetEnvironment();
227     Label funcEntry(env);
228     env->SubCfgEntry(&funcEntry);
229     Label exit(env);
230     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
231     GateRef capcityoffset =
232         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
233                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
234     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
235     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
236                                            PtrAdd(dataoffset, capcityoffset)));
237     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
238     DEFVARIABLE(hash, VariableType::INT32(), Int32(0));
239     // NameDictionary::hash
240     Label isSymbol(env);
241     Label notSymbol(env);
242     Label loopHead(env);
243     Label loopEnd(env);
244     Label afterLoop(env);
245     Label beforeDefineHash(env);
246     Branch(IsSymbol(key), &isSymbol, &notSymbol);
247     Bind(&isSymbol);
248     {
249         hash = GetInt32OfTInt(Load(VariableType::INT64(), key,
250             IntPtr(JSSymbol::HASHFIELD_OFFSET)));
251         Jump(&beforeDefineHash);
252     }
253     Bind(&notSymbol);
254     {
255         Label isString(env);
256         Label notString(env);
257         Branch(IsString(key), &isString, &notString);
258         Bind(&isString);
259         {
260             hash = GetHashcodeFromString(glue, key);
261             Jump(&beforeDefineHash);
262         }
263         Bind(&notString);
264         {
265             Jump(&beforeDefineHash);
266         }
267     }
268     Bind(&beforeDefineHash);
269     // GetFirstPosition(hash, size)
270     DEFVARIABLE(entry, VariableType::INT32(), Int32And(*hash, Int32Sub(capacity, Int32(1))));
271     Jump(&loopHead);
272     LoopBegin(&loopHead);
273     {
274         GateRef element = GetKeyFromDictionary<NameDictionary>(elements, *entry);
275         Label isHole(env);
276         Label notHole(env);
277         Branch(TaggedIsHole(element), &isHole, &notHole);
278         {
279             Bind(&isHole);
280             {
281                 Jump(&loopEnd);
282             }
283             Bind(&notHole);
284             {
285                 Label isUndefined(env);
286                 Label notUndefined(env);
287                 Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
288                 {
289                     Bind(&isUndefined);
290                     {
291                         result = Int32(-1);
292                         Jump(&exit);
293                     }
294                     Bind(&notUndefined);
295                     {
296                         Label isMatch(env);
297                         Label notMatch(env);
298                         Branch(Equal(key, element), &isMatch, &notMatch);
299                         {
300                             Bind(&isMatch);
301                             {
302                                 result = *entry;
303                                 Jump(&exit);
304                             }
305                             Bind(&notMatch);
306                             {
307                                 Jump(&loopEnd);
308                             }
309                         }
310                     }
311                 }
312             }
313         }
314         Bind(&loopEnd);
315         {
316             entry = GetNextPositionForHash(*entry, *count, capacity);
317             count = Int32Add(*count, Int32(1));
318             LoopEnd(&loopHead);
319         }
320     }
321     Bind(&exit);
322     auto ret = *result;
323     env->SubCfgExit();
324     return ret;
325 }
326 
IsMatchInTransitionDictionary(GateRef element,GateRef key,GateRef metaData,GateRef attr)327 GateRef StubBuilder::IsMatchInTransitionDictionary(GateRef element, GateRef key, GateRef metaData, GateRef attr)
328 {
329     return BoolAnd(Equal(element, key), Int32Equal(metaData, attr));
330 }
331 
332 // metaData is int32 type
FindEntryFromTransitionDictionary(GateRef glue,GateRef elements,GateRef key,GateRef metaData)333 GateRef StubBuilder::FindEntryFromTransitionDictionary(GateRef glue, GateRef elements, GateRef key, GateRef metaData)
334 {
335     auto env = GetEnvironment();
336     Label funcEntry(env);
337     env->SubCfgEntry(&funcEntry);
338     Label exit(env);
339     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
340     GateRef capcityoffset =
341         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
342                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
343     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
344     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
345                                            PtrAdd(dataoffset, capcityoffset)));
346     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
347     DEFVARIABLE(hash, VariableType::INT32(), Int32(0));
348     // TransitionDictionary::hash
349     Label isSymbol(env);
350     Label notSymbol(env);
351     Label loopHead(env);
352     Label loopEnd(env);
353     Label afterLoop(env);
354     Label beforeDefineHash(env);
355     Branch(IsSymbol(key), &isSymbol, &notSymbol);
356     Bind(&isSymbol);
357     {
358         hash = GetInt32OfTInt(Load(VariableType::INT64(), key,
359             IntPtr(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET)));
360         Jump(&beforeDefineHash);
361     }
362     Bind(&notSymbol);
363     {
364         Label isString(env);
365         Label notString(env);
366         Branch(IsString(key), &isString, &notString);
367         Bind(&isString);
368         {
369             hash = GetHashcodeFromString(glue, key);
370             Jump(&beforeDefineHash);
371         }
372         Bind(&notString);
373         {
374             Jump(&beforeDefineHash);
375         }
376     }
377     Bind(&beforeDefineHash);
378     hash = Int32Add(*hash, metaData);
379     // GetFirstPosition(hash, size)
380     DEFVARIABLE(entry, VariableType::INT32(), Int32And(*hash, Int32Sub(capacity, Int32(1))));
381     Jump(&loopHead);
382     LoopBegin(&loopHead);
383     {
384         GateRef element = GetKeyFromDictionary<TransitionsDictionary>(elements, *entry);
385         Label isHole(env);
386         Label notHole(env);
387         Branch(TaggedIsHole(element), &isHole, &notHole);
388         {
389             Bind(&isHole);
390             {
391                 Jump(&loopEnd);
392             }
393             Bind(&notHole);
394             {
395                 Label isUndefined(env);
396                 Label notUndefined(env);
397                 Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
398                 {
399                     Bind(&isUndefined);
400                     {
401                         result = Int32(-1);
402                         Jump(&exit);
403                     }
404                     Bind(&notUndefined);
405                     {
406                         Label isMatch(env);
407                         Label notMatch(env);
408                         Branch(
409                             IsMatchInTransitionDictionary(element, key, metaData,
410                                 GetAttributesFromDictionary<TransitionsDictionary>(elements, *entry)),
411                             &isMatch, &notMatch);
412                         {
413                             Bind(&isMatch);
414                             {
415                                 result = *entry;
416                                 Jump(&exit);
417                             }
418                             Bind(&notMatch);
419                             {
420                                 Jump(&loopEnd);
421                             }
422                         }
423                     }
424                 }
425             }
426         }
427         Bind(&loopEnd);
428         {
429             entry = GetNextPositionForHash(*entry, *count, capacity);
430             count = Int32Add(*count, Int32(1));
431             LoopEnd(&loopHead);
432         }
433     }
434     Bind(&exit);
435     auto ret = *result;
436     env->SubCfgExit();
437     return ret;
438 }
439 
JSObjectGetProperty(GateRef obj,GateRef hclass,GateRef attr)440 GateRef StubBuilder::JSObjectGetProperty(GateRef obj, GateRef hclass, GateRef attr)
441 {
442     auto env = GetEnvironment();
443     Label entry(env);
444     env->SubCfgEntry(&entry);
445     Label exit(env);
446     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
447     Label inlinedProp(env);
448     Label notInlinedProp(env);
449     GateRef attrOffset = GetOffsetFieldInPropAttr(attr);
450     Branch(IsInlinedProperty(attr), &inlinedProp, &notInlinedProp);
451     {
452         Bind(&inlinedProp);
453         {
454             result = GetPropertyInlinedProps(obj, hclass, attrOffset);
455             Jump(&exit);
456         }
457         Bind(&notInlinedProp);
458         {
459             // compute outOfLineProp offset, get it and return
460             GateRef array =
461                 Load(VariableType::INT64(), obj, IntPtr(JSObject::PROPERTIES_OFFSET));
462             result = GetValueFromTaggedArray(array, Int32Sub(attrOffset,
463                 GetInlinedPropertiesFromHClass(hclass)));
464             Jump(&exit);
465         }
466     }
467     Bind(&exit);
468     auto ret = *result;
469     env->SubCfgExit();
470     return ret;
471 }
472 
JSObjectSetProperty(GateRef glue,GateRef obj,GateRef hclass,GateRef attr,GateRef value)473 void StubBuilder::JSObjectSetProperty(GateRef glue, GateRef obj, GateRef hclass, GateRef attr, GateRef value)
474 {
475     auto env = GetEnvironment();
476     Label subEntry(env);
477     env->SubCfgEntry(&subEntry);
478     Label exit(env);
479     Label inlinedProp(env);
480     Label notInlinedProp(env);
481     GateRef attrOffset = GetOffsetFieldInPropAttr(attr);
482     Branch(IsInlinedProperty(attr), &inlinedProp, &notInlinedProp);
483     {
484         Bind(&inlinedProp);
485         {
486             SetPropertyInlinedProps(glue, obj, hclass, value, attrOffset);
487             Jump(&exit);
488         }
489         Bind(&notInlinedProp);
490         {
491             // compute outOfLineProp offset, get it and return
492             GateRef array = Load(VariableType::JS_POINTER(), obj,
493                                  IntPtr(JSObject::PROPERTIES_OFFSET));
494             SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, Int32Sub(attrOffset,
495                 GetInlinedPropertiesFromHClass(hclass)), value);
496             Jump(&exit);
497         }
498     }
499     Bind(&exit);
500     env->SubCfgExit();
501     return;
502 }
503 
ComputePropertyCapacityInJSObj(GateRef oldLength)504 GateRef StubBuilder::ComputePropertyCapacityInJSObj(GateRef oldLength)
505 {
506     auto env = GetEnvironment();
507     Label subEntry(env);
508     env->SubCfgEntry(&subEntry);
509     Label exit(env);
510     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
511     GateRef newL = Int32Add(oldLength, Int32(JSObject::PROPERTIES_GROW_SIZE));
512     Label reachMax(env);
513     Label notReachMax(env);
514     Branch(Int32GreaterThan(newL, Int32(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)),
515         &reachMax, &notReachMax);
516     {
517         Bind(&reachMax);
518         result = Int32(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS);
519         Jump(&exit);
520         Bind(&notReachMax);
521         result = newL;
522         Jump(&exit);
523     }
524     Bind(&exit);
525     auto ret = *result;
526     env->SubCfgExit();
527     return ret;
528 }
529 
CallGetterHelper(GateRef glue,GateRef receiver,GateRef holder,GateRef accessor)530 GateRef StubBuilder::CallGetterHelper(GateRef glue, GateRef receiver, GateRef holder, GateRef accessor)
531 {
532     auto env = GetEnvironment();
533     Label subEntry(env);
534     env->SubCfgEntry(&subEntry);
535     Label exit(env);
536     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
537 
538     Label isInternal(env);
539     Label notInternal(env);
540     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
541     Bind(&isInternal);
542     {
543         Label arrayLength(env);
544         Label tryContinue(env);
545         auto lengthAccessor = GetGlobalConstantValue(
546             VariableType::JS_POINTER(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
547         Branch(Equal(accessor, lengthAccessor), &arrayLength, &tryContinue);
548         Bind(&arrayLength);
549         {
550             result = Load(VariableType::JS_ANY(), holder,
551                           IntPtr(JSArray::LENGTH_OFFSET));
552             Jump(&exit);
553         }
554         Bind(&tryContinue);
555         result = CallRuntime(glue, RTSTUB_ID(CallInternalGetter), { accessor, holder });
556         Jump(&exit);
557     }
558     Bind(&notInternal);
559     {
560         auto getter = Load(VariableType::JS_ANY(), accessor,
561                            IntPtr(AccessorData::GETTER_OFFSET));
562         Label objIsUndefined(env);
563         Label objNotUndefined(env);
564         Branch(TaggedIsUndefined(getter), &objIsUndefined, &objNotUndefined);
565         // if getter is undefined, return undefiend
566         Bind(&objIsUndefined);
567         {
568             result = Undefined();
569             Jump(&exit);
570         }
571         Bind(&objNotUndefined);
572         {
573             auto retValue = JSCallDispatch(glue, getter, Int32(0), 0, Circuit::NullGate(),
574                                            JSCallMode::CALL_GETTER, { receiver });
575             Label noPendingException(env);
576             Branch(HasPendingException(glue), &exit, &noPendingException);
577             Bind(&noPendingException);
578             {
579                 result = retValue;
580                 Jump(&exit);
581             }
582         }
583     }
584     Bind(&exit);
585     auto ret = *result;
586     env->SubCfgExit();
587     return ret;
588 }
589 
CallSetterHelper(GateRef glue,GateRef receiver,GateRef accessor,GateRef value)590 GateRef StubBuilder::CallSetterHelper(GateRef glue, GateRef receiver, GateRef accessor, GateRef value)
591 {
592     auto env = GetEnvironment();
593     Label subEntry(env);
594     env->SubCfgEntry(&subEntry);
595     Label exit(env);
596     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
597 
598     Label isInternal(env);
599     Label notInternal(env);
600     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
601     Bind(&isInternal);
602     {
603         result = CallRuntime(glue, RTSTUB_ID(CallInternalSetter), { receiver, accessor, value });
604         Jump(&exit);
605     }
606     Bind(&notInternal);
607     {
608         auto setter = Load(VariableType::JS_ANY(), accessor,
609                            IntPtr(AccessorData::SETTER_OFFSET));
610         Label objIsUndefined(env);
611         Label objNotUndefined(env);
612         Branch(TaggedIsUndefined(setter), &objIsUndefined, &objNotUndefined);
613         Bind(&objIsUndefined);
614         {
615             CallRuntime(glue, RTSTUB_ID(ThrowSetterIsUndefinedException), {});
616             result = Exception();
617             Jump(&exit);
618         }
619         Bind(&objNotUndefined);
620         {
621             auto retValue = JSCallDispatch(glue, setter, Int32(1), 0, Circuit::NullGate(),
622                                            JSCallMode::CALL_SETTER, { receiver, value });
623             Label noPendingException(env);
624             Branch(HasPendingException(glue), &exit, &noPendingException);
625             Bind(&noPendingException);
626             {
627                 result = retValue;
628                 Jump(&exit);
629             }
630         }
631     }
632     Bind(&exit);
633     auto ret = *result;
634     env->SubCfgExit();
635     return ret;
636 }
637 
ShouldCallSetter(GateRef receiver,GateRef holder,GateRef accessor,GateRef attr)638 GateRef StubBuilder::ShouldCallSetter(GateRef receiver, GateRef holder, GateRef accessor, GateRef attr)
639 {
640     auto env = GetEnvironment();
641     Label subEntry(env);
642     env->SubCfgEntry(&subEntry);
643     Label exit(env);
644     DEFVARIABLE(result, VariableType::BOOL(), True());
645     Label isInternal(env);
646     Label notInternal(env);
647     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
648     Bind(&isInternal);
649     {
650         Label receiverEqualsHolder(env);
651         Label receiverNotEqualsHolder(env);
652         Branch(Equal(receiver, holder), &receiverEqualsHolder, &receiverNotEqualsHolder);
653         Bind(&receiverEqualsHolder);
654         {
655             result = IsWritable(attr);
656             Jump(&exit);
657         }
658         Bind(&receiverNotEqualsHolder);
659         {
660             result = False();
661             Jump(&exit);
662         }
663     }
664     Bind(&notInternal);
665     {
666         result = True();
667         Jump(&exit);
668     }
669     Bind(&exit);
670     auto ret = *result;
671     env->SubCfgExit();
672     return ret;
673 }
674 
JSHClassAddProperty(GateRef glue,GateRef receiver,GateRef key,GateRef attr)675 void StubBuilder::JSHClassAddProperty(GateRef glue, GateRef receiver, GateRef key, GateRef attr)
676 {
677     auto env = GetEnvironment();
678     Label subEntry(env);
679     env->SubCfgEntry(&subEntry);
680     Label exit(env);
681     GateRef hclass = LoadHClass(receiver);
682     GateRef metaData = GetPropertyMetaDataFromAttr(attr);
683     GateRef newClass = FindTransitions(glue, receiver, hclass, key, metaData);
684     Label findHClass(env);
685     Label notFindHClass(env);
686     Branch(Equal(newClass, Undefined()), &notFindHClass, &findHClass);
687     Bind(&findHClass);
688     {
689         Jump(&exit);
690     }
691     Bind(&notFindHClass);
692     {
693         GateRef type = GetObjectType(hclass);
694         GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass),
695                                 Int32(JSTaggedValue::TaggedTypeSize()));
696         GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass);
697         GateRef newJshclass = CallRuntime(glue, RTSTUB_ID(NewEcmaHClass),
698             { IntToTaggedInt(size), IntToTaggedInt(type),
699               IntToTaggedInt(inlineProps) });
700         CopyAllHClass(glue, newJshclass, hclass);
701         CallRuntime(glue, RTSTUB_ID(UpdateLayOutAndAddTransition),
702                     { hclass, newJshclass, key, IntToTaggedInt(attr) });
703 #if ECMASCRIPT_ENABLE_IC
704         NotifyHClassChanged(glue, hclass, newJshclass);
705 #endif
706         StoreHClass(glue, receiver, newJshclass);
707         Jump(&exit);
708     }
709     Bind(&exit);
710     env->SubCfgExit();
711     return;
712 }
713 
714 // if condition:objHandle->IsJSArray() &&
715 //      keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()
SetHasConstructorCondition(GateRef glue,GateRef receiver,GateRef key)716 GateRef StubBuilder::SetHasConstructorCondition(GateRef glue, GateRef receiver, GateRef key)
717 {
718     GateRef gConstOffset = PtrAdd(glue,
719                                   IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
720     GateRef gCtorStr = Load(VariableType::JS_ANY(),
721         gConstOffset,
722         Int64Mul(Int64(sizeof(JSTaggedValue)),
723             Int64(static_cast<uint64_t>(ConstantIndex::CONSTRUCTOR_STRING_INDEX))));
724     GateRef isCtorStr = Equal(key, gCtorStr);
725     return BoolAnd(IsJsArray(receiver), isCtorStr);
726 }
727 
728 // Note: set return exit node
AddPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef propertyAttributes)729 GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value,
730                                 GateRef propertyAttributes)
731 {
732     auto env = GetEnvironment();
733     Label subentry(env);
734     env->SubCfgEntry(&subentry);
735     Label exit(env);
736     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
737     Label setHasCtor(env);
738     Label notSetHasCtor(env);
739     Label afterCtorCon(env);
740     GateRef hclass = LoadHClass(receiver);
741     Branch(SetHasConstructorCondition(glue, receiver, key), &setHasCtor, &notSetHasCtor);
742     {
743         Bind(&setHasCtor);
744         SetHasConstructorToHClass(glue, hclass, Int32(1));
745         Jump(&afterCtorCon);
746         Bind(&notSetHasCtor);
747         Jump(&afterCtorCon);
748     }
749     Bind(&afterCtorCon);
750     // 0x111 : default attribute for property: writable, enumerable, configurable
751     DEFVARIABLE(attr, VariableType::INT32(), propertyAttributes);
752     GateRef numberOfProps = GetNumberOfPropsFromHClass(hclass);
753     GateRef inlinedProperties = GetInlinedPropertiesFromHClass(hclass);
754     Label hasUnusedInProps(env);
755     Label noUnusedInProps(env);
756     Label afterInPropsCon(env);
757     Branch(Int32UnsignedLessThan(numberOfProps, inlinedProperties), &hasUnusedInProps, &noUnusedInProps);
758     {
759         Bind(&noUnusedInProps);
760         Jump(&afterInPropsCon);
761         Bind(&hasUnusedInProps);
762         {
763             SetPropertyInlinedProps(glue, receiver, hclass, value, numberOfProps);
764             attr = SetOffsetFieldInPropAttr(*attr, numberOfProps);
765             attr = SetIsInlinePropsFieldInPropAttr(*attr, Int32(1)); // 1: set inInlineProps true
766             JSHClassAddProperty(glue, receiver, key, *attr);
767             result = Undefined();
768             Jump(&exit);
769         }
770     }
771     Bind(&afterInPropsCon);
772     DEFVARIABLE(array, VariableType::JS_POINTER(), GetPropertiesArray(receiver));
773     DEFVARIABLE(length, VariableType::INT32(), GetLengthOfTaggedArray(*array));
774     Label lenIsZero(env);
775     Label lenNotZero(env);
776     Label afterLenCon(env);
777     Branch(Int32Equal(*length, Int32(0)), &lenIsZero, &lenNotZero);
778     {
779         Bind(&lenIsZero);
780         {
781             length = Int32(JSObject::MIN_PROPERTIES_LENGTH);
782             array = CallRuntime(glue, RTSTUB_ID(NewTaggedArray), { IntToTaggedInt(*length) });
783             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array);
784             Jump(&afterLenCon);
785         }
786         Bind(&lenNotZero);
787         Jump(&afterLenCon);
788     }
789     Bind(&afterLenCon);
790     Label isDictMode(env);
791     Label notDictMode(env);
792     Branch(IsDictionaryMode(*array), &isDictMode, &notDictMode);
793     {
794         Bind(&isDictMode);
795         {
796             GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent),
797                                       {receiver, *array, key, value, IntToTaggedInt(*attr), TaggedFalse()});
798             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res);
799             Jump(&exit);
800         }
801         Bind(&notDictMode);
802         {
803             attr = SetIsInlinePropsFieldInPropAttr(*attr, Int32(0));
804             GateRef outProps = Int32Sub(numberOfProps, inlinedProperties);
805             Label isArrayFull(env);
806             Label arrayNotFull(env);
807             Label afterArrLenCon(env);
808             Branch(Int32Equal(*length, outProps), &isArrayFull, &arrayNotFull);
809             {
810                 Bind(&isArrayFull);
811                 {
812                     Label ChangeToDict(env);
813                     Label notChangeToDict(env);
814                     Label afterDictChangeCon(env);
815                     Branch(Int32Equal(*length, Int32(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)),
816                         &ChangeToDict, &notChangeToDict);
817                     {
818                         Bind(&ChangeToDict);
819                         {
820                             attr = SetDictionaryOrderFieldInPropAttr(*attr,
821                                 Int32(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES));
822                             GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent),
823                                 { receiver, *array, key, value, IntToTaggedInt(*attr), TaggedTrue() });
824                             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res);
825                             result = Undefined();
826                             Jump(&exit);
827                         }
828                         Bind(&notChangeToDict);
829                         Jump(&afterDictChangeCon);
830                     }
831                     Bind(&afterDictChangeCon);
832                     GateRef capacity = ComputePropertyCapacityInJSObj(*length);
833                     array = CallRuntime(glue, RTSTUB_ID(CopyArray),
834                         { *array, IntToTaggedInt(*length), IntToTaggedInt(capacity) });
835                     SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array);
836                     Jump(&afterArrLenCon);
837                 }
838                 Bind(&arrayNotFull);
839                 Jump(&afterArrLenCon);
840             }
841             Bind(&afterArrLenCon);
842             {
843                 attr = SetOffsetFieldInPropAttr(*attr, numberOfProps);
844                 JSHClassAddProperty(glue, receiver, key, *attr);
845                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, *array, outProps, value);
846                 Jump(&exit);
847             }
848         }
849     }
850     Bind(&exit);
851     auto ret = *result;
852     env->SubCfgExit();
853     return ret;
854 }
855 
ThrowTypeAndReturn(GateRef glue,int messageId,GateRef val)856 void StubBuilder::ThrowTypeAndReturn(GateRef glue, int messageId, GateRef val)
857 {
858     GateRef msgIntId = Int32(messageId);
859     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(msgIntId) });
860     Return(val);
861 }
862 
TaggedToRepresentation(GateRef value)863 GateRef StubBuilder::TaggedToRepresentation(GateRef value)
864 {
865     auto env = GetEnvironment();
866     Label entry(env);
867     env->SubCfgEntry(&entry);
868     Label exit(env);
869     DEFVARIABLE(resultRep, VariableType::INT64(),
870                 Int64(static_cast<int32_t>(Representation::OBJECT)));
871     Label isInt(env);
872     Label notInt(env);
873 
874     Branch(TaggedIsInt(value), &isInt, &notInt);
875     Bind(&isInt);
876     {
877         resultRep = Int64(static_cast<int32_t>(Representation::INT));
878         Jump(&exit);
879     }
880     Bind(&notInt);
881     {
882         Label isDouble(env);
883         Label notDouble(env);
884         Branch(TaggedIsDouble(value), &isDouble, &notDouble);
885         Bind(&isDouble);
886         {
887             resultRep = Int64(static_cast<int32_t>(Representation::DOUBLE));
888             Jump(&exit);
889         }
890         Bind(&notDouble);
891         {
892             resultRep = Int64(static_cast<int32_t>(Representation::OBJECT));
893             Jump(&exit);
894         }
895     }
896     Bind(&exit);
897     auto ret = *resultRep;
898     env->SubCfgExit();
899     return ret;
900 }
901 
Store(VariableType type,GateRef glue,GateRef base,GateRef offset,GateRef value)902 void StubBuilder::Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value)
903 {
904     if (!env_->IsAsmInterp()) {
905         env_->GetBuilder()->Store(type, glue, base, offset, value);
906     } else {
907         auto depend = env_->GetCurrentLabel()->GetDepend();
908         GateRef ptr = PtrAdd(base, offset);
909         GateRef result = env_->GetCircuit()->NewGate(
910             env_->GetCircuit()->Store(), MachineType::NOVALUE,
911             { depend, value, ptr }, type.GetGateType());
912         env_->GetCurrentLabel()->SetDepend(result);
913         if (type == VariableType::JS_POINTER() || type == VariableType::JS_ANY()) {
914             auto env = GetEnvironment();
915             Label entry(env);
916             env->SubCfgEntry(&entry);
917             Label exit(env);
918             Label isHeapObject(env);
919 
920             Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
921             Bind(&isHeapObject);
922             {
923                 CallNGCRuntime(glue, RTSTUB_ID(StoreBarrier), { glue, base, offset, value });
924                 Jump(&exit);
925             }
926             Bind(&exit);
927             env->SubCfgExit();
928         }
929     }
930 }
931 
SetValueWithBarrier(GateRef glue,GateRef obj,GateRef offset,GateRef value)932 void StubBuilder::SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value)
933 {
934     auto env = GetEnvironment();
935     Label entry(env);
936     env->SubCfgEntry(&entry);
937     Label exit(env);
938     Label isHeapObject(env);
939     Label isVailedIndex(env);
940     Label notValidIndex(env);
941 
942     Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
943     Bind(&isHeapObject);
944     {
945         // ObjectAddressToRange function may cause obj is not an object. GC may not mark this obj.
946         GateRef objectRegion = ObjectAddressToRange(obj);
947         GateRef valueRegion = ObjectAddressToRange(value);
948         GateRef slotAddr = PtrAdd(TaggedCastToIntPtr(obj), offset);
949         GateRef objectNotInYoung = BoolNot(InYoungGeneration(objectRegion));
950         GateRef valueRegionInYoung = InYoungGeneration(valueRegion);
951         Branch(BoolAnd(objectNotInYoung, valueRegionInYoung), &isVailedIndex, &notValidIndex);
952         Bind(&isVailedIndex);
953         {
954             GateRef loadOffset = IntPtr(Region::PackedData::GetOldToNewSetOffset(env_->Is32Bit()));
955             auto oldToNewSet = Load(VariableType::NATIVE_POINTER(), objectRegion, loadOffset);
956             Label isNullPtr(env);
957             Label notNullPtr(env);
958             Branch(IntPtrEuqal(oldToNewSet, IntPtr(0)), &isNullPtr, &notNullPtr);
959             Bind(&notNullPtr);
960             {
961                 // (slotAddr - this) >> TAGGED_TYPE_SIZE_LOG
962                 GateRef bitOffsetPtr = IntPtrLSR(PtrSub(slotAddr, objectRegion), IntPtr(TAGGED_TYPE_SIZE_LOG));
963                 GateRef bitOffset = TruncPtrToInt32(bitOffsetPtr);
964                 GateRef bitPerWordLog2 = Int32(GCBitset::BIT_PER_WORD_LOG2);
965                 GateRef bytePerWord = Int32(GCBitset::BYTE_PER_WORD);
966                 // bitOffset >> BIT_PER_WORD_LOG2
967                 GateRef index = Int32LSR(bitOffset, bitPerWordLog2);
968                 GateRef byteIndex = Int32Mul(index, bytePerWord);
969                 // bitset_[index] |= mask;
970                 GateRef bitsetData = PtrAdd(oldToNewSet, IntPtr(RememberedSet::GCBITSET_DATA_OFFSET));
971                 GateRef oldsetValue = Load(VariableType::INT32(), bitsetData, byteIndex);
972                 GateRef newmapValue = Int32Or(oldsetValue, GetBitMask(bitOffset));
973 
974                 Store(VariableType::INT32(), glue, bitsetData, byteIndex, newmapValue);
975                 Jump(&notValidIndex);
976             }
977             Bind(&isNullPtr);
978             {
979                 CallNGCRuntime(glue, RTSTUB_ID(InsertOldToNewRSet), { glue, obj, offset });
980                 Jump(&notValidIndex);
981             }
982         }
983         Bind(&notValidIndex);
984         {
985             Label marking(env);
986             bool isArch32 = GetEnvironment()->Is32Bit();
987             GateRef stateBitFieldAddr = Int64Add(glue,
988                                                  Int64(JSThread::GlueData::GetStateBitFieldOffset(isArch32)));
989             GateRef stateBitField = Load(VariableType::INT64(), stateBitFieldAddr, Int64(0));
990             // mask: 1 << JSThread::CONCURRENT_MARKING_BITFIELD_NUM - 1
991             GateRef markingBitMask = Int64Sub(
992                 Int64LSL(Int64(1), Int64(JSThread::CONCURRENT_MARKING_BITFIELD_NUM)), Int64(1));
993             GateRef state = Int64And(stateBitField, markingBitMask);
994             Branch(Int64Equal(state, Int64(static_cast<int64_t>(MarkStatus::READY_TO_MARK))), &exit, &marking);
995 
996             Bind(&marking);
997             CallNGCRuntime(
998                 glue,
999                 RTSTUB_ID(MarkingBarrier), { glue, obj, offset, value });
1000             Jump(&exit);
1001         }
1002     }
1003     Bind(&exit);
1004     env->SubCfgExit();
1005 }
1006 
TaggedIsBigInt(GateRef obj)1007 GateRef StubBuilder::TaggedIsBigInt(GateRef obj)
1008 {
1009     auto env = GetEnvironment();
1010     Label entry(env);
1011     env->SubCfgEntry(&entry);
1012     Label exit(env);
1013     Label isHeapObject(env);
1014     DEFVARIABLE(result, VariableType::BOOL(), False());
1015     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
1016     Bind(&isHeapObject);
1017     {
1018         result = Int32Equal(GetObjectType(LoadHClass(obj)),
1019                             Int32(static_cast<int32_t>(JSType::BIGINT)));
1020         Jump(&exit);
1021     }
1022     Bind(&exit);
1023     auto ret = *result;
1024     env->SubCfgExit();
1025     return ret;
1026 }
1027 
TaggedIsPropertyBox(GateRef obj)1028 GateRef StubBuilder::TaggedIsPropertyBox(GateRef obj)
1029 {
1030     auto env = GetEnvironment();
1031     Label entry(env);
1032     env->SubCfgEntry(&entry);
1033     Label exit(env);
1034     Label isHeapObject(env);
1035     DEFVARIABLE(result, VariableType::BOOL(), False());
1036     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
1037     Bind(&isHeapObject);
1038     {
1039         GateRef type = GetObjectType(LoadHClass(obj));
1040         result = Int32Equal(type, Int32(static_cast<int32_t>(JSType::PROPERTY_BOX)));
1041         Jump(&exit);
1042     }
1043     Bind(&exit);
1044     auto ret = *result;
1045     env->SubCfgExit();
1046     return ret;
1047 }
1048 
TaggedIsAccessor(GateRef x)1049 GateRef StubBuilder::TaggedIsAccessor(GateRef x)
1050 {
1051     auto env = GetEnvironment();
1052     Label entry(env);
1053     env->SubCfgEntry(&entry);
1054     Label exit(env);
1055     Label isHeapObject(env);
1056     DEFVARIABLE(result, VariableType::BOOL(), False());
1057     Branch(TaggedIsHeapObject(x), &isHeapObject, &exit);
1058     Bind(&isHeapObject);
1059     {
1060         GateRef type = GetObjectType(LoadHClass(x));
1061         result = BoolOr(Int32Equal(type, Int32(static_cast<int32_t>(JSType::ACCESSOR_DATA))),
1062                         Int32Equal(type, Int32(static_cast<int32_t>(JSType::INTERNAL_ACCESSOR))));
1063         Jump(&exit);
1064     }
1065     Bind(&exit);
1066     auto ret = *result;
1067     env->SubCfgExit();
1068     return ret;
1069 }
1070 
IsUtf16String(GateRef string)1071 GateRef StubBuilder::IsUtf16String(GateRef string)
1072 {
1073     // compressedStringsEnabled fixed to true constant
1074     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1075     return Int32Equal(
1076         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
1077         Int32(EcmaString::STRING_UNCOMPRESSED));
1078 }
1079 
IsUtf8String(GateRef string)1080 GateRef StubBuilder::IsUtf8String(GateRef string)
1081 {
1082     // compressedStringsEnabled fixed to true constant
1083     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1084     return Int32Equal(
1085         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
1086         Int32(EcmaString::STRING_COMPRESSED));
1087 }
1088 
IsInternalString(GateRef string)1089 GateRef StubBuilder::IsInternalString(GateRef string)
1090 {
1091     // compressedStringsEnabled fixed to true constant
1092     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1093     return Int32NotEqual(
1094         Int32And(len, Int32(EcmaString::STRING_INTERN_BIT)),
1095         Int32(0));
1096 }
1097 
IsDigit(GateRef ch)1098 GateRef StubBuilder::IsDigit(GateRef ch)
1099 {
1100     return BoolAnd(Int32LessThanOrEqual(ch, Int32('9')),
1101         Int32GreaterThanOrEqual(ch, Int32('0')));
1102 }
1103 
StringToElementIndex(GateRef string)1104 GateRef StubBuilder::StringToElementIndex(GateRef string)
1105 {
1106     auto env = GetEnvironment();
1107     Label entry(env);
1108     env->SubCfgEntry(&entry);
1109     Label exit(env);
1110     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
1111     Label greatThanZero(env);
1112     Label inRange(env);
1113     auto len = GetLengthFromString(string);
1114     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
1115     Bind(&greatThanZero);
1116     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
1117     Bind(&inRange);
1118     {
1119         GateRef dataUtf16 = PtrAdd(string, IntPtr(EcmaString::DATA_OFFSET));
1120         DEFVARIABLE(c, VariableType::INT32(), Int32(0));
1121         Label isUtf16(env);
1122         Label isUtf8(env);
1123         Label getChar1(env);
1124         GateRef isUtf16String = IsUtf16String(string);
1125         Branch(isUtf16String, &isUtf16, &isUtf8);
1126         Bind(&isUtf16);
1127         {
1128             c = ZExtInt16ToInt32(Load(VariableType::INT16(), dataUtf16));
1129             Jump(&getChar1);
1130         }
1131         Bind(&isUtf8);
1132         {
1133             c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf16));
1134             Jump(&getChar1);
1135         }
1136         Bind(&getChar1);
1137         {
1138             Label isDigitZero(env);
1139             Label notDigitZero(env);
1140             Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
1141             Bind(&isDigitZero);
1142             {
1143                 Label lengthIsOne(env);
1144                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
1145                 Bind(&lengthIsOne);
1146                 {
1147                     result = Int32(0);
1148                     Jump(&exit);
1149                 }
1150             }
1151             Bind(&notDigitZero);
1152             {
1153                 Label isDigit(env);
1154                 DEFVARIABLE(i, VariableType::INT32(), Int32(1));
1155                 DEFVARIABLE(n, VariableType::INT32(), Int32Sub(*c, Int32('0')));
1156                 Branch(IsDigit(*c), &isDigit, &exit);
1157                 Label loopHead(env);
1158                 Label loopEnd(env);
1159                 Label afterLoop(env);
1160                 Bind(&isDigit);
1161                 Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
1162                 LoopBegin(&loopHead);
1163                 {
1164                     Label isUtf16A(env);
1165                     Label notUtf16(env);
1166                     Label getChar2(env);
1167                     Branch(isUtf16String, &isUtf16A, &notUtf16);
1168                     Bind(&isUtf16A);
1169                     {
1170                         // 2 : 2 means utf16 char width is two bytes
1171                         auto charOffset = PtrMul(ZExtInt32ToPtr(*i),  IntPtr(2));
1172                         c = ZExtInt16ToInt32(Load(VariableType::INT16(), dataUtf16, charOffset));
1173                         Jump(&getChar2);
1174                     }
1175                     Bind(&notUtf16);
1176                     {
1177                         c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf16, ZExtInt32ToPtr(*i)));
1178                         Jump(&getChar2);
1179                     }
1180                     Bind(&getChar2);
1181                     {
1182                         Label isDigit2(env);
1183                         Label notDigit2(env);
1184                         Branch(IsDigit(*c), &isDigit2, &notDigit2);
1185                         Bind(&isDigit2);
1186                         {
1187                             // 10 means the base of digit is 10.
1188                             n = Int32Add(Int32Mul(*n, Int32(10)),
1189                                          Int32Sub(*c, Int32('0')));
1190                             i = Int32Add(*i, Int32(1));
1191                             Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
1192                         }
1193                         Bind(&notDigit2);
1194                         Jump(&exit);
1195                     }
1196                 }
1197                 Bind(&loopEnd);
1198                 LoopEnd(&loopHead);
1199                 Bind(&afterLoop);
1200                 {
1201                     Label lessThanMaxIndex(env);
1202                     Branch(Int32UnsignedLessThan(*n, Int32(JSObject::MAX_ELEMENT_INDEX)),
1203                            &lessThanMaxIndex, &exit);
1204                     Bind(&lessThanMaxIndex);
1205                     {
1206                         result = *n;
1207                         Jump(&exit);
1208                     }
1209                 }
1210             }
1211         }
1212     }
1213     Bind(&exit);
1214     auto ret = *result;
1215     env->SubCfgExit();
1216     return ret;
1217 }
1218 
TryToElementsIndex(GateRef key)1219 GateRef StubBuilder::TryToElementsIndex(GateRef key)
1220 {
1221     auto env = GetEnvironment();
1222     Label entry(env);
1223     env->SubCfgEntry(&entry);
1224     Label exit(env);
1225     Label isKeyInt(env);
1226     Label notKeyInt(env);
1227 
1228     DEFVARIABLE(resultKey, VariableType::INT32(), Int32(-1));
1229     Branch(TaggedIsInt(key), &isKeyInt, &notKeyInt);
1230     Bind(&isKeyInt);
1231     {
1232         resultKey = GetInt32OfTInt(key);
1233         Jump(&exit);
1234     }
1235     Bind(&notKeyInt);
1236     {
1237         Label isString(env);
1238         Label notString(env);
1239         Branch(TaggedIsString(key), &isString, &notString);
1240         Bind(&isString);
1241         {
1242             resultKey = StringToElementIndex(key);
1243             Jump(&exit);
1244         }
1245         Bind(&notString);
1246         {
1247             Label isDouble(env);
1248             Branch(TaggedIsDouble(key), &isDouble, &exit);
1249             Bind(&isDouble);
1250             {
1251                 GateRef number = GetDoubleOfTDouble(key);
1252                 GateRef integer = ChangeFloat64ToInt32(number);
1253                 Label isEqual(env);
1254                 Branch(DoubleEqual(number, ChangeInt32ToFloat64(integer)), &isEqual, &exit);
1255                 Bind(&isEqual);
1256                 {
1257                     resultKey = integer;
1258                     Jump(&exit);
1259                 }
1260             }
1261         }
1262     }
1263     Bind(&exit);
1264     auto ret = *resultKey;
1265     env->SubCfgExit();
1266     return ret;
1267 }
1268 
LdGlobalRecord(GateRef glue,GateRef key)1269 GateRef StubBuilder::LdGlobalRecord(GateRef glue, GateRef key)
1270 {
1271     auto env = GetEnvironment();
1272     Label entry(env);
1273     env->SubCfgEntry(&entry);
1274     Label exit(env);
1275 
1276     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1277     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1278     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1279     GateRef globalRecord = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::GLOBAL_RECORD);
1280     GateRef recordEntry = FindEntryFromNameDictionary(glue, globalRecord, key);
1281     Label foundInGlobalRecord(env);
1282     Branch(Int32NotEqual(recordEntry, Int32(-1)), &foundInGlobalRecord, &exit);
1283     Bind(&foundInGlobalRecord);
1284     {
1285         result = GetBoxFromGlobalDictionary(globalRecord, recordEntry);
1286         Jump(&exit);
1287     }
1288     Bind(&exit);
1289     auto ret = *result;
1290     env->SubCfgExit();
1291     return ret;
1292 }
1293 
LoadFromField(GateRef receiver,GateRef handlerInfo)1294 GateRef StubBuilder::LoadFromField(GateRef receiver, GateRef handlerInfo)
1295 {
1296     auto env = GetEnvironment();
1297     Label entry(env);
1298     env->SubCfgEntry(&entry);
1299     Label exit(env);
1300     Label handlerInfoIsInlinedProps(env);
1301     Label handlerInfoNotInlinedProps(env);
1302     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1303     GateRef index = HandlerBaseGetOffset(handlerInfo);
1304     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
1305     Bind(&handlerInfoIsInlinedProps);
1306     {
1307         result = Load(VariableType::JS_ANY(), receiver, PtrMul(ZExtInt32ToPtr(index),
1308             IntPtr(JSTaggedValue::TaggedTypeSize())));
1309         Jump(&exit);
1310     }
1311     Bind(&handlerInfoNotInlinedProps);
1312     {
1313         result = GetValueFromTaggedArray(GetPropertiesArray(receiver), index);
1314         Jump(&exit);
1315     }
1316     Bind(&exit);
1317     auto ret = *result;
1318     env->SubCfgExit();
1319     return ret;
1320 }
1321 
LoadGlobal(GateRef cell)1322 GateRef StubBuilder::LoadGlobal(GateRef cell)
1323 {
1324     auto env = GetEnvironment();
1325     Label entry(env);
1326     env->SubCfgEntry(&entry);
1327     Label exit(env);
1328     Label cellIsInvalid(env);
1329     Label cellNotInvalid(env);
1330     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1331     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
1332     Bind(&cellIsInvalid);
1333     {
1334         Jump(&exit);
1335     }
1336     Bind(&cellNotInvalid);
1337     {
1338         result = GetValueFromPropertyBox(cell);
1339         Jump(&exit);
1340     }
1341     Bind(&exit);
1342     auto ret = *result;
1343     env->SubCfgExit();
1344     return ret;
1345 }
1346 
CheckPolyHClass(GateRef cachedValue,GateRef hclass)1347 GateRef StubBuilder::CheckPolyHClass(GateRef cachedValue, GateRef hclass)
1348 {
1349     auto env = GetEnvironment();
1350     Label entry(env);
1351     env->SubCfgEntry(&entry);
1352     Label exit(env);
1353     Label loopHead(env);
1354     Label loopEnd(env);
1355     Label iLessLength(env);
1356     Label hasHclass(env);
1357     Label cachedValueNotWeak(env);
1358     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1359     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1360     Branch(TaggedIsWeak(cachedValue), &exit, &cachedValueNotWeak);
1361     Bind(&cachedValueNotWeak);
1362     {
1363         GateRef length = GetLengthOfTaggedArray(cachedValue);
1364         Jump(&loopHead);
1365         LoopBegin(&loopHead);
1366         {
1367             Branch(Int32UnsignedLessThan(*i, length), &iLessLength, &exit);
1368             Bind(&iLessLength);
1369             {
1370                 GateRef element = GetValueFromTaggedArray(cachedValue, *i);
1371                 Branch(Equal(LoadObjectFromWeakRef(element), hclass), &hasHclass, &loopEnd);
1372                 Bind(&hasHclass);
1373                 result = GetValueFromTaggedArray(cachedValue,
1374                                                  Int32Add(*i, Int32(1)));
1375                 Jump(&exit);
1376             }
1377             Bind(&loopEnd);
1378             i = Int32Add(*i, Int32(2));  // 2 means one ic, two slot
1379             LoopEnd(&loopHead);
1380         }
1381     }
1382     Bind(&exit);
1383     auto ret = *result;
1384     env->SubCfgExit();
1385     return ret;
1386 }
1387 
LoadICWithHandler(GateRef glue,GateRef receiver,GateRef argHolder,GateRef argHandler)1388 GateRef StubBuilder::LoadICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder, GateRef argHandler)
1389 {
1390     auto env = GetEnvironment();
1391     Label entry(env);
1392     env->SubCfgEntry(&entry);
1393     Label exit(env);
1394     Label handlerIsInt(env);
1395     Label handlerNotInt(env);
1396     Label handlerInfoIsField(env);
1397     Label handlerInfoNotField(env);
1398     Label handlerInfoIsNonExist(env);
1399     Label handlerInfoNotNonExist(env);
1400     Label handlerIsPrototypeHandler(env);
1401     Label handlerNotPrototypeHandler(env);
1402     Label cellHasChanged(env);
1403     Label loopHead(env);
1404     Label loopEnd(env);
1405     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1406     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
1407     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
1408 
1409     Jump(&loopHead);
1410     LoopBegin(&loopHead);
1411     {
1412         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
1413         Bind(&handlerIsInt);
1414         {
1415             GateRef handlerInfo = GetInt32OfTInt(*handler);
1416             Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
1417             Bind(&handlerInfoIsField);
1418             {
1419                 result = LoadFromField(*holder, handlerInfo);
1420                 Jump(&exit);
1421             }
1422             Bind(&handlerInfoNotField);
1423             {
1424                 Branch(IsNonExist(handlerInfo), &handlerInfoIsNonExist, &handlerInfoNotNonExist);
1425                 Bind(&handlerInfoIsNonExist);
1426                 Jump(&exit);
1427                 Bind(&handlerInfoNotNonExist);
1428                 GateRef accessor = LoadFromField(*holder, handlerInfo);
1429                 result = CallGetterHelper(glue, receiver, *holder, accessor);
1430                 Jump(&exit);
1431             }
1432         }
1433         Bind(&handlerNotInt);
1434         Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
1435         Bind(&handlerIsPrototypeHandler);
1436         {
1437             GateRef cellValue = GetProtoCell(*handler);
1438             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1439             Bind(&cellHasChanged);
1440             {
1441                 result = Hole();
1442                 Jump(&exit);
1443             }
1444             Bind(&loopEnd);
1445             holder = GetPrototypeHandlerHolder(*handler);
1446             handler = GetPrototypeHandlerHandlerInfo(*handler);
1447             LoopEnd(&loopHead);
1448         }
1449     }
1450     Bind(&handlerNotPrototypeHandler);
1451     result = LoadGlobal(*handler);
1452     Jump(&exit);
1453 
1454     Bind(&exit);
1455     auto ret = *result;
1456     env->SubCfgExit();
1457     return ret;
1458 }
1459 
LoadElement(GateRef receiver,GateRef key)1460 GateRef StubBuilder::LoadElement(GateRef receiver, GateRef key)
1461 {
1462     auto env = GetEnvironment();
1463     Label entry(env);
1464     env->SubCfgEntry(&entry);
1465     Label exit(env);
1466     Label indexLessZero(env);
1467     Label indexNotLessZero(env);
1468     Label lengthLessIndex(env);
1469     Label lengthNotLessIndex(env);
1470     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1471     GateRef index = TryToElementsIndex(key);
1472     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1473     Bind(&indexLessZero);
1474     {
1475         Jump(&exit);
1476     }
1477     Bind(&indexNotLessZero);
1478     {
1479         GateRef elements = GetElementsArray(receiver);
1480         Branch(Int32LessThanOrEqual(GetLengthOfTaggedArray(elements), index), &lengthLessIndex, &lengthNotLessIndex);
1481         Bind(&lengthLessIndex);
1482         Jump(&exit);
1483         Bind(&lengthNotLessIndex);
1484         result = GetValueFromTaggedArray(elements, index);
1485         Jump(&exit);
1486     }
1487     Bind(&exit);
1488     auto ret = *result;
1489     env->SubCfgExit();
1490     return ret;
1491 }
1492 
ICStoreElement(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef handler)1493 GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef handler)
1494 {
1495     auto env = GetEnvironment();
1496     Label entry(env);
1497     env->SubCfgEntry(&entry);
1498     Label exit(env);
1499     Label indexLessZero(env);
1500     Label indexNotLessZero(env);
1501     Label handerInfoIsJSArray(env);
1502     Label handerInfoNotJSArray(env);
1503     Label isJsCOWArray(env);
1504     Label isNotJsCOWArray(env);
1505     Label setElementsLength(env);
1506     Label indexGreaterLength(env);
1507     Label indexGreaterCapacity(env);
1508     Label callRuntime(env);
1509     Label storeElement(env);
1510     Label handlerIsInt(env);
1511     Label handlerNotInt(env);
1512     Label cellHasChanged(env);
1513     Label cellHasNotChanged(env);
1514     Label loopHead(env);
1515     Label loopEnd(env);
1516     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1517     DEFVARIABLE(varHandler, VariableType::JS_ANY(), handler);
1518     GateRef index = TryToElementsIndex(key);
1519     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1520     Bind(&indexLessZero);
1521     {
1522         Jump(&exit);
1523     }
1524     Bind(&indexNotLessZero);
1525     {
1526         Jump(&loopHead);
1527         LoopBegin(&loopHead);
1528         Branch(TaggedIsInt(*varHandler), &handlerIsInt, &handlerNotInt);
1529         Bind(&handlerIsInt);
1530         {
1531             GateRef handlerInfo = GetInt32OfTInt(*varHandler);
1532             Branch(HandlerBaseIsJSArray(handlerInfo), &handerInfoIsJSArray, &handerInfoNotJSArray);
1533             Bind(&handerInfoIsJSArray);
1534             {
1535                 Branch(IsJsCOWArray(receiver), &isJsCOWArray, &isNotJsCOWArray);
1536                 Bind(&isJsCOWArray);
1537                 {
1538                     CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {receiver});
1539                     Jump(&setElementsLength);
1540                 }
1541                 Bind(&isNotJsCOWArray);
1542                 {
1543                     Jump(&setElementsLength);
1544                 }
1545                 Bind(&setElementsLength);
1546                 {
1547                     GateRef oldLength = GetArrayLength(receiver);
1548                     Branch(Int32GreaterThanOrEqual(index, oldLength), &indexGreaterLength, &handerInfoNotJSArray);
1549                     Bind(&indexGreaterLength);
1550                     Store(VariableType::INT64(), glue, receiver,
1551                         IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET),
1552                         IntToTaggedInt(Int32Add(index, Int32(1))));
1553                 }
1554                 Jump(&handerInfoNotJSArray);
1555             }
1556             Bind(&handerInfoNotJSArray);
1557             {
1558                 GateRef elements = GetElementsArray(receiver);
1559                 GateRef capacity = GetLengthOfTaggedArray(elements);
1560                 Branch(Int32GreaterThanOrEqual(index, capacity), &callRuntime, &storeElement);
1561                 Bind(&callRuntime);
1562                 {
1563                     result = CallRuntime(glue,
1564                         RTSTUB_ID(TaggedArraySetValue),
1565                         { receiver, value, elements, IntToTaggedInt(index),
1566                           IntToTaggedInt(capacity) });
1567                     Jump(&exit);
1568                 }
1569                 Bind(&storeElement);
1570                 {
1571                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
1572                     result = Undefined();
1573                     Jump(&exit);
1574                 }
1575             }
1576         }
1577         Bind(&handlerNotInt);
1578         {
1579             GateRef cellValue = GetProtoCell(*varHandler);
1580             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1581             Bind(&cellHasChanged);
1582             {
1583                 Jump(&exit);
1584             }
1585             Bind(&loopEnd);
1586             {
1587                 varHandler = GetPrototypeHandlerHandlerInfo(*varHandler);
1588                 LoopEnd(&loopHead);
1589             }
1590         }
1591     }
1592     Bind(&exit);
1593     auto ret = *result;
1594     env->SubCfgExit();
1595     return ret;
1596 }
1597 
GetArrayLength(GateRef object)1598 GateRef StubBuilder::GetArrayLength(GateRef object)
1599 {
1600     auto env = GetEnvironment();
1601     Label entry(env);
1602     env->SubCfgEntry(&entry);
1603     Label exit(env);
1604     Label lengthIsInt(env);
1605     Label lengthNotInt(env);
1606     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
1607     GateRef lengthOffset = IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET);
1608     GateRef length = Load(VariableType::INT64(), object, lengthOffset);
1609     Branch(TaggedIsInt(length), &lengthIsInt, &lengthNotInt);
1610     Bind(&lengthIsInt);
1611     {
1612         result = GetInt32OfTInt(length);
1613         Jump(&exit);
1614     }
1615     Bind(&lengthNotInt);
1616     {
1617         result = ChangeFloat64ToInt32(GetDoubleOfTDouble(length));
1618         Jump(&exit);
1619     }
1620     Bind(&exit);
1621     auto ret = *result;
1622     env->SubCfgExit();
1623     return ret;
1624 }
1625 
StoreICWithHandler(GateRef glue,GateRef receiver,GateRef argHolder,GateRef value,GateRef argHandler)1626 GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder,
1627                                         GateRef value, GateRef argHandler)
1628 {
1629     auto env = GetEnvironment();
1630     Label entry(env);
1631     env->SubCfgEntry(&entry);
1632     Label exit(env);
1633     Label handlerIsInt(env);
1634     Label handlerNotInt(env);
1635     Label handlerInfoIsField(env);
1636     Label handlerInfoNotField(env);
1637     Label handlerIsTransitionHandler(env);
1638     Label handlerNotTransitionHandler(env);
1639     Label handlerIsTransWithProtoHandler(env);
1640     Label handlerNotTransWithProtoHandler(env);
1641     Label handlerIsPrototypeHandler(env);
1642     Label handlerNotPrototypeHandler(env);
1643     Label handlerIsPropertyBox(env);
1644     Label handlerNotPropertyBox(env);
1645     Label handlerIsStoreTSHandler(env);
1646     Label handlerNotStoreTSHandler(env);
1647     Label aotHandlerInfoIsField(env);
1648     Label aotHandlerInfoNotField(env);
1649     Label cellHasChanged(env);
1650     Label cellNotChanged(env);
1651     Label aotCellNotChanged(env);
1652     Label loopHead(env);
1653     Label loopEnd(env);
1654     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1655     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
1656     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
1657     Jump(&loopHead);
1658     LoopBegin(&loopHead);
1659     {
1660         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
1661         Bind(&handlerIsInt);
1662         {
1663             GateRef handlerInfo = GetInt32OfTInt(*handler);
1664             Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
1665             Bind(&handlerInfoIsField);
1666             {
1667                 StoreField(glue, receiver, value, handlerInfo);
1668                 Jump(&exit);
1669             }
1670             Bind(&handlerInfoNotField);
1671             {
1672                 GateRef accessor = LoadFromField(*holder, handlerInfo);
1673                 result = CallSetterHelper(glue, receiver, accessor, value);
1674                 Jump(&exit);
1675             }
1676         }
1677         Bind(&handlerNotInt);
1678         {
1679             Branch(TaggedIsTransitionHandler(*handler), &handlerIsTransitionHandler, &handlerNotTransitionHandler);
1680             Bind(&handlerIsTransitionHandler);
1681             {
1682                 StoreWithTransition(glue, receiver, value, *handler);
1683                 Jump(&exit);
1684             }
1685             Bind(&handlerNotTransitionHandler);
1686             {
1687                 Branch(TaggedIsTransWithProtoHandler(*handler), &handlerIsTransWithProtoHandler,
1688                     &handlerNotTransWithProtoHandler);
1689                 Bind(&handlerIsTransWithProtoHandler);
1690                 {
1691                     GateRef cellValue = GetProtoCell(*handler);
1692                     Branch(GetHasChanged(cellValue), &cellHasChanged, &cellNotChanged);
1693                     Bind(&cellNotChanged);
1694                     {
1695                         StoreWithTransition(glue, receiver, value, *handler, true);
1696                         Jump(&exit);
1697                     }
1698                 }
1699                 Bind(&handlerNotTransWithProtoHandler);
1700                 {
1701                     Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
1702                     Bind(&handlerNotPrototypeHandler);
1703                     {
1704                         Branch(TaggedIsPropertyBox(*handler), &handlerIsPropertyBox, &handlerNotPropertyBox);
1705                         Bind(&handlerIsPropertyBox);
1706                         StoreGlobal(glue, value, *handler);
1707                         Jump(&exit);
1708                     }
1709                 }
1710             }
1711         }
1712         Bind(&handlerIsPrototypeHandler);
1713         {
1714             GateRef cellValue = GetProtoCell(*handler);
1715             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1716             Bind(&loopEnd);
1717             {
1718                 holder = GetPrototypeHandlerHolder(*handler);
1719                 handler = GetPrototypeHandlerHandlerInfo(*handler);
1720                 LoopEnd(&loopHead);
1721             }
1722         }
1723         Bind(&handlerNotPropertyBox);
1724         {
1725             Branch(TaggedIsStoreTSHandler(*handler), &handlerIsStoreTSHandler, &handlerNotStoreTSHandler);
1726             Bind(&handlerIsStoreTSHandler);
1727             {
1728                 GateRef cellValue = GetProtoCell(*handler);
1729                 Branch(GetHasChanged(cellValue), &cellHasChanged, &aotCellNotChanged);
1730                 Bind(&aotCellNotChanged);
1731                 {
1732                     holder = GetStoreTSHandlerHolder(*handler);
1733                     handler = GetStoreTSHandlerHandlerInfo(*handler);
1734                     GateRef handlerInfo = GetInt32OfTInt(*handler);
1735                     Branch(IsField(handlerInfo), &aotHandlerInfoIsField, &aotHandlerInfoNotField);
1736                     Bind(&aotHandlerInfoIsField);
1737                     {
1738                         StoreField(glue, receiver, value, handlerInfo);
1739                         Jump(&exit);
1740                     }
1741                     Bind(&aotHandlerInfoNotField);
1742                     {
1743                         GateRef accessor = LoadFromField(*holder, handlerInfo);
1744                         result = CallSetterHelper(glue, receiver, accessor, value);
1745                         Jump(&exit);
1746                     }
1747                 }
1748             }
1749             Bind(&handlerNotStoreTSHandler);
1750             Jump(&exit);
1751         }
1752         Bind(&cellHasChanged);
1753         {
1754             result = Hole();
1755             Jump(&exit);
1756         }
1757     }
1758     Bind(&exit);
1759     auto ret = *result;
1760     env->SubCfgExit();
1761     return ret;
1762 }
1763 
StoreField(GateRef glue,GateRef receiver,GateRef value,GateRef handler)1764 void StubBuilder::StoreField(GateRef glue, GateRef receiver, GateRef value, GateRef handler)
1765 {
1766     auto env = GetEnvironment();
1767     Label entry(env);
1768     env->SubCfgEntry(&entry);
1769     Label exit(env);
1770     Label handlerIsInlinedProperty(env);
1771     Label handlerNotInlinedProperty(env);
1772     GateRef index = HandlerBaseGetOffset(handler);
1773     Branch(HandlerBaseIsInlinedProperty(handler), &handlerIsInlinedProperty, &handlerNotInlinedProperty);
1774     Bind(&handlerIsInlinedProperty);
1775     {
1776         Store(VariableType::JS_ANY(),
1777               glue,
1778               receiver,
1779               PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize())),
1780               value);
1781         Jump(&exit);
1782     }
1783     Bind(&handlerNotInlinedProperty);
1784     {
1785         GateRef array = GetPropertiesArray(receiver);
1786         SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, index, value);
1787         Jump(&exit);
1788     }
1789     Bind(&exit);
1790     env->SubCfgExit();
1791 }
1792 
StoreWithTransition(GateRef glue,GateRef receiver,GateRef value,GateRef handler,bool withPrototype)1793 void StubBuilder::StoreWithTransition(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
1794                                       bool withPrototype)
1795 {
1796     auto env = GetEnvironment();
1797     Label entry(env);
1798     env->SubCfgEntry(&entry);
1799     Label exit(env);
1800 
1801     Label handlerInfoIsInlinedProps(env);
1802     Label handlerInfoNotInlinedProps(env);
1803     Label indexMoreCapacity(env);
1804     Label indexLessCapacity(env);
1805     GateRef newHClass;
1806     GateRef handlerInfo;
1807     if (withPrototype) {
1808         newHClass = GetTransWithProtoHClass(handler);
1809         handlerInfo = GetInt32OfTInt(GetTransWithProtoHandlerInfo(handler));
1810     } else {
1811         newHClass = GetTransitionHClass(handler);
1812         handlerInfo = GetInt32OfTInt(GetTransitionHandlerInfo(handler));
1813     }
1814 
1815     StoreHClass(glue, receiver, newHClass);
1816     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
1817     Bind(&handlerInfoNotInlinedProps);
1818     {
1819         GateRef array = GetPropertiesArray(receiver);
1820         GateRef capacity = GetLengthOfTaggedArray(array);
1821         GateRef index = HandlerBaseGetOffset(handlerInfo);
1822         Branch(Int32GreaterThanOrEqual(index, capacity), &indexMoreCapacity, &indexLessCapacity);
1823         Bind(&indexMoreCapacity);
1824         {
1825             CallRuntime(glue,
1826                         RTSTUB_ID(PropertiesSetValue),
1827                         { receiver, value, array, IntToTaggedInt(capacity),
1828                           IntToTaggedInt(index) });
1829             Jump(&exit);
1830         }
1831         Bind(&indexLessCapacity);
1832         {
1833             Store(VariableType::JS_ANY(),
1834                   glue,
1835                   PtrAdd(array, IntPtr(TaggedArray::DATA_OFFSET)),
1836                   PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize())),
1837                   value);
1838             Jump(&exit);
1839         }
1840     }
1841     Bind(&handlerInfoIsInlinedProps);
1842     {
1843         StoreField(glue, receiver, value, handlerInfo);
1844         Jump(&exit);
1845     }
1846     Bind(&exit);
1847     env->SubCfgExit();
1848 }
1849 
StoreGlobal(GateRef glue,GateRef value,GateRef cell)1850 GateRef StubBuilder::StoreGlobal(GateRef glue, GateRef value, GateRef cell)
1851 {
1852     auto env = GetEnvironment();
1853     Label entry(env);
1854     env->SubCfgEntry(&entry);
1855     Label exit(env);
1856     Label cellIsInvalid(env);
1857     Label cellNotInvalid(env);
1858     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1859     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
1860     Bind(&cellIsInvalid);
1861     {
1862         Jump(&exit);
1863     }
1864     Bind(&cellNotInvalid);
1865     {
1866         Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value);
1867         result = Undefined();
1868         Jump(&exit);
1869     }
1870     Bind(&exit);
1871     auto ret = *result;
1872     env->SubCfgExit();
1873     return ret;
1874 }
1875 
1876 template<typename DictionaryT>
GetAttributesFromDictionary(GateRef elements,GateRef entry)1877 GateRef StubBuilder::GetAttributesFromDictionary(GateRef elements, GateRef entry)
1878 {
1879     GateRef arrayIndex =
1880     Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
1881              Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
1882     GateRef attributesIndex =
1883         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_DETAILS_INDEX));
1884     auto attrValue = GetValueFromTaggedArray(elements, attributesIndex);
1885     return GetInt32OfTInt(attrValue);
1886 }
1887 
1888 template<typename DictionaryT>
GetValueFromDictionary(GateRef elements,GateRef entry)1889 GateRef StubBuilder::GetValueFromDictionary(GateRef elements, GateRef entry)
1890 {
1891     GateRef arrayIndex =
1892         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
1893                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
1894     GateRef valueIndex =
1895         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_VALUE_INDEX));
1896     return GetValueFromTaggedArray(elements, valueIndex);
1897 }
1898 
1899 template<typename DictionaryT>
GetKeyFromDictionary(GateRef elements,GateRef entry)1900 GateRef StubBuilder::GetKeyFromDictionary(GateRef elements, GateRef entry)
1901 {
1902     auto env = GetEnvironment();
1903     Label subentry(env);
1904     env->SubCfgEntry(&subentry);
1905     Label exit(env);
1906     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1907     Label ltZero(env);
1908     Label notLtZero(env);
1909     Label gtLength(env);
1910     Label notGtLength(env);
1911     GateRef dictionaryLength =
1912         Load(VariableType::INT32(), elements, IntPtr(TaggedArray::LENGTH_OFFSET));
1913     GateRef arrayIndex =
1914         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
1915                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
1916     Branch(Int32LessThan(arrayIndex, Int32(0)), &ltZero, &notLtZero);
1917     Bind(&ltZero);
1918     Jump(&exit);
1919     Bind(&notLtZero);
1920     Branch(Int32GreaterThan(arrayIndex, dictionaryLength), &gtLength, &notGtLength);
1921     Bind(&gtLength);
1922     Jump(&exit);
1923     Bind(&notGtLength);
1924     result = GetValueFromTaggedArray(elements, arrayIndex);
1925     Jump(&exit);
1926     Bind(&exit);
1927     auto ret = *result;
1928     env->SubCfgExit();
1929     return ret;
1930 }
1931 
UpdateValueAndAttributes(GateRef glue,GateRef elements,GateRef index,GateRef value,GateRef attr)1932 inline void StubBuilder::UpdateValueAndAttributes(GateRef glue, GateRef elements, GateRef index,
1933                                                   GateRef value, GateRef attr)
1934 {
1935     GateRef arrayIndex =
1936         Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
1937                  Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
1938     GateRef valueIndex =
1939         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
1940     GateRef attributesIndex =
1941         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_DETAILS_INDEX));
1942     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
1943     GateRef attroffset =
1944         PtrMul(ZExtInt32ToPtr(attributesIndex), IntPtr(JSTaggedValue::TaggedTypeSize()));
1945     GateRef dataOffset = PtrAdd(attroffset, IntPtr(TaggedArray::DATA_OFFSET));
1946     Store(VariableType::INT64(), glue, elements, dataOffset, IntToTaggedInt(attr));
1947 }
1948 
UpdateValueInDict(GateRef glue,GateRef elements,GateRef index,GateRef value)1949 inline void StubBuilder::UpdateValueInDict(GateRef glue, GateRef elements, GateRef index, GateRef value)
1950 {
1951     GateRef arrayIndex = Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
1952         Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
1953     GateRef valueIndex = Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
1954     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
1955 }
1956 
GetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index)1957 GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index)
1958 {
1959     auto env = GetEnvironment();
1960     Label entry(env);
1961     env->SubCfgEntry(&entry);
1962     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1963     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
1964     Label exit(env);
1965     Label loopHead(env);
1966     Label loopEnd(env);
1967     Label loopExit(env);
1968     Label afterLoop(env);
1969     Jump(&loopHead);
1970     LoopBegin(&loopHead);
1971     {
1972         GateRef hclass = LoadHClass(*holder);
1973         GateRef jsType = GetObjectType(hclass);
1974         Label isSpecialIndexed(env);
1975         Label notSpecialIndexed(env);
1976         Branch(IsSpecialIndexedObj(jsType), &isSpecialIndexed, &notSpecialIndexed);
1977         Bind(&isSpecialIndexed);
1978         {
1979             // TypeArray
1980             Label isFastTypeArray(env);
1981             Label notFastTypeArray(env);
1982             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
1983             Bind(&isFastTypeArray);
1984             {
1985                 result = CallRuntime(glue, RTSTUB_ID(GetTypeArrayPropertyByIndex),
1986                     { *holder, IntToTaggedInt(index), IntToTaggedInt(jsType)});
1987                 Jump(&exit);
1988             }
1989             Bind(&notFastTypeArray);
1990 
1991             Label isSpecialContainer(env);
1992             Label notSpecialContainer(env);
1993             // Add SpecialContainer
1994             Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
1995             Bind(&isSpecialContainer);
1996             {
1997                 result = GetContainerProperty(glue, *holder, index, jsType);
1998                 Jump(&exit);
1999             }
2000             Bind(&notSpecialContainer);
2001             {
2002                 result = Hole();
2003                 Jump(&exit);
2004             }
2005         }
2006         Bind(&notSpecialIndexed);
2007         {
2008             GateRef elements = GetElementsArray(*holder);
2009             Label isDictionaryElement(env);
2010             Label notDictionaryElement(env);
2011             Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2012             Bind(&notDictionaryElement);
2013             {
2014                 Label lessThanLength(env);
2015                 Label notLessThanLength(env);
2016                 Branch(Int32UnsignedLessThan(index, GetLengthOfTaggedArray(elements)),
2017                        &lessThanLength, &notLessThanLength);
2018                 Bind(&lessThanLength);
2019                 {
2020                     Label notHole(env);
2021                     Label isHole(env);
2022                     GateRef value = GetValueFromTaggedArray(elements, index);
2023                     Branch(TaggedIsNotHole(value), &notHole, &isHole);
2024                     Bind(&notHole);
2025                     {
2026                         result = value;
2027                         Jump(&exit);
2028                     }
2029                     Bind(&isHole);
2030                     {
2031                         Jump(&loopExit);
2032                     }
2033                 }
2034                 Bind(&notLessThanLength);
2035                 {
2036                     result = Hole();
2037                     Jump(&exit);
2038                 }
2039             }
2040             Bind(&isDictionaryElement);
2041             {
2042                 GateRef entryA = FindElementFromNumberDictionary(glue, elements, index);
2043                 Label notNegtiveOne(env);
2044                 Label negtiveOne(env);
2045                 Branch(Int32NotEqual(entryA, Int32(-1)), &notNegtiveOne, &negtiveOne);
2046                 Bind(&notNegtiveOne);
2047                 {
2048                     GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, entryA);
2049                     GateRef value = GetValueFromDictionary<NumberDictionary>(elements, entryA);
2050                     Label isAccessor(env);
2051                     Label notAccessor(env);
2052                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2053                     Bind(&isAccessor);
2054                     {
2055                         result = CallGetterHelper(glue, receiver, *holder, value);
2056                         Jump(&exit);
2057                     }
2058                     Bind(&notAccessor);
2059                     {
2060                         result = value;
2061                         Jump(&exit);
2062                     }
2063                 }
2064                 Bind(&negtiveOne);
2065                 Jump(&loopExit);
2066             }
2067             Bind(&loopExit);
2068             {
2069                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2070                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2071             }
2072         }
2073         Bind(&loopEnd);
2074         LoopEnd(&loopHead);
2075         Bind(&afterLoop);
2076         {
2077             result = Undefined();
2078             Jump(&exit);
2079         }
2080     }
2081     Bind(&exit);
2082     auto ret = *result;
2083     env->SubCfgExit();
2084     return ret;
2085 }
2086 
GetPropertyByValue(GateRef glue,GateRef receiver,GateRef keyValue)2087 GateRef StubBuilder::GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue)
2088 {
2089     auto env = GetEnvironment();
2090     Label entry(env);
2091     env->SubCfgEntry(&entry);
2092     DEFVARIABLE(key, VariableType::JS_ANY(), keyValue);
2093     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2094     Label isNumberOrStringSymbol(env);
2095     Label notNumber(env);
2096     Label isStringOrSymbol(env);
2097     Label notStringOrSymbol(env);
2098     Label exit(env);
2099 
2100     Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, &notNumber);
2101     Bind(&notNumber);
2102     {
2103         Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, &notStringOrSymbol);
2104         Bind(&notStringOrSymbol);
2105         {
2106             result = Hole();
2107             Jump(&exit);
2108         }
2109     }
2110     Bind(&isNumberOrStringSymbol);
2111     {
2112         GateRef index = TryToElementsIndex(*key);
2113         Label validIndex(env);
2114         Label notValidIndex(env);
2115         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
2116         Bind(&validIndex);
2117         {
2118             result = GetPropertyByIndex(glue, receiver, index);
2119             Jump(&exit);
2120         }
2121         Bind(&notValidIndex);
2122         {
2123             Label notNumber1(env);
2124             Label getByName(env);
2125             Branch(TaggedIsNumber(*key), &exit, &notNumber1);
2126             Bind(&notNumber1);
2127             {
2128                 Label isString(env);
2129                 Label notString(env);
2130                 Label isInternalString(env);
2131                 Label notIntenalString(env);
2132                 Branch(TaggedIsString(*key), &isString, &notString);
2133                 Bind(&isString);
2134                 {
2135                     Branch(IsInternalString(*key), &isInternalString, &notIntenalString);
2136                     Bind(&isInternalString);
2137                     Jump(&getByName);
2138                     Bind(&notIntenalString);
2139                     {
2140                         key = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *key });
2141                         Jump(&getByName);
2142                     }
2143                 }
2144                 Bind(&notString);
2145                 {
2146                     Jump(&getByName);
2147                 }
2148             }
2149             Bind(&getByName);
2150             {
2151                 result = GetPropertyByName(glue, receiver, *key);
2152                 Jump(&exit);
2153             }
2154         }
2155     }
2156     Bind(&exit);
2157     auto ret = *result;
2158     env->SubCfgExit();
2159     return ret;
2160 }
2161 
GetPropertyByName(GateRef glue,GateRef receiver,GateRef key)2162 GateRef StubBuilder::GetPropertyByName(GateRef glue, GateRef receiver, GateRef key)
2163 {
2164     auto env = GetEnvironment();
2165     Label entry(env);
2166     env->SubCfgEntry(&entry);
2167     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2168     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2169     Label exit(env);
2170     Label loopHead(env);
2171     Label loopEnd(env);
2172     Label loopExit(env);
2173     Label afterLoop(env);
2174     Jump(&loopHead);
2175     LoopBegin(&loopHead);
2176     {
2177         GateRef hclass = LoadHClass(*holder);
2178         GateRef jsType = GetObjectType(hclass);
2179         Label isSIndexObj(env);
2180         Label notSIndexObj(env);
2181         Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2182         Bind(&isSIndexObj);
2183         {
2184             // TypeArray
2185             Label isFastTypeArray(env);
2186             Label notFastTypeArray(env);
2187             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2188             Bind(&isFastTypeArray);
2189             {
2190                 result = GetTypeArrayPropertyByName(glue, receiver, *holder, key, jsType);
2191                 Label isNull(env);
2192                 Label notNull(env);
2193                 Branch(TaggedIsNull(*result), &isNull, &notNull);
2194                 Bind(&isNull);
2195                 {
2196                     result = Hole();
2197                     Jump(&exit);
2198                 }
2199                 Bind(&notNull);
2200                 Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2201             }
2202             Bind(&notFastTypeArray);
2203             {
2204                 result = Hole();
2205                 Jump(&exit);
2206             }
2207         }
2208         Bind(&notSIndexObj);
2209         {
2210             Label isDicMode(env);
2211             Label notDicMode(env);
2212             Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2213             Bind(&notDicMode);
2214             {
2215                 GateRef layOutInfo = GetLayoutFromHClass(hclass);
2216                 GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2217                 // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2218                 GateRef entryA = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2219                 Label hasEntry(env);
2220                 Label noEntry(env);
2221                 // if branch condition : entry != -1
2222                 Branch(Int32NotEqual(entryA, Int32(-1)), &hasEntry, &noEntry);
2223                 Bind(&hasEntry);
2224                 {
2225                     // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2226                     GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entryA);
2227                     GateRef attr = GetInt32OfTInt(propAttr);
2228                     GateRef value = JSObjectGetProperty(*holder, hclass, attr);
2229                     Label isPropertyBox(env);
2230                     Label notPropertyBox(env);
2231                     Branch(TaggedIsPropertyBox(value), &isPropertyBox, &notPropertyBox);
2232                     Bind(&isPropertyBox);
2233                     {
2234                         result = GetValueFromPropertyBox(value);
2235                         Jump(&exit);
2236                     }
2237                     Bind(&notPropertyBox);
2238                     Label isAccessor(env);
2239                     Label notAccessor(env);
2240                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2241                     Bind(&isAccessor);
2242                     {
2243                         result = CallGetterHelper(glue, receiver, *holder, value);
2244                         Jump(&exit);
2245                     }
2246                     Bind(&notAccessor);
2247                     {
2248                         Label notHole(env);
2249                         Branch(TaggedIsHole(value), &noEntry, &notHole);
2250                         Bind(&notHole);
2251                         {
2252                             result = value;
2253                             Jump(&exit);
2254                         }
2255                     }
2256                 }
2257                 Bind(&noEntry);
2258                 {
2259                     Jump(&loopExit);
2260                 }
2261             }
2262             Bind(&isDicMode);
2263             {
2264                 GateRef array = GetPropertiesArray(*holder);
2265                 // int entry = dict->FindEntry(key)
2266                 GateRef entryB = FindEntryFromNameDictionary(glue, array, key);
2267                 Label notNegtiveOne(env);
2268                 Label negtiveOne(env);
2269                 // if branch condition : entry != -1
2270                 Branch(Int32NotEqual(entryB, Int32(-1)), &notNegtiveOne, &negtiveOne);
2271                 Bind(&notNegtiveOne);
2272                 {
2273                     // auto value = dict->GetValue(entry)
2274                     GateRef attr = GetAttributesFromDictionary<NameDictionary>(array, entryB);
2275                     // auto attr = dict->GetAttributes(entry)
2276                     GateRef value = GetValueFromDictionary<NameDictionary>(array, entryB);
2277                     Label isAccessor1(env);
2278                     Label notAccessor1(env);
2279                     Branch(IsAccessor(attr), &isAccessor1, &notAccessor1);
2280                     Bind(&isAccessor1);
2281                     {
2282                         result = CallGetterHelper(glue, receiver, *holder, value);
2283                         Jump(&exit);
2284                     }
2285                     Bind(&notAccessor1);
2286                     {
2287                         result = value;
2288                         Jump(&exit);
2289                     }
2290                 }
2291                 Bind(&negtiveOne);
2292                 Jump(&loopExit);
2293             }
2294             Bind(&loopExit);
2295             {
2296                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2297                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2298             }
2299         }
2300         Bind(&loopEnd);
2301         LoopEnd(&loopHead);
2302         Bind(&afterLoop);
2303         {
2304             result = Undefined();
2305             Jump(&exit);
2306         }
2307     }
2308     Bind(&exit);
2309     auto ret = *result;
2310     env->SubCfgExit();
2311     return ret;
2312 }
2313 
CopyAllHClass(GateRef glue,GateRef dstHClass,GateRef srcHClass)2314 void StubBuilder::CopyAllHClass(GateRef glue, GateRef dstHClass, GateRef srcHClass)
2315 {
2316     auto env = GetEnvironment();
2317     Label entry(env);
2318     env->SubCfgEntry(&entry);
2319     auto proto = GetPrototypeFromHClass(srcHClass);
2320     SetPrototypeToHClass(VariableType::JS_POINTER(), glue, dstHClass, proto);
2321     SetBitFieldToHClass(glue, dstHClass, GetBitFieldFromHClass(srcHClass));
2322     SetNumberOfPropsToHClass(glue, dstHClass, GetNumberOfPropsFromHClass(srcHClass));
2323     SetTransitionsToHClass(VariableType::INT64(), glue, dstHClass, Undefined());
2324     SetProtoChangeDetailsToHClass(VariableType::INT64(), glue, dstHClass, Null());
2325     SetEnumCacheToHClass(VariableType::INT64(), glue, dstHClass, Null());
2326     SetLayoutToHClass(VariableType::JS_POINTER(), glue, dstHClass, GetLayoutFromHClass(srcHClass));
2327     env->SubCfgExit();
2328     return;
2329 }
2330 
FindTransitions(GateRef glue,GateRef receiver,GateRef hclass,GateRef key,GateRef metaData)2331 GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, GateRef key, GateRef metaData)
2332 {
2333     auto env = GetEnvironment();
2334     Label entry(env);
2335     env->SubCfgEntry(&entry);
2336     Label exit(env);
2337     GateRef transitionOffset = IntPtr(JSHClass::TRANSTIONS_OFFSET);
2338     GateRef transition = Load(VariableType::JS_POINTER(), hclass, transitionOffset);
2339     DEFVARIABLE(result, VariableType::JS_ANY(), transition);
2340 
2341     Label notUndefined(env);
2342     Branch(Equal(transition, Undefined()), &exit, &notUndefined);
2343     Bind(&notUndefined);
2344     {
2345         Label isWeak(env);
2346         Label notWeak(env);
2347         Branch(TaggedIsWeak(transition), &isWeak, &notWeak);
2348         Bind(&isWeak);
2349         {
2350             GateRef transitionHClass = LoadObjectFromWeakRef(transition);
2351             GateRef propNums = GetNumberOfPropsFromHClass(transitionHClass);
2352             GateRef last = Int32Sub(propNums, Int32(1));
2353             GateRef layoutInfo = GetLayoutFromHClass(transitionHClass);
2354             GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last);
2355             GateRef cachedAttr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(layoutInfo, last));
2356             GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr);
2357             Label keyMatch(env);
2358             Label isMatch(env);
2359             Label notMatch(env);
2360             Branch(Equal(cachedKey, key), &keyMatch, &notMatch);
2361             Bind(&keyMatch);
2362             {
2363                 Branch(Int32Equal(metaData, cachedMetaData), &isMatch, &notMatch);
2364                 Bind(&isMatch);
2365                 {
2366 #if ECMASCRIPT_ENABLE_IC
2367                     NotifyHClassChanged(glue, hclass, transitionHClass);
2368 #endif
2369                     StoreHClass(glue, receiver, transitionHClass);
2370                     Jump(&exit);
2371                 }
2372             }
2373             Bind(&notMatch);
2374             {
2375                 result = Undefined();
2376                 Jump(&exit);
2377             }
2378         }
2379         Bind(&notWeak);
2380         {
2381             // need to find from dictionary
2382             GateRef entryA = FindEntryFromTransitionDictionary(glue, transition, key, metaData);
2383             Label isFound(env);
2384             Label notFound(env);
2385             Branch(Int32NotEqual(entryA, Int32(-1)), &isFound, &notFound);
2386             Bind(&isFound);
2387             auto value = GetValueFromDictionary<TransitionsDictionary>(transition, entryA);
2388             Label valueUndefined(env);
2389             Label valueNotUndefined(env);
2390             Branch(Int64NotEqual(value, Undefined()), &valueNotUndefined,
2391                 &valueUndefined);
2392             Bind(&valueNotUndefined);
2393             {
2394                 GateRef newHClass = LoadObjectFromWeakRef(value);
2395                 result = newHClass;
2396 #if ECMASCRIPT_ENABLE_IC
2397                 NotifyHClassChanged(glue, hclass, newHClass);
2398 #endif
2399                 StoreHClass(glue, receiver, newHClass);
2400                 Jump(&exit);
2401                 Bind(&notFound);
2402                 result = Undefined();
2403                 Jump(&exit);
2404             }
2405             Bind(&valueUndefined);
2406             {
2407                 result = Undefined();
2408                 Jump(&exit);
2409             }
2410         }
2411     }
2412     Bind(&exit);
2413     auto ret = *result;
2414     env->SubCfgExit();
2415     return ret;
2416 }
2417 
SetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,GateRef value,bool useOwn)2418 GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn)
2419 {
2420     auto env = GetEnvironment();
2421     Label entry(env);
2422     env->SubCfgEntry(&entry);
2423     DEFVARIABLE(returnValue, VariableType::JS_ANY(), Hole());
2424     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2425     Label exit(env);
2426     Label ifEnd(env);
2427     Label loopHead(env);
2428     Label loopEnd(env);
2429     Label loopExit(env);
2430     Label afterLoop(env);
2431     Label isJsCOWArray(env);
2432     Label isNotJsCOWArray(env);
2433     Label setElementsArray(env);
2434     if (!useOwn) {
2435         Jump(&loopHead);
2436         LoopBegin(&loopHead);
2437     }
2438     GateRef hclass = LoadHClass(*holder);
2439     GateRef jsType = GetObjectType(hclass);
2440     Label isSpecialIndex(env);
2441     Label notSpecialIndex(env);
2442     Branch(IsSpecialIndexedObj(jsType), &isSpecialIndex, &notSpecialIndex);
2443     Bind(&isSpecialIndex);
2444     {
2445         // TypeArray
2446         Label isFastTypeArray(env);
2447         Label notFastTypeArray(env);
2448         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2449         Bind(&isFastTypeArray);
2450         {
2451             returnValue = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
2452                 { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType)});
2453             Jump(&exit);
2454         }
2455         Bind(&notFastTypeArray);
2456         returnValue = Hole();
2457         Jump(&exit);
2458     }
2459     Bind(&notSpecialIndex);
2460     {
2461         GateRef elements = GetElementsArray(*holder);
2462         Label isDictionaryElement(env);
2463         Label notDictionaryElement(env);
2464         Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2465         Bind(&notDictionaryElement);
2466         {
2467             Label isReceiver(env);
2468             if (useOwn) {
2469                 Branch(Equal(*holder, receiver), &isReceiver, &ifEnd);
2470             } else {
2471                 Branch(Equal(*holder, receiver), &isReceiver, &afterLoop);
2472             }
2473             Bind(&isReceiver);
2474             {
2475                 GateRef length = GetLengthOfTaggedArray(elements);
2476                 Label inRange(env);
2477                 if (useOwn) {
2478                     Branch(Int64LessThan(index, length), &inRange, &ifEnd);
2479                 } else {
2480                     Branch(Int64LessThan(index, length), &inRange, &loopExit);
2481                 }
2482                 Bind(&inRange);
2483                 {
2484                     GateRef value1 = GetValueFromTaggedArray(elements, index);
2485                     Label notHole(env);
2486                     if (useOwn) {
2487                         Branch(Int64NotEqual(value1, Hole()), &notHole, &ifEnd);
2488                     } else {
2489                         Branch(Int64NotEqual(value1, Hole()), &notHole, &loopExit);
2490                     }
2491                     Bind(&notHole);
2492                     {
2493                         Branch(IsJsCOWArray(*holder), &isJsCOWArray, &isNotJsCOWArray);
2494                         Bind(&isJsCOWArray);
2495                         {
2496                             CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {*holder});
2497                             GateRef newElements = GetElementsArray(*holder);
2498                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, newElements, index, value);
2499                             returnValue = Undefined();
2500                             Jump(&exit);
2501                         }
2502                         Bind(&isNotJsCOWArray);
2503                         {
2504                             Jump(&setElementsArray);
2505                         }
2506                         Bind(&setElementsArray);
2507                         {
2508                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
2509                             returnValue = Undefined();
2510                             Jump(&exit);
2511                         }
2512                     }
2513                 }
2514             }
2515         }
2516         Bind(&isDictionaryElement);
2517         {
2518             returnValue = Hole();
2519             Jump(&exit);
2520         }
2521     }
2522     if (useOwn) {
2523         Bind(&ifEnd);
2524     } else {
2525         Bind(&loopExit);
2526         {
2527             holder = GetPrototypeFromHClass(LoadHClass(*holder));
2528             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2529         }
2530         Bind(&loopEnd);
2531         LoopEnd(&loopHead);
2532         Bind(&afterLoop);
2533     }
2534     Label isExtensible(env);
2535     Label notExtensible(env);
2536     Branch(IsExtensible(receiver), &isExtensible, &notExtensible);
2537     Bind(&isExtensible);
2538     {
2539         GateRef result = CallRuntime(glue, RTSTUB_ID(AddElementInternal),
2540             { receiver, IntToTaggedInt(index), value,
2541             IntToTaggedInt(Int32(PropertyAttributes::GetDefaultAttributes())) });
2542         Label success(env);
2543         Label failed(env);
2544         Branch(TaggedIsTrue(result), &success, &failed);
2545         Bind(&success);
2546         {
2547             returnValue = Undefined();
2548             Jump(&exit);
2549         }
2550         Bind(&failed);
2551         {
2552             returnValue = Exception();
2553             Jump(&exit);
2554         }
2555     }
2556     Bind(&notExtensible);
2557     {
2558         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
2559         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2560         returnValue = Exception();
2561         Jump(&exit);
2562     }
2563     Bind(&exit);
2564     auto ret = *returnValue;
2565     env->SubCfgExit();
2566     return ret;
2567 }
2568 
SetPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn)2569 GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn)
2570 {
2571     auto env = GetEnvironment();
2572     Label entryPass(env);
2573     env->SubCfgEntry(&entryPass);
2574     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2575     DEFVARIABLE(holder, VariableType::JS_POINTER(), receiver);
2576     DEFVARIABLE(receiverHoleEntry, VariableType::INT32(), Int32(-1));
2577     Label exit(env);
2578     Label ifEnd(env);
2579     Label loopHead(env);
2580     Label loopEnd(env);
2581     Label loopExit(env);
2582     Label afterLoop(env);
2583     if (!useOwn) {
2584         // a do-while loop
2585         Jump(&loopHead);
2586         LoopBegin(&loopHead);
2587     }
2588     // auto *hclass = holder.GetTaggedObject()->GetClass()
2589     // JSType jsType = hclass->GetObjectType()
2590     GateRef hclass = LoadHClass(*holder);
2591     GateRef jsType = GetObjectType(hclass);
2592     Label isSIndexObj(env);
2593     Label notSIndexObj(env);
2594     // if branch condition : IsSpecialIndexedObj(jsType)
2595     Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2596     Bind(&isSIndexObj);
2597     {
2598         Label isFastTypeArray(env);
2599         Label notFastTypeArray(env);
2600         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2601         Bind(&isFastTypeArray);
2602         {
2603             result = SetTypeArrayPropertyByName(glue, receiver, *holder, key, value, jsType);
2604             Label isNull(env);
2605             Label notNull(env);
2606             Branch(TaggedIsNull(*result), &isNull, &notNull);
2607             Bind(&isNull);
2608             {
2609                 result = Hole();
2610                 Jump(&exit);
2611             }
2612             Bind(&notNull);
2613             Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2614         }
2615         Bind(&notFastTypeArray);
2616 
2617         Label isSpecialContainer(env);
2618         Label notSpecialContainer(env);
2619         // Add SpecialContainer
2620         Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
2621         Bind(&isSpecialContainer);
2622         {
2623             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotSetPropertyOnContainer));
2624             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2625             result = Exception();
2626             Jump(&exit);
2627         }
2628         Bind(&notSpecialContainer);
2629         {
2630             result = Hole();
2631             Jump(&exit);
2632         }
2633     }
2634     Bind(&notSIndexObj);
2635     {
2636         Label isDicMode(env);
2637         Label notDicMode(env);
2638         // if branch condition : LIKELY(!hclass->IsDictionaryMode())
2639         Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2640         Bind(&notDicMode);
2641         {
2642             // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject())
2643             GateRef layOutInfo = GetLayoutFromHClass(hclass);
2644             // int propsNumber = hclass->NumberOfPropsFromHClass()
2645             GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2646             // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2647             GateRef entry = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2648             Label hasEntry(env);
2649             // if branch condition : entry != -1
2650             if (useOwn) {
2651                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &ifEnd);
2652             } else {
2653                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &loopExit);
2654             }
2655             Bind(&hasEntry);
2656             {
2657                 // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2658                 GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry);
2659                 GateRef attr = GetInt32OfTInt(propAttr);
2660                 Label isAccessor(env);
2661                 Label notAccessor(env);
2662                 Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2663                 Bind(&isAccessor);
2664                 {
2665                     // auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr)
2666                     GateRef accessor = JSObjectGetProperty(*holder, hclass, attr);
2667                     Label shouldCall(env);
2668                     // ShouldCallSetter(receiver, *holder, accessor, attr)
2669                     Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &notAccessor);
2670                     Bind(&shouldCall);
2671                     {
2672                         result = CallSetterHelper(glue, receiver, accessor, value);
2673                         Jump(&exit);
2674                     }
2675                 }
2676                 Bind(&notAccessor);
2677                 {
2678                     Label writable(env);
2679                     Label notWritable(env);
2680                     Branch(IsWritable(attr), &writable, &notWritable);
2681                     Bind(&notWritable);
2682                     {
2683                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
2684                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2685                         result = Exception();
2686                         Jump(&exit);
2687                     }
2688                     Bind(&writable);
2689                     {
2690                         Label isTS(env);
2691                         Label notTS(env);
2692                         Branch(IsTSHClass(hclass), &isTS, &notTS);
2693                         Bind(&isTS);
2694                         {
2695                             GateRef attrVal = JSObjectGetProperty(*holder, hclass, attr);
2696                             Label attrValIsHole(env);
2697                             Branch(TaggedIsHole(attrVal), &attrValIsHole, &notTS);
2698                             Bind(&attrValIsHole);
2699                             {
2700                                 Label storeReceiverHoleEntry(env);
2701                                 Label noNeedStore(env);
2702                                 GateRef checkReceiverHoleEntry = Int32Equal(*receiverHoleEntry, Int32(-1));
2703                                 GateRef checkHolderEqualsRecv = Equal(*holder, receiver);
2704                                 Branch(BoolAnd(checkReceiverHoleEntry, checkHolderEqualsRecv),
2705                                     &storeReceiverHoleEntry, &noNeedStore);
2706                                 Bind(&storeReceiverHoleEntry);
2707                                 {
2708                                     receiverHoleEntry = entry;
2709                                     Jump(&noNeedStore);
2710                                 }
2711                                 Bind(&noNeedStore);
2712                                 if (useOwn) {
2713                                     Jump(&ifEnd);
2714                                 } else {
2715                                     Jump(&loopExit);
2716                                 }
2717                             }
2718                         }
2719                         Bind(&notTS);
2720                         Label holdEqualsRecv(env);
2721                         if (useOwn) {
2722                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &ifEnd);
2723                         } else {
2724                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &afterLoop);
2725                         }
2726                         Bind(&holdEqualsRecv);
2727                         {
2728                             // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value)
2729                             // return JSTaggedValue::Undefined()
2730                             JSObjectSetProperty(glue, *holder, hclass, attr, value);
2731                             result = Undefined();
2732                             Jump(&exit);
2733                         }
2734                     }
2735                 }
2736             }
2737         }
2738         Bind(&isDicMode);
2739         {
2740             GateRef array = GetPropertiesArray(*holder);
2741             // int entry = dict->FindEntry(key)
2742             GateRef entry1 = FindEntryFromNameDictionary(glue, array, key);
2743             Label notNegtiveOne(env);
2744             // if branch condition : entry != -1
2745             if (useOwn) {
2746                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &ifEnd);
2747             } else {
2748                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &loopExit);
2749             }
2750             Bind(&notNegtiveOne);
2751             {
2752                 // auto attr = dict->GetAttributes(entry)
2753                 GateRef attr1 = GetAttributesFromDictionary<NameDictionary>(array, entry1);
2754                 Label isAccessor1(env);
2755                 Label notAccessor1(env);
2756                 // if branch condition : UNLIKELY(attr.IsAccessor())
2757                 Branch(IsAccessor(attr1), &isAccessor1, &notAccessor1);
2758                 Bind(&isAccessor1);
2759                 {
2760                     // auto accessor = dict->GetValue(entry)
2761                     GateRef accessor1 = GetValueFromDictionary<NameDictionary>(array, entry1);
2762                     Label shouldCall1(env);
2763                     Branch(ShouldCallSetter(receiver, *holder, accessor1, attr1), &shouldCall1, &notAccessor1);
2764                     Bind(&shouldCall1);
2765                     {
2766                         result = CallSetterHelper(glue, receiver, accessor1, value);
2767                         Jump(&exit);
2768                     }
2769                 }
2770                 Bind(&notAccessor1);
2771                 {
2772                     Label writable1(env);
2773                     Label notWritable1(env);
2774                     Branch(IsWritable(attr1), &writable1, &notWritable1);
2775                     Bind(&notWritable1);
2776                     {
2777                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
2778                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2779                         result = Exception();
2780                         Jump(&exit);
2781                     }
2782                     Bind(&writable1);
2783                     {
2784                         Label holdEqualsRecv1(env);
2785                         if (useOwn) {
2786                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &ifEnd);
2787                         } else {
2788                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &afterLoop);
2789                         }
2790                         Bind(&holdEqualsRecv1);
2791                         {
2792                             // dict->UpdateValue(thread, entry, value)
2793                             // return JSTaggedValue::Undefined()
2794                             UpdateValueInDict(glue, array, entry1, value);
2795                             result = Undefined();
2796                             Jump(&exit);
2797                         }
2798                     }
2799                 }
2800             }
2801         }
2802     }
2803     if (useOwn) {
2804         Bind(&ifEnd);
2805     } else {
2806         Bind(&loopExit);
2807         {
2808             // holder = hclass->GetPrototype()
2809             holder = GetPrototypeFromHClass(LoadHClass(*holder));
2810             // loop condition for a do-while loop
2811             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2812         }
2813         Bind(&loopEnd);
2814         LoopEnd(&loopHead);
2815         Bind(&afterLoop);
2816     }
2817 
2818     Label holeEntryNotNegtiveOne(env);
2819     Label holeEntryIfEnd(env);
2820     Branch(Int32NotEqual(*receiverHoleEntry, Int32(-1)), &holeEntryNotNegtiveOne, &holeEntryIfEnd);
2821     Bind(&holeEntryNotNegtiveOne);
2822     {
2823         GateRef receiverHClass = LoadHClass(receiver);
2824         GateRef receiverLayoutInfo = GetLayoutFromHClass(receiverHClass);
2825         GateRef holePropAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry);
2826         GateRef holeAttr = GetInt32OfTInt(holePropAttr);
2827         JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, value);
2828         result = Undefined();
2829         Jump(&exit);
2830     }
2831     Bind(&holeEntryIfEnd);
2832 
2833     Label extensible(env);
2834     Label inextensible(env);
2835     Branch(IsExtensible(receiver), &extensible, &inextensible);
2836     Bind(&inextensible);
2837     {
2838         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
2839         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2840         result = Exception();
2841         Jump(&exit);
2842     }
2843     Bind(&extensible);
2844     {
2845         result = AddPropertyByName(glue, receiver, key, value,
2846             Int32(PropertyAttributes::GetDefaultAttributes()));
2847         Jump(&exit);
2848     }
2849     Bind(&exit);
2850     auto ret = *result;
2851     env->SubCfgExit();
2852     return ret;
2853 }
2854 
SetPropertyByValue(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn)2855 GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn)
2856 {
2857     auto env = GetEnvironment();
2858     Label subEntry1(env);
2859     env->SubCfgEntry(&subEntry1);
2860     DEFVARIABLE(varKey, VariableType::JS_ANY(), key);
2861     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2862     Label isNumberOrStringSymbol(env);
2863     Label notNumber(env);
2864     Label isStringOrSymbol(env);
2865     Label notStringOrSymbol(env);
2866     Label exit(env);
2867     Branch(TaggedIsNumber(*varKey), &isNumberOrStringSymbol, &notNumber);
2868     Bind(&notNumber);
2869     {
2870         Branch(TaggedIsStringOrSymbol(*varKey), &isNumberOrStringSymbol, &notStringOrSymbol);
2871         Bind(&notStringOrSymbol);
2872         {
2873             result = Hole();
2874             Jump(&exit);
2875         }
2876     }
2877     Bind(&isNumberOrStringSymbol);
2878     {
2879         GateRef index = TryToElementsIndex(*varKey);
2880         Label validIndex(env);
2881         Label notValidIndex(env);
2882         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
2883         Bind(&validIndex);
2884         {
2885             result = SetPropertyByIndex(glue, receiver, index, value, useOwn);
2886             Jump(&exit);
2887         }
2888         Bind(&notValidIndex);
2889         {
2890             Label isNumber1(env);
2891             Label notNumber1(env);
2892             Label setByName(env);
2893             Branch(TaggedIsNumber(*varKey), &isNumber1, &notNumber1);
2894             Bind(&isNumber1);
2895             {
2896                 result = Hole();
2897                 Jump(&exit);
2898             }
2899             Bind(&notNumber1);
2900             {
2901                 Label isString(env);
2902                 Label notIntenalString(env);
2903                 Branch(TaggedIsString(*varKey), &isString, &setByName);
2904                 Bind(&isString);
2905                 {
2906                     Branch(IsInternalString(*varKey), &setByName, &notIntenalString);
2907                     Bind(&notIntenalString);
2908                     {
2909                         varKey = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *varKey });
2910                         Jump(&setByName);
2911                     }
2912                 }
2913             }
2914             Bind(&setByName);
2915             {
2916                 result = SetPropertyByName(glue, receiver, *varKey, value, useOwn);
2917                 Jump(&exit);
2918             }
2919         }
2920     }
2921     Bind(&exit);
2922     auto ret = *result;
2923     env->SubCfgExit();
2924     return ret;
2925 }
2926 
NotifyHClassChanged(GateRef glue,GateRef oldHClass,GateRef newHClass)2927 void StubBuilder::NotifyHClassChanged(GateRef glue, GateRef oldHClass, GateRef newHClass)
2928 {
2929     auto env = GetEnvironment();
2930     Label entry(env);
2931     env->SubCfgEntry(&entry);
2932     Label exit(env);
2933     Label isProtoType(env);
2934     Branch(IsProtoTypeHClass(oldHClass), &isProtoType, &exit);
2935     Bind(&isProtoType);
2936     {
2937         Label notEqualHClass(env);
2938         Branch(Equal(oldHClass, newHClass), &exit, &notEqualHClass);
2939         Bind(&notEqualHClass);
2940         {
2941             SetIsProtoTypeToHClass(glue, newHClass, True());
2942             CallRuntime(glue, RTSTUB_ID(NoticeThroughChainAndRefreshUser), { oldHClass, newHClass });
2943             Jump(&exit);
2944         }
2945     }
2946     Bind(&exit);
2947     env->SubCfgExit();
2948     return;
2949 }
2950 
GetContainerProperty(GateRef glue,GateRef receiver,GateRef index,GateRef jsType)2951 GateRef StubBuilder::GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType)
2952 {
2953     auto env = GetEnvironment();
2954     Label entry(env);
2955     env->SubCfgEntry(&entry);
2956     Label exit(env);
2957     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2958 
2959     Label isDefaultLabel(env);
2960     Label noDefaultLabel(env);
2961     Branch(IsSpecialContainer(jsType), &noDefaultLabel, &isDefaultLabel);
2962     Bind(&noDefaultLabel);
2963     {
2964         result = JSAPIContainerGet(glue, receiver, index);
2965         Jump(&exit);
2966     }
2967     Bind(&isDefaultLabel);
2968     {
2969         Jump(&exit);
2970     }
2971     Bind(&exit);
2972 
2973     auto ret = *result;
2974     env->SubCfgExit();
2975     return ret;
2976 }
2977 
FastTypeOf(GateRef glue,GateRef obj)2978 GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj)
2979 {
2980     auto env = GetEnvironment();
2981     Label entry(env);
2982     env->SubCfgEntry(&entry);
2983     Label exit(env);
2984 
2985     GateRef gConstAddr = PtrAdd(glue,
2986         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env->Is32Bit())));
2987     GateRef undefinedIndex = GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX);
2988     GateRef gConstUndefinedStr = Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
2989     DEFVARIABLE(result, VariableType::JS_POINTER(), gConstUndefinedStr);
2990     Label objIsTrue(env);
2991     Label objNotTrue(env);
2992     Label defaultLabel(env);
2993     GateRef gConstBooleanStr = Load(VariableType::JS_POINTER(), gConstAddr,
2994         GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX));
2995     Branch(TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
2996     Bind(&objIsTrue);
2997     {
2998         result = gConstBooleanStr;
2999         Jump(&exit);
3000     }
3001     Bind(&objNotTrue);
3002     {
3003         Label objIsFalse(env);
3004         Label objNotFalse(env);
3005         Branch(TaggedIsFalse(obj), &objIsFalse, &objNotFalse);
3006         Bind(&objIsFalse);
3007         {
3008             result = gConstBooleanStr;
3009             Jump(&exit);
3010         }
3011         Bind(&objNotFalse);
3012         {
3013             Label objIsNull(env);
3014             Label objNotNull(env);
3015             Branch(TaggedIsNull(obj), &objIsNull, &objNotNull);
3016             Bind(&objIsNull);
3017             {
3018                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3019                     GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
3020                 Jump(&exit);
3021             }
3022             Bind(&objNotNull);
3023             {
3024                 Label objIsUndefined(env);
3025                 Label objNotUndefined(env);
3026                 Branch(TaggedIsUndefined(obj), &objIsUndefined, &objNotUndefined);
3027                 Bind(&objIsUndefined);
3028                 {
3029                     result = Load(VariableType::JS_POINTER(), gConstAddr,
3030                         GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX));
3031                     Jump(&exit);
3032                 }
3033                 Bind(&objNotUndefined);
3034                 Jump(&defaultLabel);
3035             }
3036         }
3037     }
3038     Bind(&defaultLabel);
3039     {
3040         Label objIsHeapObject(env);
3041         Label objNotHeapObject(env);
3042         Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject);
3043         Bind(&objIsHeapObject);
3044         {
3045             Label objIsString(env);
3046             Label objNotString(env);
3047             Branch(IsString(obj), &objIsString, &objNotString);
3048             Bind(&objIsString);
3049             {
3050                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3051                     GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX));
3052                 Jump(&exit);
3053             }
3054             Bind(&objNotString);
3055             {
3056                 Label objIsSymbol(env);
3057                 Label objNotSymbol(env);
3058                 Branch(IsSymbol(obj), &objIsSymbol, &objNotSymbol);
3059                 Bind(&objIsSymbol);
3060                 {
3061                     result = Load(VariableType::JS_POINTER(), gConstAddr,
3062                         GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX));
3063                     Jump(&exit);
3064                 }
3065                 Bind(&objNotSymbol);
3066                 {
3067                     Label objIsCallable(env);
3068                     Label objNotCallable(env);
3069                     Branch(IsCallable(obj), &objIsCallable, &objNotCallable);
3070                     Bind(&objIsCallable);
3071                     {
3072                         result = Load(VariableType::JS_POINTER(), gConstAddr,
3073                             GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX));
3074                         Jump(&exit);
3075                     }
3076                     Bind(&objNotCallable);
3077                     {
3078                         Label objIsBigInt(env);
3079                         Label objNotBigInt(env);
3080                         Branch(TaggedObjectIsBigInt(obj), &objIsBigInt, &objNotBigInt);
3081                         Bind(&objIsBigInt);
3082                         {
3083                             result = Load(VariableType::JS_POINTER(), gConstAddr,
3084                                 GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX));
3085                             Jump(&exit);
3086                         }
3087                         Bind(&objNotBigInt);
3088                         {
3089                             result = Load(VariableType::JS_POINTER(), gConstAddr,
3090                                 GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
3091                             Jump(&exit);
3092                         }
3093                     }
3094                 }
3095             }
3096         }
3097         Bind(&objNotHeapObject);
3098         {
3099             Label objIsNum(env);
3100             Label objNotNum(env);
3101             Branch(TaggedIsNumber(obj), &objIsNum, &objNotNum);
3102             Bind(&objIsNum);
3103             {
3104                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3105                     GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX));
3106                 Jump(&exit);
3107             }
3108             Bind(&objNotNum);
3109             Jump(&exit);
3110         }
3111     }
3112     Bind(&exit);
3113     auto ret = *result;
3114     env->SubCfgExit();
3115     return ret;
3116 }
3117 
InstanceOf(GateRef glue,GateRef object,GateRef target)3118 GateRef StubBuilder::InstanceOf(GateRef glue, GateRef object, GateRef target)
3119 {
3120     auto env = GetEnvironment();
3121     Label entry(env);
3122     env->SubCfgEntry(&entry);
3123     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3124     Label exit(env);
3125 
3126     // 1.If Type(target) is not Object, throw a TypeError exception.
3127     Label targetIsHeapObject(env);
3128     Label targetIsEcmaObject(env);
3129     Label targetNotEcmaObject(env);
3130     Branch(TaggedIsHeapObject(target), &targetIsHeapObject, &targetNotEcmaObject);
3131     Bind(&targetIsHeapObject);
3132     Branch(TaggedObjectIsEcmaObject(target), &targetIsEcmaObject, &targetNotEcmaObject);
3133     Bind(&targetNotEcmaObject);
3134     {
3135         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
3136         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3137         result = Exception();
3138         Jump(&exit);
3139     }
3140     Bind(&targetIsEcmaObject);
3141     {
3142         // 2.Let instOfHandler be GetMethod(target, @@hasInstance).
3143         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3144         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3145         GateRef hasInstanceSymbol = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
3146                                                       GlobalEnv::HASINSTANCE_SYMBOL_INDEX);
3147         GateRef instof = GetMethod(glue, target, hasInstanceSymbol);
3148 
3149         // 3.ReturnIfAbrupt(instOfHandler).
3150         Label isPendingException1(env);
3151         Label noPendingException1(env);
3152         Branch(HasPendingException(glue), &isPendingException1, &noPendingException1);
3153         Bind(&isPendingException1);
3154         {
3155             result = Exception();
3156             Jump(&exit);
3157         }
3158         Bind(&noPendingException1);
3159 
3160         // 4.If instOfHandler is not undefined, then
3161         Label instOfNotUndefined(env);
3162         Label instOfIsUndefined(env);
3163         Branch(TaggedIsUndefined(instof), &instOfIsUndefined, &instOfNotUndefined);
3164         Bind(&instOfNotUndefined);
3165         {
3166             GateRef retValue = JSCallDispatch(glue, instof, Int32(1), 0, Circuit::NullGate(),
3167                                               JSCallMode::CALL_SETTER, { target, object });
3168             result =  FastToBoolean(retValue);
3169             Jump(&exit);
3170         }
3171         Bind(&instOfIsUndefined);
3172         {
3173             // 5.If IsCallable(target) is false, throw a TypeError exception.
3174             Label targetIsCallable1(env);
3175             Label targetNotCallable1(env);
3176             Branch(IsCallable(target), &targetIsCallable1, &targetNotCallable1);
3177             Bind(&targetNotCallable1);
3178             {
3179                 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
3180                 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3181                 result = Exception();
3182                 Jump(&exit);
3183             }
3184             Bind(&targetIsCallable1);
3185             {
3186                 // 6.Return ? OrdinaryHasInstance(target, object).
3187                 result = OrdinaryHasInstance(glue, target, object);
3188                 Jump(&exit);
3189             }
3190         }
3191     }
3192     Bind(&exit);
3193     auto ret = *result;
3194     env->SubCfgExit();
3195     return ret;
3196 }
3197 
GetMethod(GateRef glue,GateRef obj,GateRef key)3198 GateRef StubBuilder::GetMethod(GateRef glue, GateRef obj, GateRef key)
3199 {
3200     auto env = GetEnvironment();
3201     Label entry(env);
3202     env->SubCfgEntry(&entry);
3203     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3204     Label exit(env);
3205 
3206     GateRef value = FastGetPropertyByName(glue, obj, key);
3207 
3208     Label isPendingException2(env);
3209     Label noPendingException2(env);
3210     Branch(HasPendingException(glue), &isPendingException2, &noPendingException2);
3211     Bind(&isPendingException2);
3212     {
3213         result = Exception();
3214         Jump(&exit);
3215     }
3216     Bind(&noPendingException2);
3217     Label valueIsUndefinedOrNull(env);
3218     Label valueNotUndefinedOrNull(env);
3219     Branch(TaggedIsUndefinedOrNull(value), &valueIsUndefinedOrNull, &valueNotUndefinedOrNull);
3220     Bind(&valueIsUndefinedOrNull);
3221     {
3222         result = Undefined();
3223         Jump(&exit);
3224     }
3225     Bind(&valueNotUndefinedOrNull);
3226     {
3227         Label valueIsCallable(env);
3228         Label valueNotCallable(env);
3229         Branch(IsCallable(value), &valueIsCallable, &valueNotCallable);
3230         Bind(&valueNotCallable);
3231         {
3232             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(NonCallable));
3233             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3234             result = Exception();
3235             Jump(&exit);
3236         }
3237         Bind(&valueIsCallable);
3238         {
3239             result = value;
3240             Jump(&exit);
3241         }
3242     }
3243     Bind(&exit);
3244     auto ret = *result;
3245     env->SubCfgExit();
3246     return ret;
3247 }
3248 
FastGetPropertyByName(GateRef glue,GateRef obj,GateRef key)3249 GateRef StubBuilder::FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key)
3250 {
3251     auto env = GetEnvironment();
3252     Label entry(env);
3253     env->SubCfgEntry(&entry);
3254     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3255     Label exit(env);
3256     Label checkResult(env);
3257     Label fastpath(env);
3258     Label slowpath(env);
3259 
3260     Branch(TaggedIsHeapObject(obj), &fastpath, &slowpath);
3261     Bind(&fastpath);
3262     {
3263         result = GetPropertyByName(glue, obj, key);
3264         Branch(TaggedIsHole(*result), &slowpath, &exit);
3265     }
3266     Bind(&slowpath);
3267     {
3268         result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
3269                              { Undefined(), obj, key, Int64ToTaggedPtr(Int32(0)) });
3270         Jump(&exit);
3271     }
3272     Bind(&exit);
3273     auto ret = *result;
3274     env->SubCfgExit();
3275     return ret;
3276 }
3277 
OrdinaryHasInstance(GateRef glue,GateRef target,GateRef obj)3278 GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj)
3279 {
3280     auto env = GetEnvironment();
3281     Label entry(env);
3282     env->SubCfgEntry(&entry);
3283     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3284     Label exit(env);
3285     DEFVARIABLE(object, VariableType::JS_ANY(), obj);
3286 
3287     // 1. If IsCallable(C) is false, return false.
3288     Label targetIsCallable2(env);
3289     Label targetNotCallable2(env);
3290     Branch(IsCallable(target), &targetIsCallable2, &targetNotCallable2);
3291     Bind(&targetNotCallable2);
3292     {
3293         result = TaggedFalse();
3294         Jump(&exit);
3295     }
3296     Bind(&targetIsCallable2);
3297     {
3298         // 2. If C has a [[BoundTargetFunction]] internal slot, then
3299         //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
3300         //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
3301         Label targetIsBoundFunction(env);
3302         Label targetNotBoundFunction(env);
3303         Branch(IsBoundFunction(target), &targetIsBoundFunction, &targetNotBoundFunction);
3304         Bind(&targetIsBoundFunction);
3305         {
3306             GateRef boundTarget = Load(VariableType::JS_ANY(), target, IntPtr(JSBoundFunction::BOUND_TARGET_OFFSET));
3307             result = CallRuntime(glue, RTSTUB_ID(InstanceOf), { obj, boundTarget });
3308             Jump(&exit);
3309         }
3310         Bind(&targetNotBoundFunction);
3311         {
3312             // 3. If Type(O) is not Object, return false
3313             Label objIsHeapObject(env);
3314             Label objIsEcmaObject(env);
3315             Label objNotEcmaObject(env);
3316             Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotEcmaObject);
3317             Bind(&objIsHeapObject);
3318             Branch(TaggedObjectIsEcmaObject(obj), &objIsEcmaObject, &objNotEcmaObject);
3319             Bind(&objNotEcmaObject);
3320             {
3321                 result = TaggedFalse();
3322                 Jump(&exit);
3323             }
3324             Bind(&objIsEcmaObject);
3325             {
3326                 // 4. Let P be Get(C, "prototype").
3327                 auto prototypeString = GetGlobalConstantValue(
3328                     VariableType::JS_POINTER(), glue, ConstantIndex::PROTOTYPE_STRING_INDEX);
3329 
3330                 GateRef constructorPrototype = FastGetPropertyByName(glue, target, prototypeString);
3331 
3332                 // 5. ReturnIfAbrupt(P).
3333                 // no throw exception, so needn't return
3334                 Label isPendingException3(env);
3335                 Label noPendingException3(env);
3336                 Branch(HasPendingException(glue), &isPendingException3, &noPendingException3);
3337                 Bind(&isPendingException3);
3338                 {
3339                     result = Exception();
3340                     Jump(&exit);
3341                 }
3342                 Bind(&noPendingException3);
3343 
3344                 // 6. If Type(P) is not Object, throw a TypeError exception.
3345                 Label constructorPrototypeIsHeapObject(env);
3346                 Label constructorPrototypeIsEcmaObject(env);
3347                 Label constructorPrototypeNotEcmaObject(env);
3348                 Branch(TaggedIsHeapObject(constructorPrototype), &constructorPrototypeIsHeapObject,
3349                     &constructorPrototypeNotEcmaObject);
3350                 Bind(&constructorPrototypeIsHeapObject);
3351                 Branch(TaggedObjectIsEcmaObject(constructorPrototype), &constructorPrototypeIsEcmaObject,
3352                     &constructorPrototypeNotEcmaObject);
3353                 Bind(&constructorPrototypeNotEcmaObject);
3354                 {
3355                     GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
3356                     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3357                     result = Exception();
3358                     Jump(&exit);
3359                 }
3360                 Bind(&constructorPrototypeIsEcmaObject);
3361                 {
3362                     // 7. Repeat
3363                     //    a.Let O be O.[[GetPrototypeOf]]().
3364                     //    b.ReturnIfAbrupt(O).
3365                     //    c.If O is null, return false.
3366                     //    d.If SameValue(P, O) is true, return true.
3367                     Label loopHead(env);
3368                     Label loopEnd(env);
3369                     Label afterLoop(env);
3370                     Label strictEqual1(env);
3371                     Label notStrictEqual1(env);
3372                     Label shouldReturn(env);
3373                     Label shouldContinue(env);
3374 
3375                     Branch(TaggedIsNull(*object), &afterLoop, &loopHead);
3376                     LoopBegin(&loopHead);
3377                     {
3378                         GateRef isEqual = SameValue(glue, *object, constructorPrototype);
3379 
3380                         Branch(isEqual, &strictEqual1, &notStrictEqual1);
3381                         Bind(&strictEqual1);
3382                         {
3383                             result = TaggedTrue();
3384                             Jump(&exit);
3385                         }
3386                         Bind(&notStrictEqual1);
3387                         {
3388                             object = GetPrototype(glue, *object);
3389 
3390                             Branch(HasPendingException(glue), &shouldReturn, &shouldContinue);
3391                             Bind(&shouldReturn);
3392                             {
3393                                 result = Exception();
3394                                 Jump(&exit);
3395                             }
3396                         }
3397                         Bind(&shouldContinue);
3398                         Branch(TaggedIsNull(*object), &afterLoop, &loopEnd);
3399                     }
3400                     Bind(&loopEnd);
3401                     LoopEnd(&loopHead);
3402                     Bind(&afterLoop);
3403                     {
3404                         result = TaggedFalse();
3405                         Jump(&exit);
3406                     }
3407                 }
3408             }
3409         }
3410     }
3411     Bind(&exit);
3412     auto ret = *result;
3413     env->SubCfgExit();
3414     return ret;
3415 }
3416 
GetPrototype(GateRef glue,GateRef object)3417 GateRef StubBuilder::GetPrototype(GateRef glue, GateRef object)
3418 {
3419     auto env = GetEnvironment();
3420     Label entry(env);
3421     env->SubCfgEntry(&entry);
3422     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3423     Label exit(env);
3424     Label objectIsHeapObject(env);
3425     Label objectIsEcmaObject(env);
3426     Label objectNotEcmaObject(env);
3427 
3428     Branch(TaggedIsHeapObject(object), &objectIsHeapObject, &objectNotEcmaObject);
3429     Bind(&objectIsHeapObject);
3430     Branch(TaggedObjectIsEcmaObject(object), &objectIsEcmaObject, &objectNotEcmaObject);
3431     Bind(&objectNotEcmaObject);
3432     {
3433         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotGetNotEcmaObject));
3434         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3435         result = Exception();
3436         Jump(&exit);
3437     }
3438     Bind(&objectIsEcmaObject);
3439     {
3440         Label objectIsJsProxy(env);
3441         Label objectNotIsJsProxy(env);
3442         Branch(IsJsProxy(object), &objectIsJsProxy, &objectNotIsJsProxy);
3443         Bind(&objectIsJsProxy);
3444         {
3445             result = CallRuntime(glue, RTSTUB_ID(CallGetPrototype), { object });
3446             Jump(&exit);
3447         }
3448         Bind(&objectNotIsJsProxy);
3449         {
3450             result = GetPrototypeFromHClass(LoadHClass(object));
3451             Jump(&exit);
3452         }
3453     }
3454     Bind(&exit);
3455     auto ret = *result;
3456     env->SubCfgExit();
3457     return ret;
3458 }
3459 
SameValue(GateRef glue,GateRef left,GateRef right)3460 GateRef StubBuilder::SameValue(GateRef glue, GateRef left, GateRef right)
3461 {
3462     auto env = GetEnvironment();
3463     Label entry(env);
3464     env->SubCfgEntry(&entry);
3465     DEFVARIABLE(result, VariableType::BOOL(), False());
3466     Label exit(env);
3467     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
3468     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
3469     Label strictEqual2(env);
3470     Label stringEqualCheck(env);
3471     Label stringCompare(env);
3472     Label bigIntEqualCheck(env);
3473     Label numberEqualCheck1(env);
3474 
3475     Branch(Equal(left, right), &strictEqual2, &numberEqualCheck1);
3476     Bind(&strictEqual2);
3477     {
3478         result = True();
3479         Jump(&exit);
3480     }
3481     Bind(&numberEqualCheck1);
3482     {
3483         Label leftIsNumber(env);
3484         Label leftIsNotNumber(env);
3485         Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
3486         Bind(&leftIsNumber);
3487         {
3488             Label rightIsNumber(env);
3489             Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
3490             Bind(&rightIsNumber);
3491             {
3492                 Label numberEqualCheck2(env);
3493                 Label leftIsInt(env);
3494                 Label leftNotInt(env);
3495                 Label getRight(env);
3496                 Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
3497                 Bind(&leftIsInt);
3498                 {
3499                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
3500                     Jump(&getRight);
3501                 }
3502                 Bind(&leftNotInt);
3503                 {
3504                     doubleLeft = GetDoubleOfTDouble(left);
3505                     Jump(&getRight);
3506                 }
3507                 Bind(&getRight);
3508                 {
3509                     Label rightIsInt(env);
3510                     Label rightNotInt(env);
3511                     Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
3512                     Bind(&rightIsInt);
3513                     {
3514                         doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
3515                         Jump(&numberEqualCheck2);
3516                     }
3517                     Bind(&rightNotInt);
3518                     {
3519                         doubleRight = GetDoubleOfTDouble(right);
3520                         Jump(&numberEqualCheck2);
3521                     }
3522                 }
3523                 Bind(&numberEqualCheck2);
3524                 {
3525                     Label boolAndCheck(env);
3526                     Label signbitCheck(env);
3527                     Branch(DoubleEqual(*doubleLeft, *doubleRight), &signbitCheck, &boolAndCheck);
3528                     Bind(&signbitCheck);
3529                     {
3530                         GateRef leftEncoding = CastDoubleToInt64(*doubleLeft);
3531                         GateRef RightEncoding = CastDoubleToInt64(*doubleRight);
3532                         Label leftIsMinusZero(env);
3533                         Label leftNotMinusZero(env);
3534                         Branch(Int64Equal(leftEncoding, Int64(base::MINUS_ZERO_BITS)),
3535                             &leftIsMinusZero, &leftNotMinusZero);
3536                         Bind(&leftIsMinusZero);
3537                         {
3538                             Label rightIsMinusZero(env);
3539                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &rightIsMinusZero, &exit);
3540                             Bind(&rightIsMinusZero);
3541                             {
3542                                 result = True();
3543                                 Jump(&exit);
3544                             }
3545                         }
3546                         Bind(&leftNotMinusZero);
3547                         {
3548                             Label rightNotMinusZero(env);
3549                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &exit, &rightNotMinusZero);
3550                             Bind(&rightNotMinusZero);
3551                             {
3552                                 result = True();
3553                                 Jump(&exit);
3554                             }
3555                         }
3556                     }
3557                     Bind(&boolAndCheck);
3558                     {
3559                         result = BoolAnd(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight));
3560                         Jump(&exit);
3561                     }
3562                 }
3563             }
3564         }
3565         Bind(&leftIsNotNumber);
3566         Branch(TaggedIsNumber(right), &exit, &stringEqualCheck);
3567         Bind(&stringEqualCheck);
3568         Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
3569         Bind(&stringCompare);
3570         {
3571             result = FastStringEqual(glue, left, right);
3572             Jump(&exit);
3573         }
3574         Bind(&bigIntEqualCheck);
3575         {
3576             Label leftIsBigInt(env);
3577             Label leftIsNotBigInt(env);
3578             Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
3579             Bind(&leftIsBigInt);
3580             {
3581                 Label rightIsBigInt(env);
3582                 Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
3583                 Bind(&rightIsBigInt);
3584                 result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
3585                 Jump(&exit);
3586             }
3587         }
3588     }
3589     Bind(&exit);
3590     auto ret = *result;
3591     env->SubCfgExit();
3592     return ret;
3593 }
3594 
FastStringEqual(GateRef glue,GateRef left,GateRef right)3595 GateRef StubBuilder::FastStringEqual(GateRef glue, GateRef left, GateRef right)
3596 {
3597     auto env = GetEnvironment();
3598     Label entry(env);
3599     env->SubCfgEntry(&entry);
3600     DEFVARIABLE(result, VariableType::BOOL(), False());
3601     Label exit(env);
3602     Label lengthCompare(env);
3603     Label hashcodeCompare(env);
3604     Label contentsCompare(env);
3605 
3606     Branch(Int32Equal(ZExtInt1ToInt32(IsUtf16String(left)), ZExtInt1ToInt32(IsUtf16String(right))),
3607         &lengthCompare, &exit);
3608 
3609     Bind(&lengthCompare);
3610     Branch(Int32Equal(GetLengthFromString(left), GetLengthFromString(right)), &hashcodeCompare,
3611         &exit);
3612 
3613     Bind(&hashcodeCompare);
3614     Branch(Int32Equal(GetHashcodeFromString(glue, left), GetHashcodeFromString(glue, right)), &contentsCompare,
3615         &exit);
3616 
3617     Bind(&contentsCompare);
3618     {
3619         result = CallNGCRuntime(glue, RTSTUB_ID(StringsAreEquals), { left, right });
3620         Jump(&exit);
3621     }
3622 
3623     Bind(&exit);
3624     auto ret = *result;
3625     env->SubCfgExit();
3626     return ret;
3627 }
3628 
FastStrictEqual(GateRef glue,GateRef left,GateRef right)3629 GateRef StubBuilder::FastStrictEqual(GateRef glue, GateRef left, GateRef right)
3630 {
3631     auto env = GetEnvironment();
3632     Label entry(env);
3633     env->SubCfgEntry(&entry);
3634     DEFVARIABLE(result, VariableType::BOOL(), False());
3635     Label strictEqual(env);
3636     Label leftIsNumber(env);
3637     Label leftIsNotNumber(env);
3638     Label sameVariableCheck(env);
3639     Label stringEqualCheck(env);
3640     Label stringCompare(env);
3641     Label bigIntEqualCheck(env);
3642     Label exit(env);
3643     Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
3644     Bind(&leftIsNumber);
3645     {
3646         Label rightIsNumber(env);
3647         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
3648         Bind(&rightIsNumber);
3649         {
3650             DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
3651             DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
3652             Label leftIsInt(env);
3653             Label leftNotInt(env);
3654             Label getRight(env);
3655             Label numberEqualCheck(env);
3656             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
3657             Bind(&leftIsInt);
3658             {
3659                 doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
3660                 Jump(&getRight);
3661             }
3662             Bind(&leftNotInt);
3663             {
3664                 doubleLeft = GetDoubleOfTDouble(left);
3665                 Jump(&getRight);
3666             }
3667             Bind(&getRight);
3668             {
3669                 Label rightIsInt(env);
3670                 Label rightNotInt(env);
3671                 Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
3672                 Bind(&rightIsInt);
3673                 {
3674                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
3675                     Jump(&numberEqualCheck);
3676                 }
3677                 Bind(&rightNotInt);
3678                 {
3679                     doubleRight = GetDoubleOfTDouble(right);
3680                     Jump(&numberEqualCheck);
3681                 }
3682             }
3683             Bind(&numberEqualCheck);
3684             {
3685                 Label doubleEqualCheck(env);
3686                 Branch(BoolOr(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight)), &exit, &doubleEqualCheck);
3687                 Bind(&doubleEqualCheck);
3688                 {
3689                     result = DoubleEqual(*doubleLeft, *doubleRight);
3690                     Jump(&exit);
3691                 }
3692             }
3693         }
3694     }
3695     Bind(&leftIsNotNumber);
3696     Branch(TaggedIsNumber(right), &exit, &sameVariableCheck);
3697     Bind(&sameVariableCheck);
3698     Branch(Equal(left, right), &strictEqual, &stringEqualCheck);
3699     Bind(&stringEqualCheck);
3700     Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
3701     Bind(&stringCompare);
3702     {
3703         result = FastStringEqual(glue, left, right);
3704         Jump(&exit);
3705     }
3706     Bind(&bigIntEqualCheck);
3707     {
3708         Label leftIsBigInt(env);
3709         Label leftIsNotBigInt(env);
3710         Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
3711         Bind(&leftIsBigInt);
3712         {
3713             Label rightIsBigInt(env);
3714             Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
3715             Bind(&rightIsBigInt);
3716             result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
3717             Jump(&exit);
3718         }
3719     }
3720     Bind(&strictEqual);
3721     {
3722         result = True();
3723         Jump(&exit);
3724     }
3725     Bind(&exit);
3726     auto ret = *result;
3727     env->SubCfgExit();
3728     return ret;
3729 }
3730 
FastEqual(GateRef left,GateRef right)3731 GateRef StubBuilder::FastEqual(GateRef left, GateRef right)
3732 {
3733     auto env = GetEnvironment();
3734     Label entry(env);
3735     env->SubCfgEntry(&entry);
3736     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3737     Label leftEqualRight(env);
3738     Label leftNotEqualRight(env);
3739     Label exit(env);
3740     Branch(Equal(left, right), &leftEqualRight, &leftNotEqualRight);
3741     Bind(&leftEqualRight);
3742     {
3743         Label leftIsDouble(env);
3744         Label leftNotDoubleOrLeftNotNan(env);
3745         Branch(TaggedIsDouble(left), &leftIsDouble, &leftNotDoubleOrLeftNotNan);
3746         Bind(&leftIsDouble);
3747         {
3748             GateRef doubleLeft = GetDoubleOfTDouble(left);
3749             Label leftIsNan(env);
3750             Branch(DoubleIsNAN(doubleLeft), &leftIsNan, &leftNotDoubleOrLeftNotNan);
3751             Bind(&leftIsNan);
3752             {
3753                 result = TaggedFalse();
3754                 Jump(&exit);
3755             }
3756         }
3757         Bind(&leftNotDoubleOrLeftNotNan);
3758         {
3759             result = TaggedTrue();
3760             Jump(&exit);
3761         }
3762     }
3763     Bind(&leftNotEqualRight);
3764     {
3765         Label leftIsNumber(env);
3766         Label leftNotNumberOrLeftNotIntOrRightNotInt(env);
3767         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrLeftNotIntOrRightNotInt);
3768         Bind(&leftIsNumber);
3769         {
3770             Label leftIsInt(env);
3771             Branch(TaggedIsInt(left), &leftIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
3772             Bind(&leftIsInt);
3773             {
3774                 Label rightIsInt(env);
3775                 Branch(TaggedIsInt(right), &rightIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
3776                 Bind(&rightIsInt);
3777                 {
3778                     result = TaggedFalse();
3779                     Jump(&exit);
3780                 }
3781             }
3782         }
3783         Bind(&leftNotNumberOrLeftNotIntOrRightNotInt);
3784         {
3785             Label rightIsUndefinedOrNull(env);
3786             Label leftOrRightNotUndefinedOrNull(env);
3787             Branch(TaggedIsUndefinedOrNull(right), &rightIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull);
3788             Bind(&rightIsUndefinedOrNull);
3789             {
3790                 Label leftIsHeapObject(env);
3791                 Label leftNotHeapObject(env);
3792                 Branch(TaggedIsHeapObject(left), &leftIsHeapObject, &leftNotHeapObject);
3793                 Bind(&leftIsHeapObject);
3794                 {
3795                     result = TaggedFalse();
3796                     Jump(&exit);
3797                 }
3798                 Bind(&leftNotHeapObject);
3799                 {
3800                     Label leftIsUndefinedOrNull(env);
3801                     Branch(TaggedIsUndefinedOrNull(left), &leftIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull);
3802                     Bind(&leftIsUndefinedOrNull);
3803                     {
3804                         result = TaggedTrue();
3805                         Jump(&exit);
3806                     }
3807                 }
3808             }
3809             Bind(&leftOrRightNotUndefinedOrNull);
3810             {
3811                 Label leftIsBool(env);
3812                 Label leftNotBoolOrRightNotSpecial(env);
3813                 Branch(TaggedIsBoolean(left), &leftIsBool, &leftNotBoolOrRightNotSpecial);
3814                 Bind(&leftIsBool);
3815                 {
3816                     Label rightIsSpecial(env);
3817                     Branch(TaggedIsSpecial(right), &rightIsSpecial, &leftNotBoolOrRightNotSpecial);
3818                     Bind(&rightIsSpecial);
3819                     {
3820                         result = TaggedFalse();
3821                         Jump(&exit);
3822                     }
3823                 }
3824                 Bind(&leftNotBoolOrRightNotSpecial);
3825                 {
3826                     Jump(&exit);
3827                 }
3828             }
3829         }
3830     }
3831     Bind(&exit);
3832     auto ret = *result;
3833     env->SubCfgExit();
3834     return ret;
3835 }
3836 
FastToBoolean(GateRef value)3837 GateRef StubBuilder::FastToBoolean(GateRef value)
3838 {
3839     auto env = GetEnvironment();
3840     Label entry(env);
3841     env->SubCfgEntry(&entry);
3842     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3843     Label exit(env);
3844 
3845     Label isSpecial(env);
3846     Label notSpecial(env);
3847     Label isNumber(env);
3848     Label isInt(env);
3849     Label isDouble(env);
3850     Label notNumber(env);
3851     Label notNan(env);
3852     Label isString(env);
3853     Label notString(env);
3854     Label isBigint(env);
3855     Label lengthIsOne(env);
3856     Label returnTrue(env);
3857     Label returnFalse(env);
3858 
3859     Branch(TaggedIsSpecial(value), &isSpecial, &notSpecial);
3860     Bind(&isSpecial);
3861     {
3862         Branch(TaggedIsTrue(value), &returnTrue, &returnFalse);
3863     }
3864     Bind(&notSpecial);
3865     {
3866         Branch(TaggedIsNumber(value), &isNumber, &notNumber);
3867         Bind(&notNumber);
3868         {
3869             Branch(IsString(value), &isString, &notString);
3870             Bind(&isString);
3871             {
3872                 auto len = GetLengthFromString(value);
3873                 Branch(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue);
3874             }
3875             Bind(&notString);
3876             Branch(TaggedObjectIsBigInt(value), &isBigint, &returnTrue);
3877             Bind(&isBigint);
3878             {
3879                 auto len = Load(VariableType::INT32(), value, IntPtr(BigInt::LENGTH_OFFSET));
3880                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &returnTrue);
3881                 Bind(&lengthIsOne);
3882                 {
3883                     auto data = PtrAdd(value, IntPtr(BigInt::DATA_OFFSET));
3884                     auto data0 = Load(VariableType::INT32(), data, Int32(0));
3885                     Branch(Int32Equal(data0, Int32(0)), &returnFalse, &returnTrue);
3886                 }
3887             }
3888         }
3889         Bind(&isNumber);
3890         {
3891             Branch(TaggedIsInt(value), &isInt, &isDouble);
3892             Bind(&isInt);
3893             {
3894                 auto intValue = GetInt32OfTInt(value);
3895                 Branch(Int32Equal(intValue, Int32(0)), &returnFalse, &returnTrue);
3896             }
3897             Bind(&isDouble);
3898             {
3899                 auto doubleValue = GetDoubleOfTDouble(value);
3900                 Branch(DoubleIsNAN(doubleValue), &returnFalse, &notNan);
3901                 Bind(&notNan);
3902                 Branch(DoubleEqual(doubleValue, Double(0.0)), &returnFalse, &returnTrue);
3903             }
3904         }
3905     }
3906     Bind(&returnTrue);
3907     {
3908         result = TaggedTrue();
3909         Jump(&exit);
3910     }
3911     Bind(&returnFalse);
3912     {
3913         result = TaggedFalse();
3914         Jump(&exit);
3915     }
3916 
3917     Bind(&exit);
3918     auto ret = *result;
3919     env->SubCfgExit();
3920     return ret;
3921 }
3922 
FastDiv(GateRef left,GateRef right)3923 GateRef StubBuilder::FastDiv(GateRef left, GateRef right)
3924 {
3925     auto env = GetEnvironment();
3926     Label entry(env);
3927     env->SubCfgEntry(&entry);
3928     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3929     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
3930     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
3931     Label leftIsNumber(env);
3932     Label leftNotNumberOrRightNotNumber(env);
3933     Label leftIsNumberAndRightIsNumber(env);
3934     Label leftIsDoubleAndRightIsDouble(env);
3935     Label exit(env);
3936     Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
3937     Bind(&leftIsNumber);
3938     {
3939         Label rightIsNumber(env);
3940         Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
3941         Bind(&rightIsNumber);
3942         {
3943             Label leftIsInt(env);
3944             Label leftNotInt(env);
3945             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
3946             Bind(&leftIsInt);
3947             {
3948                 doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
3949                 Jump(&leftIsNumberAndRightIsNumber);
3950             }
3951             Bind(&leftNotInt);
3952             {
3953                 doubleLeft = GetDoubleOfTDouble(left);
3954                 Jump(&leftIsNumberAndRightIsNumber);
3955             }
3956         }
3957     }
3958     Bind(&leftNotNumberOrRightNotNumber);
3959     {
3960         Jump(&exit);
3961     }
3962     Bind(&leftIsNumberAndRightIsNumber);
3963     {
3964         Label rightIsInt(env);
3965         Label rightNotInt(env);
3966         Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
3967         Bind(&rightIsInt);
3968         {
3969             doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
3970             Jump(&leftIsDoubleAndRightIsDouble);
3971         }
3972         Bind(&rightNotInt);
3973         {
3974             doubleRight = GetDoubleOfTDouble(right);
3975             Jump(&leftIsDoubleAndRightIsDouble);
3976         }
3977     }
3978     Bind(&leftIsDoubleAndRightIsDouble);
3979     {
3980         Label rightIsZero(env);
3981         Label rightNotZero(env);
3982         Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZero, &rightNotZero);
3983         Bind(&rightIsZero);
3984         {
3985             Label leftIsZero(env);
3986             Label leftNotZero(env);
3987             Label leftIsZeroOrNan(env);
3988             Label leftNotZeroAndNotNan(env);
3989             Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZero, &leftNotZero);
3990             Bind(&leftIsZero);
3991             {
3992                 Jump(&leftIsZeroOrNan);
3993             }
3994             Bind(&leftNotZero);
3995             {
3996                 Label leftIsNan(env);
3997                 Branch(DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan);
3998                 Bind(&leftIsNan);
3999                 {
4000                     Jump(&leftIsZeroOrNan);
4001                 }
4002             }
4003             Bind(&leftIsZeroOrNan);
4004             {
4005                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
4006                 Jump(&exit);
4007             }
4008             Bind(&leftNotZeroAndNotNan);
4009             {
4010                 GateRef intLeftTmp = CastDoubleToInt64(*doubleLeft);
4011                 GateRef intRightTmp = CastDoubleToInt64(*doubleRight);
4012                 GateRef flagBit = Int64And(Int64Xor(intLeftTmp, intRightTmp), Int64(base::DOUBLE_SIGN_MASK));
4013                 GateRef tmpResult = Int64Xor(flagBit, CastDoubleToInt64(Double(base::POSITIVE_INFINITY)));
4014                 result = DoubleToTaggedDoublePtr(CastInt64ToFloat64(tmpResult));
4015                 Jump(&exit);
4016             }
4017         }
4018         Bind(&rightNotZero);
4019         {
4020             result = DoubleToTaggedDoublePtr(DoubleDiv(*doubleLeft, *doubleRight));
4021             Jump(&exit);
4022         }
4023     }
4024     Bind(&exit);
4025     auto ret = *result;
4026     env->SubCfgExit();
4027     return ret;
4028 }
4029 
FastBinaryOp(GateRef left,GateRef right,const BinaryOperation & intOp,const BinaryOperation & floatOp)4030 GateRef StubBuilder::FastBinaryOp(GateRef left, GateRef right,
4031                                   const BinaryOperation& intOp,
4032                                   const BinaryOperation& floatOp)
4033 {
4034     auto env = GetEnvironment();
4035     Label entry(env);
4036     env->SubCfgEntry(&entry);
4037     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4038     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4039     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4040 
4041     Label exit(env);
4042     Label doFloatOp(env);
4043     Label doIntOp(env);
4044     Label leftIsNumber(env);
4045     Label rightIsNumber(env);
4046     Label leftIsIntRightIsDouble(env);
4047     Label rightIsInt(env);
4048     Label rightIsDouble(env);
4049 
4050     Branch(TaggedIsNumber(left), &leftIsNumber, &exit);
4051     Bind(&leftIsNumber);
4052     {
4053         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4054         Bind(&rightIsNumber);
4055         {
4056             Label leftIsInt(env);
4057             Label leftIsDouble(env);
4058             Branch(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
4059             Bind(&leftIsInt);
4060             {
4061                 Branch(TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
4062                 Bind(&leftIsIntRightIsDouble);
4063                 {
4064                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4065                     doubleRight = GetDoubleOfTDouble(right);
4066                     Jump(&doFloatOp);
4067                 }
4068             }
4069             Bind(&leftIsDouble);
4070             {
4071                 Branch(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
4072                 Bind(&rightIsInt);
4073                 {
4074                     doubleLeft = GetDoubleOfTDouble(left);
4075                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4076                     Jump(&doFloatOp);
4077                 }
4078                 Bind(&rightIsDouble);
4079                 {
4080                     doubleLeft = GetDoubleOfTDouble(left);
4081                     doubleRight = GetDoubleOfTDouble(right);
4082                     Jump(&doFloatOp);
4083                 }
4084             }
4085         }
4086     }
4087     Bind(&doIntOp);
4088     {
4089         result = intOp(env, left, right);
4090         Jump(&exit);
4091     }
4092     Bind(&doFloatOp);
4093     {
4094         result = floatOp(env, *doubleLeft, *doubleRight);
4095         Jump(&exit);
4096     }
4097     Bind(&exit);
4098     auto ret = *result;
4099     env->SubCfgExit();
4100     return ret;
4101 }
4102 
4103 template<OpCode Op>
FastAddSubAndMul(GateRef left,GateRef right)4104 GateRef StubBuilder::FastAddSubAndMul(GateRef left, GateRef right)
4105 {
4106     auto intOperation = [=](Environment *env, GateRef left, GateRef right) {
4107         Label entry(env);
4108         env->SubCfgEntry(&entry);
4109         DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4110         Label exit(env);
4111         Label overflow(env);
4112         Label notOverflow(env);
4113         auto res = BinaryOp<Op, MachineType::I64>(GetInt64OfTInt(left), GetInt64OfTInt(right));
4114         auto condition1 = Int64GreaterThan(res, Int64(INT32_MAX));
4115         auto condition2 = Int64LessThan(res, Int64(INT32_MIN));
4116         Branch(BoolOr(condition1, condition2), &overflow, &notOverflow);
4117         Bind(&overflow);
4118         {
4119             auto doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4120             auto doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4121             auto ret = BinaryOp<Op, MachineType::F64>(doubleLeft, doubleRight);
4122             result = DoubleToTaggedDoublePtr(ret);
4123             Jump(&exit);
4124         }
4125         Bind(&notOverflow);
4126         {
4127             result = IntToTaggedPtr(TruncInt64ToInt32(res));
4128             Jump(&exit);
4129         }
4130         Bind(&exit);
4131         auto ret = *result;
4132         env->SubCfgExit();
4133         return ret;
4134     };
4135     auto floatOperation = [=]([[maybe_unused]] Environment *env, GateRef left, GateRef right) {
4136         auto res = BinaryOp<Op, MachineType::F64>(left, right);
4137         return DoubleToTaggedDoublePtr(res);
4138     };
4139     return FastBinaryOp(left, right, intOperation, floatOperation);
4140 }
4141 
FastAdd(GateRef left,GateRef right)4142 GateRef StubBuilder::FastAdd(GateRef left, GateRef right)
4143 {
4144     return FastAddSubAndMul<OpCode::ADD>(left, right);
4145 }
4146 
FastSub(GateRef left,GateRef right)4147 GateRef StubBuilder::FastSub(GateRef left, GateRef right)
4148 {
4149     return FastAddSubAndMul<OpCode::SUB>(left, right);
4150 }
4151 
FastMul(GateRef left,GateRef right)4152 GateRef StubBuilder::FastMul(GateRef left, GateRef right)
4153 {
4154     return FastAddSubAndMul<OpCode::MUL>(left, right);
4155 }
4156 
FastMod(GateRef glue,GateRef left,GateRef right)4157 GateRef StubBuilder::FastMod(GateRef glue, GateRef left, GateRef right)
4158 {
4159     auto env = GetEnvironment();
4160     Label entry(env);
4161     env->SubCfgEntry(&entry);
4162     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4163     DEFVARIABLE(intLeft, VariableType::INT32(), Int32(0));
4164     DEFVARIABLE(intRight, VariableType::INT32(), Int32(0));
4165     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4166     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4167     Label leftIsInt(env);
4168     Label leftNotIntOrRightNotInt(env);
4169     Label exit(env);
4170     Branch(TaggedIsInt(left), &leftIsInt, &leftNotIntOrRightNotInt);
4171     Bind(&leftIsInt);
4172     {
4173         Label rightIsInt(env);
4174         Branch(TaggedIsInt(right), &rightIsInt, &leftNotIntOrRightNotInt);
4175         Bind(&rightIsInt);
4176         {
4177             intLeft = GetInt32OfTInt(left);
4178             intRight = GetInt32OfTInt(right);
4179             Label leftGreaterZero(env);
4180             Branch(Int32GreaterThan(*intLeft, Int32(0)), &leftGreaterZero, &leftNotIntOrRightNotInt);
4181             Bind(&leftGreaterZero);
4182             {
4183                 Label rightGreaterZero(env);
4184                 Branch(Int32GreaterThan(*intRight, Int32(0)), &rightGreaterZero, &leftNotIntOrRightNotInt);
4185                 Bind(&rightGreaterZero);
4186                 {
4187                     result = IntToTaggedPtr(Int32Mod(*intLeft, *intRight));
4188                     Jump(&exit);
4189                 }
4190             }
4191         }
4192     }
4193     Bind(&leftNotIntOrRightNotInt);
4194     {
4195         Label leftIsNumber(env);
4196         Label leftNotNumberOrRightNotNumber(env);
4197         Label leftIsNumberAndRightIsNumber(env);
4198         Label leftIsDoubleAndRightIsDouble(env);
4199         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
4200         Bind(&leftIsNumber);
4201         {
4202             Label rightIsNumber(env);
4203             Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
4204             Bind(&rightIsNumber);
4205             {
4206                 Label leftIsInt1(env);
4207                 Label leftNotInt1(env);
4208                 Branch(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
4209                 Bind(&leftIsInt1);
4210                 {
4211                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4212                     Jump(&leftIsNumberAndRightIsNumber);
4213                 }
4214                 Bind(&leftNotInt1);
4215                 {
4216                     doubleLeft = GetDoubleOfTDouble(left);
4217                     Jump(&leftIsNumberAndRightIsNumber);
4218                 }
4219             }
4220         }
4221         Bind(&leftNotNumberOrRightNotNumber);
4222         {
4223             Jump(&exit);
4224         }
4225         Bind(&leftIsNumberAndRightIsNumber);
4226         {
4227             Label rightIsInt1(env);
4228             Label rightNotInt1(env);
4229             Branch(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
4230             Bind(&rightIsInt1);
4231             {
4232                 doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4233                 Jump(&leftIsDoubleAndRightIsDouble);
4234             }
4235             Bind(&rightNotInt1);
4236             {
4237                 doubleRight = GetDoubleOfTDouble(right);
4238                 Jump(&leftIsDoubleAndRightIsDouble);
4239             }
4240         }
4241         Bind(&leftIsDoubleAndRightIsDouble);
4242         {
4243             Label rightNotZero(env);
4244             Label rightIsZeroOrNanOrLeftIsNanOrInf(env);
4245             Label rightNotZeroAndNanAndLeftNotNanAndInf(env);
4246             Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotZero);
4247             Bind(&rightNotZero);
4248             {
4249                 Label rightNotNan(env);
4250                 Branch(DoubleIsNAN(*doubleRight), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotNan);
4251                 Bind(&rightNotNan);
4252                 {
4253                     Label leftNotNan(env);
4254                     Branch(DoubleIsNAN(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &leftNotNan);
4255                     Bind(&leftNotNan);
4256                     {
4257                         Branch(DoubleIsINF(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf,
4258                             &rightNotZeroAndNanAndLeftNotNanAndInf);
4259                     }
4260                 }
4261             }
4262             Bind(&rightIsZeroOrNanOrLeftIsNanOrInf);
4263             {
4264                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
4265                 Jump(&exit);
4266             }
4267             Bind(&rightNotZeroAndNanAndLeftNotNanAndInf);
4268             {
4269                 Label leftNotZero(env);
4270                 Label leftIsZeroOrRightIsInf(env);
4271                 Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZeroOrRightIsInf, &leftNotZero);
4272                 Bind(&leftNotZero);
4273                 {
4274                     Label rightNotInf(env);
4275                     Branch(DoubleIsINF(*doubleRight), &leftIsZeroOrRightIsInf, &rightNotInf);
4276                     Bind(&rightNotInf);
4277                     {
4278                         result = CallNGCRuntime(glue, RTSTUB_ID(FloatMod), { *doubleLeft, *doubleRight });
4279                         Jump(&exit);
4280                     }
4281                 }
4282                 Bind(&leftIsZeroOrRightIsInf);
4283                 {
4284                     result = DoubleToTaggedDoublePtr(*doubleLeft);
4285                     Jump(&exit);
4286                 }
4287             }
4288         }
4289     }
4290     Bind(&exit);
4291     auto ret = *result;
4292     env->SubCfgExit();
4293     return ret;
4294 }
4295 
GetGlobalOwnProperty(GateRef glue,GateRef receiver,GateRef key)4296 GateRef StubBuilder::GetGlobalOwnProperty(GateRef glue, GateRef receiver, GateRef key)
4297 {
4298     auto env = GetEnvironment();
4299     Label entryLabel(env);
4300     env->SubCfgEntry(&entryLabel);
4301     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4302     GateRef properties = GetPropertiesFromJSObject(receiver);
4303     GateRef entry = FindEntryFromNameDictionary(glue, properties, key);
4304     Label notNegtiveOne(env);
4305     Label exit(env);
4306     Branch(Int32NotEqual(entry, Int32(-1)), &notNegtiveOne, &exit);
4307     Bind(&notNegtiveOne);
4308     {
4309         result = GetValueFromGlobalDictionary(properties, entry);
4310         Label callGetter(env);
4311         Branch(TaggedIsAccessor(*result), &callGetter, &exit);
4312         Bind(&callGetter);
4313         {
4314             result = CallGetterHelper(glue, receiver, receiver, *result);
4315             Jump(&exit);
4316         }
4317     }
4318     Bind(&exit);
4319     auto ret = *result;
4320     env->SubCfgExit();
4321     return ret;
4322 }
4323 
GetStringFromConstPool(GateRef glue,GateRef constpool,GateRef index)4324 GateRef StubBuilder::GetStringFromConstPool(GateRef glue, GateRef constpool, GateRef index)
4325 {
4326     GateRef module = Circuit::NullGate();
4327     return env_->GetBuilder()->GetObjectFromConstPool(glue, constpool, module, index, ConstPoolType::STRING);
4328 }
4329 
GetMethodFromConstPool(GateRef glue,GateRef constpool,GateRef index)4330 GateRef StubBuilder::GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index)
4331 {
4332     GateRef module = Circuit::NullGate();
4333     return env_->GetBuilder()->GetObjectFromConstPool(glue, constpool, module, index, ConstPoolType::METHOD);
4334 }
4335 
GetArrayLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)4336 GateRef StubBuilder::GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
4337 {
4338     return env_->GetBuilder()->GetObjectFromConstPool(glue, constpool, module, index, ConstPoolType::ARRAY_LITERAL);
4339 }
4340 
GetObjectLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)4341 GateRef StubBuilder::GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
4342 {
4343     return env_->GetBuilder()->GetObjectFromConstPool(glue, constpool, module, index, ConstPoolType::OBJECT_LITERAL);
4344 }
4345 
JSAPIContainerGet(GateRef glue,GateRef receiver,GateRef index)4346 GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index)
4347 {
4348     auto env = GetEnvironment();
4349     Label entry(env);
4350     env->SubCfgEntry(&entry);
4351     Label exit(env);
4352     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4353 
4354     GateRef lengthOffset = IntPtr(panda::ecmascript::JSAPIArrayList::LENGTH_OFFSET);
4355     GateRef length = GetInt32OfTInt(Load(VariableType::INT64(), receiver, lengthOffset));
4356     Label isVailedIndex(env);
4357     Label notValidIndex(env);
4358     Branch(BoolAnd(Int32GreaterThanOrEqual(index, Int32(0)),
4359         Int32UnsignedLessThan(index, length)), &isVailedIndex, &notValidIndex);
4360     Bind(&isVailedIndex);
4361     {
4362         GateRef elements = GetElementsArray(receiver);
4363         result = GetValueFromTaggedArray(elements, index);
4364         Jump(&exit);
4365     }
4366     Bind(&notValidIndex);
4367     {
4368         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(GetPropertyOutOfBounds));
4369         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
4370         result = Exception();
4371         Jump(&exit);
4372     }
4373 
4374     Bind(&exit);
4375     auto ret = *result;
4376     env->SubCfgExit();
4377     return ret;
4378 }
4379 
DoubleToInt(GateRef glue,GateRef x)4380 GateRef StubBuilder::DoubleToInt(GateRef glue, GateRef x)
4381 {
4382     auto env = GetEnvironment();
4383     Label entry(env);
4384     env->SubCfgEntry(&entry);
4385     Label exit(env);
4386     Label overflow(env);
4387 
4388     GateRef xInt = ChangeFloat64ToInt32(x);
4389     DEFVARIABLE(result, VariableType::INT32(), xInt);
4390 
4391     if (env->IsAmd64()) {
4392         // 0x80000000: amd64 overflow return value
4393         Branch(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit);
4394     } else {
4395         GateRef xInt64 = CastDoubleToInt64(x);
4396         // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
4397         GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
4398         exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
4399         exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
4400         GateRef bits = Int32(base::INT32_BITS - 1);
4401         // exp < 32 - 1
4402         Branch(Int32LessThan(exp, bits), &exit, &overflow);
4403     }
4404     Bind(&overflow);
4405     {
4406         result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), { x });
4407         Jump(&exit);
4408     }
4409     Bind(&exit);
4410     auto ret = *result;
4411     env->SubCfgExit();
4412     return ret;
4413 }
4414 
ReturnExceptionIfAbruptCompletion(GateRef glue)4415 void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue)
4416 {
4417     auto env = GetEnvironment();
4418     Label entry(env);
4419     env->SubCfgEntry(&entry);
4420     Label exit(env);
4421     Label hasPendingException(env);
4422     GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env->IsArch32Bit()));
4423     GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset);
4424     Branch(TaggedIsNotHole(exception), &hasPendingException, &exit);
4425     Bind(&hasPendingException);
4426     Return(Exception());
4427     Bind(&exit);
4428     env->SubCfgExit();
4429     return;
4430 }
4431 
GetHashcodeFromString(GateRef glue,GateRef value)4432 GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
4433 {
4434     auto env = GetEnvironment();
4435     Label subentry(env);
4436     env->SubCfgEntry(&subentry);
4437     Label noRawHashcode(env);
4438     Label exit(env);
4439     DEFVARIABLE(hashcode, VariableType::INT32(), Int32(0));
4440     hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::HASHCODE_OFFSET));
4441     Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
4442     Bind(&noRawHashcode);
4443     {
4444         hashcode = GetInt32OfTInt(CallRuntime(glue, RTSTUB_ID(ComputeHashcode), { value }));
4445         Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
4446         Jump(&exit);
4447     }
4448     Bind(&exit);
4449     auto ret = *hashcode;
4450     env->SubCfgExit();
4451     return ret;
4452 }
4453 
ConstructorCheck(GateRef glue,GateRef ctor,GateRef outPut,GateRef thisObj)4454 GateRef StubBuilder::ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut, GateRef thisObj)
4455 {
4456     auto env = GetEnvironment();
4457     Label entryPass(env);
4458     Label exit(env);
4459     env->SubCfgEntry(&entryPass);
4460     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
4461     Label isHeapObject(env);
4462     Label isEcmaObj(env);
4463     Label notEcmaObj(env);
4464     Branch(TaggedIsHeapObject(outPut), &isHeapObject, &notEcmaObj);
4465     Bind(&isHeapObject);
4466     Branch(TaggedObjectIsEcmaObject(outPut), &isEcmaObj, &notEcmaObj);
4467     Bind(&isEcmaObj);
4468     {
4469         result = outPut;
4470         Jump(&exit);
4471     }
4472     Bind(&notEcmaObj);
4473     {
4474         Label ctorIsBase(env);
4475         Label ctorNotBase(env);
4476         Branch(IsBase(ctor), &ctorIsBase, &ctorNotBase);
4477         Bind(&ctorIsBase);
4478         {
4479             result = thisObj;
4480             Jump(&exit);
4481         }
4482         Bind(&ctorNotBase);
4483         {
4484             Label throwExeption(env);
4485             Label returnObj(env);
4486             Branch(TaggedIsUndefined(outPut), &returnObj, &throwExeption);
4487             Bind(&returnObj);
4488             result = thisObj;
4489             Jump(&exit);
4490             Bind(&throwExeption);
4491             {
4492                 CallRuntime(glue, RTSTUB_ID(ThrowNonConstructorException), {});
4493                 Jump(&exit);
4494             }
4495         }
4496     }
4497     Bind(&exit);
4498     auto ret = *result;
4499     env->SubCfgExit();
4500     return ret;
4501 }
4502 
JSCallDispatch(GateRef glue,GateRef func,GateRef actualNumArgs,GateRef jumpSize,GateRef hotnessCounter,JSCallMode mode,std::initializer_list<GateRef> args)4503 GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize,
4504                                     GateRef hotnessCounter, JSCallMode mode, std::initializer_list<GateRef> args)
4505 {
4506     auto env = GetEnvironment();
4507     Label entryPass(env);
4508     Label exit(env);
4509     env->SubCfgEntry(&entryPass);
4510     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
4511     // 1. call initialize
4512     Label funcIsHeapObject(env);
4513     Label funcIsCallable(env);
4514     Label funcNotCallable(env);
4515     // save pc
4516     SavePcIfNeeded(glue);
4517     GateRef bitfield = 0;
4518     if (!AssemblerModule::IsCallNew(mode)) {
4519         Branch(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable);
4520         Bind(&funcIsHeapObject);
4521         GateRef hclass = LoadHClass(func);
4522         bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
4523         Branch(IsCallableFromBitField(bitfield), &funcIsCallable, &funcNotCallable);
4524         Bind(&funcNotCallable);
4525         {
4526             CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {});
4527             Jump(&exit);
4528         }
4529         Bind(&funcIsCallable);
4530     }
4531     GateRef method = GetMethodFromJSFunction(func);
4532     GateRef callField = GetCallFieldFromMethod(method);
4533     GateRef isNativeMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsNativeBit::START_BIT);
4534 
4535     // 2. call dispatch
4536     Label methodIsNative(env);
4537     Label methodNotNative(env);
4538     Branch(Int64NotEqual(Int64And(callField, isNativeMask), Int64(0)), &methodIsNative, &methodNotNative);
4539     auto data = std::begin(args);
4540     Label notFastBuiltinsArg0(env);
4541     Label notFastBuiltinsArg1(env);
4542     Label notFastBuiltinsArg2(env);
4543     Label notFastBuiltinsArg3(env);
4544     Label notFastBuiltins(env);
4545     // 3. call native
4546     Bind(&methodIsNative);
4547     {
4548         GateRef nativeCode = Load(VariableType::NATIVE_POINTER(), method,
4549             IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
4550         GateRef newTarget = Undefined();
4551         GateRef thisValue = Undefined();
4552         GateRef numArgs = Int32Add(actualNumArgs, Int32(NUM_MANDATORY_JSFUNC_ARGS));
4553         switch (mode) {
4554             case JSCallMode::CALL_THIS_ARG0: {
4555                 thisValue = data[0];
4556                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
4557                     method, &notFastBuiltinsArg0, &exit, &result, args, mode);
4558                 Bind(&notFastBuiltinsArg0);
4559                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4560                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
4561                 break;
4562             }
4563             case JSCallMode::CALL_ARG0:
4564             case JSCallMode::DEPRECATED_CALL_ARG0:
4565                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4566                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
4567                 break;
4568             case JSCallMode::CALL_THIS_ARG1: {
4569                 thisValue = data[1];
4570                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
4571                     method, &notFastBuiltinsArg1, &exit, &result, args, mode);
4572                 Bind(&notFastBuiltinsArg1);
4573                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4574                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
4575                 break;
4576             }
4577             case JSCallMode::CALL_ARG1:
4578             case JSCallMode::DEPRECATED_CALL_ARG1:
4579                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4580                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
4581                 break;
4582             case JSCallMode::CALL_THIS_ARG2: {
4583                 thisValue = data[2];
4584                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
4585                     method, &notFastBuiltinsArg2, &exit, &result, args, mode);
4586                 Bind(&notFastBuiltinsArg2);
4587                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4588                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
4589                 break;
4590             }
4591             case JSCallMode::CALL_ARG2:
4592             case JSCallMode::DEPRECATED_CALL_ARG2:
4593                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4594                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
4595                 break;
4596             case JSCallMode::CALL_THIS_ARG3: {
4597                 thisValue = data[3];
4598                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
4599                     method, &notFastBuiltinsArg3, &exit, &result, args, mode);
4600                 Bind(&notFastBuiltinsArg3);
4601                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4602                     { nativeCode, glue, numArgs, func,
4603                         newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
4604                 break;
4605             }
4606             case JSCallMode::CALL_ARG3:
4607             case JSCallMode::DEPRECATED_CALL_ARG3:
4608                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4609                     { nativeCode, glue, numArgs, func,
4610                       newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
4611                 break;
4612             case JSCallMode::CALL_THIS_WITH_ARGV:
4613             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV: {
4614                 thisValue = data[2]; // 2: this input
4615                 [[fallthrough]];
4616             }
4617             case JSCallMode::CALL_WITH_ARGV:
4618             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
4619                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatchNative),
4620                     { glue, nativeCode, func, thisValue, data[0], data[1] });
4621                 break;
4622             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
4623             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV: {
4624                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
4625                     method, &notFastBuiltins, &exit, &result, args, mode);
4626                 Bind(&notFastBuiltins);
4627                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatchNative),
4628                     { glue, nativeCode, func, data[2], data[0], data[1] });
4629                 break;
4630             }
4631             case JSCallMode::CALL_GETTER:
4632                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4633                     { nativeCode, glue, numArgs, func, newTarget, data[0] });
4634                 break;
4635             case JSCallMode::CALL_SETTER:
4636                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4637                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1] });
4638                 break;
4639             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
4640                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
4641                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1], data[2], data[3] });
4642                 break;
4643             default:
4644                 UNREACHABLE();
4645         }
4646         Jump(&exit);
4647     }
4648     // 4. call nonNative
4649     Bind(&methodNotNative);
4650     Label funcIsClassConstructor(env);
4651     Label funcNotClassConstructor(env);
4652     PGOProfiler(glue, func);
4653     if (!AssemblerModule::IsCallNew(mode)) {
4654         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &funcNotClassConstructor);
4655         Bind(&funcIsClassConstructor);
4656         {
4657             CallRuntime(glue, RTSTUB_ID(ThrowCallConstructorException), {});
4658             Jump(&exit);
4659         }
4660         Bind(&funcNotClassConstructor);
4661     }
4662     GateRef sp = 0;
4663     if (env->IsAsmInterp()) {
4664         sp = Argument(static_cast<size_t>(InterpreterHandlerInputs::SP));
4665     }
4666     Label methodisAot(env);
4667     Label methodNotAot(env);
4668     {
4669         GateRef isAotMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsAotCodeBit::START_BIT);
4670         Branch(Int64Equal(Int64And(callField, isAotMask), Int64(0)),  &methodNotAot, &methodisAot);
4671         Bind(&methodisAot);
4672         {
4673             GateRef newTarget = Undefined();
4674             GateRef thisValue = Undefined();
4675             GateRef lexEnv = env_->GetBuilder()->GetFunctionLexicalEnv(func);
4676             GateRef realNumArgs = Int64Add(ZExtInt32ToInt64(actualNumArgs), Int64(NUM_MANDATORY_JSFUNC_ARGS));
4677             switch (mode) {
4678                 case JSCallMode::CALL_THIS_ARG0:
4679                     thisValue = data[0];
4680                     [[fallthrough]];
4681                 case JSCallMode::CALL_ARG0:
4682                 case JSCallMode::DEPRECATED_CALL_ARG0:
4683                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4684                         { glue, lexEnv, realNumArgs, func, newTarget, thisValue});
4685                     Jump(&exit);
4686                     break;
4687                 case JSCallMode::CALL_THIS_ARG1:
4688                     thisValue = data[1];
4689                     [[fallthrough]];
4690                 case JSCallMode::CALL_ARG1:
4691                 case JSCallMode::DEPRECATED_CALL_ARG1:
4692                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4693                         { glue, lexEnv, realNumArgs, func, newTarget, thisValue,  data[0] });
4694                     Jump(&exit);
4695                     break;
4696                 case JSCallMode::CALL_THIS_ARG2:
4697                     thisValue = data[2];
4698                     [[fallthrough]];
4699                 case JSCallMode::CALL_ARG2:
4700                 case JSCallMode::DEPRECATED_CALL_ARG2:
4701                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4702                         { glue, lexEnv, realNumArgs, func, newTarget, thisValue,  data[0], data[1] });
4703                     Jump(&exit);
4704                     break;
4705                 case JSCallMode::CALL_THIS_ARG3:
4706                     thisValue = data[3];
4707                     [[fallthrough]];
4708                 case JSCallMode::CALL_ARG3:
4709                 case JSCallMode::DEPRECATED_CALL_ARG3:
4710                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4711                         { glue, lexEnv, realNumArgs, func, newTarget, thisValue,
4712                           data[0], data[1], data[2] }); // 2: args2
4713                     Jump(&exit);
4714                     break;
4715                 case JSCallMode::CALL_THIS_WITH_ARGV:
4716                 case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
4717                     thisValue = data[2]; // 2: this input
4718                     [[fallthrough]];
4719                 case JSCallMode::CALL_WITH_ARGV:
4720                 case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
4721                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
4722                         { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
4723                     Jump(&exit);
4724                     break;
4725                 case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
4726                 case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
4727                     result = CallNGCRuntime(glue, RTSTUB_ID(ConstructorJSCallWithArgV),
4728                         { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
4729                     result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
4730                     Jump(&exit);
4731                     break;
4732                 case JSCallMode::CALL_GETTER:
4733                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4734                         { glue, lexEnv, realNumArgs, func, newTarget, data[0]});
4735                     Jump(&exit);
4736                     break;
4737                 case JSCallMode::CALL_SETTER:
4738                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4739                         { glue, lexEnv, realNumArgs, func, newTarget, data[0], data[1]});
4740                     Jump(&exit);
4741                     break;
4742                 case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
4743                     result = CallNGCRuntime(glue, RTSTUB_ID(JSCall),
4744                         { glue, lexEnv, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
4745                     Jump(&exit);
4746                     break;
4747                 default:
4748                     UNREACHABLE();
4749             }
4750         }
4751         Bind(&methodNotAot);
4752         if (jumpSize != 0) {
4753             SaveJumpSizeIfNeeded(glue, jumpSize);
4754         }
4755         SaveHotnessCounterIfNeeded(glue, sp, hotnessCounter, mode);
4756         switch (mode) {
4757             case JSCallMode::CALL_THIS_ARG0:
4758                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg0AndDispatch),
4759                     { glue, sp, func, method, callField, data[0] });
4760                 Return();
4761                 break;
4762             case JSCallMode::CALL_ARG0:
4763             case JSCallMode::DEPRECATED_CALL_ARG0:
4764                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg0AndDispatch),
4765                     { glue, sp, func, method, callField });
4766                 Return();
4767                 break;
4768             case JSCallMode::CALL_THIS_ARG1:
4769                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg1AndDispatch),
4770                     { glue, sp, func, method, callField, data[0], data[1] });
4771                 Return();
4772                 break;
4773             case JSCallMode::CALL_ARG1:
4774             case JSCallMode::DEPRECATED_CALL_ARG1:
4775                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg1AndDispatch),
4776                     { glue, sp, func, method, callField, data[0] });
4777                 Return();
4778                 break;
4779             case JSCallMode::CALL_THIS_ARG2:
4780                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs2AndDispatch),
4781                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
4782                 Return();
4783                 break;
4784             case JSCallMode::CALL_ARG2:
4785             case JSCallMode::DEPRECATED_CALL_ARG2:
4786                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs2AndDispatch),
4787                     { glue, sp, func, method, callField, data[0], data[1] });
4788                 Return();
4789                 break;
4790             case JSCallMode::CALL_THIS_ARG3:
4791                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs3AndDispatch),
4792                     { glue, sp, func, method, callField, data[0], data[1], data[2], data[3] });
4793                 Return();
4794                 break;
4795             case JSCallMode::CALL_ARG3:
4796             case JSCallMode::DEPRECATED_CALL_ARG3:
4797                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs3AndDispatch),
4798                     { glue, sp, func, method, callField, data[0], data[1], data[2] }); // 2: args2
4799                 Return();
4800                 break;
4801             case JSCallMode::CALL_WITH_ARGV:
4802             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
4803                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatch),
4804                     { glue, sp, func, method, callField, data[0], data[1] });
4805                 Return();
4806                 break;
4807             case JSCallMode::CALL_THIS_WITH_ARGV:
4808             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
4809                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisRangeAndDispatch),
4810                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
4811                 Return();
4812                 break;
4813             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
4814             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
4815                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatch),
4816                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
4817                 Return();
4818                 break;
4819             case JSCallMode::CALL_GETTER:
4820                 result = CallNGCRuntime(glue, RTSTUB_ID(CallGetter),
4821                     { glue, func, method, callField, data[0] });
4822                 Jump(&exit);
4823                 break;
4824             case JSCallMode::CALL_SETTER:
4825                 result = CallNGCRuntime(glue, RTSTUB_ID(CallSetter),
4826                     { glue, func, method, callField, data[1], data[0] });
4827                 Jump(&exit);
4828                 break;
4829             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
4830                 result = CallNGCRuntime(glue, RTSTUB_ID(CallContainersArgs3),
4831                     { glue, func, method, callField, data[1], data[2], data[3], data[0] });
4832                 Jump(&exit);
4833                 break;
4834             default:
4835                 UNREACHABLE();
4836         }
4837     }
4838     Bind(&exit);
4839     auto ret = *result;
4840     env->SubCfgExit();
4841     return ret;
4842 }
4843 
CallFastPath(GateRef glue,GateRef nativeCode,GateRef func,GateRef thisValue,GateRef actualNumArgs,GateRef callField,GateRef method,Label * notFastBuiltins,Label * exit,Variable * result,std::initializer_list<GateRef> args,JSCallMode mode)4844 void StubBuilder::CallFastPath(GateRef glue, GateRef nativeCode, GateRef func, GateRef thisValue,
4845     GateRef actualNumArgs, GateRef callField, GateRef method, Label* notFastBuiltins, Label* exit, Variable* result,
4846     std::initializer_list<GateRef> args, JSCallMode mode)
4847 {
4848     auto env = GetEnvironment();
4849     Label isFastBuiltins(env);
4850     auto data = std::begin(args);
4851     GateRef numArgs = ZExtInt32ToPtr(actualNumArgs);
4852     GateRef isFastBuiltinsMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsFastBuiltinBit::START_BIT);
4853     Branch(Int64NotEqual(Int64And(callField, isFastBuiltinsMask), Int64(0)),
4854         &isFastBuiltins, notFastBuiltins);
4855     Bind(&isFastBuiltins);
4856     {
4857         GateRef builtinId = GetBuiltinId(method);
4858         GateRef ret;
4859         switch (mode) {
4860             case JSCallMode::CALL_THIS_ARG0:
4861                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue, numArgs });
4862                 break;
4863             case JSCallMode::CALL_THIS_ARG1:
4864                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(),
4865                                                           thisValue, numArgs, data[0] });
4866                 break;
4867             case JSCallMode::CALL_THIS_ARG2:
4868                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
4869                                                           numArgs, data[0], data[1] });
4870                 break;
4871             case JSCallMode::CALL_THIS_ARG3:
4872                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
4873                                                           numArgs, data[0], data[1], data[2] });
4874                 break;
4875             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
4876             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
4877                 ret = DispatchBuiltinsWithArgv(glue, builtinId, { glue, nativeCode, func, func, thisValue,
4878                                                                   numArgs, data[1] });
4879                 break;
4880             default:
4881                 UNREACHABLE();
4882         }
4883         result->WriteVariable(ret);
4884         Jump(exit);
4885     }
4886     Bind(notFastBuiltins);
4887 }
4888 
TryStringOrSymbelToElementIndex(GateRef key)4889 GateRef StubBuilder::TryStringOrSymbelToElementIndex(GateRef key)
4890 {
4891     auto env = GetEnvironment();
4892     Label entry(env);
4893     env->SubCfgEntry(&entry);
4894     Label exit(env);
4895     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
4896 
4897     Label keyNotSymbol(env);
4898     Branch(IsSymbol(key), &exit, &keyNotSymbol);
4899     Bind(&keyNotSymbol);
4900 
4901     Label greatThanZero(env);
4902     Label inRange(env);
4903     auto len = GetLengthFromString(key);
4904     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
4905     Bind(&greatThanZero);
4906     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
4907     Bind(&inRange);
4908     {
4909         Label isUtf8(env);
4910         Branch(IsUtf16String(key), &exit, &isUtf8);
4911         Bind(&isUtf8);
4912 
4913         GateRef data = PtrAdd(key, IntPtr(EcmaString::DATA_OFFSET));
4914         DEFVARIABLE(c, VariableType::INT32(), Int32(0));
4915         c = ZExtInt8ToInt32(Load(VariableType::INT8(), data));
4916         Label isDigitZero(env);
4917         Label notDigitZero(env);
4918         Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
4919         Bind(&isDigitZero);
4920         {
4921             Label lengthIsOne(env);
4922             Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
4923             Bind(&lengthIsOne);
4924             {
4925                 result = Int32(0);
4926                 Jump(&exit);
4927             }
4928         }
4929         Bind(&notDigitZero);
4930         {
4931             Label isDigit(env);
4932             Label notIsDigit(env);
4933             DEFVARIABLE(i, VariableType::INT32(), Int32(1));
4934             DEFVARIABLE(n, VariableType::INT32(), Int32Sub(*c, Int32('0')));
4935 
4936             Branch(IsDigit(*c), &isDigit, &notIsDigit);
4937             Label loopHead(env);
4938             Label loopEnd(env);
4939             Label afterLoop(env);
4940             Bind(&isDigit);
4941             Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
4942             LoopBegin(&loopHead);
4943             {
4944                 c = ZExtInt8ToInt32(Load(VariableType::INT8(), data, ZExtInt32ToPtr(*i)));
4945                 Label isDigit2(env);
4946                 Label notDigit2(env);
4947                 Branch(IsDigit(*c), &isDigit2, &notDigit2);
4948                 Bind(&isDigit2);
4949                 {
4950                     // 10 means the base of digit is 10.
4951                     n = Int32Add(Int32Mul(*n, Int32(10)),
4952                                  Int32Sub(*c, Int32('0')));
4953                     i = Int32Add(*i, Int32(1));
4954                     Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
4955                 }
4956                 Bind(&notDigit2);
4957                 {
4958                     Label hasPoint(env);
4959                     Branch(Int32Equal(*c, Int32('.')), &hasPoint, &exit);
4960                     Bind(&hasPoint);
4961                     {
4962                         result = Int32(-2); // -2:return -2 means should goto slow path
4963                         Jump(&exit);
4964                     }
4965                 }
4966             }
4967             Bind(&loopEnd);
4968             LoopEnd(&loopHead);
4969             Bind(&afterLoop);
4970             {
4971                 Label lessThanMaxIndex(env);
4972                 Branch(Int32UnsignedLessThan(*n, Int32(JSObject::MAX_ELEMENT_INDEX)),
4973                        &lessThanMaxIndex, &exit);
4974                 Bind(&lessThanMaxIndex);
4975                 {
4976                     result = *n;
4977                     Jump(&exit);
4978                 }
4979             }
4980             Bind(&notIsDigit);
4981             {
4982                 Label isNegative(env);
4983                 Branch(Int32Equal(*c, Int32('-')), &isNegative, &exit);
4984                 Bind(&isNegative);
4985                 {
4986                     result = Int32(-2); // -2:return -2 means should goto slow path
4987                     Jump(&exit);
4988                 }
4989             }
4990         }
4991     }
4992     Bind(&exit);
4993     auto ret = *result;
4994     env->SubCfgExit();
4995     return ret;
4996 }
4997 
GetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef jsType)4998 GateRef StubBuilder::GetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder,
4999                                                 GateRef key, GateRef jsType)
5000 {
5001     auto env = GetEnvironment();
5002     Label entry(env);
5003     env->SubCfgEntry(&entry);
5004     Label exit(env);
5005     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5006 
5007     Label notOnProtoChain(env);
5008     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
5009     Bind(&notOnProtoChain);
5010 
5011     auto negativeZero = GetGlobalConstantValue(
5012         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
5013     Label isNegativeZero(env);
5014     Label notNegativeZero(env);
5015     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
5016     Bind(&isNegativeZero);
5017     {
5018         result = Undefined();
5019         Jump(&exit);
5020     }
5021     Bind(&notNegativeZero);
5022     {
5023         GateRef index = TryStringOrSymbelToElementIndex(key);
5024         Label validIndex(env);
5025         Label notValidIndex(env);
5026         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
5027         Bind(&validIndex);
5028         {
5029             result = CallRuntime(glue, RTSTUB_ID(GetTypeArrayPropertyByIndex),
5030                                  { holder, IntToTaggedInt(index), IntToTaggedInt(jsType) });
5031             Jump(&exit);
5032         }
5033         Bind(&notValidIndex);
5034         {
5035             Label returnNull(env);
5036             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
5037             Bind(&returnNull);
5038             {
5039                 result = Null();
5040                 Jump(&exit);
5041             }
5042         }
5043     }
5044 
5045     Bind(&exit);
5046     auto ret = *result;
5047     env->SubCfgExit();
5048     return ret;
5049 }
5050 
SetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef value,GateRef jsType)5051 GateRef StubBuilder::SetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder, GateRef key,
5052                                                 GateRef value, GateRef jsType)
5053 {
5054     auto env = GetEnvironment();
5055     Label entry(env);
5056     env->SubCfgEntry(&entry);
5057     Label exit(env);
5058     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5059     Label notOnProtoChain(env);
5060     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
5061     Bind(&notOnProtoChain);
5062 
5063     auto negativeZero = GetGlobalConstantValue(
5064         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
5065     Label isNegativeZero(env);
5066     Label notNegativeZero(env);
5067     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
5068     Bind(&isNegativeZero);
5069     {
5070         Label isObj(env);
5071         Label notObj(env);
5072         Branch(IsEcmaObject(value), &isObj, &notObj);
5073         Bind(&isObj);
5074         {
5075             result = Null();
5076             Jump(&exit);
5077         }
5078         Bind(&notObj);
5079         result = Undefined();
5080         Jump(&exit);
5081     }
5082     Bind(&notNegativeZero);
5083     {
5084         GateRef index = TryStringOrSymbelToElementIndex(key);
5085         Label validIndex(env);
5086         Label notValidIndex(env);
5087         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
5088         Bind(&validIndex);
5089         {
5090             result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
5091                 { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType) });
5092             Jump(&exit);
5093         }
5094         Bind(&notValidIndex);
5095         {
5096             Label returnNull(env);
5097             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
5098             Bind(&returnNull);
5099             {
5100                 result = Null();
5101                 Jump(&exit);
5102             }
5103         }
5104     }
5105 
5106     Bind(&exit);
5107     auto ret = *result;
5108     env->SubCfgExit();
5109     return ret;
5110 }
5111 
PGOProfiler(GateRef glue,GateRef func)5112 void StubBuilder::PGOProfiler(GateRef glue, GateRef func)
5113 {
5114     auto env = GetEnvironment();
5115     if (env->IsAsmInterp()) {
5116         Label subEntry(env);
5117         env->SubCfgEntry(&subEntry);
5118 
5119         // Decode bitfield
5120         GateRef stateBitFieldAddr = Int64Add(glue,
5121                                              Int64(JSThread::GlueData::GetStateBitFieldOffset(env->Is32Bit())));
5122         GateRef stateBitField = Load(VariableType::INT64(), stateBitFieldAddr, Int64(0));
5123         // equal stateBitField >> JSThread::CONCURRENT_MARKING_BITFIELD_NUM
5124         GateRef profilerBitOffset = Int64LSR(stateBitField, Int64(JSThread::CONCURRENT_MARKING_BITFIELD_NUM));
5125         // mask: 1 << JSThread::PGO_PROFILER_BITFIELD_NUM - 1
5126         GateRef profilerBitMask = Int64Sub(Int64LSL(Int64(1), Int64(JSThread::PGO_PROFILER_BITFIELD_NUM)), Int64(1));
5127         GateRef state = Int64And(profilerBitOffset, profilerBitMask);
5128         Label exit(env);
5129         Label pgoProfiler(env);
5130         Branch(Int64Equal(state, Int64(static_cast<int64_t>(PGOProfilerStatus::PGO_PROFILER_ENABLE))),
5131             &pgoProfiler, &exit);
5132         Bind(&pgoProfiler);
5133         {
5134             CallNGCRuntime(glue, RTSTUB_ID(PGOProfiler), { glue, func });
5135             Jump(&exit);
5136         }
5137         Bind(&exit);
5138         env->SubCfgExit();
5139     }
5140 }
5141 
Assert(int messageId,int line,GateRef glue,GateRef condition,Label * nextLabel)5142 void StubBuilder::Assert(int messageId, int line, GateRef glue, GateRef condition, Label *nextLabel)
5143 {
5144     auto env = GetEnvironment();
5145     Label ok(env);
5146     Label notOk(env);
5147     Branch(condition, &ok, &notOk);
5148     Bind(&ok);
5149     {
5150         Jump(nextLabel);
5151     }
5152     Bind(&notOk);
5153     {
5154         FatalPrint(glue, { Int32(messageId), Int32(line) });
5155         Jump(nextLabel);
5156     }
5157 }
5158 }  // namespace panda::ecmascript::kungfu
5159