• 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/access_object_stub_builder.h"
20 #include "ecmascript/compiler/interpreter_stub.h"
21 #include "ecmascript/compiler/llvm_ir_builder.h"
22 #include "ecmascript/compiler/new_object_stub_builder.h"
23 #include "ecmascript/compiler/profiler_stub_builder.h"
24 #include "ecmascript/compiler/rt_call_signature.h"
25 #include "ecmascript/compiler/typed_array_stub_builder.h"
26 #include "ecmascript/js_api/js_api_arraylist.h"
27 #include "ecmascript/js_api/js_api_vector.h"
28 #include "ecmascript/js_object.h"
29 #include "ecmascript/js_arguments.h"
30 #include "ecmascript/mem/remembered_set.h"
31 #include "ecmascript/message_string.h"
32 #include "ecmascript/pgo_profiler/pgo_profiler_type.h"
33 #include "ecmascript/property_attributes.h"
34 #include "ecmascript/tagged_dictionary.h"
35 #include "ecmascript/tagged_hash_table.h"
36 
37 namespace panda::ecmascript::kungfu {
Jump(Label * label)38 void StubBuilder::Jump(Label *label)
39 {
40     ASSERT(label);
41     auto currentLabel = env_->GetCurrentLabel();
42     auto currentControl = currentLabel->GetControl();
43     auto jump = env_->GetBuilder()->Goto(currentControl);
44     currentLabel->SetControl(jump);
45     label->AppendPredecessor(currentLabel);
46     label->MergeControl(currentLabel->GetControl());
47     env_->SetCurrentLabel(nullptr);
48 }
49 
Branch(GateRef condition,Label * trueLabel,Label * falseLabel)50 void StubBuilder::Branch(GateRef condition, Label *trueLabel, Label *falseLabel)
51 {
52     auto currentLabel = env_->GetCurrentLabel();
53     auto currentControl = currentLabel->GetControl();
54     GateRef ifBranch = env_->GetBuilder()->Branch(currentControl, condition);
55     currentLabel->SetControl(ifBranch);
56     GateRef ifTrue = env_->GetBuilder()->IfTrue(ifBranch);
57     trueLabel->AppendPredecessor(env_->GetCurrentLabel());
58     trueLabel->MergeControl(ifTrue);
59     GateRef ifFalse = env_->GetBuilder()->IfFalse(ifBranch);
60     falseLabel->AppendPredecessor(env_->GetCurrentLabel());
61     falseLabel->MergeControl(ifFalse);
62     env_->SetCurrentLabel(nullptr);
63 }
64 
Switch(GateRef index,Label * defaultLabel,int64_t * keysValue,Label * keysLabel,int numberOfKeys)65 void StubBuilder::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys)
66 {
67     auto currentLabel = env_->GetCurrentLabel();
68     auto currentControl = currentLabel->GetControl();
69     GateRef switchBranch = env_->GetBuilder()->SwitchBranch(currentControl, index, numberOfKeys);
70     currentLabel->SetControl(switchBranch);
71     for (int i = 0; i < numberOfKeys; i++) {
72         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
73         GateRef switchCase = env_->GetBuilder()->SwitchCase(switchBranch, keysValue[i]);
74         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
75         keysLabel[i].AppendPredecessor(currentLabel);
76         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
77         keysLabel[i].MergeControl(switchCase);
78     }
79 
80     GateRef defaultCase = env_->GetBuilder()->DefaultCase(switchBranch);
81     defaultLabel->AppendPredecessor(currentLabel);
82     defaultLabel->MergeControl(defaultCase);
83     env_->SetCurrentLabel(nullptr);
84 }
85 
LoopBegin(Label * loopHead)86 void StubBuilder::LoopBegin(Label *loopHead)
87 {
88     ASSERT(loopHead);
89     auto loopControl = env_->GetBuilder()->LoopBegin(loopHead->GetControl());
90     loopHead->SetControl(loopControl);
91     loopHead->SetPreControl(loopControl);
92     loopHead->Bind();
93     env_->SetCurrentLabel(loopHead);
94 }
95 
LoopEnd(Label * loopHead)96 void StubBuilder::LoopEnd(Label *loopHead)
97 {
98     ASSERT(loopHead);
99     auto currentLabel = env_->GetCurrentLabel();
100     auto currentControl = currentLabel->GetControl();
101     auto loopend = env_->GetBuilder()->LoopEnd(currentControl);
102     currentLabel->SetControl(loopend);
103     loopHead->AppendPredecessor(currentLabel);
104     loopHead->MergeControl(loopend);
105     loopHead->Seal();
106     loopHead->MergeAllControl();
107     loopHead->MergeAllDepend();
108     env_->SetCurrentLabel(nullptr);
109 }
110 
111 // FindElementWithCache in ecmascript/layout_info-inl.h
FindElementWithCache(GateRef glue,GateRef layoutInfo,GateRef hclass,GateRef key,GateRef propsNum)112 GateRef StubBuilder::FindElementWithCache(GateRef glue, GateRef layoutInfo, GateRef hclass,
113     GateRef key, GateRef propsNum)
114 {
115     auto env = GetEnvironment();
116     Label subEntry(env);
117     env->SubCfgEntry(&subEntry);
118     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
119     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
120     Label exit(env);
121     Label notExceedUpper(env);
122     Label exceedUpper(env);
123     Label afterExceedCon(env);
124     // 9 : Builtins Object properties number is nine
125     Branch(Int32LessThanOrEqual(propsNum, Int32(9)), &notExceedUpper, &exceedUpper);
126     {
127         Bind(&notExceedUpper);
128             Label loopHead(env);
129             Label loopEnd(env);
130             Label afterLoop(env);
131             Jump(&loopHead);
132             LoopBegin(&loopHead);
133             {
134                 Label propsNumIsZero(env);
135                 Label propsNumNotZero(env);
136                 Branch(Int32Equal(propsNum, Int32(0)), &propsNumIsZero, &propsNumNotZero);
137                 Bind(&propsNumIsZero);
138                 Jump(&afterLoop);
139                 Bind(&propsNumNotZero);
140                 GateRef elementAddr = GetPropertiesAddrFromLayoutInfo(layoutInfo);
141                 GateRef keyInProperty = Load(VariableType::JS_ANY(),
142                                              elementAddr,
143                                              PtrMul(ZExtInt32ToPtr(*i),
144                                                     IntPtr(sizeof(panda::ecmascript::Properties))));
145                 Label equal(env);
146                 Label notEqual(env);
147                 Label afterEqualCon(env);
148                 Branch(Equal(keyInProperty, key), &equal, &notEqual);
149                 Bind(&equal);
150                 result = *i;
151                 Jump(&exit);
152                 Bind(&notEqual);
153                 Jump(&afterEqualCon);
154                 Bind(&afterEqualCon);
155                 i = Int32Add(*i, Int32(1));
156                 Branch(Int32UnsignedLessThan(*i, propsNum), &loopEnd, &afterLoop);
157                 Bind(&loopEnd);
158                 LoopEnd(&loopHead);
159             }
160             Bind(&afterLoop);
161             result = Int32(-1);
162             Jump(&exit);
163         Bind(&exceedUpper);
164         Jump(&afterExceedCon);
165     }
166     Bind(&afterExceedCon);
167     result = CallNGCRuntime(glue, RTSTUB_ID(FindElementWithCache), { glue, hclass, key, propsNum });
168     Jump(&exit);
169     Bind(&exit);
170     auto ret = *result;
171     env->SubCfgExit();
172     return ret;
173 }
174 
FindElementFromNumberDictionary(GateRef glue,GateRef elements,GateRef index)175 GateRef StubBuilder::FindElementFromNumberDictionary(GateRef glue, GateRef elements, GateRef index)
176 {
177     auto env = GetEnvironment();
178     Label subentry(env);
179     env->SubCfgEntry(&subentry);
180     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
181     Label exit(env);
182     GateRef capcityoffset =
183         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
184                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
185     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
186     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
187                                            PtrAdd(dataoffset, capcityoffset)));
188     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
189     GateRef len = Int32(sizeof(int) / sizeof(uint8_t));
190     GateRef hash = CallRuntime(glue, RTSTUB_ID(GetHash32),
191         { IntToTaggedInt(index), IntToTaggedInt(len) });
192     DEFVARIABLE(entry, VariableType::INT32(),
193         Int32And(TruncInt64ToInt32(ChangeTaggedPointerToInt64(hash)), Int32Sub(capacity, Int32(1))));
194     Label loopHead(env);
195     Label loopEnd(env);
196     Label afterLoop(env);
197     Jump(&loopHead);
198     LoopBegin(&loopHead);
199     GateRef element = GetKeyFromDictionary<NumberDictionary>(elements, *entry);
200     Label isHole(env);
201     Label notHole(env);
202     Branch(TaggedIsHole(element), &isHole, &notHole);
203     Bind(&isHole);
204     Jump(&loopEnd);
205     Bind(&notHole);
206     Label isUndefined(env);
207     Label notUndefined(env);
208     Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
209     Bind(&isUndefined);
210     result = Int32(-1);
211     Jump(&exit);
212     Bind(&notUndefined);
213     Label isMatch(env);
214     Label notMatch(env);
215     Branch(Int32Equal(index, GetInt32OfTInt(element)), &isMatch, &notMatch);
216     Bind(&isMatch);
217     result = *entry;
218     Jump(&exit);
219     Bind(&notMatch);
220     Jump(&loopEnd);
221     Bind(&loopEnd);
222     entry = GetNextPositionForHash(*entry, *count, capacity);
223     count = Int32Add(*count, Int32(1));
224     LoopEnd(&loopHead);
225     Bind(&exit);
226     auto ret = *result;
227     env->SubCfgExit();
228     return ret;
229 }
230 
231 // int TaggedHashTable<Derived>::FindEntry(const JSTaggedValue &key) in tagged_hash_table.h
FindEntryFromNameDictionary(GateRef glue,GateRef elements,GateRef key)232 GateRef StubBuilder::FindEntryFromNameDictionary(GateRef glue, GateRef elements, GateRef key)
233 {
234     auto env = GetEnvironment();
235     Label funcEntry(env);
236     env->SubCfgEntry(&funcEntry);
237     Label exit(env);
238     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
239     GateRef capcityoffset =
240         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
241                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
242     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
243     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
244                                            PtrAdd(dataoffset, capcityoffset)));
245     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
246     DEFVARIABLE(hash, VariableType::INT32(), Int32(0));
247     // NameDictionary::hash
248     Label isSymbol(env);
249     Label notSymbol(env);
250     Label loopHead(env);
251     Label loopEnd(env);
252     Label afterLoop(env);
253     Label beforeDefineHash(env);
254     Branch(IsSymbol(key), &isSymbol, &notSymbol);
255     Bind(&isSymbol);
256     {
257         hash = GetInt32OfTInt(Load(VariableType::INT64(), key,
258             IntPtr(JSSymbol::HASHFIELD_OFFSET)));
259         Jump(&beforeDefineHash);
260     }
261     Bind(&notSymbol);
262     {
263         Label isString(env);
264         Label notString(env);
265         Branch(IsString(key), &isString, &notString);
266         Bind(&isString);
267         {
268             hash = GetHashcodeFromString(glue, key);
269             Jump(&beforeDefineHash);
270         }
271         Bind(&notString);
272         {
273             Jump(&beforeDefineHash);
274         }
275     }
276     Bind(&beforeDefineHash);
277     // GetFirstPosition(hash, size)
278     DEFVARIABLE(entry, VariableType::INT32(), Int32And(*hash, Int32Sub(capacity, Int32(1))));
279     Jump(&loopHead);
280     LoopBegin(&loopHead);
281     {
282         GateRef element = GetKeyFromDictionary<NameDictionary>(elements, *entry);
283         Label isHole(env);
284         Label notHole(env);
285         Branch(TaggedIsHole(element), &isHole, &notHole);
286         {
287             Bind(&isHole);
288             {
289                 Jump(&loopEnd);
290             }
291             Bind(&notHole);
292             {
293                 Label isUndefined(env);
294                 Label notUndefined(env);
295                 Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
296                 {
297                     Bind(&isUndefined);
298                     {
299                         result = Int32(-1);
300                         Jump(&exit);
301                     }
302                     Bind(&notUndefined);
303                     {
304                         Label isMatch(env);
305                         Label notMatch(env);
306                         Branch(Equal(key, element), &isMatch, &notMatch);
307                         {
308                             Bind(&isMatch);
309                             {
310                                 result = *entry;
311                                 Jump(&exit);
312                             }
313                             Bind(&notMatch);
314                             {
315                                 Jump(&loopEnd);
316                             }
317                         }
318                     }
319                 }
320             }
321         }
322         Bind(&loopEnd);
323         {
324             entry = GetNextPositionForHash(*entry, *count, capacity);
325             count = Int32Add(*count, Int32(1));
326             LoopEnd(&loopHead);
327         }
328     }
329     Bind(&exit);
330     auto ret = *result;
331     env->SubCfgExit();
332     return ret;
333 }
334 
IsMatchInTransitionDictionary(GateRef element,GateRef key,GateRef metaData,GateRef attr)335 GateRef StubBuilder::IsMatchInTransitionDictionary(GateRef element, GateRef key, GateRef metaData, GateRef attr)
336 {
337     return BoolAnd(Equal(element, key), Int32Equal(metaData, attr));
338 }
339 
340 // metaData is int32 type
FindEntryFromTransitionDictionary(GateRef glue,GateRef elements,GateRef key,GateRef metaData)341 GateRef StubBuilder::FindEntryFromTransitionDictionary(GateRef glue, GateRef elements, GateRef key, GateRef metaData)
342 {
343     auto env = GetEnvironment();
344     Label funcEntry(env);
345     env->SubCfgEntry(&funcEntry);
346     Label exit(env);
347     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
348     GateRef capcityoffset =
349         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
350                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
351     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
352     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
353                                            PtrAdd(dataoffset, capcityoffset)));
354     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
355     DEFVARIABLE(hash, VariableType::INT32(), Int32(0));
356     // TransitionDictionary::hash
357     Label isSymbol(env);
358     Label notSymbol(env);
359     Label loopHead(env);
360     Label loopEnd(env);
361     Label afterLoop(env);
362     Label beforeDefineHash(env);
363     Branch(IsSymbol(key), &isSymbol, &notSymbol);
364     Bind(&isSymbol);
365     {
366         hash = GetInt32OfTInt(Load(VariableType::INT64(), key,
367             IntPtr(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET)));
368         Jump(&beforeDefineHash);
369     }
370     Bind(&notSymbol);
371     {
372         Label isString(env);
373         Label notString(env);
374         Branch(IsString(key), &isString, &notString);
375         Bind(&isString);
376         {
377             hash = GetHashcodeFromString(glue, key);
378             Jump(&beforeDefineHash);
379         }
380         Bind(&notString);
381         {
382             Jump(&beforeDefineHash);
383         }
384     }
385     Bind(&beforeDefineHash);
386     hash = Int32Add(*hash, metaData);
387     // GetFirstPosition(hash, size)
388     DEFVARIABLE(entry, VariableType::INT32(), Int32And(*hash, Int32Sub(capacity, Int32(1))));
389     Jump(&loopHead);
390     LoopBegin(&loopHead);
391     {
392         GateRef element = GetKeyFromDictionary<TransitionsDictionary>(elements, *entry);
393         Label isHole(env);
394         Label notHole(env);
395         Branch(TaggedIsHole(element), &isHole, &notHole);
396         {
397             Bind(&isHole);
398             {
399                 Jump(&loopEnd);
400             }
401             Bind(&notHole);
402             {
403                 Label isUndefined(env);
404                 Label notUndefined(env);
405                 Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
406                 {
407                     Bind(&isUndefined);
408                     {
409                         result = Int32(-1);
410                         Jump(&exit);
411                     }
412                     Bind(&notUndefined);
413                     {
414                         Label isMatch(env);
415                         Label notMatch(env);
416                         Branch(
417                             IsMatchInTransitionDictionary(element, key, metaData,
418                                 GetAttributesFromDictionary<TransitionsDictionary>(elements, *entry)),
419                             &isMatch, &notMatch);
420                         {
421                             Bind(&isMatch);
422                             {
423                                 result = *entry;
424                                 Jump(&exit);
425                             }
426                             Bind(&notMatch);
427                             {
428                                 Jump(&loopEnd);
429                             }
430                         }
431                     }
432                 }
433             }
434         }
435         Bind(&loopEnd);
436         {
437             entry = GetNextPositionForHash(*entry, *count, capacity);
438             count = Int32Add(*count, Int32(1));
439             LoopEnd(&loopHead);
440         }
441     }
442     Bind(&exit);
443     auto ret = *result;
444     env->SubCfgExit();
445     return ret;
446 }
447 
JSObjectGetProperty(GateRef obj,GateRef hclass,GateRef attr)448 GateRef StubBuilder::JSObjectGetProperty(GateRef obj, GateRef hclass, GateRef attr)
449 {
450     auto env = GetEnvironment();
451     Label entry(env);
452     env->SubCfgEntry(&entry);
453     Label exit(env);
454     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
455     Label inlinedProp(env);
456     Label notInlinedProp(env);
457     Label post(env);
458     GateRef attrOffset = GetOffsetFieldInPropAttr(attr);
459     GateRef rep = GetRepInPropAttr(attr);
460     Branch(IsInlinedProperty(attr), &inlinedProp, &notInlinedProp);
461     {
462         Bind(&inlinedProp);
463         {
464             result = GetPropertyInlinedProps(obj, hclass, attrOffset);
465             Jump(&post);
466         }
467         Bind(&notInlinedProp);
468         {
469             // compute outOfLineProp offset, get it and return
470             GateRef array =
471                 Load(VariableType::INT64(), obj, IntPtr(JSObject::PROPERTIES_OFFSET));
472             result = GetValueFromTaggedArray(array, Int32Sub(attrOffset,
473                 GetInlinedPropertiesFromHClass(hclass)));
474             Jump(&post);
475         }
476     }
477     Bind(&post);
478     {
479         Label nonDoubleToTagged(env);
480         Label doubleToTagged(env);
481         Branch(IsDoubleRepInPropAttr(rep), &doubleToTagged, &nonDoubleToTagged);
482         Bind(&doubleToTagged);
483         {
484             result = TaggedPtrToTaggedDoublePtr(*result);
485             Jump(&exit);
486         }
487         Bind(&nonDoubleToTagged);
488         {
489             Label intToTagged(env);
490             Branch(IsIntRepInPropAttr(rep), &intToTagged, &exit);
491             Bind(&intToTagged);
492             {
493                 result = TaggedPtrToTaggedIntPtr(*result);
494                 Jump(&exit);
495             }
496         }
497     }
498     Bind(&exit);
499     auto ret = *result;
500     env->SubCfgExit();
501     return ret;
502 }
503 
JSObjectSetProperty(GateRef glue,GateRef obj,GateRef hclass,GateRef attr,GateRef key,GateRef value)504 void StubBuilder::JSObjectSetProperty(
505     GateRef glue, GateRef obj, GateRef hclass, GateRef attr, GateRef key, GateRef value)
506 {
507     auto env = GetEnvironment();
508     Label subEntry(env);
509     env->SubCfgEntry(&subEntry);
510     Label exit(env);
511     Label inlinedProp(env);
512     Label notInlinedProp(env);
513     GateRef attrIndex = GetOffsetFieldInPropAttr(attr);
514     Branch(IsInlinedProperty(attr), &inlinedProp, &notInlinedProp);
515     {
516         Bind(&inlinedProp);
517         {
518             GateRef offset = GetInlinedPropOffsetFromHClass(hclass, attrIndex);
519             SetValueWithAttr(glue, obj, offset, key, value, attr);
520             Jump(&exit);
521         }
522         Bind(&notInlinedProp);
523         {
524             // compute outOfLineProp offset, get it and return
525             GateRef array = Load(VariableType::JS_POINTER(), obj,
526                                  IntPtr(JSObject::PROPERTIES_OFFSET));
527             GateRef offset = Int32Sub(attrIndex, GetInlinedPropertiesFromHClass(hclass));
528             SetValueToTaggedArrayWithAttr(glue, array, offset, key, value, attr);
529             Jump(&exit);
530         }
531     }
532     Bind(&exit);
533     env->SubCfgExit();
534     return;
535 }
536 
ComputePropertyCapacityInJSObj(GateRef oldLength)537 GateRef StubBuilder::ComputePropertyCapacityInJSObj(GateRef oldLength)
538 {
539     auto env = GetEnvironment();
540     Label subEntry(env);
541     env->SubCfgEntry(&subEntry);
542     Label exit(env);
543     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
544     GateRef newL = Int32Add(oldLength, Int32(JSObject::PROPERTIES_GROW_SIZE));
545     Label reachMax(env);
546     Label notReachMax(env);
547     Branch(Int32GreaterThan(newL, Int32(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)),
548         &reachMax, &notReachMax);
549     {
550         Bind(&reachMax);
551         result = Int32(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS);
552         Jump(&exit);
553         Bind(&notReachMax);
554         result = newL;
555         Jump(&exit);
556     }
557     Bind(&exit);
558     auto ret = *result;
559     env->SubCfgExit();
560     return ret;
561 }
562 
CallGetterHelper(GateRef glue,GateRef receiver,GateRef holder,GateRef accessor,ProfileOperation callback)563 GateRef StubBuilder::CallGetterHelper(
564     GateRef glue, GateRef receiver, GateRef holder, GateRef accessor, ProfileOperation callback)
565 {
566     auto env = GetEnvironment();
567     Label subEntry(env);
568     env->SubCfgEntry(&subEntry);
569     Label exit(env);
570     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
571 
572     Label isInternal(env);
573     Label notInternal(env);
574     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
575     Bind(&isInternal);
576     {
577         Label arrayLength(env);
578         Label tryContinue(env);
579         auto lengthAccessor = GetGlobalConstantValue(
580             VariableType::JS_POINTER(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
581         Branch(Equal(accessor, lengthAccessor), &arrayLength, &tryContinue);
582         Bind(&arrayLength);
583         {
584             result = IntToTaggedPtr(Load(VariableType::INT32(), holder, IntPtr(JSArray::LENGTH_OFFSET)));
585             Jump(&exit);
586         }
587         Bind(&tryContinue);
588         result = CallRuntime(glue, RTSTUB_ID(CallInternalGetter), { accessor, holder });
589         Jump(&exit);
590     }
591     Bind(&notInternal);
592     {
593         auto getter = Load(VariableType::JS_ANY(), accessor,
594                            IntPtr(AccessorData::GETTER_OFFSET));
595         Label objIsUndefined(env);
596         Label objNotUndefined(env);
597         Branch(TaggedIsUndefined(getter), &objIsUndefined, &objNotUndefined);
598         // if getter is undefined, return undefiend
599         Bind(&objIsUndefined);
600         {
601             result = Undefined();
602             Jump(&exit);
603         }
604         Bind(&objNotUndefined);
605         {
606             auto retValue = JSCallDispatch(glue, getter, Int32(0), 0, Circuit::NullGate(),
607                                            JSCallMode::CALL_GETTER, { receiver }, callback);
608             Label noPendingException(env);
609             Branch(HasPendingException(glue), &exit, &noPendingException);
610             Bind(&noPendingException);
611             {
612                 result = retValue;
613                 Jump(&exit);
614             }
615         }
616     }
617     Bind(&exit);
618     auto ret = *result;
619     env->SubCfgExit();
620     return ret;
621 }
622 
CallSetterHelper(GateRef glue,GateRef receiver,GateRef accessor,GateRef value,ProfileOperation callback)623 GateRef StubBuilder::CallSetterHelper(
624     GateRef glue, GateRef receiver, GateRef accessor, GateRef value, ProfileOperation callback)
625 {
626     auto env = GetEnvironment();
627     Label subEntry(env);
628     env->SubCfgEntry(&subEntry);
629     Label exit(env);
630     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
631 
632     Label isInternal(env);
633     Label notInternal(env);
634     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
635     Bind(&isInternal);
636     {
637         result = CallRuntime(glue, RTSTUB_ID(CallInternalSetter), { receiver, accessor, value });
638         Jump(&exit);
639     }
640     Bind(&notInternal);
641     {
642         auto setter = Load(VariableType::JS_ANY(), accessor,
643                            IntPtr(AccessorData::SETTER_OFFSET));
644         Label objIsUndefined(env);
645         Label objNotUndefined(env);
646         Branch(TaggedIsUndefined(setter), &objIsUndefined, &objNotUndefined);
647         Bind(&objIsUndefined);
648         {
649             CallRuntime(glue, RTSTUB_ID(ThrowSetterIsUndefinedException), {});
650             result = Exception();
651             Jump(&exit);
652         }
653         Bind(&objNotUndefined);
654         {
655             auto retValue = JSCallDispatch(glue, setter, Int32(1), 0, Circuit::NullGate(),
656                                            JSCallMode::CALL_SETTER, { receiver, value }, callback);
657             Label noPendingException(env);
658             Branch(HasPendingException(glue), &exit, &noPendingException);
659             Bind(&noPendingException);
660             {
661                 result = retValue;
662                 Jump(&exit);
663             }
664         }
665     }
666     Bind(&exit);
667     auto ret = *result;
668     env->SubCfgExit();
669     return ret;
670 }
671 
ShouldCallSetter(GateRef receiver,GateRef holder,GateRef accessor,GateRef attr)672 GateRef StubBuilder::ShouldCallSetter(GateRef receiver, GateRef holder, GateRef accessor, GateRef attr)
673 {
674     auto env = GetEnvironment();
675     Label subEntry(env);
676     env->SubCfgEntry(&subEntry);
677     Label exit(env);
678     DEFVARIABLE(result, VariableType::BOOL(), True());
679     Label isInternal(env);
680     Label notInternal(env);
681     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
682     Bind(&isInternal);
683     {
684         Label receiverEqualsHolder(env);
685         Label receiverNotEqualsHolder(env);
686         Branch(Equal(receiver, holder), &receiverEqualsHolder, &receiverNotEqualsHolder);
687         Bind(&receiverEqualsHolder);
688         {
689             result = IsWritable(attr);
690             Jump(&exit);
691         }
692         Bind(&receiverNotEqualsHolder);
693         {
694             result = False();
695             Jump(&exit);
696         }
697     }
698     Bind(&notInternal);
699     {
700         result = True();
701         Jump(&exit);
702     }
703     Bind(&exit);
704     auto ret = *result;
705     env->SubCfgExit();
706     return ret;
707 }
708 
JSHClassAddProperty(GateRef glue,GateRef receiver,GateRef key,GateRef attr)709 void StubBuilder::JSHClassAddProperty(GateRef glue, GateRef receiver, GateRef key, GateRef attr)
710 {
711     auto env = GetEnvironment();
712     Label subEntry(env);
713     env->SubCfgEntry(&subEntry);
714     Label exit(env);
715     GateRef hclass = LoadHClass(receiver);
716     GateRef metaData = GetPropertyMetaDataFromAttr(attr);
717     GateRef newClass = FindTransitions(glue, receiver, hclass, key, metaData);
718     Label findHClass(env);
719     Label notFindHClass(env);
720     Branch(Equal(newClass, Undefined()), &notFindHClass, &findHClass);
721     Bind(&findHClass);
722     {
723         Jump(&exit);
724     }
725     Bind(&notFindHClass);
726     {
727         GateRef type = GetObjectType(hclass);
728         GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass),
729                                 Int32(JSTaggedValue::TaggedTypeSize()));
730         GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass);
731         GateRef newJshclass = CallRuntime(glue, RTSTUB_ID(NewEcmaHClass),
732             { IntToTaggedInt(size), IntToTaggedInt(type),
733               IntToTaggedInt(inlineProps) });
734         CopyAllHClass(glue, newJshclass, hclass);
735         CallRuntime(glue, RTSTUB_ID(UpdateLayOutAndAddTransition),
736                     { hclass, newJshclass, key, IntToTaggedInt(attr) });
737 #if ECMASCRIPT_ENABLE_IC
738         NotifyHClassChanged(glue, hclass, newJshclass);
739 #endif
740         StoreHClass(glue, receiver, newJshclass);
741         Jump(&exit);
742     }
743     Bind(&exit);
744     env->SubCfgExit();
745     return;
746 }
747 
748 // if condition:objHandle->IsJSArray() &&
749 //      keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()
SetHasConstructorCondition(GateRef glue,GateRef receiver,GateRef key)750 GateRef StubBuilder::SetHasConstructorCondition(GateRef glue, GateRef receiver, GateRef key)
751 {
752     GateRef gConstOffset = Load(VariableType::JS_ANY(), glue,
753         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
754 
755     GateRef gCtorStr = Load(VariableType::JS_ANY(),
756         gConstOffset,
757         Int64Mul(Int64(sizeof(JSTaggedValue)),
758             Int64(static_cast<uint64_t>(ConstantIndex::CONSTRUCTOR_STRING_INDEX))));
759     GateRef isCtorStr = Equal(key, gCtorStr);
760     return BoolAnd(IsJsArray(receiver), isCtorStr);
761 }
762 
763 // Note: set return exit node
AddPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef propertyAttributes,ProfileOperation callback)764 GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value,
765                                        GateRef propertyAttributes, ProfileOperation callback)
766 {
767     auto env = GetEnvironment();
768     Label subentry(env);
769     env->SubCfgEntry(&subentry);
770     Label exit(env);
771     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
772     Label setHasCtor(env);
773     Label notSetHasCtor(env);
774     Label afterCtorCon(env);
775     GateRef hclass = LoadHClass(receiver);
776     Branch(SetHasConstructorCondition(glue, receiver, key), &setHasCtor, &notSetHasCtor);
777     {
778         Bind(&setHasCtor);
779         SetHasConstructorToHClass(glue, hclass, Int32(1));
780         Jump(&afterCtorCon);
781         Bind(&notSetHasCtor);
782         Jump(&afterCtorCon);
783     }
784     Bind(&afterCtorCon);
785     // 0x111 : default attribute for property: writable, enumerable, configurable
786     DEFVARIABLE(attr, VariableType::INT32(), propertyAttributes);
787     GateRef numberOfProps = GetNumberOfPropsFromHClass(hclass);
788     GateRef inlinedProperties = GetInlinedPropertiesFromHClass(hclass);
789     Label hasUnusedInProps(env);
790     Label noUnusedInProps(env);
791     Label afterInPropsCon(env);
792     Branch(Int32UnsignedLessThan(numberOfProps, inlinedProperties), &hasUnusedInProps, &noUnusedInProps);
793     {
794         Bind(&noUnusedInProps);
795         Jump(&afterInPropsCon);
796         Bind(&hasUnusedInProps);
797         {
798             SetPropertyInlinedProps(glue, receiver, hclass, value, numberOfProps);
799             attr = SetOffsetFieldInPropAttr(*attr, numberOfProps);
800             attr = SetIsInlinePropsFieldInPropAttr(*attr, Int32(1)); // 1: set inInlineProps true
801             attr = SetTaggedRepInPropAttr(*attr);
802             attr = ProfilerStubBuilder(env).UpdateTrackTypeInPropAttr(*attr, value, callback);
803             JSHClassAddProperty(glue, receiver, key, *attr);
804             callback.ProfileObjLayoutByStore(receiver);
805             result = Undefined();
806             Jump(&exit);
807         }
808     }
809     Bind(&afterInPropsCon);
810     DEFVARIABLE(array, VariableType::JS_POINTER(), GetPropertiesArray(receiver));
811     DEFVARIABLE(length, VariableType::INT32(), GetLengthOfTaggedArray(*array));
812     Label lenIsZero(env);
813     Label lenNotZero(env);
814     Label afterLenCon(env);
815     Branch(Int32Equal(*length, Int32(0)), &lenIsZero, &lenNotZero);
816     {
817         Bind(&lenIsZero);
818         {
819             length = Int32(JSObject::MIN_PROPERTIES_LENGTH);
820             array = CallRuntime(glue, RTSTUB_ID(NewTaggedArray), { IntToTaggedInt(*length) });
821             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array);
822             Jump(&afterLenCon);
823         }
824         Bind(&lenNotZero);
825         Jump(&afterLenCon);
826     }
827     Bind(&afterLenCon);
828     Label isDictMode(env);
829     Label notDictMode(env);
830     Branch(IsDictionaryMode(*array), &isDictMode, &notDictMode);
831     {
832         Bind(&isDictMode);
833         {
834             GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent),
835                                       {receiver, *array, key, value, IntToTaggedInt(*attr), TaggedFalse()});
836             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res);
837             Jump(&exit);
838         }
839         Bind(&notDictMode);
840         {
841             attr = SetIsInlinePropsFieldInPropAttr(*attr, Int32(0));
842             GateRef outProps = Int32Sub(numberOfProps, inlinedProperties);
843             Label isArrayFull(env);
844             Label arrayNotFull(env);
845             Label afterArrLenCon(env);
846             Branch(Int32GreaterThanOrEqual(*length, outProps), &isArrayFull, &arrayNotFull);
847             {
848                 Bind(&isArrayFull);
849                 {
850                     Label ChangeToDict(env);
851                     Label notChangeToDict(env);
852                     Label afterDictChangeCon(env);
853                     Branch(Int32GreaterThanOrEqual(*length, Int32(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)),
854                         &ChangeToDict, &notChangeToDict);
855                     {
856                         Bind(&ChangeToDict);
857                         {
858                             attr = SetDictionaryOrderFieldInPropAttr(*attr,
859                                 Int32(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES));
860                             GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent),
861                                 { receiver, *array, key, value, IntToTaggedInt(*attr), TaggedTrue() });
862                             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res);
863                             result = Undefined();
864                             Jump(&exit);
865                         }
866                         Bind(&notChangeToDict);
867                         Jump(&afterDictChangeCon);
868                     }
869                     Bind(&afterDictChangeCon);
870                     GateRef capacity = ComputePropertyCapacityInJSObj(*length);
871                     array = CallRuntime(glue, RTSTUB_ID(CopyArray),
872                         { *array, IntToTaggedInt(*length), IntToTaggedInt(capacity) });
873                     SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array);
874                     Jump(&afterArrLenCon);
875                 }
876                 Bind(&arrayNotFull);
877                 Jump(&afterArrLenCon);
878             }
879             Bind(&afterArrLenCon);
880             {
881                 attr = SetOffsetFieldInPropAttr(*attr, numberOfProps);
882                 attr = SetTaggedRepInPropAttr(*attr);
883                 attr = ProfilerStubBuilder(env).UpdateTrackTypeInPropAttr(*attr, value, callback);
884                 JSHClassAddProperty(glue, receiver, key, *attr);
885                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, *array, outProps, value);
886                 callback.ProfileObjLayoutByStore(receiver);
887                 Jump(&exit);
888             }
889         }
890     }
891     Bind(&exit);
892     auto ret = *result;
893     env->SubCfgExit();
894     return ret;
895 }
896 
ThrowTypeAndReturn(GateRef glue,int messageId,GateRef val)897 void StubBuilder::ThrowTypeAndReturn(GateRef glue, int messageId, GateRef val)
898 {
899     GateRef msgIntId = Int32(messageId);
900     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(msgIntId) });
901     Return(val);
902 }
903 
TaggedToRepresentation(GateRef value)904 GateRef StubBuilder::TaggedToRepresentation(GateRef value)
905 {
906     auto env = GetEnvironment();
907     Label entry(env);
908     env->SubCfgEntry(&entry);
909     Label exit(env);
910     DEFVARIABLE(resultRep, VariableType::INT64(),
911                 Int64(static_cast<int32_t>(Representation::TAGGED)));
912     Label isInt(env);
913     Label notInt(env);
914 
915     Branch(TaggedIsInt(value), &isInt, &notInt);
916     Bind(&isInt);
917     {
918         resultRep = Int64(static_cast<int32_t>(Representation::INT));
919         Jump(&exit);
920     }
921     Bind(&notInt);
922     {
923         Label isDouble(env);
924         Label notDouble(env);
925         Branch(TaggedIsDouble(value), &isDouble, &notDouble);
926         Bind(&isDouble);
927         {
928             resultRep = Int64(static_cast<int32_t>(Representation::DOUBLE));
929             Jump(&exit);
930         }
931         Bind(&notDouble);
932         {
933             resultRep = Int64(static_cast<int32_t>(Representation::TAGGED));
934             Jump(&exit);
935         }
936     }
937     Bind(&exit);
938     auto ret = *resultRep;
939     env->SubCfgExit();
940     return ret;
941 }
942 
TaggedToElementKind(GateRef value)943 GateRef StubBuilder::TaggedToElementKind(GateRef value)
944 {
945     auto env = GetEnvironment();
946     Label entry(env);
947     env->SubCfgEntry(&entry);
948     Label exit(env);
949 
950     DEFVARIABLE(result, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::TAGGED)));
951     Label isInt(env);
952     Label isNotInt(env);
953     Branch(TaggedIsInt(value), &isInt, &isNotInt);
954     Bind(&isInt);
955     {
956         result = Int32(static_cast<int32_t>(ElementsKind::INT));
957         Jump(&exit);
958     }
959     Bind(&isNotInt);
960     {
961         Label isObject(env);
962         Label isDouble(env);
963         Branch(TaggedIsObject(value), &isObject, &isDouble);
964         Bind(&isDouble);
965         {
966             result = Int32(static_cast<int32_t>(ElementsKind::DOUBLE));
967             Jump(&exit);
968         }
969         Bind(&isObject);
970         {
971             Label isHeapObject(env);
972             Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
973             Bind(&isHeapObject);
974             {
975                 Label isString(env);
976                 Label isNonString(env);
977                 Branch(TaggedIsString(value), &isString, &isNonString);
978                 Bind(&isString);
979                 {
980                     result = Int32(static_cast<int32_t>(ElementsKind::STRING));
981                     Jump(&exit);
982                 }
983                 Bind(&isNonString);
984                 {
985                     result = Int32(static_cast<int32_t>(ElementsKind::OBJECT));
986                     Jump(&exit);
987                 }
988             }
989         }
990     }
991     Bind(&exit);
992     auto ret = *result;
993     env->SubCfgExit();
994     return ret;
995 }
996 
Store(VariableType type,GateRef glue,GateRef base,GateRef offset,GateRef value)997 void StubBuilder::Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value)
998 {
999     if (!env_->IsAsmInterp()) {
1000         env_->GetBuilder()->Store(type, glue, base, offset, value);
1001     } else {
1002         auto depend = env_->GetCurrentLabel()->GetDepend();
1003         GateRef ptr = PtrAdd(base, offset);
1004         GateRef result = env_->GetCircuit()->NewGate(
1005             env_->GetCircuit()->Store(), MachineType::NOVALUE,
1006             { depend, value, ptr }, type.GetGateType());
1007         env_->GetCurrentLabel()->SetDepend(result);
1008         if (type == VariableType::JS_POINTER() || type == VariableType::JS_ANY()) {
1009             auto env = GetEnvironment();
1010             Label entry(env);
1011             env->SubCfgEntry(&entry);
1012             Label exit(env);
1013             Label isHeapObject(env);
1014 
1015             Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
1016             Bind(&isHeapObject);
1017             {
1018                 CallNGCRuntime(glue, RTSTUB_ID(StoreBarrier), { glue, base, offset, value });
1019                 Jump(&exit);
1020             }
1021             Bind(&exit);
1022             env->SubCfgExit();
1023         }
1024     }
1025 }
1026 
SetValueWithAttr(GateRef glue,GateRef obj,GateRef offset,GateRef key,GateRef value,GateRef attr)1027 void StubBuilder::SetValueWithAttr(GateRef glue, GateRef obj, GateRef offset, GateRef key, GateRef value, GateRef attr)
1028 {
1029     auto env = GetEnvironment();
1030     Label entry(env);
1031     env->SubCfgEntry(&entry);
1032 
1033     Label exit(env);
1034     Label repChange(env);
1035     GateRef rep = GetRepInPropAttr(attr);
1036     SetValueWithRep(glue, obj, offset, value, rep, &repChange);
1037     Jump(&exit);
1038     Bind(&repChange);
1039     {
1040         attr = SetTaggedRepInPropAttr(attr);
1041         TransitionForRepChange(glue, obj, key, attr);
1042         Store(VariableType::JS_ANY(), glue, obj, offset, value);
1043         Jump(&exit);
1044     }
1045     Bind(&exit);
1046     env->SubCfgExit();
1047 }
1048 
SetValueWithRep(GateRef glue,GateRef obj,GateRef offset,GateRef value,GateRef rep,Label * repChange)1049 void StubBuilder::SetValueWithRep(
1050     GateRef glue, GateRef obj, GateRef offset, GateRef value, GateRef rep, Label *repChange)
1051 {
1052     auto env = GetEnvironment();
1053     Label entry(env);
1054     env->SubCfgEntry(&entry);
1055 
1056     Label exit(env);
1057     Label repIsDouble(env);
1058     Label repIsNonDouble(env);
1059     Branch(IsDoubleRepInPropAttr(rep), &repIsDouble, &repIsNonDouble);
1060     Bind(&repIsDouble);
1061     {
1062         Label valueIsInt(env);
1063         Label valueIsNotInt(env);
1064         Branch(TaggedIsInt(value), &valueIsInt, &valueIsNotInt);
1065         Bind(&valueIsInt);
1066         {
1067             GateRef result = GetDoubleOfTInt(value);
1068             Store(VariableType::FLOAT64(), glue, obj, offset, result);
1069             Jump(&exit);
1070         }
1071         Bind(&valueIsNotInt);
1072         {
1073             Label valueIsObject(env);
1074             Label valueIsDouble(env);
1075             Branch(TaggedIsObject(value), &valueIsObject, &valueIsDouble);
1076             Bind(&valueIsDouble);
1077             {
1078                 // TaggedDouble to double
1079                 GateRef result = GetDoubleOfTDouble(value);
1080                 Store(VariableType::FLOAT64(), glue, obj, offset, result);
1081                 Jump(&exit);
1082             }
1083             Bind(&valueIsObject);
1084             {
1085                 Jump(repChange);
1086             }
1087         }
1088     }
1089     Bind(&repIsNonDouble);
1090     {
1091         Label repIsInt(env);
1092         Label repIsTagged(env);
1093         Branch(IsIntRepInPropAttr(rep), &repIsInt, &repIsTagged);
1094         Bind(&repIsInt);
1095         {
1096             Label valueIsInt(env);
1097             Label valueIsNotInt(env);
1098             Branch(TaggedIsInt(value), &valueIsInt, &valueIsNotInt);
1099             Bind(&valueIsInt);
1100             {
1101                 GateRef result = GetInt32OfTInt(value);
1102                 Store(VariableType::INT32(), glue, obj, offset, result);
1103                 Jump(&exit);
1104             }
1105             Bind(&valueIsNotInt);
1106             {
1107                 Jump(repChange);
1108             }
1109         }
1110         Bind(&repIsTagged);
1111         {
1112             Store(VariableType::JS_ANY(), glue, obj, offset, value);
1113             Jump(&exit);
1114         }
1115     }
1116 
1117     Bind(&exit);
1118     env->SubCfgExit();
1119     return;
1120 }
1121 
1122 
SetValueWithBarrier(GateRef glue,GateRef obj,GateRef offset,GateRef value)1123 void StubBuilder::SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value)
1124 {
1125     auto env = GetEnvironment();
1126     Label entry(env);
1127     env->SubCfgEntry(&entry);
1128     Label exit(env);
1129     Label isVailedIndex(env);
1130     Label notValidIndex(env);
1131 
1132     // ObjectAddressToRange function may cause obj is not an object. GC may not mark this obj.
1133     GateRef objectRegion = ObjectAddressToRange(obj);
1134     GateRef valueRegion = ObjectAddressToRange(value);
1135     GateRef slotAddr = PtrAdd(TaggedCastToIntPtr(obj), offset);
1136     GateRef objectNotInYoung = BoolNot(InYoungGeneration(objectRegion));
1137     GateRef valueRegionInYoung = InYoungGeneration(valueRegion);
1138     Branch(BoolAnd(objectNotInYoung, valueRegionInYoung), &isVailedIndex, &notValidIndex);
1139     Bind(&isVailedIndex);
1140     {
1141         GateRef loadOffset = IntPtr(Region::PackedData::GetOldToNewSetOffset(env_->Is32Bit()));
1142         auto oldToNewSet = Load(VariableType::NATIVE_POINTER(), objectRegion, loadOffset);
1143         Label isNullPtr(env);
1144         Label notNullPtr(env);
1145         Branch(IntPtrEuqal(oldToNewSet, IntPtr(0)), &isNullPtr, &notNullPtr);
1146         Bind(&notNullPtr);
1147         {
1148             // (slotAddr - this) >> TAGGED_TYPE_SIZE_LOG
1149             GateRef bitOffsetPtr = IntPtrLSR(PtrSub(slotAddr, objectRegion), IntPtr(TAGGED_TYPE_SIZE_LOG));
1150             GateRef bitOffset = TruncPtrToInt32(bitOffsetPtr);
1151             GateRef bitPerWordLog2 = Int32(GCBitset::BIT_PER_WORD_LOG2);
1152             GateRef bytePerWord = Int32(GCBitset::BYTE_PER_WORD);
1153             // bitOffset >> BIT_PER_WORD_LOG2
1154             GateRef index = Int32LSR(bitOffset, bitPerWordLog2);
1155             GateRef byteIndex = Int32Mul(index, bytePerWord);
1156             // bitset_[index] |= mask;
1157             GateRef bitsetData = PtrAdd(oldToNewSet, IntPtr(RememberedSet::GCBITSET_DATA_OFFSET));
1158             GateRef oldsetValue = Load(VariableType::INT32(), bitsetData, byteIndex);
1159             GateRef newmapValue = Int32Or(oldsetValue, GetBitMask(bitOffset));
1160 
1161             Store(VariableType::INT32(), glue, bitsetData, byteIndex, newmapValue);
1162             Jump(&notValidIndex);
1163         }
1164         Bind(&isNullPtr);
1165         {
1166             CallNGCRuntime(glue, RTSTUB_ID(InsertOldToNewRSet), { glue, obj, offset });
1167             Jump(&notValidIndex);
1168         }
1169     }
1170     Bind(&notValidIndex);
1171     {
1172         Label marking(env);
1173         bool isArch32 = GetEnvironment()->Is32Bit();
1174         GateRef stateBitFieldAddr = Int64Add(glue,
1175                                              Int64(JSThread::GlueData::GetStateBitFieldOffset(isArch32)));
1176         GateRef stateBitField = Load(VariableType::INT64(), stateBitFieldAddr, Int64(0));
1177         // mask: 1 << JSThread::CONCURRENT_MARKING_BITFIELD_NUM - 1
1178         GateRef markingBitMask = Int64Sub(
1179             Int64LSL(Int64(1), Int64(JSThread::CONCURRENT_MARKING_BITFIELD_NUM)), Int64(1));
1180         GateRef state = Int64And(stateBitField, markingBitMask);
1181         Branch(Int64Equal(state, Int64(static_cast<int64_t>(MarkStatus::READY_TO_MARK))), &exit, &marking);
1182 
1183         Bind(&marking);
1184         CallNGCRuntime(
1185             glue,
1186             RTSTUB_ID(MarkingBarrier), { glue, obj, offset, value });
1187         Jump(&exit);
1188     }
1189     Bind(&exit);
1190     env->SubCfgExit();
1191 }
1192 
TaggedIsBigInt(GateRef obj)1193 GateRef StubBuilder::TaggedIsBigInt(GateRef obj)
1194 {
1195     auto env = GetEnvironment();
1196     Label entry(env);
1197     env->SubCfgEntry(&entry);
1198     Label exit(env);
1199     Label isHeapObject(env);
1200     DEFVARIABLE(result, VariableType::BOOL(), False());
1201     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
1202     Bind(&isHeapObject);
1203     {
1204         result = Int32Equal(GetObjectType(LoadHClass(obj)),
1205                             Int32(static_cast<int32_t>(JSType::BIGINT)));
1206         Jump(&exit);
1207     }
1208     Bind(&exit);
1209     auto ret = *result;
1210     env->SubCfgExit();
1211     return ret;
1212 }
1213 
TaggedIsPropertyBox(GateRef obj)1214 GateRef StubBuilder::TaggedIsPropertyBox(GateRef obj)
1215 {
1216     auto env = GetEnvironment();
1217     Label entry(env);
1218     env->SubCfgEntry(&entry);
1219     Label exit(env);
1220     Label isHeapObject(env);
1221     DEFVARIABLE(result, VariableType::BOOL(), False());
1222     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
1223     Bind(&isHeapObject);
1224     {
1225         GateRef type = GetObjectType(LoadHClass(obj));
1226         result = Int32Equal(type, Int32(static_cast<int32_t>(JSType::PROPERTY_BOX)));
1227         Jump(&exit);
1228     }
1229     Bind(&exit);
1230     auto ret = *result;
1231     env->SubCfgExit();
1232     return ret;
1233 }
1234 
TaggedIsAccessor(GateRef x)1235 GateRef StubBuilder::TaggedIsAccessor(GateRef x)
1236 {
1237     auto env = GetEnvironment();
1238     Label entry(env);
1239     env->SubCfgEntry(&entry);
1240     Label exit(env);
1241     Label isHeapObject(env);
1242     DEFVARIABLE(result, VariableType::BOOL(), False());
1243     Branch(TaggedIsHeapObject(x), &isHeapObject, &exit);
1244     Bind(&isHeapObject);
1245     {
1246         GateRef type = GetObjectType(LoadHClass(x));
1247         result = BoolOr(Int32Equal(type, Int32(static_cast<int32_t>(JSType::ACCESSOR_DATA))),
1248                         Int32Equal(type, Int32(static_cast<int32_t>(JSType::INTERNAL_ACCESSOR))));
1249         Jump(&exit);
1250     }
1251     Bind(&exit);
1252     auto ret = *result;
1253     env->SubCfgExit();
1254     return ret;
1255 }
1256 
IsUtf16String(GateRef string)1257 GateRef StubBuilder::IsUtf16String(GateRef string)
1258 {
1259     // compressedStringsEnabled fixed to true constant
1260     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1261     return Int32Equal(
1262         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
1263         Int32(EcmaString::STRING_UNCOMPRESSED));
1264 }
1265 
IsUtf8String(GateRef string)1266 GateRef StubBuilder::IsUtf8String(GateRef string)
1267 {
1268     // compressedStringsEnabled fixed to true constant
1269     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1270     return Int32Equal(
1271         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
1272         Int32(EcmaString::STRING_COMPRESSED));
1273 }
1274 
IsInternalString(GateRef string)1275 GateRef StubBuilder::IsInternalString(GateRef string)
1276 {
1277     // compressedStringsEnabled fixed to true constant
1278     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1279     return Int32NotEqual(
1280         Int32And(len, Int32(EcmaString::STRING_INTERN_BIT)),
1281         Int32(0));
1282 }
1283 
IsDigit(GateRef ch)1284 GateRef StubBuilder::IsDigit(GateRef ch)
1285 {
1286     return BoolAnd(Int32LessThanOrEqual(ch, Int32('9')),
1287         Int32GreaterThanOrEqual(ch, Int32('0')));
1288 }
1289 
StringToElementIndex(GateRef glue,GateRef string)1290 GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string)
1291 {
1292     auto env = GetEnvironment();
1293     Label entry(env);
1294     env->SubCfgEntry(&entry);
1295     Label exit(env);
1296     DEFVARIABLE(result, VariableType::INT64(), Int64(-1));
1297     Label greatThanZero(env);
1298     Label inRange(env);
1299     auto len = GetLengthFromString(string);
1300     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
1301     Bind(&greatThanZero);
1302     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
1303     Bind(&inRange);
1304     {
1305         Label isUtf8(env);
1306         GateRef isUtf16String = IsUtf16String(string);
1307         Branch(isUtf16String, &exit, &isUtf8);
1308         Bind(&isUtf8);
1309         {
1310             GateRef dataUtf8 = GetNormalStringData(FlattenString(glue, string));
1311             DEFVARIABLE(c, VariableType::INT32(), Int32(0));
1312             c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf8));
1313             Label isDigitZero(env);
1314             Label notDigitZero(env);
1315             Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
1316             Bind(&isDigitZero);
1317             {
1318                 Label lengthIsOne(env);
1319                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
1320                 Bind(&lengthIsOne);
1321                 {
1322                     result = Int64(0);
1323                     Jump(&exit);
1324                 }
1325             }
1326             Bind(&notDigitZero);
1327             {
1328                 Label isDigit(env);
1329                 DEFVARIABLE(i, VariableType::INT32(), Int32(1));
1330                 DEFVARIABLE(n, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(*c), Int64('0')));
1331                 Branch(IsDigit(*c), &isDigit, &exit);
1332                 Label loopHead(env);
1333                 Label loopEnd(env);
1334                 Label afterLoop(env);
1335                 Bind(&isDigit);
1336                 Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
1337                 LoopBegin(&loopHead);
1338                 {
1339                     c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf8, ZExtInt32ToPtr(*i)));
1340                     Label isDigit2(env);
1341                     Label notDigit2(env);
1342                     Branch(IsDigit(*c), &isDigit2, &notDigit2);
1343                     Bind(&isDigit2);
1344                     {
1345                         // 10 means the base of digit is 10.
1346                         n = Int64Add(Int64Mul(*n, Int64(10)), Int64Sub(ZExtInt32ToInt64(*c), Int64('0')));
1347                         i = Int32Add(*i, Int32(1));
1348                         Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
1349                     }
1350                     Bind(&notDigit2);
1351                     Jump(&exit);
1352                 }
1353                 Bind(&loopEnd);
1354                 LoopEnd(&loopHead);
1355                 Bind(&afterLoop);
1356                 {
1357                     Label lessThanMaxIndex(env);
1358                     Branch(Int64LessThan(*n, Int64(JSObject::MAX_ELEMENT_INDEX)),
1359                            &lessThanMaxIndex, &exit);
1360                     Bind(&lessThanMaxIndex);
1361                     {
1362                         result = *n;
1363                         Jump(&exit);
1364                     }
1365                 }
1366             }
1367         }
1368     }
1369     Bind(&exit);
1370     auto ret = *result;
1371     env->SubCfgExit();
1372     return ret;
1373 }
1374 
TryToElementsIndex(GateRef glue,GateRef key)1375 GateRef StubBuilder::TryToElementsIndex(GateRef glue, GateRef key)
1376 {
1377     auto env = GetEnvironment();
1378     Label entry(env);
1379     env->SubCfgEntry(&entry);
1380     Label exit(env);
1381     Label isKeyInt(env);
1382     Label notKeyInt(env);
1383 
1384     DEFVARIABLE(resultKey, VariableType::INT64(), Int64(-1));
1385     Branch(TaggedIsInt(key), &isKeyInt, &notKeyInt);
1386     Bind(&isKeyInt);
1387     {
1388         resultKey = GetInt64OfTInt(key);
1389         Jump(&exit);
1390     }
1391     Bind(&notKeyInt);
1392     {
1393         Label isString(env);
1394         Label notString(env);
1395         Branch(TaggedIsString(key), &isString, &notString);
1396         Bind(&isString);
1397         {
1398             resultKey = StringToElementIndex(glue, key);
1399             Jump(&exit);
1400         }
1401         Bind(&notString);
1402         {
1403             Label isDouble(env);
1404             Branch(TaggedIsDouble(key), &isDouble, &exit);
1405             Bind(&isDouble);
1406             {
1407                 GateRef number = GetDoubleOfTDouble(key);
1408                 GateRef integer = ChangeFloat64ToInt32(number);
1409                 Label isEqual(env);
1410                 Branch(DoubleEqual(number, ChangeInt32ToFloat64(integer)), &isEqual, &exit);
1411                 Bind(&isEqual);
1412                 {
1413                     resultKey = SExtInt32ToInt64(integer);
1414                     Jump(&exit);
1415                 }
1416             }
1417         }
1418     }
1419     Bind(&exit);
1420     auto ret = *resultKey;
1421     env->SubCfgExit();
1422     return ret;
1423 }
1424 
LdGlobalRecord(GateRef glue,GateRef key)1425 GateRef StubBuilder::LdGlobalRecord(GateRef glue, GateRef key)
1426 {
1427     auto env = GetEnvironment();
1428     Label entry(env);
1429     env->SubCfgEntry(&entry);
1430     Label exit(env);
1431 
1432     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1433     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1434     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1435     GateRef globalRecord = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::GLOBAL_RECORD);
1436     GateRef recordEntry = FindEntryFromNameDictionary(glue, globalRecord, key);
1437     Label foundInGlobalRecord(env);
1438     Branch(Int32NotEqual(recordEntry, Int32(-1)), &foundInGlobalRecord, &exit);
1439     Bind(&foundInGlobalRecord);
1440     {
1441         result = GetBoxFromGlobalDictionary(globalRecord, recordEntry);
1442         Jump(&exit);
1443     }
1444     Bind(&exit);
1445     auto ret = *result;
1446     env->SubCfgExit();
1447     return ret;
1448 }
1449 
LoadFromField(GateRef receiver,GateRef handlerInfo)1450 GateRef StubBuilder::LoadFromField(GateRef receiver, GateRef handlerInfo)
1451 {
1452     auto env = GetEnvironment();
1453     Label entry(env);
1454     env->SubCfgEntry(&entry);
1455     Label exit(env);
1456     Label handlerInfoIsInlinedProps(env);
1457     Label handlerInfoNotInlinedProps(env);
1458     Label handlerPost(env);
1459     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1460     GateRef index = HandlerBaseGetOffset(handlerInfo);
1461     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
1462     Bind(&handlerInfoIsInlinedProps);
1463     {
1464         result = Load(VariableType::JS_ANY(), receiver, PtrMul(ZExtInt32ToPtr(index),
1465             IntPtr(JSTaggedValue::TaggedTypeSize())));
1466         Jump(&handlerPost);
1467     }
1468     Bind(&handlerInfoNotInlinedProps);
1469     {
1470         result = GetValueFromTaggedArray(GetPropertiesArray(receiver), index);
1471         Jump(&handlerPost);
1472     }
1473     Bind(&handlerPost);
1474     {
1475         Label nonDoubleToTagged(env);
1476         Label doubleToTagged(env);
1477         GateRef rep = HandlerBaseGetRep(handlerInfo);
1478         Branch(IsDoubleRepInPropAttr(rep), &doubleToTagged, &nonDoubleToTagged);
1479         Bind(&doubleToTagged);
1480         {
1481             result = TaggedPtrToTaggedDoublePtr(*result);
1482             Jump(&exit);
1483         }
1484         Bind(&nonDoubleToTagged);
1485         {
1486             Label intToTagged(env);
1487             Branch(IsIntRepInPropAttr(rep), &intToTagged, &exit);
1488             Bind(&intToTagged);
1489             {
1490                 result = TaggedPtrToTaggedIntPtr(*result);
1491                 Jump(&exit);
1492             }
1493         }
1494     }
1495     Bind(&exit);
1496     auto ret = *result;
1497     env->SubCfgExit();
1498     return ret;
1499 }
1500 
LoadGlobal(GateRef cell)1501 GateRef StubBuilder::LoadGlobal(GateRef cell)
1502 {
1503     auto env = GetEnvironment();
1504     Label entry(env);
1505     env->SubCfgEntry(&entry);
1506     Label exit(env);
1507     Label cellIsInvalid(env);
1508     Label cellNotInvalid(env);
1509     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1510     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
1511     Bind(&cellIsInvalid);
1512     {
1513         Jump(&exit);
1514     }
1515     Bind(&cellNotInvalid);
1516     {
1517         result = GetValueFromPropertyBox(cell);
1518         Jump(&exit);
1519     }
1520     Bind(&exit);
1521     auto ret = *result;
1522     env->SubCfgExit();
1523     return ret;
1524 }
1525 
CheckPolyHClass(GateRef cachedValue,GateRef hclass)1526 GateRef StubBuilder::CheckPolyHClass(GateRef cachedValue, GateRef hclass)
1527 {
1528     auto env = GetEnvironment();
1529     Label entry(env);
1530     env->SubCfgEntry(&entry);
1531     Label exit(env);
1532     Label loopHead(env);
1533     Label loopEnd(env);
1534     Label iLessLength(env);
1535     Label hasHclass(env);
1536     Label cachedValueNotWeak(env);
1537     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1538     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1539     Branch(TaggedIsWeak(cachedValue), &exit, &cachedValueNotWeak);
1540     Bind(&cachedValueNotWeak);
1541     {
1542         GateRef length = GetLengthOfTaggedArray(cachedValue);
1543         Jump(&loopHead);
1544         LoopBegin(&loopHead);
1545         {
1546             Branch(Int32UnsignedLessThan(*i, length), &iLessLength, &exit);
1547             Bind(&iLessLength);
1548             {
1549                 GateRef element = GetValueFromTaggedArray(cachedValue, *i);
1550                 Branch(Equal(LoadObjectFromWeakRef(element), hclass), &hasHclass, &loopEnd);
1551                 Bind(&hasHclass);
1552                 result = GetValueFromTaggedArray(cachedValue,
1553                                                  Int32Add(*i, Int32(1)));
1554                 Jump(&exit);
1555             }
1556             Bind(&loopEnd);
1557             i = Int32Add(*i, Int32(2));  // 2 means one ic, two slot
1558             LoopEnd(&loopHead);
1559         }
1560     }
1561     Bind(&exit);
1562     auto ret = *result;
1563     env->SubCfgExit();
1564     return ret;
1565 }
1566 
LoadICWithHandler(GateRef glue,GateRef receiver,GateRef argHolder,GateRef argHandler,ProfileOperation callback)1567 GateRef StubBuilder::LoadICWithHandler(
1568     GateRef glue, GateRef receiver, GateRef argHolder, GateRef argHandler, ProfileOperation callback)
1569 {
1570     auto env = GetEnvironment();
1571     Label entry(env);
1572     env->SubCfgEntry(&entry);
1573     Label exit(env);
1574     Label handlerIsInt(env);
1575     Label handlerNotInt(env);
1576     Label handlerInfoIsField(env);
1577     Label handlerInfoNotField(env);
1578     Label handlerInfoIsNonExist(env);
1579     Label handlerInfoNotNonExist(env);
1580     Label handlerIsPrototypeHandler(env);
1581     Label handlerNotPrototypeHandler(env);
1582     Label cellHasChanged(env);
1583     Label loopHead(env);
1584     Label loopEnd(env);
1585     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1586     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
1587     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
1588 
1589     Jump(&loopHead);
1590     LoopBegin(&loopHead);
1591     {
1592         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
1593         Bind(&handlerIsInt);
1594         {
1595             GateRef handlerInfo = GetInt32OfTInt(*handler);
1596             Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
1597             Bind(&handlerInfoIsField);
1598             {
1599                 result = LoadFromField(*holder, handlerInfo);
1600                 Jump(&exit);
1601             }
1602             Bind(&handlerInfoNotField);
1603             {
1604                 Branch(IsNonExist(handlerInfo), &handlerInfoIsNonExist, &handlerInfoNotNonExist);
1605                 Bind(&handlerInfoIsNonExist);
1606                 Jump(&exit);
1607                 Bind(&handlerInfoNotNonExist);
1608                 GateRef accessor = LoadFromField(*holder, handlerInfo);
1609                 result = CallGetterHelper(glue, receiver, *holder, accessor, callback);
1610                 Jump(&exit);
1611             }
1612         }
1613         Bind(&handlerNotInt);
1614         Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
1615         Bind(&handlerIsPrototypeHandler);
1616         {
1617             GateRef cellValue = GetProtoCell(*handler);
1618             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1619             Bind(&cellHasChanged);
1620             {
1621                 result = Hole();
1622                 Jump(&exit);
1623             }
1624             Bind(&loopEnd);
1625             holder = GetPrototypeHandlerHolder(*handler);
1626             handler = GetPrototypeHandlerHandlerInfo(*handler);
1627             LoopEnd(&loopHead);
1628         }
1629     }
1630     Bind(&handlerNotPrototypeHandler);
1631     result = LoadGlobal(*handler);
1632     Jump(&exit);
1633 
1634     Bind(&exit);
1635     auto ret = *result;
1636     env->SubCfgExit();
1637     return ret;
1638 }
1639 
LoadElement(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback)1640 GateRef StubBuilder::LoadElement(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
1641 {
1642     auto env = GetEnvironment();
1643     Label entry(env);
1644     env->SubCfgEntry(&entry);
1645     Label exit(env);
1646     Label indexLessZero(env);
1647     Label indexNotLessZero(env);
1648     Label lengthLessIndex(env);
1649     Label lengthNotLessIndex(env);
1650     Label greaterThanInt32Max(env);
1651     Label notGreaterThanInt32Max(env);
1652     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1653     GateRef index64 = TryToElementsIndex(glue, key);
1654     Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
1655     Bind(&greaterThanInt32Max);
1656     {
1657         Jump(&exit);
1658     }
1659     Bind(&notGreaterThanInt32Max);
1660     GateRef index = TruncInt64ToInt32(index64);
1661     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1662     Bind(&indexLessZero);
1663     {
1664         Jump(&exit);
1665     }
1666     Bind(&indexNotLessZero);
1667     {
1668         GateRef elements = GetElementsArray(receiver);
1669         Branch(Int32LessThanOrEqual(GetLengthOfTaggedArray(elements), index), &lengthLessIndex, &lengthNotLessIndex);
1670         Bind(&lengthLessIndex);
1671         Jump(&exit);
1672         Bind(&lengthNotLessIndex);
1673         result = GetValueFromTaggedArray(elements, index);
1674         callback.ProfileObjLayoutByLoad(receiver);
1675         Jump(&exit);
1676     }
1677     Bind(&exit);
1678     auto ret = *result;
1679     env->SubCfgExit();
1680     return ret;
1681 }
1682 
ICStoreElement(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef handler,ProfileOperation callback)1683 GateRef StubBuilder::ICStoreElement(
1684     GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef handler, ProfileOperation callback)
1685 {
1686     auto env = GetEnvironment();
1687     Label entry(env);
1688     env->SubCfgEntry(&entry);
1689     Label exit(env);
1690     Label indexLessZero(env);
1691     Label indexNotLessZero(env);
1692     Label handerInfoIsJSArray(env);
1693     Label handerInfoNotJSArray(env);
1694     Label isJsCOWArray(env);
1695     Label isNotJsCOWArray(env);
1696     Label setElementsLength(env);
1697     Label indexGreaterLength(env);
1698     Label indexGreaterCapacity(env);
1699     Label callRuntime(env);
1700     Label storeElement(env);
1701     Label handlerIsInt(env);
1702     Label handlerNotInt(env);
1703     Label cellHasChanged(env);
1704     Label cellHasNotChanged(env);
1705     Label loopHead(env);
1706     Label loopEnd(env);
1707     Label greaterThanInt32Max(env);
1708     Label notGreaterThanInt32Max(env);
1709     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1710     DEFVARIABLE(varHandler, VariableType::JS_ANY(), handler);
1711     GateRef index64 = TryToElementsIndex(glue, key);
1712     Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
1713     Bind(&greaterThanInt32Max);
1714     {
1715         Jump(&exit);
1716     }
1717     Bind(&notGreaterThanInt32Max);
1718     GateRef index = TruncInt64ToInt32(index64);
1719     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1720     Bind(&indexLessZero);
1721     {
1722         Jump(&exit);
1723     }
1724     Bind(&indexNotLessZero);
1725     {
1726         Jump(&loopHead);
1727         LoopBegin(&loopHead);
1728         Branch(TaggedIsInt(*varHandler), &handlerIsInt, &handlerNotInt);
1729         Bind(&handlerIsInt);
1730         {
1731             GateRef handlerInfo = GetInt32OfTInt(*varHandler);
1732             Branch(HandlerBaseIsJSArray(handlerInfo), &handerInfoIsJSArray, &handerInfoNotJSArray);
1733             Bind(&handerInfoIsJSArray);
1734             {
1735                 Branch(IsJsCOWArray(receiver), &isJsCOWArray, &isNotJsCOWArray);
1736                 Bind(&isJsCOWArray);
1737                 {
1738                     CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {receiver});
1739                     Jump(&setElementsLength);
1740                 }
1741                 Bind(&isNotJsCOWArray);
1742                 {
1743                     Jump(&setElementsLength);
1744                 }
1745                 Bind(&setElementsLength);
1746                 {
1747                     GateRef oldLength = GetArrayLength(receiver);
1748                     Branch(Int32GreaterThanOrEqual(index, oldLength), &indexGreaterLength, &handerInfoNotJSArray);
1749                     Bind(&indexGreaterLength);
1750                     Store(VariableType::INT32(), glue, receiver,
1751                         IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET),
1752                         Int32Add(index, Int32(1)));
1753                 }
1754                 Jump(&handerInfoNotJSArray);
1755             }
1756             Bind(&handerInfoNotJSArray);
1757             {
1758                 GateRef elements = GetElementsArray(receiver);
1759                 GateRef capacity = GetLengthOfTaggedArray(elements);
1760                 Branch(Int32GreaterThanOrEqual(index, capacity), &callRuntime, &storeElement);
1761                 Bind(&callRuntime);
1762                 {
1763                     result = CallRuntime(glue,
1764                         RTSTUB_ID(TaggedArraySetValue),
1765                         { receiver, value, elements, IntToTaggedInt(index),
1766                           IntToTaggedInt(capacity) });
1767                     Label transition(env);
1768                     Branch(TaggedIsHole(*result), &exit, &transition);
1769                     Bind(&transition);
1770                     {
1771                         Label hole(env);
1772                         Label notHole(env);
1773                         DEFVARIABLE(kind, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::NONE)));
1774                         Branch(Int32GreaterThan(index, capacity), &hole, &notHole);
1775                         Bind(&hole);
1776                         {
1777                             kind = Int32(static_cast<int32_t>(ElementsKind::HOLE));
1778                             Jump(&notHole);
1779                         }
1780                         Bind(&notHole);
1781                         {
1782                             TransitToElementsKind(glue, receiver, value, *kind);
1783                             callback.ProfileObjLayoutByStore(receiver);
1784                             Jump(&exit);
1785                         }
1786                     }
1787                 }
1788                 Bind(&storeElement);
1789                 {
1790                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
1791                     TransitToElementsKind(
1792                         glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
1793                     callback.ProfileObjLayoutByStore(receiver);
1794                     result = Undefined();
1795                     Jump(&exit);
1796                 }
1797             }
1798         }
1799         Bind(&handlerNotInt);
1800         {
1801             GateRef cellValue = GetProtoCell(*varHandler);
1802             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1803             Bind(&cellHasChanged);
1804             {
1805                 Jump(&exit);
1806             }
1807             Bind(&loopEnd);
1808             {
1809                 varHandler = GetPrototypeHandlerHandlerInfo(*varHandler);
1810                 LoopEnd(&loopHead);
1811             }
1812         }
1813     }
1814     Bind(&exit);
1815     auto ret = *result;
1816     env->SubCfgExit();
1817     return ret;
1818 }
1819 
GetArrayLength(GateRef object)1820 GateRef StubBuilder::GetArrayLength(GateRef object)
1821 {
1822     GateRef lengthOffset = IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET);
1823     GateRef result = Load(VariableType::INT32(), object, lengthOffset);
1824     return result;
1825 }
1826 
StoreICWithHandler(GateRef glue,GateRef receiver,GateRef argHolder,GateRef value,GateRef argHandler,ProfileOperation callback)1827 GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder,
1828                                         GateRef value, GateRef argHandler, ProfileOperation callback)
1829 {
1830     auto env = GetEnvironment();
1831     Label entry(env);
1832     env->SubCfgEntry(&entry);
1833     Label exit(env);
1834     Label handlerIsInt(env);
1835     Label handlerNotInt(env);
1836     Label handlerInfoIsField(env);
1837     Label handlerInfoNotField(env);
1838     Label handlerIsTransitionHandler(env);
1839     Label handlerNotTransitionHandler(env);
1840     Label handlerIsTransWithProtoHandler(env);
1841     Label handlerNotTransWithProtoHandler(env);
1842     Label handlerIsPrototypeHandler(env);
1843     Label handlerNotPrototypeHandler(env);
1844     Label handlerIsPropertyBox(env);
1845     Label handlerNotPropertyBox(env);
1846     Label handlerIsStoreTSHandler(env);
1847     Label handlerNotStoreTSHandler(env);
1848     Label aotHandlerInfoIsField(env);
1849     Label aotHandlerInfoNotField(env);
1850     Label cellHasChanged(env);
1851     Label cellNotChanged(env);
1852     Label aotCellNotChanged(env);
1853     Label loopHead(env);
1854     Label loopEnd(env);
1855     Label cellNotNull(env);
1856     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1857     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
1858     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
1859     Jump(&loopHead);
1860     LoopBegin(&loopHead);
1861     {
1862         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
1863         Bind(&handlerIsInt);
1864         {
1865             GateRef handlerInfo = GetInt32OfTInt(*handler);
1866             Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
1867             Bind(&handlerInfoIsField);
1868             {
1869                 result = StoreField(glue, receiver, value, handlerInfo, callback);
1870                 Jump(&exit);
1871             }
1872             Bind(&handlerInfoNotField);
1873             {
1874                 GateRef accessor = LoadFromField(*holder, handlerInfo);
1875                 result = CallSetterHelper(glue, receiver, accessor, value, callback);
1876                 Jump(&exit);
1877             }
1878         }
1879         Bind(&handlerNotInt);
1880         {
1881             Branch(TaggedIsTransitionHandler(*handler), &handlerIsTransitionHandler, &handlerNotTransitionHandler);
1882             Bind(&handlerIsTransitionHandler);
1883             {
1884                 result = StoreWithTransition(glue, receiver, value, *handler, callback);
1885                 Jump(&exit);
1886             }
1887             Bind(&handlerNotTransitionHandler);
1888             {
1889                 Branch(TaggedIsTransWithProtoHandler(*handler), &handlerIsTransWithProtoHandler,
1890                     &handlerNotTransWithProtoHandler);
1891                 Bind(&handlerIsTransWithProtoHandler);
1892                 {
1893                     GateRef cellValue = GetProtoCell(*handler);
1894                     Branch(GetHasChanged(cellValue), &cellHasChanged, &cellNotChanged);
1895                     Bind(&cellNotChanged);
1896                     {
1897                         result = StoreWithTransition(glue, receiver, value, *handler, callback, true);
1898                         Jump(&exit);
1899                     }
1900                 }
1901                 Bind(&handlerNotTransWithProtoHandler);
1902                 {
1903                     Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
1904                     Bind(&handlerNotPrototypeHandler);
1905                     {
1906                         Branch(TaggedIsPropertyBox(*handler), &handlerIsPropertyBox, &handlerNotPropertyBox);
1907                         Bind(&handlerIsPropertyBox);
1908                         StoreGlobal(glue, value, *handler);
1909                         Jump(&exit);
1910                     }
1911                 }
1912             }
1913         }
1914         Bind(&handlerIsPrototypeHandler);
1915         {
1916             GateRef cellValue = GetProtoCell(*handler);
1917             Branch(TaggedIsNull(cellValue), &cellHasChanged, &cellNotNull);
1918             Bind(&cellNotNull);
1919             {
1920                 Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1921             }
1922             Bind(&loopEnd);
1923             {
1924                 holder = GetPrototypeHandlerHolder(*handler);
1925                 handler = GetPrototypeHandlerHandlerInfo(*handler);
1926                 LoopEnd(&loopHead);
1927             }
1928         }
1929         Bind(&handlerNotPropertyBox);
1930         {
1931             Branch(TaggedIsStoreTSHandler(*handler), &handlerIsStoreTSHandler, &handlerNotStoreTSHandler);
1932             Bind(&handlerIsStoreTSHandler);
1933             {
1934                 GateRef cellValue = GetProtoCell(*handler);
1935                 Branch(GetHasChanged(cellValue), &cellHasChanged, &aotCellNotChanged);
1936                 Bind(&aotCellNotChanged);
1937                 {
1938                     holder = GetStoreTSHandlerHolder(*handler);
1939                     handler = GetStoreTSHandlerHandlerInfo(*handler);
1940                     GateRef handlerInfo = GetInt32OfTInt(*handler);
1941                     Branch(IsField(handlerInfo), &aotHandlerInfoIsField, &aotHandlerInfoNotField);
1942                     Bind(&aotHandlerInfoIsField);
1943                     {
1944                         result = StoreField(glue, receiver, value, handlerInfo, callback);
1945                         Jump(&exit);
1946                     }
1947                     Bind(&aotHandlerInfoNotField);
1948                     {
1949                         GateRef accessor = LoadFromField(*holder, handlerInfo);
1950                         result = CallSetterHelper(glue, receiver, accessor, value, callback);
1951                         Jump(&exit);
1952                     }
1953                 }
1954             }
1955             Bind(&handlerNotStoreTSHandler);
1956             Jump(&exit);
1957         }
1958         Bind(&cellHasChanged);
1959         {
1960             result = Hole();
1961             Jump(&exit);
1962         }
1963     }
1964     Bind(&exit);
1965     auto ret = *result;
1966     env->SubCfgExit();
1967     return ret;
1968 }
1969 
StoreField(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback)1970 GateRef StubBuilder::StoreField(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
1971     ProfileOperation callback)
1972 {
1973     auto env = GetEnvironment();
1974     Label entry(env);
1975     env->SubCfgEntry(&entry);
1976     ProfilerStubBuilder(env).UpdatePropAttrIC(glue, receiver, value, handler, callback);
1977     Label exit(env);
1978     Label handlerIsInlinedProperty(env);
1979     Label handlerNotInlinedProperty(env);
1980     GateRef index = HandlerBaseGetOffset(handler);
1981     GateRef rep = HandlerBaseGetRep(handler);
1982     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1983     Label repChange(env);
1984     Branch(HandlerBaseIsInlinedProperty(handler), &handlerIsInlinedProperty, &handlerNotInlinedProperty);
1985     Bind(&handlerIsInlinedProperty);
1986     {
1987         GateRef toOffset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
1988         SetValueWithRep(glue, receiver, toOffset, value, rep, &repChange);
1989         Jump(&exit);
1990     }
1991     Bind(&handlerNotInlinedProperty);
1992     {
1993         GateRef array = GetPropertiesArray(receiver);
1994         SetValueToTaggedArrayWithRep(glue, array, index, value, rep, &repChange);
1995         Jump(&exit);
1996     }
1997     Bind(&repChange);
1998     {
1999         result = Hole();
2000         Jump(&exit);
2001     }
2002 
2003     Bind(&exit);
2004     auto ret = *result;
2005     env->SubCfgExit();
2006     return ret;
2007 }
2008 
StoreWithTransition(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback,bool withPrototype)2009 GateRef StubBuilder::StoreWithTransition(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
2010                                          ProfileOperation callback, bool withPrototype)
2011 {
2012     auto env = GetEnvironment();
2013     Label entry(env);
2014     env->SubCfgEntry(&entry);
2015     Label exit(env);
2016 
2017     Label handlerInfoIsInlinedProps(env);
2018     Label handlerInfoNotInlinedProps(env);
2019     Label indexMoreCapacity(env);
2020     Label indexLessCapacity(env);
2021     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2022     GateRef newHClass;
2023     GateRef handlerInfo;
2024     if (withPrototype) {
2025         newHClass = GetTransWithProtoHClass(handler);
2026         handlerInfo = GetInt32OfTInt(GetTransWithProtoHandlerInfo(handler));
2027     } else {
2028         newHClass = GetTransitionHClass(handler);
2029         handlerInfo = GetInt32OfTInt(GetTransitionHandlerInfo(handler));
2030     }
2031 
2032     StoreHClass(glue, receiver, newHClass);
2033     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
2034     Bind(&handlerInfoNotInlinedProps);
2035     {
2036         ProfilerStubBuilder(env).UpdatePropAttrIC(glue, receiver, value, handlerInfo, callback);
2037         Label repChange(env);
2038         GateRef array = GetPropertiesArray(receiver);
2039         GateRef capacity = GetLengthOfTaggedArray(array);
2040         GateRef index = HandlerBaseGetOffset(handlerInfo);
2041         Branch(Int32GreaterThanOrEqual(index, capacity), &indexMoreCapacity, &indexLessCapacity);
2042         Bind(&indexMoreCapacity);
2043         {
2044             CallRuntime(glue,
2045                         RTSTUB_ID(PropertiesSetValue),
2046                         { receiver, value, array, IntToTaggedInt(capacity),
2047                           IntToTaggedInt(index) });
2048             Jump(&exit);
2049         }
2050         Bind(&indexLessCapacity);
2051         {
2052             GateRef rep = HandlerBaseGetRep(handlerInfo);
2053             GateRef base = PtrAdd(array, IntPtr(TaggedArray::DATA_OFFSET));
2054             GateRef toIndex = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
2055             SetValueWithRep(glue, base, toIndex, value, rep, &repChange);
2056             Jump(&exit);
2057         }
2058         Bind(&repChange);
2059         {
2060             result = Hole();
2061             Jump(&exit);
2062         }
2063     }
2064     Bind(&handlerInfoIsInlinedProps);
2065     {
2066         result = StoreField(glue, receiver, value, handlerInfo, callback);
2067         Jump(&exit);
2068     }
2069     Bind(&exit);
2070     auto ret = *result;
2071     env->SubCfgExit();
2072     return ret;
2073 }
2074 
StoreGlobal(GateRef glue,GateRef value,GateRef cell)2075 GateRef StubBuilder::StoreGlobal(GateRef glue, GateRef value, GateRef cell)
2076 {
2077     auto env = GetEnvironment();
2078     Label entry(env);
2079     env->SubCfgEntry(&entry);
2080     Label exit(env);
2081     Label cellIsInvalid(env);
2082     Label cellNotInvalid(env);
2083     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2084     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
2085     Bind(&cellIsInvalid);
2086     {
2087         Jump(&exit);
2088     }
2089     Bind(&cellNotInvalid);
2090     {
2091         Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value);
2092         result = Undefined();
2093         Jump(&exit);
2094     }
2095     Bind(&exit);
2096     auto ret = *result;
2097     env->SubCfgExit();
2098     return ret;
2099 }
2100 
2101 template<typename DictionaryT>
GetAttributesFromDictionary(GateRef elements,GateRef entry)2102 GateRef StubBuilder::GetAttributesFromDictionary(GateRef elements, GateRef entry)
2103 {
2104     GateRef arrayIndex =
2105     Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2106              Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2107     GateRef attributesIndex =
2108         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_DETAILS_INDEX));
2109     auto attrValue = GetValueFromTaggedArray(elements, attributesIndex);
2110     return GetInt32OfTInt(attrValue);
2111 }
2112 
2113 template<typename DictionaryT>
GetValueFromDictionary(GateRef elements,GateRef entry)2114 GateRef StubBuilder::GetValueFromDictionary(GateRef elements, GateRef entry)
2115 {
2116     GateRef arrayIndex =
2117         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2118                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2119     GateRef valueIndex =
2120         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_VALUE_INDEX));
2121     return GetValueFromTaggedArray(elements, valueIndex);
2122 }
2123 
2124 template<typename DictionaryT>
GetKeyFromDictionary(GateRef elements,GateRef entry)2125 GateRef StubBuilder::GetKeyFromDictionary(GateRef elements, GateRef entry)
2126 {
2127     auto env = GetEnvironment();
2128     Label subentry(env);
2129     env->SubCfgEntry(&subentry);
2130     Label exit(env);
2131     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2132     Label ltZero(env);
2133     Label notLtZero(env);
2134     Label gtLength(env);
2135     Label notGtLength(env);
2136     GateRef dictionaryLength =
2137         Load(VariableType::INT32(), elements, IntPtr(TaggedArray::LENGTH_OFFSET));
2138     GateRef arrayIndex =
2139         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2140                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2141     Branch(Int32LessThan(arrayIndex, Int32(0)), &ltZero, &notLtZero);
2142     Bind(&ltZero);
2143     Jump(&exit);
2144     Bind(&notLtZero);
2145     Branch(Int32GreaterThan(arrayIndex, dictionaryLength), &gtLength, &notGtLength);
2146     Bind(&gtLength);
2147     Jump(&exit);
2148     Bind(&notGtLength);
2149     result = GetValueFromTaggedArray(elements, arrayIndex);
2150     Jump(&exit);
2151     Bind(&exit);
2152     auto ret = *result;
2153     env->SubCfgExit();
2154     return ret;
2155 }
2156 
UpdateValueAndAttributes(GateRef glue,GateRef elements,GateRef index,GateRef value,GateRef attr)2157 inline void StubBuilder::UpdateValueAndAttributes(GateRef glue, GateRef elements, GateRef index,
2158                                                   GateRef value, GateRef attr)
2159 {
2160     GateRef arrayIndex =
2161         Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
2162                  Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
2163     GateRef valueIndex =
2164         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
2165     GateRef attributesIndex =
2166         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_DETAILS_INDEX));
2167     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
2168     GateRef attroffset =
2169         PtrMul(ZExtInt32ToPtr(attributesIndex), IntPtr(JSTaggedValue::TaggedTypeSize()));
2170     GateRef dataOffset = PtrAdd(attroffset, IntPtr(TaggedArray::DATA_OFFSET));
2171     Store(VariableType::INT64(), glue, elements, dataOffset, IntToTaggedInt(attr));
2172 }
2173 
UpdateValueInDict(GateRef glue,GateRef elements,GateRef index,GateRef value)2174 inline void StubBuilder::UpdateValueInDict(GateRef glue, GateRef elements, GateRef index, GateRef value)
2175 {
2176     GateRef arrayIndex = Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
2177         Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
2178     GateRef valueIndex = Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
2179     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
2180 }
2181 
GetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,ProfileOperation callback)2182 GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, ProfileOperation callback)
2183 {
2184     auto env = GetEnvironment();
2185     Label entry(env);
2186     env->SubCfgEntry(&entry);
2187     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2188     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2189     Label exit(env);
2190     Label loopHead(env);
2191     Label loopEnd(env);
2192     Label loopExit(env);
2193     Label afterLoop(env);
2194     Jump(&loopHead);
2195     LoopBegin(&loopHead);
2196     {
2197         GateRef hclass = LoadHClass(*holder);
2198         GateRef jsType = GetObjectType(hclass);
2199         Label isSpecialIndexed(env);
2200         Label notSpecialIndexed(env);
2201         Branch(IsSpecialIndexedObj(jsType), &isSpecialIndexed, &notSpecialIndexed);
2202         Bind(&isSpecialIndexed);
2203         {
2204             // TypeArray
2205             Label isFastTypeArray(env);
2206             Label notFastTypeArray(env);
2207             Label notTypedArrayProto(env);
2208             Branch(Int32Equal(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY))), &exit, &notTypedArrayProto);
2209             Bind(&notTypedArrayProto);
2210             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2211             Bind(&isFastTypeArray);
2212             {
2213                 TypedArrayStubBuilder typedArrayStubBuilder(this);
2214                 result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, *holder, index, jsType);
2215                 Jump(&exit);
2216             }
2217             Bind(&notFastTypeArray);
2218 
2219             Label isSpecialContainer(env);
2220             Label notSpecialContainer(env);
2221             // Add SpecialContainer
2222             Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
2223             Bind(&isSpecialContainer);
2224             {
2225                 result = GetContainerProperty(glue, *holder, index, jsType);
2226                 Jump(&exit);
2227             }
2228             Bind(&notSpecialContainer);
2229             {
2230                 result = Hole();
2231                 Jump(&exit);
2232             }
2233         }
2234         Bind(&notSpecialIndexed);
2235         {
2236             GateRef elements = GetElementsArray(*holder);
2237             Label isDictionaryElement(env);
2238             Label notDictionaryElement(env);
2239             Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2240             Bind(&notDictionaryElement);
2241             {
2242                 Label lessThanLength(env);
2243                 Label notLessThanLength(env);
2244                 Branch(Int32UnsignedLessThan(index, GetLengthOfTaggedArray(elements)),
2245                        &lessThanLength, &notLessThanLength);
2246                 Bind(&lessThanLength);
2247                 {
2248                     Label notHole(env);
2249                     Label isHole(env);
2250                     GateRef value = GetValueFromTaggedArray(elements, index);
2251                     callback.ProfileObjLayoutByLoad(receiver);
2252                     Branch(TaggedIsNotHole(value), &notHole, &isHole);
2253                     Bind(&notHole);
2254                     {
2255                         result = value;
2256                         Jump(&exit);
2257                     }
2258                     Bind(&isHole);
2259                     {
2260                         Jump(&loopExit);
2261                     }
2262                 }
2263                 Bind(&notLessThanLength);
2264                 {
2265                     result = Hole();
2266                     Jump(&exit);
2267                 }
2268             }
2269             Bind(&isDictionaryElement);
2270             {
2271                 GateRef entryA = FindElementFromNumberDictionary(glue, elements, index);
2272                 Label notNegtiveOne(env);
2273                 Label negtiveOne(env);
2274                 Branch(Int32NotEqual(entryA, Int32(-1)), &notNegtiveOne, &negtiveOne);
2275                 Bind(&notNegtiveOne);
2276                 {
2277                     GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, entryA);
2278                     GateRef value = GetValueFromDictionary<NumberDictionary>(elements, entryA);
2279                     Label isAccessor(env);
2280                     Label notAccessor(env);
2281                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2282                     Bind(&isAccessor);
2283                     {
2284                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2285                         Jump(&exit);
2286                     }
2287                     Bind(&notAccessor);
2288                     {
2289                         result = value;
2290                         Jump(&exit);
2291                     }
2292                 }
2293                 Bind(&negtiveOne);
2294                 Jump(&loopExit);
2295             }
2296             Bind(&loopExit);
2297             {
2298                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2299                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2300             }
2301         }
2302         Bind(&loopEnd);
2303         LoopEnd(&loopHead);
2304         Bind(&afterLoop);
2305         {
2306             result = Undefined();
2307             Jump(&exit);
2308         }
2309     }
2310     Bind(&exit);
2311     auto ret = *result;
2312     env->SubCfgExit();
2313     return ret;
2314 }
2315 
GetPropertyByValue(GateRef glue,GateRef receiver,GateRef keyValue,ProfileOperation callback)2316 GateRef StubBuilder::GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue, ProfileOperation callback)
2317 {
2318     auto env = GetEnvironment();
2319     Label entry(env);
2320     env->SubCfgEntry(&entry);
2321     DEFVARIABLE(key, VariableType::JS_ANY(), keyValue);
2322     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2323     Label isNumberOrStringSymbol(env);
2324     Label notNumber(env);
2325     Label isStringOrSymbol(env);
2326     Label notStringOrSymbol(env);
2327     Label exit(env);
2328 
2329     Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, &notNumber);
2330     Bind(&notNumber);
2331     {
2332         Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, &notStringOrSymbol);
2333         Bind(&notStringOrSymbol);
2334         {
2335             result = Hole();
2336             Jump(&exit);
2337         }
2338     }
2339     Bind(&isNumberOrStringSymbol);
2340     {
2341         GateRef index64 = TryToElementsIndex(glue, *key);
2342         Label validIndex(env);
2343         Label notValidIndex(env);
2344         Label greaterThanInt32Max(env);
2345         Label notGreaterThanInt32Max(env);
2346         Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
2347         Bind(&greaterThanInt32Max);
2348         {
2349             Jump(&exit);
2350         }
2351         Bind(&notGreaterThanInt32Max);
2352         GateRef index = TruncInt64ToInt32(index64);
2353         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
2354         Bind(&validIndex);
2355         {
2356             result = GetPropertyByIndex(glue, receiver, index, callback);
2357             Jump(&exit);
2358         }
2359         Bind(&notValidIndex);
2360         {
2361             Label notNumber1(env);
2362             Label getByName(env);
2363             Branch(TaggedIsNumber(*key), &exit, &notNumber1);
2364             Bind(&notNumber1);
2365             {
2366                 Label isString(env);
2367                 Label notString(env);
2368                 Label isInternalString(env);
2369                 Label notIntenalString(env);
2370                 Branch(TaggedIsString(*key), &isString, &notString);
2371                 Bind(&isString);
2372                 {
2373                     Branch(IsInternalString(*key), &isInternalString, &notIntenalString);
2374                     Bind(&isInternalString);
2375                     Jump(&getByName);
2376                     Bind(&notIntenalString);
2377                     {
2378                         key = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *key });
2379                         Jump(&getByName);
2380                     }
2381                 }
2382                 Bind(&notString);
2383                 {
2384                     Jump(&getByName);
2385                 }
2386             }
2387             Bind(&getByName);
2388             {
2389                 result = GetPropertyByName(glue, receiver, *key, callback);
2390                 Jump(&exit);
2391             }
2392         }
2393     }
2394     Bind(&exit);
2395     auto ret = *result;
2396     env->SubCfgExit();
2397     return ret;
2398 }
2399 
GetPropertyByName(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback)2400 GateRef StubBuilder::GetPropertyByName(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
2401 {
2402     auto env = GetEnvironment();
2403     Label entry(env);
2404     env->SubCfgEntry(&entry);
2405     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2406     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2407     Label exit(env);
2408     Label loopHead(env);
2409     Label loopEnd(env);
2410     Label loopExit(env);
2411     Label afterLoop(env);
2412     Jump(&loopHead);
2413     LoopBegin(&loopHead);
2414     {
2415         GateRef hclass = LoadHClass(*holder);
2416         GateRef jsType = GetObjectType(hclass);
2417         Label isSIndexObj(env);
2418         Label notSIndexObj(env);
2419         Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2420         Bind(&isSIndexObj);
2421         {
2422             // TypeArray
2423             Label isFastTypeArray(env);
2424             Label notFastTypeArray(env);
2425             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2426             Bind(&isFastTypeArray);
2427             {
2428                 result = GetTypeArrayPropertyByName(glue, receiver, *holder, key, jsType);
2429                 Label isNull(env);
2430                 Label notNull(env);
2431                 Branch(TaggedIsNull(*result), &isNull, &notNull);
2432                 Bind(&isNull);
2433                 {
2434                     result = Hole();
2435                     Jump(&exit);
2436                 }
2437                 Bind(&notNull);
2438                 Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2439             }
2440             Bind(&notFastTypeArray);
2441             {
2442                 result = Hole();
2443                 Jump(&exit);
2444             }
2445         }
2446         Bind(&notSIndexObj);
2447         {
2448             Label isDicMode(env);
2449             Label notDicMode(env);
2450             Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2451             Bind(&notDicMode);
2452             {
2453                 GateRef layOutInfo = GetLayoutFromHClass(hclass);
2454                 GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2455                 // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2456                 GateRef entryA = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2457                 Label hasEntry(env);
2458                 Label noEntry(env);
2459                 // if branch condition : entry != -1
2460                 Branch(Int32NotEqual(entryA, Int32(-1)), &hasEntry, &noEntry);
2461                 Bind(&hasEntry);
2462                 {
2463                     // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2464                     GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entryA);
2465                     GateRef attr = GetInt32OfTInt(propAttr);
2466                     GateRef value = JSObjectGetProperty(*holder, hclass, attr);
2467                     Label isPropertyBox(env);
2468                     Label notPropertyBox(env);
2469                     Branch(TaggedIsPropertyBox(value), &isPropertyBox, &notPropertyBox);
2470                     Bind(&isPropertyBox);
2471                     {
2472                         result = GetValueFromPropertyBox(value);
2473                         Jump(&exit);
2474                     }
2475                     Bind(&notPropertyBox);
2476                     Label isAccessor(env);
2477                     Label notAccessor(env);
2478                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2479                     Bind(&isAccessor);
2480                     {
2481                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2482                         Jump(&exit);
2483                     }
2484                     Bind(&notAccessor);
2485                     {
2486                         Label notHole(env);
2487                         Branch(TaggedIsHole(value), &noEntry, &notHole);
2488                         Bind(&notHole);
2489                         {
2490                             result = value;
2491                             Jump(&exit);
2492                         }
2493                     }
2494                 }
2495                 Bind(&noEntry);
2496                 {
2497                     Jump(&loopExit);
2498                 }
2499             }
2500             Bind(&isDicMode);
2501             {
2502                 GateRef array = GetPropertiesArray(*holder);
2503                 // int entry = dict->FindEntry(key)
2504                 GateRef entryB = FindEntryFromNameDictionary(glue, array, key);
2505                 Label notNegtiveOne(env);
2506                 Label negtiveOne(env);
2507                 // if branch condition : entry != -1
2508                 Branch(Int32NotEqual(entryB, Int32(-1)), &notNegtiveOne, &negtiveOne);
2509                 Bind(&notNegtiveOne);
2510                 {
2511                     // auto value = dict->GetValue(entry)
2512                     GateRef attr = GetAttributesFromDictionary<NameDictionary>(array, entryB);
2513                     // auto attr = dict->GetAttributes(entry)
2514                     GateRef value = GetValueFromDictionary<NameDictionary>(array, entryB);
2515                     Label isAccessor1(env);
2516                     Label notAccessor1(env);
2517                     Branch(IsAccessor(attr), &isAccessor1, &notAccessor1);
2518                     Bind(&isAccessor1);
2519                     {
2520                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2521                         Jump(&exit);
2522                     }
2523                     Bind(&notAccessor1);
2524                     {
2525                         result = value;
2526                         Jump(&exit);
2527                     }
2528                 }
2529                 Bind(&negtiveOne);
2530                 Jump(&loopExit);
2531             }
2532             Bind(&loopExit);
2533             {
2534                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2535                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2536             }
2537         }
2538         Bind(&loopEnd);
2539         LoopEnd(&loopHead);
2540         Bind(&afterLoop);
2541         {
2542             result = Undefined();
2543             Jump(&exit);
2544         }
2545     }
2546     Bind(&exit);
2547     auto ret = *result;
2548     env->SubCfgExit();
2549     return ret;
2550 }
2551 
CopyAllHClass(GateRef glue,GateRef dstHClass,GateRef srcHClass)2552 void StubBuilder::CopyAllHClass(GateRef glue, GateRef dstHClass, GateRef srcHClass)
2553 {
2554     auto env = GetEnvironment();
2555     Label entry(env);
2556     env->SubCfgEntry(&entry);
2557     auto proto = GetPrototypeFromHClass(srcHClass);
2558     SetPrototypeToHClass(VariableType::JS_POINTER(), glue, dstHClass, proto);
2559     SetBitFieldToHClass(glue, dstHClass, GetBitFieldFromHClass(srcHClass));
2560     SetIsAllTaggedProp(glue, dstHClass, GetIsAllTaggedPropFromHClass(srcHClass));
2561     SetNumberOfPropsToHClass(glue, dstHClass, GetNumberOfPropsFromHClass(srcHClass));
2562     SetTransitionsToHClass(VariableType::INT64(), glue, dstHClass, Undefined());
2563     SetProtoChangeDetailsToHClass(VariableType::INT64(), glue, dstHClass, Null());
2564     SetEnumCacheToHClass(VariableType::INT64(), glue, dstHClass, Null());
2565     SetLayoutToHClass(VariableType::JS_POINTER(), glue, dstHClass, GetLayoutFromHClass(srcHClass));
2566     env->SubCfgExit();
2567     return;
2568 }
2569 
TransitionForRepChange(GateRef glue,GateRef receiver,GateRef key,GateRef attr)2570 void StubBuilder::TransitionForRepChange(GateRef glue, GateRef receiver, GateRef key, GateRef attr)
2571 {
2572     auto env = GetEnvironment();
2573     Label subEntry(env);
2574     env->SubCfgEntry(&subEntry);
2575     GateRef hclass = LoadHClass(receiver);
2576     GateRef type = GetObjectType(hclass);
2577     GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass),
2578                             Int32(JSTaggedValue::TaggedTypeSize()));
2579     GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass);
2580     GateRef newJshclass = CallRuntime(glue, RTSTUB_ID(NewEcmaHClass),
2581         { IntToTaggedInt(size), IntToTaggedInt(type),
2582           IntToTaggedInt(inlineProps) });
2583     CopyAllHClass(glue, newJshclass, hclass);
2584     CallRuntime(glue, RTSTUB_ID(CopyAndUpdateObjLayout),
2585                 { hclass, newJshclass, key, IntToTaggedInt(attr) });
2586 #if ECMASCRIPT_ENABLE_IC
2587     NotifyHClassChanged(glue, hclass, newJshclass);
2588 #endif
2589     StoreHClass(glue, receiver, newJshclass);
2590     env->SubCfgExit();
2591 }
2592 
TransitToElementsKind(GateRef glue,GateRef receiver,GateRef value,GateRef kind)2593 void StubBuilder::TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind)
2594 {
2595     auto env = GetEnvironment();
2596     Label subEntry(env);
2597     env->SubCfgEntry(&subEntry);
2598     Label exit(env);
2599 
2600     GateRef hclass = LoadHClass(receiver);
2601     GateRef elementsKind = GetElementsKindFromHClass(hclass);
2602 
2603     Label isNoneDefault(env);
2604     Branch(Int32Equal(elementsKind, Int32(static_cast<int32_t>(ElementsKind::GENERIC))), &exit, &isNoneDefault);
2605     Bind(&isNoneDefault);
2606     {
2607         GateRef newKind = TaggedToElementKind(value);
2608         newKind = Int32Or(newKind, kind);
2609         newKind = Int32Or(newKind, elementsKind);
2610         Label change(env);
2611         Branch(Int32Equal(elementsKind, newKind), &exit, &change);
2612         Bind(&change);
2613         {
2614             CallRuntime(glue, RTSTUB_ID(UpdateHClassForElementsKind), { receiver, newKind });
2615             Jump(&exit);
2616         }
2617     }
2618 
2619     Bind(&exit);
2620     env->SubCfgExit();
2621 }
2622 
FindTransitions(GateRef glue,GateRef receiver,GateRef hclass,GateRef key,GateRef metaData)2623 GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, GateRef key, GateRef metaData)
2624 {
2625     auto env = GetEnvironment();
2626     Label entry(env);
2627     env->SubCfgEntry(&entry);
2628     Label exit(env);
2629     GateRef transitionOffset = IntPtr(JSHClass::TRANSTIONS_OFFSET);
2630     GateRef transition = Load(VariableType::JS_POINTER(), hclass, transitionOffset);
2631     DEFVARIABLE(result, VariableType::JS_ANY(), transition);
2632 
2633     Label notUndefined(env);
2634     Branch(Equal(transition, Undefined()), &exit, &notUndefined);
2635     Bind(&notUndefined);
2636     {
2637         Label isWeak(env);
2638         Label notWeak(env);
2639         Branch(TaggedIsWeak(transition), &isWeak, &notWeak);
2640         Bind(&isWeak);
2641         {
2642             GateRef transitionHClass = LoadObjectFromWeakRef(transition);
2643             GateRef propNums = GetNumberOfPropsFromHClass(transitionHClass);
2644             GateRef last = Int32Sub(propNums, Int32(1));
2645             GateRef layoutInfo = GetLayoutFromHClass(transitionHClass);
2646             GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last);
2647             GateRef cachedAttr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(layoutInfo, last));
2648             GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr);
2649             Label keyMatch(env);
2650             Label isMatch(env);
2651             Label notMatch(env);
2652             Branch(Equal(cachedKey, key), &keyMatch, &notMatch);
2653             Bind(&keyMatch);
2654             {
2655                 Branch(Int32Equal(metaData, cachedMetaData), &isMatch, &notMatch);
2656                 Bind(&isMatch);
2657                 {
2658 #if ECMASCRIPT_ENABLE_IC
2659                     NotifyHClassChanged(glue, hclass, transitionHClass);
2660 #endif
2661                     StoreHClass(glue, receiver, transitionHClass);
2662                     Jump(&exit);
2663                 }
2664             }
2665             Bind(&notMatch);
2666             {
2667                 result = Undefined();
2668                 Jump(&exit);
2669             }
2670         }
2671         Bind(&notWeak);
2672         {
2673             // need to find from dictionary
2674             GateRef entryA = FindEntryFromTransitionDictionary(glue, transition, key, metaData);
2675             Label isFound(env);
2676             Label notFound(env);
2677             Branch(Int32NotEqual(entryA, Int32(-1)), &isFound, &notFound);
2678             Bind(&isFound);
2679             auto value = GetValueFromDictionary<TransitionsDictionary>(transition, entryA);
2680             Label valueUndefined(env);
2681             Label valueNotUndefined(env);
2682             Branch(Int64NotEqual(value, Undefined()), &valueNotUndefined,
2683                 &valueUndefined);
2684             Bind(&valueNotUndefined);
2685             {
2686                 GateRef newHClass = LoadObjectFromWeakRef(value);
2687                 result = newHClass;
2688 #if ECMASCRIPT_ENABLE_IC
2689                 NotifyHClassChanged(glue, hclass, newHClass);
2690 #endif
2691                 StoreHClass(glue, receiver, newHClass);
2692                 Jump(&exit);
2693                 Bind(&notFound);
2694                 result = Undefined();
2695                 Jump(&exit);
2696             }
2697             Bind(&valueUndefined);
2698             {
2699                 result = Undefined();
2700                 Jump(&exit);
2701             }
2702         }
2703     }
2704     Bind(&exit);
2705     auto ret = *result;
2706     env->SubCfgExit();
2707     return ret;
2708 }
2709 
SetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,GateRef value,bool useOwn,ProfileOperation callback)2710 GateRef StubBuilder::SetPropertyByIndex(
2711     GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn, ProfileOperation callback)
2712 {
2713     auto env = GetEnvironment();
2714     Label entry(env);
2715     env->SubCfgEntry(&entry);
2716     DEFVARIABLE(returnValue, VariableType::JS_ANY(), Hole());
2717     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2718     Label exit(env);
2719     Label ifEnd(env);
2720     Label loopHead(env);
2721     Label loopEnd(env);
2722     Label loopExit(env);
2723     Label afterLoop(env);
2724     Label isJsCOWArray(env);
2725     Label isNotJsCOWArray(env);
2726     Label setElementsArray(env);
2727     if (!useOwn) {
2728         Jump(&loopHead);
2729         LoopBegin(&loopHead);
2730     }
2731     GateRef hclass = LoadHClass(*holder);
2732     GateRef jsType = GetObjectType(hclass);
2733     Label isSpecialIndex(env);
2734     Label notSpecialIndex(env);
2735     Branch(IsSpecialIndexedObj(jsType), &isSpecialIndex, &notSpecialIndex);
2736     Bind(&isSpecialIndex);
2737     {
2738         // TypeArray
2739         Label isFastTypeArray(env);
2740         Label notFastTypeArray(env);
2741         Label checkIsOnPrototypeChain(env);
2742         Label notTypedArrayProto(env);
2743         Branch(Int32Equal(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY))), &exit, &notTypedArrayProto);
2744         Bind(&notTypedArrayProto);
2745         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2746         Bind(&isFastTypeArray);
2747         {
2748             Branch(Equal(*holder, receiver), &checkIsOnPrototypeChain, &exit);
2749             Bind(&checkIsOnPrototypeChain);
2750             {
2751                 returnValue = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
2752                     { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType)});
2753                 Jump(&exit);
2754             }
2755         }
2756         Bind(&notFastTypeArray);
2757         returnValue = Hole();
2758         Jump(&exit);
2759     }
2760     Bind(&notSpecialIndex);
2761     {
2762         GateRef elements = GetElementsArray(*holder);
2763         Label isDictionaryElement(env);
2764         Label notDictionaryElement(env);
2765         Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2766         Bind(&notDictionaryElement);
2767         {
2768             Label isReceiver(env);
2769             if (useOwn) {
2770                 Branch(Equal(*holder, receiver), &isReceiver, &ifEnd);
2771             } else {
2772                 Branch(Equal(*holder, receiver), &isReceiver, &afterLoop);
2773             }
2774             Bind(&isReceiver);
2775             {
2776                 GateRef length = GetLengthOfTaggedArray(elements);
2777                 Label inRange(env);
2778                 if (useOwn) {
2779                     Branch(Int64LessThan(index, length), &inRange, &ifEnd);
2780                 } else {
2781                     Branch(Int64LessThan(index, length), &inRange, &loopExit);
2782                 }
2783                 Bind(&inRange);
2784                 {
2785                     GateRef value1 = GetValueFromTaggedArray(elements, index);
2786                     Label notHole(env);
2787                     if (useOwn) {
2788                         Branch(Int64NotEqual(value1, Hole()), &notHole, &ifEnd);
2789                     } else {
2790                         Branch(Int64NotEqual(value1, Hole()), &notHole, &loopExit);
2791                     }
2792                     Bind(&notHole);
2793                     {
2794                         Branch(IsJsCOWArray(*holder), &isJsCOWArray, &isNotJsCOWArray);
2795                         Bind(&isJsCOWArray);
2796                         {
2797                             GateRef newElements = CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {*holder});
2798                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, newElements, index, value);
2799                             TransitToElementsKind(
2800                                 glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
2801                             callback.ProfileObjLayoutByStore(receiver);
2802                             returnValue = Undefined();
2803                             Jump(&exit);
2804                         }
2805                         Bind(&isNotJsCOWArray);
2806                         {
2807                             Jump(&setElementsArray);
2808                         }
2809                         Bind(&setElementsArray);
2810                         {
2811                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
2812                             TransitToElementsKind(
2813                                 glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
2814                             callback.ProfileObjLayoutByStore(receiver);
2815                             returnValue = Undefined();
2816                             Jump(&exit);
2817                         }
2818                     }
2819                 }
2820             }
2821         }
2822         Bind(&isDictionaryElement);
2823         {
2824             returnValue = Hole();
2825             Jump(&exit);
2826         }
2827     }
2828     if (useOwn) {
2829         Bind(&ifEnd);
2830     } else {
2831         Bind(&loopExit);
2832         {
2833             holder = GetPrototypeFromHClass(LoadHClass(*holder));
2834             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2835         }
2836         Bind(&loopEnd);
2837         LoopEnd(&loopHead);
2838         Bind(&afterLoop);
2839     }
2840     Label isExtensible(env);
2841     Label notExtensible(env);
2842     Branch(IsExtensible(receiver), &isExtensible, &notExtensible);
2843     Bind(&isExtensible);
2844     {
2845         GateRef result = CallRuntime(glue, RTSTUB_ID(AddElementInternal),
2846             { receiver, IntToTaggedInt(index), value,
2847             IntToTaggedInt(Int32(PropertyAttributes::GetDefaultAttributes())) });
2848         Label success(env);
2849         Label failed(env);
2850         Branch(TaggedIsTrue(result), &success, &failed);
2851         Bind(&success);
2852         {
2853             callback.ProfileObjLayoutByStore(receiver);
2854             returnValue = Undefined();
2855             Jump(&exit);
2856         }
2857         Bind(&failed);
2858         {
2859             returnValue = Exception();
2860             Jump(&exit);
2861         }
2862     }
2863     Bind(&notExtensible);
2864     {
2865         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
2866         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2867         returnValue = Exception();
2868         Jump(&exit);
2869     }
2870     Bind(&exit);
2871     auto ret = *returnValue;
2872     env->SubCfgExit();
2873     return ret;
2874 }
2875 
SetPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn,ProfileOperation callback)2876 GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn,
2877     ProfileOperation callback)
2878 {
2879     auto env = GetEnvironment();
2880     Label entryPass(env);
2881     env->SubCfgEntry(&entryPass);
2882     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2883     DEFVARIABLE(holder, VariableType::JS_POINTER(), receiver);
2884     DEFVARIABLE(receiverHoleEntry, VariableType::INT32(), Int32(-1));
2885     Label exit(env);
2886     Label ifEnd(env);
2887     Label loopHead(env);
2888     Label loopEnd(env);
2889     Label loopExit(env);
2890     Label afterLoop(env);
2891     if (!useOwn) {
2892         // a do-while loop
2893         Jump(&loopHead);
2894         LoopBegin(&loopHead);
2895     }
2896     // auto *hclass = holder.GetTaggedObject()->GetClass()
2897     // JSType jsType = hclass->GetObjectType()
2898     GateRef hclass = LoadHClass(*holder);
2899     GateRef jsType = GetObjectType(hclass);
2900     Label isSIndexObj(env);
2901     Label notSIndexObj(env);
2902     // if branch condition : IsSpecialIndexedObj(jsType)
2903     Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2904     Bind(&isSIndexObj);
2905     {
2906         Label isFastTypeArray(env);
2907         Label notFastTypeArray(env);
2908         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2909         Bind(&isFastTypeArray);
2910         {
2911             result = SetTypeArrayPropertyByName(glue, receiver, *holder, key, value, jsType);
2912             Label isNull(env);
2913             Label notNull(env);
2914             Branch(TaggedIsNull(*result), &isNull, &notNull);
2915             Bind(&isNull);
2916             {
2917                 result = Hole();
2918                 Jump(&exit);
2919             }
2920             Bind(&notNull);
2921             Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2922         }
2923         Bind(&notFastTypeArray);
2924 
2925         Label isSpecialContainer(env);
2926         Label notSpecialContainer(env);
2927         // Add SpecialContainer
2928         Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
2929         Bind(&isSpecialContainer);
2930         {
2931             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotSetPropertyOnContainer));
2932             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2933             result = Exception();
2934             Jump(&exit);
2935         }
2936         Bind(&notSpecialContainer);
2937         {
2938             result = Hole();
2939             Jump(&exit);
2940         }
2941     }
2942     Bind(&notSIndexObj);
2943     {
2944         Label isDicMode(env);
2945         Label notDicMode(env);
2946         // if branch condition : LIKELY(!hclass->IsDictionaryMode())
2947         Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2948         Bind(&notDicMode);
2949         {
2950             // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject())
2951             GateRef layOutInfo = GetLayoutFromHClass(hclass);
2952             // int propsNumber = hclass->NumberOfPropsFromHClass()
2953             GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2954             // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2955             GateRef entry = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2956             Label hasEntry(env);
2957             // if branch condition : entry != -1
2958             if (useOwn) {
2959                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &ifEnd);
2960             } else {
2961                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &loopExit);
2962             }
2963             Bind(&hasEntry);
2964             {
2965                 // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2966                 GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry);
2967                 GateRef attr = GetInt32OfTInt(propAttr);
2968                 Label isAccessor(env);
2969                 Label notAccessor(env);
2970                 Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2971                 Bind(&isAccessor);
2972                 {
2973                     // auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr)
2974                     GateRef accessor = JSObjectGetProperty(*holder, hclass, attr);
2975                     Label shouldCall(env);
2976                     // ShouldCallSetter(receiver, *holder, accessor, attr)
2977                     Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &notAccessor);
2978                     Bind(&shouldCall);
2979                     {
2980                         result = CallSetterHelper(glue, receiver, accessor, value, callback);
2981                         Jump(&exit);
2982                     }
2983                 }
2984                 Bind(&notAccessor);
2985                 {
2986                     Label writable(env);
2987                     Label notWritable(env);
2988                     Branch(IsWritable(attr), &writable, &notWritable);
2989                     Bind(&notWritable);
2990                     {
2991                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
2992                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2993                         result = Exception();
2994                         Jump(&exit);
2995                     }
2996                     Bind(&writable);
2997                     {
2998                         Label isTS(env);
2999                         Label notTS(env);
3000                         Branch(IsTSHClass(hclass), &isTS, &notTS);
3001                         Bind(&isTS);
3002                         {
3003                             GateRef attrVal = JSObjectGetProperty(*holder, hclass, attr);
3004                             Label attrValIsHole(env);
3005                             Branch(TaggedIsHole(attrVal), &attrValIsHole, &notTS);
3006                             Bind(&attrValIsHole);
3007                             {
3008                                 Label storeReceiverHoleEntry(env);
3009                                 Label noNeedStore(env);
3010                                 GateRef checkReceiverHoleEntry = Int32Equal(*receiverHoleEntry, Int32(-1));
3011                                 GateRef checkHolderEqualsRecv = Equal(*holder, receiver);
3012                                 Branch(BoolAnd(checkReceiverHoleEntry, checkHolderEqualsRecv),
3013                                     &storeReceiverHoleEntry, &noNeedStore);
3014                                 Bind(&storeReceiverHoleEntry);
3015                                 {
3016                                     receiverHoleEntry = entry;
3017                                     Jump(&noNeedStore);
3018                                 }
3019                                 Bind(&noNeedStore);
3020                                 if (useOwn) {
3021                                     Jump(&ifEnd);
3022                                 } else {
3023                                     Jump(&loopExit);
3024                                 }
3025                             }
3026                         }
3027                         Bind(&notTS);
3028                         Label holdEqualsRecv(env);
3029                         if (useOwn) {
3030                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &ifEnd);
3031                         } else {
3032                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &afterLoop);
3033                         }
3034                         Bind(&holdEqualsRecv);
3035                         {
3036                             // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value)
3037                             // return JSTaggedValue::Undefined()
3038                             JSObjectSetProperty(glue, *holder, hclass, attr, key, value);
3039                             ProfilerStubBuilder(env).UpdatePropAttrWithValue(
3040                                 glue, *holder, layOutInfo, attr, entry, value, callback);
3041                             result = Undefined();
3042                             Jump(&exit);
3043                         }
3044                     }
3045                 }
3046             }
3047         }
3048         Bind(&isDicMode);
3049         {
3050             GateRef array = GetPropertiesArray(*holder);
3051             // int entry = dict->FindEntry(key)
3052             GateRef entry1 = FindEntryFromNameDictionary(glue, array, key);
3053             Label notNegtiveOne(env);
3054             // if branch condition : entry != -1
3055             if (useOwn) {
3056                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &ifEnd);
3057             } else {
3058                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &loopExit);
3059             }
3060             Bind(&notNegtiveOne);
3061             {
3062                 // auto attr = dict->GetAttributes(entry)
3063                 GateRef attr1 = GetAttributesFromDictionary<NameDictionary>(array, entry1);
3064                 Label isAccessor1(env);
3065                 Label notAccessor1(env);
3066                 // if branch condition : UNLIKELY(attr.IsAccessor())
3067                 Branch(IsAccessor(attr1), &isAccessor1, &notAccessor1);
3068                 Bind(&isAccessor1);
3069                 {
3070                     // auto accessor = dict->GetValue(entry)
3071                     GateRef accessor1 = GetValueFromDictionary<NameDictionary>(array, entry1);
3072                     Label shouldCall1(env);
3073                     Branch(ShouldCallSetter(receiver, *holder, accessor1, attr1), &shouldCall1, &notAccessor1);
3074                     Bind(&shouldCall1);
3075                     {
3076                         result = CallSetterHelper(glue, receiver, accessor1, value, callback);
3077                         Jump(&exit);
3078                     }
3079                 }
3080                 Bind(&notAccessor1);
3081                 {
3082                     Label writable1(env);
3083                     Label notWritable1(env);
3084                     Branch(IsWritable(attr1), &writable1, &notWritable1);
3085                     Bind(&notWritable1);
3086                     {
3087                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
3088                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3089                         result = Exception();
3090                         Jump(&exit);
3091                     }
3092                     Bind(&writable1);
3093                     {
3094                         Label holdEqualsRecv1(env);
3095                         if (useOwn) {
3096                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &ifEnd);
3097                         } else {
3098                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &afterLoop);
3099                         }
3100                         Bind(&holdEqualsRecv1);
3101                         {
3102                             // dict->UpdateValue(thread, entry, value)
3103                             // return JSTaggedValue::Undefined()
3104                             UpdateValueInDict(glue, array, entry1, value);
3105                             result = Undefined();
3106                             Jump(&exit);
3107                         }
3108                     }
3109                 }
3110             }
3111         }
3112     }
3113     if (useOwn) {
3114         Bind(&ifEnd);
3115     } else {
3116         Bind(&loopExit);
3117         {
3118             // holder = hclass->GetPrototype()
3119             holder = GetPrototypeFromHClass(LoadHClass(*holder));
3120             // loop condition for a do-while loop
3121             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
3122         }
3123         Bind(&loopEnd);
3124         LoopEnd(&loopHead);
3125         Bind(&afterLoop);
3126     }
3127 
3128     Label holeEntryNotNegtiveOne(env);
3129     Label holeEntryIfEnd(env);
3130     Branch(Int32NotEqual(*receiverHoleEntry, Int32(-1)), &holeEntryNotNegtiveOne, &holeEntryIfEnd);
3131     Bind(&holeEntryNotNegtiveOne);
3132     {
3133         GateRef receiverHClass = LoadHClass(receiver);
3134         GateRef receiverLayoutInfo = GetLayoutFromHClass(receiverHClass);
3135         GateRef holePropAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry);
3136         GateRef holeAttr = GetInt32OfTInt(holePropAttr);
3137         JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, key, value);
3138         ProfilerStubBuilder(env).UpdatePropAttrWithValue(
3139             glue, receiver, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback);
3140         result = Undefined();
3141         Jump(&exit);
3142     }
3143     Bind(&holeEntryIfEnd);
3144 
3145     Label extensible(env);
3146     Label inextensible(env);
3147     Branch(IsExtensible(receiver), &extensible, &inextensible);
3148     Bind(&inextensible);
3149     {
3150         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
3151         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3152         result = Exception();
3153         Jump(&exit);
3154     }
3155     Bind(&extensible);
3156     {
3157         result = AddPropertyByName(glue, receiver, key, value,
3158             Int32(PropertyAttributes::GetDefaultAttributes()), callback);
3159         Jump(&exit);
3160     }
3161     Bind(&exit);
3162     auto ret = *result;
3163     env->SubCfgExit();
3164     return ret;
3165 }
3166 
SetPropertyByValue(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn,ProfileOperation callback)3167 GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn,
3168     ProfileOperation callback)
3169 {
3170     auto env = GetEnvironment();
3171     Label subEntry1(env);
3172     env->SubCfgEntry(&subEntry1);
3173     DEFVARIABLE(varKey, VariableType::JS_ANY(), key);
3174     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3175     Label isNumberOrStringSymbol(env);
3176     Label notNumber(env);
3177     Label isStringOrSymbol(env);
3178     Label notStringOrSymbol(env);
3179     Label exit(env);
3180     Branch(TaggedIsNumber(*varKey), &isNumberOrStringSymbol, &notNumber);
3181     Bind(&notNumber);
3182     {
3183         Branch(TaggedIsStringOrSymbol(*varKey), &isNumberOrStringSymbol, &notStringOrSymbol);
3184         Bind(&notStringOrSymbol);
3185         {
3186             result = Hole();
3187             Jump(&exit);
3188         }
3189     }
3190     Bind(&isNumberOrStringSymbol);
3191     {
3192         GateRef index64 = TryToElementsIndex(glue, *varKey);
3193         Label validIndex(env);
3194         Label notValidIndex(env);
3195         Label greaterThanInt32Max(env);
3196         Label notGreaterThanInt32Max(env);
3197         Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
3198         Bind(&greaterThanInt32Max);
3199         {
3200             Jump(&exit);
3201         }
3202         Bind(&notGreaterThanInt32Max);
3203         GateRef index = TruncInt64ToInt32(index64);
3204         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
3205         Bind(&validIndex);
3206         {
3207             result = SetPropertyByIndex(glue, receiver, index, value, useOwn, callback);
3208             Jump(&exit);
3209         }
3210         Bind(&notValidIndex);
3211         {
3212             Label isNumber1(env);
3213             Label notNumber1(env);
3214             Label setByName(env);
3215             Branch(TaggedIsNumber(*varKey), &isNumber1, &notNumber1);
3216             Bind(&isNumber1);
3217             {
3218                 result = Hole();
3219                 Jump(&exit);
3220             }
3221             Bind(&notNumber1);
3222             {
3223                 Label isString(env);
3224                 Label notIntenalString(env);
3225                 Branch(TaggedIsString(*varKey), &isString, &setByName);
3226                 Bind(&isString);
3227                 {
3228                     Branch(IsInternalString(*varKey), &setByName, &notIntenalString);
3229                     Bind(&notIntenalString);
3230                     {
3231                         varKey = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *varKey });
3232                         Jump(&setByName);
3233                     }
3234                 }
3235             }
3236             Bind(&setByName);
3237             {
3238                 result = SetPropertyByName(glue, receiver, *varKey, value, useOwn, callback);
3239                 Jump(&exit);
3240             }
3241         }
3242     }
3243     Bind(&exit);
3244     auto ret = *result;
3245     env->SubCfgExit();
3246     return ret;
3247 }
3248 
NotifyHClassChanged(GateRef glue,GateRef oldHClass,GateRef newHClass)3249 void StubBuilder::NotifyHClassChanged(GateRef glue, GateRef oldHClass, GateRef newHClass)
3250 {
3251     auto env = GetEnvironment();
3252     Label entry(env);
3253     env->SubCfgEntry(&entry);
3254     Label exit(env);
3255     Label isProtoType(env);
3256     Branch(IsProtoTypeHClass(oldHClass), &isProtoType, &exit);
3257     Bind(&isProtoType);
3258     {
3259         Label notEqualHClass(env);
3260         Branch(Equal(oldHClass, newHClass), &exit, &notEqualHClass);
3261         Bind(&notEqualHClass);
3262         {
3263             SetIsProtoTypeToHClass(glue, newHClass, True());
3264             CallRuntime(glue, RTSTUB_ID(NoticeThroughChainAndRefreshUser), { oldHClass, newHClass });
3265             Jump(&exit);
3266         }
3267     }
3268     Bind(&exit);
3269     env->SubCfgExit();
3270     return;
3271 }
3272 
GetContainerProperty(GateRef glue,GateRef receiver,GateRef index,GateRef jsType)3273 GateRef StubBuilder::GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType)
3274 {
3275     auto env = GetEnvironment();
3276     Label entry(env);
3277     env->SubCfgEntry(&entry);
3278     Label exit(env);
3279     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3280 
3281     Label isDefaultLabel(env);
3282     Label noDefaultLabel(env);
3283     Branch(IsSpecialContainer(jsType), &noDefaultLabel, &isDefaultLabel);
3284     Bind(&noDefaultLabel);
3285     {
3286         result = JSAPIContainerGet(glue, receiver, index);
3287         Jump(&exit);
3288     }
3289     Bind(&isDefaultLabel);
3290     {
3291         Jump(&exit);
3292     }
3293     Bind(&exit);
3294 
3295     auto ret = *result;
3296     env->SubCfgExit();
3297     return ret;
3298 }
3299 
FastTypeOf(GateRef glue,GateRef obj)3300 GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj)
3301 {
3302     auto env = GetEnvironment();
3303     Label entry(env);
3304     env->SubCfgEntry(&entry);
3305     Label exit(env);
3306 
3307     GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
3308         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
3309     GateRef undefinedIndex = GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX);
3310     GateRef gConstUndefinedStr = Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
3311     DEFVARIABLE(result, VariableType::JS_POINTER(), gConstUndefinedStr);
3312     Label objIsTrue(env);
3313     Label objNotTrue(env);
3314     Label defaultLabel(env);
3315     GateRef gConstBooleanStr = Load(VariableType::JS_POINTER(), gConstAddr,
3316         GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX));
3317     Branch(TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
3318     Bind(&objIsTrue);
3319     {
3320         result = gConstBooleanStr;
3321         Jump(&exit);
3322     }
3323     Bind(&objNotTrue);
3324     {
3325         Label objIsFalse(env);
3326         Label objNotFalse(env);
3327         Branch(TaggedIsFalse(obj), &objIsFalse, &objNotFalse);
3328         Bind(&objIsFalse);
3329         {
3330             result = gConstBooleanStr;
3331             Jump(&exit);
3332         }
3333         Bind(&objNotFalse);
3334         {
3335             Label objIsNull(env);
3336             Label objNotNull(env);
3337             Branch(TaggedIsNull(obj), &objIsNull, &objNotNull);
3338             Bind(&objIsNull);
3339             {
3340                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3341                     GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
3342                 Jump(&exit);
3343             }
3344             Bind(&objNotNull);
3345             {
3346                 Label objIsUndefined(env);
3347                 Label objNotUndefined(env);
3348                 Branch(TaggedIsUndefined(obj), &objIsUndefined, &objNotUndefined);
3349                 Bind(&objIsUndefined);
3350                 {
3351                     result = Load(VariableType::JS_POINTER(), gConstAddr,
3352                         GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX));
3353                     Jump(&exit);
3354                 }
3355                 Bind(&objNotUndefined);
3356                 Jump(&defaultLabel);
3357             }
3358         }
3359     }
3360     Bind(&defaultLabel);
3361     {
3362         Label objIsHeapObject(env);
3363         Label objNotHeapObject(env);
3364         Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject);
3365         Bind(&objIsHeapObject);
3366         {
3367             Label objIsString(env);
3368             Label objNotString(env);
3369             Branch(IsString(obj), &objIsString, &objNotString);
3370             Bind(&objIsString);
3371             {
3372                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3373                     GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX));
3374                 Jump(&exit);
3375             }
3376             Bind(&objNotString);
3377             {
3378                 Label objIsSymbol(env);
3379                 Label objNotSymbol(env);
3380                 Branch(IsSymbol(obj), &objIsSymbol, &objNotSymbol);
3381                 Bind(&objIsSymbol);
3382                 {
3383                     result = Load(VariableType::JS_POINTER(), gConstAddr,
3384                         GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX));
3385                     Jump(&exit);
3386                 }
3387                 Bind(&objNotSymbol);
3388                 {
3389                     Label objIsCallable(env);
3390                     Label objNotCallable(env);
3391                     Branch(IsCallable(obj), &objIsCallable, &objNotCallable);
3392                     Bind(&objIsCallable);
3393                     {
3394                         result = Load(VariableType::JS_POINTER(), gConstAddr,
3395                             GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX));
3396                         Jump(&exit);
3397                     }
3398                     Bind(&objNotCallable);
3399                     {
3400                         Label objIsBigInt(env);
3401                         Label objNotBigInt(env);
3402                         Branch(TaggedObjectIsBigInt(obj), &objIsBigInt, &objNotBigInt);
3403                         Bind(&objIsBigInt);
3404                         {
3405                             result = Load(VariableType::JS_POINTER(), gConstAddr,
3406                                 GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX));
3407                             Jump(&exit);
3408                         }
3409                         Bind(&objNotBigInt);
3410                         {
3411                             result = Load(VariableType::JS_POINTER(), gConstAddr,
3412                                 GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
3413                             Jump(&exit);
3414                         }
3415                     }
3416                 }
3417             }
3418         }
3419         Bind(&objNotHeapObject);
3420         {
3421             Label objIsNum(env);
3422             Label objNotNum(env);
3423             Branch(TaggedIsNumber(obj), &objIsNum, &objNotNum);
3424             Bind(&objIsNum);
3425             {
3426                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3427                     GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX));
3428                 Jump(&exit);
3429             }
3430             Bind(&objNotNum);
3431             Jump(&exit);
3432         }
3433     }
3434     Bind(&exit);
3435     auto ret = *result;
3436     env->SubCfgExit();
3437     return ret;
3438 }
3439 
InstanceOf(GateRef glue,GateRef object,GateRef target,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)3440 GateRef StubBuilder::InstanceOf(
3441     GateRef glue, GateRef object, GateRef target, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
3442 {
3443     auto env = GetEnvironment();
3444     Label entry(env);
3445     env->SubCfgEntry(&entry);
3446     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3447     Label exit(env);
3448 
3449     // 1.If Type(target) is not Object, throw a TypeError exception.
3450     Label targetIsHeapObject(env);
3451     Label targetIsEcmaObject(env);
3452     Label targetNotEcmaObject(env);
3453     Branch(TaggedIsHeapObject(target), &targetIsHeapObject, &targetNotEcmaObject);
3454     Bind(&targetIsHeapObject);
3455     Branch(TaggedObjectIsEcmaObject(target), &targetIsEcmaObject, &targetNotEcmaObject);
3456     Bind(&targetNotEcmaObject);
3457     {
3458         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
3459         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3460         result = Exception();
3461         Jump(&exit);
3462     }
3463     Bind(&targetIsEcmaObject);
3464     {
3465         // 2.Let instOfHandler be GetMethod(target, @@hasInstance).
3466         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3467         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3468         GateRef hasInstanceSymbol = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
3469                                                       GlobalEnv::HASINSTANCE_SYMBOL_INDEX);
3470         GateRef instof = GetMethod(glue, target, hasInstanceSymbol, profileTypeInfo, slotId);
3471 
3472         // 3.ReturnIfAbrupt(instOfHandler).
3473         Label isPendingException(env);
3474         Label noPendingException(env);
3475         Branch(HasPendingException(glue), &isPendingException, &noPendingException);
3476         Bind(&isPendingException);
3477         {
3478             result = Exception();
3479             Jump(&exit);
3480         }
3481         Bind(&noPendingException);
3482 
3483         // 4.If instOfHandler is not undefined, then
3484         Label instOfNotUndefined(env);
3485         Label instOfIsUndefined(env);
3486         Label fastPath(env);
3487         Label targetNotCallable(env);
3488         Branch(TaggedIsUndefined(instof), &instOfIsUndefined, &instOfNotUndefined);
3489         Bind(&instOfNotUndefined);
3490         {
3491             TryFastHasInstance(glue, instof, target, object, &fastPath, &exit, &result, callback);
3492         }
3493         Bind(&instOfIsUndefined);
3494         {
3495             // 5.If IsCallable(target) is false, throw a TypeError exception.
3496             Branch(IsCallable(target), &fastPath, &targetNotCallable);
3497             Bind(&targetNotCallable);
3498             {
3499                 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
3500                 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3501                 result = Exception();
3502                 Jump(&exit);
3503             }
3504         }
3505         Bind(&fastPath);
3506         {
3507             // 6.Return ? OrdinaryHasInstance(target, object).
3508             result = OrdinaryHasInstance(glue, target, object);
3509             Jump(&exit);
3510         }
3511     }
3512     Bind(&exit);
3513     auto ret = *result;
3514     env->SubCfgExit();
3515     return ret;
3516 }
3517 
TryFastHasInstance(GateRef glue,GateRef instof,GateRef target,GateRef object,Label * fastPath,Label * exit,Variable * result,ProfileOperation callback)3518 void StubBuilder::TryFastHasInstance(GateRef glue, GateRef instof, GateRef target, GateRef object, Label *fastPath,
3519                                      Label *exit, Variable *result, ProfileOperation callback)
3520 {
3521     auto env = GetEnvironment();
3522 
3523     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3524     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3525     GateRef function = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::HASINSTANCE_FUNCTION_INDEX);
3526 
3527     Label slowPath(env);
3528     Label tryFastPath(env);
3529     GateRef isEqual = IntPtrEqual(instof, function);
3530     Branch(isEqual, &tryFastPath, &slowPath);
3531     Bind(&tryFastPath);
3532     Jump(fastPath);
3533     Bind(&slowPath);
3534     {
3535         GateRef retValue = JSCallDispatch(glue, instof, Int32(1), 0, Circuit::NullGate(),
3536                                           JSCallMode::CALL_SETTER, { target, object }, callback);
3537         result->WriteVariable(FastToBoolean(retValue));
3538         Jump(exit);
3539     }
3540 }
3541 
GetMethod(GateRef glue,GateRef obj,GateRef key,GateRef profileTypeInfo,GateRef slotId)3542 GateRef StubBuilder::GetMethod(GateRef glue, GateRef obj, GateRef key, GateRef profileTypeInfo, GateRef slotId)
3543 {
3544     auto env = GetEnvironment();
3545     Label entry(env);
3546     env->SubCfgEntry(&entry);
3547     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3548     Label exit(env);
3549 
3550     StringIdInfo info;
3551     AccessObjectStubBuilder builder(this);
3552     GateRef value = builder.LoadObjByName(glue, obj, key, info, profileTypeInfo, slotId, ProfileOperation());
3553 
3554     Label isPendingException(env);
3555     Label noPendingException(env);
3556     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
3557     Bind(&isPendingException);
3558     {
3559         result = Exception();
3560         Jump(&exit);
3561     }
3562     Bind(&noPendingException);
3563     Label valueIsUndefinedOrNull(env);
3564     Label valueNotUndefinedOrNull(env);
3565     Branch(TaggedIsUndefinedOrNull(value), &valueIsUndefinedOrNull, &valueNotUndefinedOrNull);
3566     Bind(&valueIsUndefinedOrNull);
3567     {
3568         result = Undefined();
3569         Jump(&exit);
3570     }
3571     Bind(&valueNotUndefinedOrNull);
3572     {
3573         Label valueIsCallable(env);
3574         Label valueNotCallable(env);
3575         Branch(IsCallable(value), &valueIsCallable, &valueNotCallable);
3576         Bind(&valueNotCallable);
3577         {
3578             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(NonCallable));
3579             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3580             result = Exception();
3581             Jump(&exit);
3582         }
3583         Bind(&valueIsCallable);
3584         {
3585             result = value;
3586             Jump(&exit);
3587         }
3588     }
3589     Bind(&exit);
3590     auto ret = *result;
3591     env->SubCfgExit();
3592     return ret;
3593 }
3594 
FastGetPropertyByName(GateRef glue,GateRef obj,GateRef key,ProfileOperation callback)3595 GateRef StubBuilder::FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback)
3596 {
3597     auto env = GetEnvironment();
3598     Label entry(env);
3599     env->SubCfgEntry(&entry);
3600     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3601     Label exit(env);
3602     Label checkResult(env);
3603     Label fastpath(env);
3604     Label slowpath(env);
3605 
3606     Branch(TaggedIsHeapObject(obj), &fastpath, &slowpath);
3607     Bind(&fastpath);
3608     {
3609         result = GetPropertyByName(glue, obj, key, callback);
3610         Branch(TaggedIsHole(*result), &slowpath, &exit);
3611     }
3612     Bind(&slowpath);
3613     {
3614         result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
3615                              { Undefined(), obj, key, Int64ToTaggedPtr(Int32(0)) });
3616         Jump(&exit);
3617     }
3618     Bind(&exit);
3619     auto ret = *result;
3620     env->SubCfgExit();
3621     return ret;
3622 }
3623 
FastGetPropertyByIndex(GateRef glue,GateRef obj,GateRef index,ProfileOperation callback)3624 GateRef StubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback)
3625 {
3626     auto env = GetEnvironment();
3627     Label entry(env);
3628     env->SubCfgEntry(&entry);
3629     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3630     Label exit(env);
3631     Label fastPath(env);
3632     Label slowPath(env);
3633 
3634     Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath);
3635     Bind(&fastPath);
3636     {
3637         result = GetPropertyByIndex(glue, obj, index, callback);
3638         Label notHole(env);
3639         Branch(TaggedIsHole(*result), &slowPath, &exit);
3640     }
3641     Bind(&slowPath);
3642     {
3643         result = CallRuntime(glue, RTSTUB_ID(LdObjByIndex),
3644             { obj, IntToTaggedInt(index), TaggedFalse(), Undefined() });
3645         Jump(&exit);
3646     }
3647     Bind(&exit);
3648     auto ret = *result;
3649     env->SubCfgExit();
3650     return ret;
3651 }
3652 
OrdinaryHasInstance(GateRef glue,GateRef target,GateRef obj)3653 GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj)
3654 {
3655     auto env = GetEnvironment();
3656     Label entry(env);
3657     env->SubCfgEntry(&entry);
3658     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3659     Label exit(env);
3660     DEFVARIABLE(object, VariableType::JS_ANY(), obj);
3661 
3662     // 1. If IsCallable(C) is false, return false.
3663     Label targetIsCallable(env);
3664     Label targetNotCallable(env);
3665     Branch(IsCallable(target), &targetIsCallable, &targetNotCallable);
3666     Bind(&targetNotCallable);
3667     {
3668         result = TaggedFalse();
3669         Jump(&exit);
3670     }
3671     Bind(&targetIsCallable);
3672     {
3673         // 2. If C has a [[BoundTargetFunction]] internal slot, then
3674         //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
3675         //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
3676         Label targetIsBoundFunction(env);
3677         Label targetNotBoundFunction(env);
3678         Branch(IsBoundFunction(target), &targetIsBoundFunction, &targetNotBoundFunction);
3679         Bind(&targetIsBoundFunction);
3680         {
3681             GateRef boundTarget = Load(VariableType::JS_ANY(), target, IntPtr(JSBoundFunction::BOUND_TARGET_OFFSET));
3682             result = CallRuntime(glue, RTSTUB_ID(InstanceOf), { obj, boundTarget });
3683             Jump(&exit);
3684         }
3685         Bind(&targetNotBoundFunction);
3686         {
3687             // 3. If Type(O) is not Object, return false
3688             Label objIsHeapObject(env);
3689             Label objIsEcmaObject(env);
3690             Label objNotEcmaObject(env);
3691             Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotEcmaObject);
3692             Bind(&objIsHeapObject);
3693             Branch(TaggedObjectIsEcmaObject(obj), &objIsEcmaObject, &objNotEcmaObject);
3694             Bind(&objNotEcmaObject);
3695             {
3696                 result = TaggedFalse();
3697                 Jump(&exit);
3698             }
3699             Bind(&objIsEcmaObject);
3700             {
3701                 // 4. Let P be Get(C, "prototype").
3702                 auto prototypeString = GetGlobalConstantValue(
3703                     VariableType::JS_POINTER(), glue, ConstantIndex::PROTOTYPE_STRING_INDEX);
3704 
3705                 GateRef constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation());
3706 
3707                 // 5. ReturnIfAbrupt(P).
3708                 // no throw exception, so needn't return
3709                 Label isPendingException(env);
3710                 Label noPendingException(env);
3711                 Branch(HasPendingException(glue), &isPendingException, &noPendingException);
3712                 Bind(&isPendingException);
3713                 {
3714                     result = Exception();
3715                     Jump(&exit);
3716                 }
3717                 Bind(&noPendingException);
3718 
3719                 // 6. If Type(P) is not Object, throw a TypeError exception.
3720                 Label constructorPrototypeIsHeapObject(env);
3721                 Label constructorPrototypeIsEcmaObject(env);
3722                 Label constructorPrototypeNotEcmaObject(env);
3723                 Branch(TaggedIsHeapObject(constructorPrototype), &constructorPrototypeIsHeapObject,
3724                     &constructorPrototypeNotEcmaObject);
3725                 Bind(&constructorPrototypeIsHeapObject);
3726                 Branch(TaggedObjectIsEcmaObject(constructorPrototype), &constructorPrototypeIsEcmaObject,
3727                     &constructorPrototypeNotEcmaObject);
3728                 Bind(&constructorPrototypeNotEcmaObject);
3729                 {
3730                     GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
3731                     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3732                     result = Exception();
3733                     Jump(&exit);
3734                 }
3735                 Bind(&constructorPrototypeIsEcmaObject);
3736                 {
3737                     // 7. Repeat
3738                     //    a.Let O be O.[[GetPrototypeOf]]().
3739                     //    b.ReturnIfAbrupt(O).
3740                     //    c.If O is null, return false.
3741                     //    d.If SameValue(P, O) is true, return true.
3742                     Label loopHead(env);
3743                     Label loopEnd(env);
3744                     Label afterLoop(env);
3745                     Label strictEqual1(env);
3746                     Label notStrictEqual1(env);
3747                     Label shouldReturn(env);
3748                     Label shouldContinue(env);
3749 
3750                     Branch(TaggedIsNull(*object), &afterLoop, &loopHead);
3751                     LoopBegin(&loopHead);
3752                     {
3753                         GateRef isEqual = SameValue(glue, *object, constructorPrototype);
3754 
3755                         Branch(isEqual, &strictEqual1, &notStrictEqual1);
3756                         Bind(&strictEqual1);
3757                         {
3758                             result = TaggedTrue();
3759                             Jump(&exit);
3760                         }
3761                         Bind(&notStrictEqual1);
3762                         {
3763                             object = GetPrototype(glue, *object);
3764 
3765                             Branch(HasPendingException(glue), &shouldReturn, &shouldContinue);
3766                             Bind(&shouldReturn);
3767                             {
3768                                 result = Exception();
3769                                 Jump(&exit);
3770                             }
3771                         }
3772                         Bind(&shouldContinue);
3773                         Branch(TaggedIsNull(*object), &afterLoop, &loopEnd);
3774                     }
3775                     Bind(&loopEnd);
3776                     LoopEnd(&loopHead);
3777                     Bind(&afterLoop);
3778                     {
3779                         result = TaggedFalse();
3780                         Jump(&exit);
3781                     }
3782                 }
3783             }
3784         }
3785     }
3786     Bind(&exit);
3787     auto ret = *result;
3788     env->SubCfgExit();
3789     return ret;
3790 }
3791 
GetPrototype(GateRef glue,GateRef object)3792 GateRef StubBuilder::GetPrototype(GateRef glue, GateRef object)
3793 {
3794     auto env = GetEnvironment();
3795     Label entry(env);
3796     env->SubCfgEntry(&entry);
3797     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3798     Label exit(env);
3799     Label objectIsHeapObject(env);
3800     Label objectIsEcmaObject(env);
3801     Label objectNotEcmaObject(env);
3802 
3803     Branch(TaggedIsHeapObject(object), &objectIsHeapObject, &objectNotEcmaObject);
3804     Bind(&objectIsHeapObject);
3805     Branch(TaggedObjectIsEcmaObject(object), &objectIsEcmaObject, &objectNotEcmaObject);
3806     Bind(&objectNotEcmaObject);
3807     {
3808         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotGetNotEcmaObject));
3809         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3810         result = Exception();
3811         Jump(&exit);
3812     }
3813     Bind(&objectIsEcmaObject);
3814     {
3815         Label objectIsJsProxy(env);
3816         Label objectNotIsJsProxy(env);
3817         Branch(IsJsProxy(object), &objectIsJsProxy, &objectNotIsJsProxy);
3818         Bind(&objectIsJsProxy);
3819         {
3820             result = CallRuntime(glue, RTSTUB_ID(CallGetPrototype), { object });
3821             Jump(&exit);
3822         }
3823         Bind(&objectNotIsJsProxy);
3824         {
3825             result = GetPrototypeFromHClass(LoadHClass(object));
3826             Jump(&exit);
3827         }
3828     }
3829     Bind(&exit);
3830     auto ret = *result;
3831     env->SubCfgExit();
3832     return ret;
3833 }
3834 
SameValue(GateRef glue,GateRef left,GateRef right)3835 GateRef StubBuilder::SameValue(GateRef glue, GateRef left, GateRef right)
3836 {
3837     auto env = GetEnvironment();
3838     Label entry(env);
3839     env->SubCfgEntry(&entry);
3840     DEFVARIABLE(result, VariableType::BOOL(), False());
3841     Label exit(env);
3842     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
3843     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
3844     Label strictEqual(env);
3845     Label stringEqualCheck(env);
3846     Label stringCompare(env);
3847     Label bigIntEqualCheck(env);
3848     Label numberEqualCheck1(env);
3849 
3850     Branch(Equal(left, right), &strictEqual, &numberEqualCheck1);
3851     Bind(&strictEqual);
3852     {
3853         result = True();
3854         Jump(&exit);
3855     }
3856     Bind(&numberEqualCheck1);
3857     {
3858         Label leftIsNumber(env);
3859         Label leftIsNotNumber(env);
3860         Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
3861         Bind(&leftIsNumber);
3862         {
3863             Label rightIsNumber(env);
3864             Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
3865             Bind(&rightIsNumber);
3866             {
3867                 Label numberEqualCheck2(env);
3868                 Label leftIsInt(env);
3869                 Label leftNotInt(env);
3870                 Label getRight(env);
3871                 Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
3872                 Bind(&leftIsInt);
3873                 {
3874                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
3875                     Jump(&getRight);
3876                 }
3877                 Bind(&leftNotInt);
3878                 {
3879                     doubleLeft = GetDoubleOfTDouble(left);
3880                     Jump(&getRight);
3881                 }
3882                 Bind(&getRight);
3883                 {
3884                     Label rightIsInt(env);
3885                     Label rightNotInt(env);
3886                     Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
3887                     Bind(&rightIsInt);
3888                     {
3889                         doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
3890                         Jump(&numberEqualCheck2);
3891                     }
3892                     Bind(&rightNotInt);
3893                     {
3894                         doubleRight = GetDoubleOfTDouble(right);
3895                         Jump(&numberEqualCheck2);
3896                     }
3897                 }
3898                 Bind(&numberEqualCheck2);
3899                 {
3900                     Label boolAndCheck(env);
3901                     Label signbitCheck(env);
3902                     Branch(DoubleEqual(*doubleLeft, *doubleRight), &signbitCheck, &boolAndCheck);
3903                     Bind(&signbitCheck);
3904                     {
3905                         GateRef leftEncoding = CastDoubleToInt64(*doubleLeft);
3906                         GateRef RightEncoding = CastDoubleToInt64(*doubleRight);
3907                         Label leftIsMinusZero(env);
3908                         Label leftNotMinusZero(env);
3909                         Branch(Int64Equal(leftEncoding, Int64(base::MINUS_ZERO_BITS)),
3910                             &leftIsMinusZero, &leftNotMinusZero);
3911                         Bind(&leftIsMinusZero);
3912                         {
3913                             Label rightIsMinusZero(env);
3914                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &rightIsMinusZero, &exit);
3915                             Bind(&rightIsMinusZero);
3916                             {
3917                                 result = True();
3918                                 Jump(&exit);
3919                             }
3920                         }
3921                         Bind(&leftNotMinusZero);
3922                         {
3923                             Label rightNotMinusZero(env);
3924                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &exit, &rightNotMinusZero);
3925                             Bind(&rightNotMinusZero);
3926                             {
3927                                 result = True();
3928                                 Jump(&exit);
3929                             }
3930                         }
3931                     }
3932                     Bind(&boolAndCheck);
3933                     {
3934                         result = BoolAnd(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight));
3935                         Jump(&exit);
3936                     }
3937                 }
3938             }
3939         }
3940         Bind(&leftIsNotNumber);
3941         Branch(TaggedIsNumber(right), &exit, &stringEqualCheck);
3942         Bind(&stringEqualCheck);
3943         Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
3944         Bind(&stringCompare);
3945         {
3946             result = FastStringEqual(glue, left, right);
3947             Jump(&exit);
3948         }
3949         Bind(&bigIntEqualCheck);
3950         {
3951             Label leftIsBigInt(env);
3952             Label leftIsNotBigInt(env);
3953             Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
3954             Bind(&leftIsBigInt);
3955             {
3956                 Label rightIsBigInt(env);
3957                 Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
3958                 Bind(&rightIsBigInt);
3959                 result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
3960                 Jump(&exit);
3961             }
3962         }
3963     }
3964     Bind(&exit);
3965     auto ret = *result;
3966     env->SubCfgExit();
3967     return ret;
3968 }
3969 
FastStringEqual(GateRef glue,GateRef left,GateRef right)3970 GateRef StubBuilder::FastStringEqual(GateRef glue, GateRef left, GateRef right)
3971 {
3972     auto env = GetEnvironment();
3973     Label entry(env);
3974     env->SubCfgEntry(&entry);
3975     DEFVARIABLE(result, VariableType::BOOL(), False());
3976     Label exit(env);
3977     Label lengthCompare(env);
3978     Label hashcodeCompare(env);
3979     Label contentsCompare(env);
3980 
3981     Branch(Int32Equal(ZExtInt1ToInt32(IsUtf16String(left)), ZExtInt1ToInt32(IsUtf16String(right))),
3982         &lengthCompare, &exit);
3983 
3984     Bind(&lengthCompare);
3985     Branch(Int32Equal(GetLengthFromString(left), GetLengthFromString(right)), &hashcodeCompare,
3986         &exit);
3987 
3988     Bind(&hashcodeCompare);
3989     Label leftNotNeg(env);
3990     GateRef leftHash = TryGetHashcodeFromString(left);
3991     GateRef rightHash = TryGetHashcodeFromString(right);
3992     Branch(Int64Equal(leftHash, Int64(-1)), &contentsCompare, &leftNotNeg);
3993     Bind(&leftNotNeg);
3994     {
3995         Label rightNotNeg(env);
3996         Branch(Int64Equal(rightHash, Int64(-1)), &contentsCompare, &rightNotNeg);
3997         Bind(&rightNotNeg);
3998         Branch(Int64Equal(leftHash, rightHash), &contentsCompare, &exit);
3999     }
4000 
4001     Bind(&contentsCompare);
4002     {
4003         GateRef stringEqual = CallRuntime(glue, RTSTUB_ID(StringEqual), { left, right });
4004         result = Equal(stringEqual, TaggedTrue());
4005         Jump(&exit);
4006     }
4007 
4008     Bind(&exit);
4009     auto ret = *result;
4010     env->SubCfgExit();
4011     return ret;
4012 }
4013 
FastStrictEqual(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)4014 GateRef StubBuilder::FastStrictEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
4015 {
4016     auto env = GetEnvironment();
4017     Label entry(env);
4018     env->SubCfgEntry(&entry);
4019     DEFVARIABLE(result, VariableType::BOOL(), False());
4020     Label strictEqual(env);
4021     Label leftIsNumber(env);
4022     Label leftIsNotNumber(env);
4023     Label sameVariableCheck(env);
4024     Label stringEqualCheck(env);
4025     Label stringCompare(env);
4026     Label bigIntEqualCheck(env);
4027     Label exit(env);
4028     Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
4029     Bind(&leftIsNumber);
4030     {
4031         Label rightIsNumber(env);
4032         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4033         Bind(&rightIsNumber);
4034         {
4035             DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
4036             DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
4037             DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::IntType()));
4038             Label leftIsInt(env);
4039             Label leftNotInt(env);
4040             Label getRight(env);
4041             Label numberEqualCheck(env);
4042 
4043             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
4044             Bind(&leftIsInt);
4045             {
4046                 doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4047                 Jump(&getRight);
4048             }
4049             Bind(&leftNotInt);
4050             {
4051                 curType = Int32(PGOSampleType::DoubleType());
4052                 doubleLeft = GetDoubleOfTDouble(left);
4053                 Jump(&getRight);
4054             }
4055             Bind(&getRight);
4056             {
4057                 Label rightIsInt(env);
4058                 Label rightNotInt(env);
4059                 Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
4060                 Bind(&rightIsInt);
4061                 {
4062                     GateRef type = Int32(PGOSampleType::IntType());
4063                     COMBINE_TYPE_CALL_BACK(curType, type);
4064                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4065                     Jump(&numberEqualCheck);
4066                 }
4067                 Bind(&rightNotInt);
4068                 {
4069                     GateRef type = Int32(PGOSampleType::DoubleType());
4070                     COMBINE_TYPE_CALL_BACK(curType, type);
4071                     doubleRight = GetDoubleOfTDouble(right);
4072                     Jump(&numberEqualCheck);
4073                 }
4074             }
4075             Bind(&numberEqualCheck);
4076             {
4077                 Label doubleEqualCheck(env);
4078                 Branch(BoolOr(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight)), &exit, &doubleEqualCheck);
4079                 Bind(&doubleEqualCheck);
4080                 {
4081                     result = DoubleEqual(*doubleLeft, *doubleRight);
4082                     Jump(&exit);
4083                 }
4084             }
4085         }
4086     }
4087     Bind(&leftIsNotNumber);
4088     Branch(TaggedIsNumber(right), &exit, &sameVariableCheck);
4089     Bind(&sameVariableCheck);
4090     Branch(Equal(left, right), &strictEqual, &stringEqualCheck);
4091     Bind(&stringEqualCheck);
4092     Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
4093     Bind(&stringCompare);
4094     {
4095         callback.ProfileOpType(Int32(PGOSampleType::StringType()));
4096         result = FastStringEqual(glue, left, right);
4097         Jump(&exit);
4098     }
4099     Bind(&bigIntEqualCheck);
4100     {
4101         Label leftIsBigInt(env);
4102         Label leftIsNotBigInt(env);
4103         Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
4104         Bind(&leftIsBigInt);
4105         {
4106             Label rightIsBigInt(env);
4107             Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
4108             Bind(&rightIsBigInt);
4109             callback.ProfileOpType(Int32(PGOSampleType::BigIntType()));
4110             result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
4111             Jump(&exit);
4112         }
4113     }
4114     Bind(&strictEqual);
4115     {
4116         callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
4117         result = True();
4118         Jump(&exit);
4119     }
4120     Bind(&exit);
4121     auto ret = *result;
4122     env->SubCfgExit();
4123     return ret;
4124 }
4125 
FastEqual(GateRef left,GateRef right,ProfileOperation callback)4126 GateRef StubBuilder::FastEqual(GateRef left, GateRef right, ProfileOperation callback)
4127 {
4128     auto env = GetEnvironment();
4129     Label entry(env);
4130     env->SubCfgEntry(&entry);
4131     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4132     Label leftEqualRight(env);
4133     Label leftNotEqualRight(env);
4134     Label exit(env);
4135     Branch(Equal(left, right), &leftEqualRight, &leftNotEqualRight);
4136     Bind(&leftEqualRight);
4137     {
4138         Label leftIsDouble(env);
4139         Label leftNotDoubleOrLeftNotNan(env);
4140         Branch(TaggedIsDouble(left), &leftIsDouble, &leftNotDoubleOrLeftNotNan);
4141         Bind(&leftIsDouble);
4142         {
4143             callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
4144             GateRef doubleLeft = GetDoubleOfTDouble(left);
4145             Label leftIsNan(env);
4146             Label leftIsNotNan(env);
4147             Branch(DoubleIsNAN(doubleLeft), &leftIsNan, &leftIsNotNan);
4148             Bind(&leftIsNan);
4149             {
4150                 result = TaggedFalse();
4151                 Jump(&exit);
4152             }
4153             Bind(&leftIsNotNan);
4154             {
4155                 result = TaggedTrue();
4156                 Jump(&exit);
4157             }
4158         }
4159         Bind(&leftNotDoubleOrLeftNotNan);
4160         {
4161             // Collect the type of left value
4162             result = TaggedTrue();
4163             Label leftIsInt(env);
4164             Label leftIsNotInt(env);
4165             Branch(TaggedIsInt(left), &leftIsInt, &leftIsNotInt);
4166             Bind(&leftIsInt);
4167             {
4168                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4169                 Jump(&exit);
4170             }
4171             Bind(&leftIsNotInt);
4172             {
4173                 callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
4174                 Jump(&exit);
4175             }
4176         }
4177     }
4178     Bind(&leftNotEqualRight);
4179     {
4180         Label leftIsNumber(env);
4181         Label leftNotNumberOrLeftNotIntOrRightNotInt(env);
4182         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrLeftNotIntOrRightNotInt);
4183         Bind(&leftIsNumber);
4184         {
4185             Label leftIsInt(env);
4186             Branch(TaggedIsInt(left), &leftIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
4187             Bind(&leftIsInt);
4188             {
4189                 Label rightIsInt(env);
4190                 Branch(TaggedIsInt(right), &rightIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
4191                 Bind(&rightIsInt);
4192                 {
4193                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4194                     result = TaggedFalse();
4195                     Jump(&exit);
4196                 }
4197             }
4198         }
4199         Bind(&leftNotNumberOrLeftNotIntOrRightNotInt);
4200         {
4201             DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
4202             Label rightIsUndefinedOrNull(env);
4203             Label leftOrRightNotUndefinedOrNull(env);
4204             Branch(TaggedIsUndefinedOrNull(right), &rightIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull);
4205             Bind(&rightIsUndefinedOrNull);
4206             {
4207                 curType = Int32(PGOSampleType::UndefineOrNullType());
4208                 Label leftIsHeapObject(env);
4209                 Label leftNotHeapObject(env);
4210                 Branch(TaggedIsHeapObject(left), &leftIsHeapObject, &leftNotHeapObject);
4211                 Bind(&leftIsHeapObject);
4212                 {
4213                     GateRef type = Int32(PGOSampleType::HeapObjectType());
4214                     COMBINE_TYPE_CALL_BACK(curType, type);
4215                     result = TaggedFalse();
4216                     Jump(&exit);
4217                 }
4218                 Bind(&leftNotHeapObject);
4219                 {
4220                     Label leftIsUndefinedOrNull(env);
4221                     Branch(TaggedIsUndefinedOrNull(left), &leftIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull);
4222                     Bind(&leftIsUndefinedOrNull);
4223                     {
4224                         callback.ProfileOpType(*curType);
4225                         result = TaggedTrue();
4226                         Jump(&exit);
4227                     }
4228                 }
4229             }
4230             Bind(&leftOrRightNotUndefinedOrNull);
4231             {
4232                 Label leftIsBool(env);
4233                 Label leftNotBoolOrRightNotSpecial(env);
4234                 Branch(TaggedIsBoolean(left), &leftIsBool, &leftNotBoolOrRightNotSpecial);
4235                 Bind(&leftIsBool);
4236                 {
4237                     curType = Int32(PGOSampleType::BooleanType());
4238                     Label rightIsSpecial(env);
4239                     Branch(TaggedIsSpecial(right), &rightIsSpecial, &leftNotBoolOrRightNotSpecial);
4240                     Bind(&rightIsSpecial);
4241                     {
4242                         GateRef type = Int32(PGOSampleType::SpecialType());
4243                         COMBINE_TYPE_CALL_BACK(curType, type);
4244                         result = TaggedFalse();
4245                         Jump(&exit);
4246                     }
4247                 }
4248                 Bind(&leftNotBoolOrRightNotSpecial);
4249                 {
4250                     callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
4251                     Jump(&exit);
4252                 }
4253             }
4254         }
4255     }
4256     Bind(&exit);
4257     auto ret = *result;
4258     env->SubCfgExit();
4259     return ret;
4260 }
4261 
FastToBoolean(GateRef value)4262 GateRef StubBuilder::FastToBoolean(GateRef value)
4263 {
4264     auto env = GetEnvironment();
4265     Label entry(env);
4266     env->SubCfgEntry(&entry);
4267     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4268     Label exit(env);
4269 
4270     Label isSpecial(env);
4271     Label notSpecial(env);
4272     Label isNumber(env);
4273     Label isInt(env);
4274     Label isDouble(env);
4275     Label notNumber(env);
4276     Label notNan(env);
4277     Label isString(env);
4278     Label notString(env);
4279     Label isBigint(env);
4280     Label lengthIsOne(env);
4281     Label returnTrue(env);
4282     Label returnFalse(env);
4283 
4284     Branch(TaggedIsSpecial(value), &isSpecial, &notSpecial);
4285     Bind(&isSpecial);
4286     {
4287         Branch(TaggedIsTrue(value), &returnTrue, &returnFalse);
4288     }
4289     Bind(&notSpecial);
4290     {
4291         Branch(TaggedIsNumber(value), &isNumber, &notNumber);
4292         Bind(&notNumber);
4293         {
4294             Branch(IsString(value), &isString, &notString);
4295             Bind(&isString);
4296             {
4297                 auto len = GetLengthFromString(value);
4298                 Branch(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue);
4299             }
4300             Bind(&notString);
4301             Branch(TaggedObjectIsBigInt(value), &isBigint, &returnTrue);
4302             Bind(&isBigint);
4303             {
4304                 auto len = Load(VariableType::INT32(), value, IntPtr(BigInt::LENGTH_OFFSET));
4305                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &returnTrue);
4306                 Bind(&lengthIsOne);
4307                 {
4308                     auto data = PtrAdd(value, IntPtr(BigInt::DATA_OFFSET));
4309                     auto data0 = Load(VariableType::INT32(), data, Int32(0));
4310                     Branch(Int32Equal(data0, Int32(0)), &returnFalse, &returnTrue);
4311                 }
4312             }
4313         }
4314         Bind(&isNumber);
4315         {
4316             Branch(TaggedIsInt(value), &isInt, &isDouble);
4317             Bind(&isInt);
4318             {
4319                 auto intValue = GetInt32OfTInt(value);
4320                 Branch(Int32Equal(intValue, Int32(0)), &returnFalse, &returnTrue);
4321             }
4322             Bind(&isDouble);
4323             {
4324                 auto doubleValue = GetDoubleOfTDouble(value);
4325                 Branch(DoubleIsNAN(doubleValue), &returnFalse, &notNan);
4326                 Bind(&notNan);
4327                 Branch(DoubleEqual(doubleValue, Double(0.0)), &returnFalse, &returnTrue);
4328             }
4329         }
4330     }
4331     Bind(&returnTrue);
4332     {
4333         result = TaggedTrue();
4334         Jump(&exit);
4335     }
4336     Bind(&returnFalse);
4337     {
4338         result = TaggedFalse();
4339         Jump(&exit);
4340     }
4341 
4342     Bind(&exit);
4343     auto ret = *result;
4344     env->SubCfgExit();
4345     return ret;
4346 }
4347 
FastDiv(GateRef left,GateRef right,ProfileOperation callback)4348 GateRef StubBuilder::FastDiv(GateRef left, GateRef right, ProfileOperation callback)
4349 {
4350     auto env = GetEnvironment();
4351     Label entry(env);
4352     env->SubCfgEntry(&entry);
4353     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4354     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4355     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4356     DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
4357     Label leftIsNumber(env);
4358     Label leftNotNumberOrRightNotNumber(env);
4359     Label leftIsNumberAndRightIsNumber(env);
4360     Label leftIsDoubleAndRightIsDouble(env);
4361     Label exit(env);
4362     Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
4363     Bind(&leftIsNumber);
4364     {
4365         Label rightIsNumber(env);
4366         Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
4367         Bind(&rightIsNumber);
4368         {
4369             Label leftIsInt(env);
4370             Label leftNotInt(env);
4371             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
4372             Bind(&leftIsInt);
4373             {
4374                 Label rightIsInt(env);
4375                 Label bailout(env);
4376                 Branch(TaggedIsInt(right), &rightIsInt, &bailout);
4377                 Bind(&rightIsInt);
4378                 {
4379                     result = FastIntDiv(left, right, &bailout, callback);
4380                     Jump(&exit);
4381                 }
4382                 Bind(&bailout);
4383                 {
4384                     curType = Int32(PGOSampleType::IntOverFlowType());
4385                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4386                     Jump(&leftIsNumberAndRightIsNumber);
4387                 }
4388             }
4389             Bind(&leftNotInt);
4390             {
4391                 curType = Int32(PGOSampleType::DoubleType());
4392                 doubleLeft = GetDoubleOfTDouble(left);
4393                 Jump(&leftIsNumberAndRightIsNumber);
4394             }
4395         }
4396     }
4397     Bind(&leftNotNumberOrRightNotNumber);
4398     {
4399         Jump(&exit);
4400     }
4401     Bind(&leftIsNumberAndRightIsNumber);
4402     {
4403         Label rightIsInt(env);
4404         Label rightNotInt(env);
4405         Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
4406         Bind(&rightIsInt);
4407         {
4408             GateRef type = Int32(PGOSampleType::IntType());
4409             COMBINE_TYPE_CALL_BACK(curType, type);
4410             doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4411             Jump(&leftIsDoubleAndRightIsDouble);
4412         }
4413         Bind(&rightNotInt);
4414         {
4415             GateRef type = Int32(PGOSampleType::DoubleType());
4416             COMBINE_TYPE_CALL_BACK(curType, type);
4417             doubleRight = GetDoubleOfTDouble(right);
4418             Jump(&leftIsDoubleAndRightIsDouble);
4419         }
4420     }
4421     Bind(&leftIsDoubleAndRightIsDouble);
4422     {
4423         Label rightIsZero(env);
4424         Label rightNotZero(env);
4425         Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZero, &rightNotZero);
4426         Bind(&rightIsZero);
4427         {
4428             Label leftIsZero(env);
4429             Label leftNotZero(env);
4430             Label leftIsZeroOrNan(env);
4431             Label leftNotZeroAndNotNan(env);
4432             Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZero, &leftNotZero);
4433             Bind(&leftIsZero);
4434             {
4435                 Jump(&leftIsZeroOrNan);
4436             }
4437             Bind(&leftNotZero);
4438             {
4439                 Label leftIsNan(env);
4440                 Branch(DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan);
4441                 Bind(&leftIsNan);
4442                 {
4443                     Jump(&leftIsZeroOrNan);
4444                 }
4445             }
4446             Bind(&leftIsZeroOrNan);
4447             {
4448                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
4449                 Jump(&exit);
4450             }
4451             Bind(&leftNotZeroAndNotNan);
4452             {
4453                 GateRef intLeftTmp = CastDoubleToInt64(*doubleLeft);
4454                 GateRef intRightTmp = CastDoubleToInt64(*doubleRight);
4455                 GateRef flagBit = Int64And(Int64Xor(intLeftTmp, intRightTmp), Int64(base::DOUBLE_SIGN_MASK));
4456                 GateRef tmpResult = Int64Xor(flagBit, CastDoubleToInt64(Double(base::POSITIVE_INFINITY)));
4457                 result = DoubleToTaggedDoublePtr(CastInt64ToFloat64(tmpResult));
4458                 Jump(&exit);
4459             }
4460         }
4461         Bind(&rightNotZero);
4462         {
4463             result = DoubleToTaggedDoublePtr(DoubleDiv(*doubleLeft, *doubleRight));
4464             Jump(&exit);
4465         }
4466     }
4467     Bind(&exit);
4468     auto ret = *result;
4469     env->SubCfgExit();
4470     return ret;
4471 }
4472 
FastBinaryOp(GateRef left,GateRef right,const BinaryOperation & intOp,const BinaryOperation & floatOp,ProfileOperation callback)4473 GateRef StubBuilder::FastBinaryOp(GateRef left, GateRef right,
4474                                   const BinaryOperation& intOp,
4475                                   const BinaryOperation& floatOp,
4476                                   ProfileOperation callback)
4477 {
4478     auto env = GetEnvironment();
4479     Label entry(env);
4480     env->SubCfgEntry(&entry);
4481     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4482     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4483     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4484 
4485     Label exit(env);
4486     Label doFloatOp(env);
4487     Label doIntOp(env);
4488     Label leftIsNumber(env);
4489     Label rightIsNumber(env);
4490     Label leftIsIntRightIsDouble(env);
4491     Label rightIsInt(env);
4492     Label rightIsDouble(env);
4493 
4494     Branch(TaggedIsNumber(left), &leftIsNumber, &exit);
4495     Bind(&leftIsNumber);
4496     {
4497         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4498         Bind(&rightIsNumber);
4499         {
4500             Label leftIsInt(env);
4501             Label leftIsDouble(env);
4502             Branch(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
4503             Bind(&leftIsInt);
4504             {
4505                 Branch(TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
4506                 Bind(&leftIsIntRightIsDouble);
4507                 {
4508                     callback.ProfileOpType(Int32(PGOSampleType::NumberType()));
4509                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4510                     doubleRight = GetDoubleOfTDouble(right);
4511                     Jump(&doFloatOp);
4512                 }
4513             }
4514             Bind(&leftIsDouble);
4515             {
4516                 Branch(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
4517                 Bind(&rightIsInt);
4518                 {
4519                     callback.ProfileOpType(Int32(PGOSampleType::NumberType()));
4520                     doubleLeft = GetDoubleOfTDouble(left);
4521                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4522                     Jump(&doFloatOp);
4523                 }
4524                 Bind(&rightIsDouble);
4525                 {
4526                     callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
4527                     doubleLeft = GetDoubleOfTDouble(left);
4528                     doubleRight = GetDoubleOfTDouble(right);
4529                     Jump(&doFloatOp);
4530                 }
4531             }
4532         }
4533     }
4534     Bind(&doIntOp);
4535     {
4536         result = intOp(env, left, right);
4537         Jump(&exit);
4538     }
4539     Bind(&doFloatOp);
4540     {
4541         result = floatOp(env, *doubleLeft, *doubleRight);
4542         Jump(&exit);
4543     }
4544     Bind(&exit);
4545     auto ret = *result;
4546     env->SubCfgExit();
4547     return ret;
4548 }
4549 
4550 template<OpCode Op>
FastAddSubAndMul(GateRef left,GateRef right,ProfileOperation callback)4551 GateRef StubBuilder::FastAddSubAndMul(GateRef left, GateRef right, ProfileOperation callback)
4552 {
4553     auto intOperation = [=](Environment *env, GateRef left, GateRef right) {
4554         Label entry(env);
4555         env->SubCfgEntry(&entry);
4556         DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4557         Label exit(env);
4558         Label overflow(env);
4559         Label notOverflow(env);
4560         auto res = BinaryOpWithOverflow<Op, MachineType::I32>(GetInt32OfTInt(left), GetInt32OfTInt(right));
4561         GateRef condition = env->GetBuilder()->ExtractValue(MachineType::I1, res, Int32(1));
4562         Branch(condition, &overflow, &notOverflow);
4563         Bind(&overflow);
4564         {
4565             auto doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4566             auto doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4567             auto ret = BinaryOp<Op, MachineType::F64>(doubleLeft, doubleRight);
4568             result = DoubleToTaggedDoublePtr(ret);
4569             callback.ProfileOpType(Int32(PGOSampleType::IntOverFlowType()));
4570             Jump(&exit);
4571         }
4572         Bind(&notOverflow);
4573         {
4574             res = env->GetBuilder()->ExtractValue(MachineType::I32, res, Int32(0));
4575             if (Op == OpCode::MUL) {
4576                 Label resultIsZero(env);
4577                 Label returnNegativeZero(env);
4578                 Label returnResult(env);
4579                 Branch(Int32Equal(res, Int32(0)), &resultIsZero, &returnResult);
4580                 Bind(&resultIsZero);
4581                 GateRef leftNegative = Int32LessThan(GetInt32OfTInt(left), Int32(0));
4582                 GateRef rightNegative = Int32LessThan(GetInt32OfTInt(right), Int32(0));
4583                 Branch(BoolOr(leftNegative, rightNegative), &returnNegativeZero, &returnResult);
4584                 Bind(&returnNegativeZero);
4585                 result = DoubleToTaggedDoublePtr(Double(-0.0));
4586                 callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
4587                 Jump(&exit);
4588                 Bind(&returnResult);
4589                 result = IntToTaggedPtr(res);
4590                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4591                 Jump(&exit);
4592             } else {
4593                 result = IntToTaggedPtr(res);
4594                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4595                 Jump(&exit);
4596             }
4597         }
4598         Bind(&exit);
4599         auto ret = *result;
4600         env->SubCfgExit();
4601         return ret;
4602     };
4603     auto floatOperation = [=]([[maybe_unused]] Environment *env, GateRef left, GateRef right) {
4604         auto res = BinaryOp<Op, MachineType::F64>(left, right);
4605         return DoubleToTaggedDoublePtr(res);
4606     };
4607     return FastBinaryOp(left, right, intOperation, floatOperation, callback);
4608 }
4609 
FastIntDiv(GateRef left,GateRef right,Label * bailout,ProfileOperation callback)4610 GateRef StubBuilder::FastIntDiv(GateRef left, GateRef right, Label *bailout, ProfileOperation callback)
4611 {
4612     auto env = GetEnvironment();
4613     Label entry(env);
4614     env->SubCfgEntry(&entry);
4615     DEFVARIABLE(intResult, VariableType::INT32(), Int32(0));
4616 
4617     GateRef intLeft = GetInt32OfTInt(left);
4618     GateRef intRight = GetInt32OfTInt(right);
4619     Label exit(env);
4620     Label rightIsNotZero(env);
4621     Branch(Int32Equal(intRight, Int32(0)), bailout, &rightIsNotZero);
4622     Bind(&rightIsNotZero);
4623     {
4624         Label leftIsZero(env);
4625         Label leftIsNotZero(env);
4626         Branch(Int32Equal(intLeft, Int32(0)), &leftIsZero, &leftIsNotZero);
4627         Bind(&leftIsZero);
4628         {
4629             Branch(Int32LessThan(intRight, Int32(0)), bailout, &leftIsNotZero);
4630         }
4631         Bind(&leftIsNotZero);
4632         {
4633             intResult = Int32Div(intLeft, intRight);
4634             GateRef truncated = Int32Mul(*intResult, intRight);
4635             Branch(Equal(intLeft, truncated), &exit, bailout);
4636         }
4637     }
4638     Bind(&exit);
4639     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4640     auto ret = IntToTaggedPtr(*intResult);
4641     env->SubCfgExit();
4642     return ret;
4643 }
4644 
FastAdd(GateRef left,GateRef right,ProfileOperation callback)4645 GateRef StubBuilder::FastAdd(GateRef left, GateRef right, ProfileOperation callback)
4646 {
4647     return FastAddSubAndMul<OpCode::ADD>(left, right, callback);
4648 }
4649 
FastSub(GateRef left,GateRef right,ProfileOperation callback)4650 GateRef StubBuilder::FastSub(GateRef left, GateRef right, ProfileOperation callback)
4651 {
4652     return FastAddSubAndMul<OpCode::SUB>(left, right, callback);
4653 }
4654 
FastMul(GateRef left,GateRef right,ProfileOperation callback)4655 GateRef StubBuilder::FastMul(GateRef left, GateRef right, ProfileOperation callback)
4656 {
4657     return FastAddSubAndMul<OpCode::MUL>(left, right, callback);
4658 }
4659 
FastMod(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)4660 GateRef StubBuilder::FastMod(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
4661 {
4662     auto env = GetEnvironment();
4663     Label entry(env);
4664     env->SubCfgEntry(&entry);
4665     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4666     DEFVARIABLE(intLeft, VariableType::INT32(), Int32(0));
4667     DEFVARIABLE(intRight, VariableType::INT32(), Int32(0));
4668     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4669     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4670     Label leftIsInt(env);
4671     Label leftNotIntOrRightNotInt(env);
4672     Label exit(env);
4673     Branch(TaggedIsInt(left), &leftIsInt, &leftNotIntOrRightNotInt);
4674     Bind(&leftIsInt);
4675     {
4676         Label rightIsInt(env);
4677         Branch(TaggedIsInt(right), &rightIsInt, &leftNotIntOrRightNotInt);
4678         Bind(&rightIsInt);
4679         {
4680             intLeft = GetInt32OfTInt(left);
4681             intRight = GetInt32OfTInt(right);
4682             Label leftGreaterZero(env);
4683             Branch(Int32GreaterThanOrEqual(*intLeft, Int32(0)), &leftGreaterZero, &leftNotIntOrRightNotInt);
4684             Bind(&leftGreaterZero);
4685             {
4686                 Label rightGreaterZero(env);
4687                 Branch(Int32GreaterThan(*intRight, Int32(0)), &rightGreaterZero, &leftNotIntOrRightNotInt);
4688                 Bind(&rightGreaterZero);
4689                 {
4690                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4691                     result = IntToTaggedPtr(Int32Mod(*intLeft, *intRight));
4692                     Jump(&exit);
4693                 }
4694             }
4695         }
4696     }
4697     Bind(&leftNotIntOrRightNotInt);
4698     {
4699         Label leftIsNumber(env);
4700         Label leftNotNumberOrRightNotNumber(env);
4701         Label leftIsNumberAndRightIsNumber(env);
4702         Label leftIsDoubleAndRightIsDouble(env);
4703         DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
4704         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
4705         Bind(&leftIsNumber);
4706         {
4707             Label rightIsNumber(env);
4708             Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
4709             Bind(&rightIsNumber);
4710             {
4711                 Label leftIsInt1(env);
4712                 Label leftNotInt1(env);
4713                 Branch(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
4714                 Bind(&leftIsInt1);
4715                 {
4716                     curType = Int32(PGOSampleType::IntType());
4717                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4718                     Jump(&leftIsNumberAndRightIsNumber);
4719                 }
4720                 Bind(&leftNotInt1);
4721                 {
4722                     curType = Int32(PGOSampleType::DoubleType());
4723                     doubleLeft = GetDoubleOfTDouble(left);
4724                     Jump(&leftIsNumberAndRightIsNumber);
4725                 }
4726             }
4727         }
4728         Bind(&leftNotNumberOrRightNotNumber);
4729         {
4730             Jump(&exit);
4731         }
4732         Bind(&leftIsNumberAndRightIsNumber);
4733         {
4734             Label rightIsInt1(env);
4735             Label rightNotInt1(env);
4736             Branch(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
4737             Bind(&rightIsInt1);
4738             {
4739                 GateRef type = Int32(PGOSampleType::IntType());
4740                 COMBINE_TYPE_CALL_BACK(curType, type);
4741                 doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4742                 Jump(&leftIsDoubleAndRightIsDouble);
4743             }
4744             Bind(&rightNotInt1);
4745             {
4746                 GateRef type = Int32(PGOSampleType::DoubleType());
4747                 COMBINE_TYPE_CALL_BACK(curType, type);
4748                 doubleRight = GetDoubleOfTDouble(right);
4749                 Jump(&leftIsDoubleAndRightIsDouble);
4750             }
4751         }
4752         Bind(&leftIsDoubleAndRightIsDouble);
4753         {
4754             Label rightNotZero(env);
4755             Label rightIsZeroOrNanOrLeftIsNanOrInf(env);
4756             Label rightNotZeroAndNanAndLeftNotNanAndInf(env);
4757             Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotZero);
4758             Bind(&rightNotZero);
4759             {
4760                 Label rightNotNan(env);
4761                 Branch(DoubleIsNAN(*doubleRight), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotNan);
4762                 Bind(&rightNotNan);
4763                 {
4764                     Label leftNotNan(env);
4765                     Branch(DoubleIsNAN(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &leftNotNan);
4766                     Bind(&leftNotNan);
4767                     {
4768                         Branch(DoubleIsINF(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf,
4769                             &rightNotZeroAndNanAndLeftNotNanAndInf);
4770                     }
4771                 }
4772             }
4773             Bind(&rightIsZeroOrNanOrLeftIsNanOrInf);
4774             {
4775                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
4776                 Jump(&exit);
4777             }
4778             Bind(&rightNotZeroAndNanAndLeftNotNanAndInf);
4779             {
4780                 Label leftNotZero(env);
4781                 Label leftIsZeroOrRightIsInf(env);
4782                 Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZeroOrRightIsInf, &leftNotZero);
4783                 Bind(&leftNotZero);
4784                 {
4785                     Label rightNotInf(env);
4786                     Branch(DoubleIsINF(*doubleRight), &leftIsZeroOrRightIsInf, &rightNotInf);
4787                     Bind(&rightNotInf);
4788                     {
4789                         result = DoubleToTaggedDoublePtr(CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
4790                             { *doubleLeft, *doubleRight }));
4791                         Jump(&exit);
4792                     }
4793                 }
4794                 Bind(&leftIsZeroOrRightIsInf);
4795                 {
4796                     result = DoubleToTaggedDoublePtr(*doubleLeft);
4797                     Jump(&exit);
4798                 }
4799             }
4800         }
4801     }
4802     Bind(&exit);
4803     auto ret = *result;
4804     env->SubCfgExit();
4805     return ret;
4806 }
4807 
GetGlobalOwnProperty(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback)4808 GateRef StubBuilder::GetGlobalOwnProperty(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
4809 {
4810     auto env = GetEnvironment();
4811     Label entryLabel(env);
4812     env->SubCfgEntry(&entryLabel);
4813     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4814     GateRef properties = GetPropertiesFromJSObject(receiver);
4815     GateRef entry = FindEntryFromNameDictionary(glue, properties, key);
4816     Label notNegtiveOne(env);
4817     Label exit(env);
4818     Branch(Int32NotEqual(entry, Int32(-1)), &notNegtiveOne, &exit);
4819     Bind(&notNegtiveOne);
4820     {
4821         result = GetValueFromGlobalDictionary(properties, entry);
4822         Label callGetter(env);
4823         Branch(TaggedIsAccessor(*result), &callGetter, &exit);
4824         Bind(&callGetter);
4825         {
4826             result = CallGetterHelper(glue, receiver, receiver, *result, callback);
4827             Jump(&exit);
4828         }
4829     }
4830     Bind(&exit);
4831     auto ret = *result;
4832     env->SubCfgExit();
4833     return ret;
4834 }
4835 
GetConstPoolFromFunction(GateRef jsFunc)4836 GateRef StubBuilder::GetConstPoolFromFunction(GateRef jsFunc)
4837 {
4838     return env_->GetBuilder()->GetConstPoolFromFunction(jsFunc);
4839 }
4840 
GetStringFromConstPool(GateRef glue,GateRef constpool,GateRef index)4841 GateRef StubBuilder::GetStringFromConstPool(GateRef glue, GateRef constpool, GateRef index)
4842 {
4843     GateRef module = Circuit::NullGate();
4844     GateRef hirGate = Circuit::NullGate();
4845     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::STRING);
4846 }
4847 
GetMethodFromConstPool(GateRef glue,GateRef constpool,GateRef index)4848 GateRef StubBuilder::GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index)
4849 {
4850     GateRef module = Circuit::NullGate();
4851     GateRef hirGate = Circuit::NullGate();
4852     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::METHOD);
4853 }
4854 
GetArrayLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)4855 GateRef StubBuilder::GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
4856 {
4857     GateRef hirGate = Circuit::NullGate();
4858     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index,
4859                                                       ConstPoolType::ARRAY_LITERAL);
4860 }
4861 
GetObjectLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)4862 GateRef StubBuilder::GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
4863 {
4864     GateRef hirGate = Circuit::NullGate();
4865     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index,
4866                                                       ConstPoolType::OBJECT_LITERAL);
4867 }
4868 
4869 // return elements
BuildArgumentsListFastElements(GateRef glue,GateRef arrayObj)4870 GateRef StubBuilder::BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj)
4871 {
4872     auto env = GetEnvironment();
4873     Label subentry(env);
4874     env->SubCfgEntry(&subentry);
4875     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
4876     Label exit(env);
4877     Label hasStableElements(env);
4878     Label targetIsStableJSArguments(env);
4879     Label targetNotStableJSArguments(env);
4880     Label targetIsInt(env);
4881     Label hClassEqual(env);
4882     Label targetIsStableJSArray(env);
4883     Label targetNotStableJSArray(env);
4884 
4885     Branch(HasStableElements(glue, arrayObj), &hasStableElements, &exit);
4886     Bind(&hasStableElements);
4887     {
4888         Branch(IsStableJSArguments(glue, arrayObj), &targetIsStableJSArguments, &targetNotStableJSArguments);
4889         Bind(&targetIsStableJSArguments);
4890         {
4891             GateRef hClass = LoadHClass(arrayObj);
4892             GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
4893             GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
4894             GateRef argmentsClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
4895                                                       GlobalEnv::ARGUMENTS_CLASS);
4896             Branch(Int32Equal(hClass, argmentsClass), &hClassEqual, &exit);
4897             Bind(&hClassEqual);
4898             {
4899                 GateRef PropertyInlinedPropsOffset = IntPtr(JSArguments::LENGTH_INLINE_PROPERTY_INDEX);
4900                 GateRef result = GetPropertyInlinedProps(arrayObj, hClass, PropertyInlinedPropsOffset);
4901                 Branch(TaggedIsInt(result), &targetIsInt, &exit);
4902                 Bind(&targetIsInt);
4903                 {
4904                     res = GetElementsArray(arrayObj);
4905                     Jump(&exit);
4906                 }
4907             }
4908         }
4909         Bind(&targetNotStableJSArguments);
4910         {
4911             Branch(IsStableJSArray(glue, arrayObj), &targetIsStableJSArray, &targetNotStableJSArray);
4912             Bind(&targetIsStableJSArray);
4913             {
4914                 res = GetElementsArray(arrayObj);
4915                 Jump(&exit);
4916             }
4917             Bind(&targetNotStableJSArray);
4918             {
4919                 FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
4920                 Jump(&exit);
4921             }
4922         }
4923     }
4924     Bind(&exit);
4925     auto ret = *res;
4926     env->SubCfgExit();
4927     return ret;
4928 }
4929 
MakeArgListWithHole(GateRef glue,GateRef argv,GateRef length)4930 GateRef StubBuilder::MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length)
4931 {
4932     auto env = GetEnvironment();
4933     Label subentry(env);
4934     env->SubCfgEntry(&subentry);
4935     DEFVARIABLE(res, VariableType::INT32(), length);
4936     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
4937     Label exit(env);
4938 
4939     GateRef argsLength = GetLengthOfTaggedArray(argv);
4940 
4941     Label lengthGreaterThanArgsLength(env);
4942     Label lengthLessThanArgsLength(env);
4943     Branch(Int32GreaterThan(length, argsLength), &lengthGreaterThanArgsLength, &lengthLessThanArgsLength);
4944     Bind(&lengthGreaterThanArgsLength);
4945     {
4946         res = argsLength;
4947         Jump(&lengthLessThanArgsLength);
4948     }
4949     Bind(&lengthLessThanArgsLength);
4950     {
4951         Label loopHead(env);
4952         Label loopEnd(env);
4953         Label afterLoop(env);
4954         Label targetIsHole(env);
4955         Label targetNotHole(env);
4956         Branch(Int32UnsignedLessThan(*i, *res), &loopHead, &afterLoop);
4957         LoopBegin(&loopHead);
4958         {
4959             GateRef value = GetValueFromTaggedArray(argv, *i);
4960             Branch(TaggedIsHole(value), &targetIsHole, &targetNotHole);
4961             Bind(&targetIsHole);
4962             {
4963                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argv, *i, Undefined());
4964                 Jump(&targetNotHole);
4965             }
4966             Bind(&targetNotHole);
4967             i = Int32Add(*i, Int32(1));
4968             Branch(Int32UnsignedLessThan(*i, *res), &loopEnd, &afterLoop);
4969         }
4970         Bind(&loopEnd);
4971         LoopEnd(&loopHead);
4972         Bind(&afterLoop);
4973         {
4974             res = length;
4975             Jump(&exit);
4976         }
4977     }
4978     Bind(&exit);
4979     auto ret = *res;
4980     env->SubCfgExit();
4981     return ret;
4982 }
4983 
JSAPIContainerGet(GateRef glue,GateRef receiver,GateRef index)4984 GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index)
4985 {
4986     auto env = GetEnvironment();
4987     Label entry(env);
4988     env->SubCfgEntry(&entry);
4989     Label exit(env);
4990     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4991 
4992     GateRef lengthOffset = IntPtr(panda::ecmascript::JSAPIArrayList::LENGTH_OFFSET);
4993     GateRef length = GetInt32OfTInt(Load(VariableType::INT64(), receiver, lengthOffset));
4994     Label isVailedIndex(env);
4995     Label notValidIndex(env);
4996     Branch(BoolAnd(Int32GreaterThanOrEqual(index, Int32(0)),
4997         Int32UnsignedLessThan(index, length)), &isVailedIndex, &notValidIndex);
4998     Bind(&isVailedIndex);
4999     {
5000         GateRef elements = GetElementsArray(receiver);
5001         result = GetValueFromTaggedArray(elements, index);
5002         Jump(&exit);
5003     }
5004     Bind(&notValidIndex);
5005     {
5006         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(GetPropertyOutOfBounds));
5007         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
5008         result = Exception();
5009         Jump(&exit);
5010     }
5011 
5012     Bind(&exit);
5013     auto ret = *result;
5014     env->SubCfgExit();
5015     return ret;
5016 }
5017 
DoubleToInt(GateRef glue,GateRef x)5018 GateRef StubBuilder::DoubleToInt(GateRef glue, GateRef x)
5019 {
5020     auto env = GetEnvironment();
5021     Label entry(env);
5022     env->SubCfgEntry(&entry);
5023     Label exit(env);
5024     Label overflow(env);
5025 
5026     GateRef xInt = ChangeFloat64ToInt32(x);
5027     DEFVARIABLE(result, VariableType::INT32(), xInt);
5028 
5029     if (env->IsAmd64()) {
5030         // 0x80000000: amd64 overflow return value
5031         Branch(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit);
5032     } else {
5033         GateRef xInt64 = CastDoubleToInt64(x);
5034         // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
5035         GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
5036         exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
5037         exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
5038         GateRef bits = Int32(base::INT32_BITS - 1);
5039         // exp < 32 - 1
5040         Branch(Int32LessThan(exp, bits), &exit, &overflow);
5041     }
5042     Bind(&overflow);
5043     {
5044         result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), { x });
5045         Jump(&exit);
5046     }
5047     Bind(&exit);
5048     auto ret = *result;
5049     env->SubCfgExit();
5050     return ret;
5051 }
5052 
ReturnExceptionIfAbruptCompletion(GateRef glue)5053 void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue)
5054 {
5055     auto env = GetEnvironment();
5056     Label entry(env);
5057     env->SubCfgEntry(&entry);
5058     Label exit(env);
5059     Label hasPendingException(env);
5060     GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env->IsArch32Bit()));
5061     GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset);
5062     Branch(TaggedIsNotHole(exception), &hasPendingException, &exit);
5063     Bind(&hasPendingException);
5064     Return(Exception());
5065     Bind(&exit);
5066     env->SubCfgExit();
5067     return;
5068 }
5069 
GetHashcodeFromString(GateRef glue,GateRef value)5070 GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
5071 {
5072     auto env = GetEnvironment();
5073     Label subentry(env);
5074     env->SubCfgEntry(&subentry);
5075     Label noRawHashcode(env);
5076     Label exit(env);
5077     DEFVARIABLE(hashcode, VariableType::INT32(), Int32(0));
5078     hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::HASHCODE_OFFSET));
5079     Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
5080     Bind(&noRawHashcode);
5081     {
5082         hashcode = GetInt32OfTInt(CallRuntime(glue, RTSTUB_ID(ComputeHashcode), { value }));
5083         Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
5084         Jump(&exit);
5085     }
5086     Bind(&exit);
5087     auto ret = *hashcode;
5088     env->SubCfgExit();
5089     return ret;
5090 }
5091 
ConstructorCheck(GateRef glue,GateRef ctor,GateRef outPut,GateRef thisObj)5092 GateRef StubBuilder::ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut, GateRef thisObj)
5093 {
5094     auto env = GetEnvironment();
5095     Label entryPass(env);
5096     Label exit(env);
5097     env->SubCfgEntry(&entryPass);
5098     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
5099     Label isHeapObject(env);
5100     Label isEcmaObj(env);
5101     Label notEcmaObj(env);
5102     Branch(TaggedIsHeapObject(outPut), &isHeapObject, &notEcmaObj);
5103     Bind(&isHeapObject);
5104     Branch(TaggedObjectIsEcmaObject(outPut), &isEcmaObj, &notEcmaObj);
5105     Bind(&isEcmaObj);
5106     {
5107         result = outPut;
5108         Jump(&exit);
5109     }
5110     Bind(&notEcmaObj);
5111     {
5112         Label ctorIsBase(env);
5113         Label ctorNotBase(env);
5114         Branch(IsBase(ctor), &ctorIsBase, &ctorNotBase);
5115         Bind(&ctorIsBase);
5116         {
5117             result = thisObj;
5118             Jump(&exit);
5119         }
5120         Bind(&ctorNotBase);
5121         {
5122             Label throwExeption(env);
5123             Label returnObj(env);
5124             Branch(TaggedIsUndefined(outPut), &returnObj, &throwExeption);
5125             Bind(&returnObj);
5126             result = thisObj;
5127             Jump(&exit);
5128             Bind(&throwExeption);
5129             {
5130                 CallRuntime(glue, RTSTUB_ID(ThrowNonConstructorException), {});
5131                 Jump(&exit);
5132             }
5133         }
5134     }
5135     Bind(&exit);
5136     auto ret = *result;
5137     env->SubCfgExit();
5138     return ret;
5139 }
5140 
JSCallDispatch(GateRef glue,GateRef func,GateRef actualNumArgs,GateRef jumpSize,GateRef hotnessCounter,JSCallMode mode,std::initializer_list<GateRef> args,ProfileOperation callback)5141 GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize,
5142                                     GateRef hotnessCounter, JSCallMode mode, std::initializer_list<GateRef> args,
5143                                     ProfileOperation callback)
5144 {
5145     auto env = GetEnvironment();
5146     Label entryPass(env);
5147     Label exit(env);
5148     env->SubCfgEntry(&entryPass);
5149     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
5150     // 1. call initialize
5151     Label funcIsHeapObject(env);
5152     Label funcIsCallable(env);
5153     Label funcNotCallable(env);
5154     // save pc
5155     SavePcIfNeeded(glue);
5156     GateRef bitfield = 0;
5157 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
5158     CallNGCRuntime(glue, RTSTUB_ID(StartCallTimer), { glue, func, False()});
5159 #endif
5160     Branch(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable);
5161     Bind(&funcIsHeapObject);
5162     GateRef hclass = LoadHClass(func);
5163     bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
5164     Branch(IsCallableFromBitField(bitfield), &funcIsCallable, &funcNotCallable);
5165     Bind(&funcNotCallable);
5166     {
5167         CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {});
5168         Jump(&exit);
5169     }
5170     Bind(&funcIsCallable);
5171     GateRef method = GetMethodFromJSFunction(func);
5172     GateRef callField = GetCallFieldFromMethod(method);
5173     GateRef isNativeMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsNativeBit::START_BIT);
5174 
5175     // 2. call dispatch
5176     Label methodIsNative(env);
5177     Label methodNotNative(env);
5178     Branch(Int64NotEqual(Int64And(callField, isNativeMask), Int64(0)), &methodIsNative, &methodNotNative);
5179     auto data = std::begin(args);
5180     Label notFastBuiltinsArg0(env);
5181     Label notFastBuiltinsArg1(env);
5182     Label notFastBuiltinsArg2(env);
5183     Label notFastBuiltinsArg3(env);
5184     Label notFastBuiltins(env);
5185     // 3. call native
5186     Bind(&methodIsNative);
5187     {
5188         GateRef nativeCode = Load(VariableType::NATIVE_POINTER(), method,
5189             IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
5190         GateRef newTarget = Undefined();
5191         GateRef thisValue = Undefined();
5192         GateRef numArgs = Int32Add(actualNumArgs, Int32(NUM_MANDATORY_JSFUNC_ARGS));
5193         switch (mode) {
5194             case JSCallMode::CALL_THIS_ARG0: {
5195                 thisValue = data[0];
5196                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5197                     method, &notFastBuiltinsArg0, &exit, &result, args, mode);
5198                 Bind(&notFastBuiltinsArg0);
5199                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5200                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
5201                 break;
5202             }
5203             case JSCallMode::CALL_ARG0:
5204             case JSCallMode::DEPRECATED_CALL_ARG0:
5205                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5206                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
5207                 break;
5208             case JSCallMode::CALL_THIS_ARG1: {
5209                 thisValue = data[1];
5210                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5211                     method, &notFastBuiltinsArg1, &exit, &result, args, mode);
5212                 Bind(&notFastBuiltinsArg1);
5213                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5214                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
5215                 break;
5216             }
5217             case JSCallMode::CALL_ARG1:
5218             case JSCallMode::DEPRECATED_CALL_ARG1:
5219                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5220                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
5221                 break;
5222             case JSCallMode::CALL_THIS_ARG2: {
5223                 thisValue = data[2];
5224                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5225                     method, &notFastBuiltinsArg2, &exit, &result, args, mode);
5226                 Bind(&notFastBuiltinsArg2);
5227                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5228                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
5229                 break;
5230             }
5231             case JSCallMode::CALL_ARG2:
5232             case JSCallMode::DEPRECATED_CALL_ARG2:
5233                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5234                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
5235                 break;
5236             case JSCallMode::CALL_THIS_ARG3: {
5237                 thisValue = data[3];
5238                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5239                     method, &notFastBuiltinsArg3, &exit, &result, args, mode);
5240                 Bind(&notFastBuiltinsArg3);
5241                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5242                     { nativeCode, glue, numArgs, func,
5243                         newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
5244                 break;
5245             }
5246             case JSCallMode::CALL_ARG3:
5247             case JSCallMode::DEPRECATED_CALL_ARG3:
5248                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5249                     { nativeCode, glue, numArgs, func,
5250                       newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
5251                 break;
5252             case JSCallMode::CALL_THIS_WITH_ARGV:
5253             case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5254             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV: {
5255                 thisValue = data[2]; // 2: this input
5256                 [[fallthrough]];
5257             }
5258             case JSCallMode::CALL_WITH_ARGV:
5259             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5260                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatchNative),
5261                     { glue, nativeCode, func, thisValue, data[0], data[1] });
5262                 break;
5263             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5264             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV: {
5265                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5266                     method, &notFastBuiltins, &exit, &result, args, mode);
5267                 Bind(&notFastBuiltins);
5268                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatchNative),
5269                     { glue, nativeCode, func, data[2], data[0], data[1] });
5270                 break;
5271             }
5272             case JSCallMode::CALL_GETTER:
5273                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5274                     { nativeCode, glue, numArgs, func, newTarget, data[0] });
5275                 break;
5276             case JSCallMode::CALL_SETTER:
5277                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5278                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1] });
5279                 break;
5280             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5281                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5282                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5283                 break;
5284             default:
5285                 LOG_ECMA(FATAL) << "this branch is unreachable";
5286                 UNREACHABLE();
5287         }
5288         Jump(&exit);
5289     }
5290     // 4. call nonNative
5291     Bind(&methodNotNative);
5292 
5293     callback.ProfileCall(func);
5294     Label funcIsClassConstructor(env);
5295     Label funcNotClassConstructor(env);
5296     Label methodNotAot(env);
5297     if (!AssemblerModule::IsCallNew(mode)) {
5298         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &funcNotClassConstructor);
5299         Bind(&funcIsClassConstructor);
5300         {
5301             CallRuntime(glue, RTSTUB_ID(ThrowCallConstructorException), {});
5302             Jump(&exit);
5303         }
5304         Bind(&funcNotClassConstructor);
5305     } else {
5306         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &methodNotAot);
5307         Bind(&funcIsClassConstructor);
5308     }
5309     GateRef sp = 0;
5310     if (env->IsAsmInterp()) {
5311         sp = Argument(static_cast<size_t>(InterpreterHandlerInputs::SP));
5312     }
5313     Label methodisAot(env);
5314     Label methodIsFastCall(env);
5315     Label methodNotFastCall(env);
5316     Label fastCall(env);
5317     Label fastCallBridge(env);
5318     Label slowCall(env);
5319     Label slowCallBridge(env);
5320     {
5321         GateRef newTarget = Undefined();
5322         GateRef thisValue = Undefined();
5323         GateRef realNumArgs = Int64Add(ZExtInt32ToInt64(actualNumArgs), Int64(NUM_MANDATORY_JSFUNC_ARGS));
5324         Branch(CanFastCallWithBitField(bitfield), &methodIsFastCall, &methodNotFastCall);
5325         Bind(&methodIsFastCall);
5326         {
5327             GateRef expectedNum = Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
5328                 Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
5329             GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
5330             Branch(Int64LessThanOrEqual(expectedArgc, realNumArgs), &fastCall, &fastCallBridge);
5331             Bind(&fastCall);
5332             {
5333                 GateRef code = GetAotCodeAddr(method);
5334                 switch (mode) {
5335                     case JSCallMode::CALL_THIS_ARG0:
5336                         thisValue = data[0];
5337                         [[fallthrough]];
5338                     case JSCallMode::CALL_ARG0:
5339                     case JSCallMode::DEPRECATED_CALL_ARG0:
5340                         result = FastCallOptimized(glue, code, { glue, func, thisValue});
5341                         Jump(&exit);
5342                         break;
5343                     case JSCallMode::CALL_THIS_ARG1:
5344                         thisValue = data[1];
5345                         [[fallthrough]];
5346                     case JSCallMode::CALL_ARG1:
5347                     case JSCallMode::DEPRECATED_CALL_ARG1:
5348                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0] });
5349                         Jump(&exit);
5350                         break;
5351                     case JSCallMode::CALL_THIS_ARG2:
5352                         thisValue = data[2];
5353                         [[fallthrough]];
5354                     case JSCallMode::CALL_ARG2:
5355                     case JSCallMode::DEPRECATED_CALL_ARG2:
5356                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0], data[1] });
5357                         Jump(&exit);
5358                         break;
5359                     case JSCallMode::CALL_THIS_ARG3:
5360                         thisValue = data[3];
5361                         [[fallthrough]];
5362                     case JSCallMode::CALL_ARG3:
5363                     case JSCallMode::DEPRECATED_CALL_ARG3:
5364                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0], data[1], data[2] });
5365                         Jump(&exit);
5366                         break;
5367                     case JSCallMode::CALL_THIS_WITH_ARGV:
5368                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5369                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5370                         thisValue = data[2]; // 2: this input
5371                         [[fallthrough]];
5372                     case JSCallMode::CALL_WITH_ARGV:
5373                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5374                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgV),
5375                             { glue, func, thisValue, ZExtInt32ToInt64(actualNumArgs), data[1] });
5376                         Jump(&exit);
5377                         break;
5378                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5379                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5380                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgV),
5381                             { glue, func, data[2], ZExtInt32ToInt64(actualNumArgs), data[1]});
5382                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5383                         Jump(&exit);
5384                         break;
5385                     case JSCallMode::CALL_GETTER:
5386                         result = FastCallOptimized(glue, code, { glue, func, data[0] });
5387                         Jump(&exit);
5388                         break;
5389                     case JSCallMode::CALL_SETTER:
5390                         result = FastCallOptimized(glue, code, { glue, func, data[0], data[1] });
5391                         Jump(&exit);
5392                         break;
5393                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5394                         result = FastCallOptimized(glue, code, { glue, func, data[0], data[1], data[2], data[3] });
5395                         Jump(&exit);
5396                         break;
5397                     default:
5398                         LOG_ECMA(FATAL) << "this branch is unreachable";
5399                         UNREACHABLE();
5400                 }
5401             }
5402             Bind(&fastCallBridge);
5403             {
5404                 switch (mode) {
5405                     case JSCallMode::CALL_THIS_ARG0:
5406                         thisValue = data[0];
5407                         [[fallthrough]];
5408                     case JSCallMode::CALL_ARG0:
5409                     case JSCallMode::DEPRECATED_CALL_ARG0:
5410                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5411                             { glue, realNumArgs, func, newTarget, thisValue});
5412                         Jump(&exit);
5413                         break;
5414                     case JSCallMode::CALL_THIS_ARG1:
5415                         thisValue = data[1];
5416                         [[fallthrough]];
5417                     case JSCallMode::CALL_ARG1:
5418                     case JSCallMode::DEPRECATED_CALL_ARG1:
5419                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5420                             { glue, realNumArgs, func, newTarget, thisValue, data[0] });
5421                         Jump(&exit);
5422                         break;
5423                     case JSCallMode::CALL_THIS_ARG2:
5424                         thisValue = data[2];
5425                         [[fallthrough]];
5426                     case JSCallMode::CALL_ARG2:
5427                     case JSCallMode::DEPRECATED_CALL_ARG2:
5428                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5429                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
5430                         Jump(&exit);
5431                         break;
5432                     case JSCallMode::CALL_THIS_ARG3:
5433                         thisValue = data[3];
5434                         [[fallthrough]];
5435                     case JSCallMode::CALL_ARG3:
5436                     case JSCallMode::DEPRECATED_CALL_ARG3:
5437                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5438                             { glue, realNumArgs, func, newTarget, thisValue,
5439                             data[0], data[1], data[2] }); // 2: args2
5440                         Jump(&exit);
5441                         break;
5442                     case JSCallMode::CALL_THIS_WITH_ARGV:
5443                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5444                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5445                         thisValue = data[2]; // 2: this input
5446                         [[fallthrough]];
5447                     case JSCallMode::CALL_WITH_ARGV:
5448                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5449                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgVAndPushUndefined),
5450                             { glue, func, thisValue, ZExtInt32ToInt64(actualNumArgs), data[1], expectedNum });
5451                         Jump(&exit);
5452                         break;
5453                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5454                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5455                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgVAndPushUndefined),
5456                             { glue, func, data[2], ZExtInt32ToInt64(actualNumArgs), data[1], expectedNum });
5457                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5458                         Jump(&exit);
5459                         break;
5460                     case JSCallMode::CALL_GETTER:
5461                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5462                             { glue, realNumArgs, func, newTarget, data[0]});
5463                         Jump(&exit);
5464                         break;
5465                     case JSCallMode::CALL_SETTER:
5466                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5467                             { glue, realNumArgs, func, newTarget, data[0], data[1]});
5468                         Jump(&exit);
5469                         break;
5470                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5471                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5472                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5473                         Jump(&exit);
5474                         break;
5475                     default:
5476                         LOG_ECMA(FATAL) << "this branch is unreachable";
5477                         UNREACHABLE();
5478                 }
5479             }
5480         }
5481 
5482         Bind(&methodNotFastCall);
5483         Branch(IsOptimizedWithBitField(bitfield), &methodisAot, &methodNotAot);
5484         Bind(&methodisAot);
5485         {
5486             GateRef expectedNum = Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
5487                 Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
5488             GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
5489             Branch(Int64LessThanOrEqual(expectedArgc, realNumArgs), &slowCall, &slowCallBridge);
5490             Bind(&slowCall);
5491             {
5492                 GateRef code = GetAotCodeAddr(method);
5493                 switch (mode) {
5494                     case JSCallMode::CALL_THIS_ARG0:
5495                         thisValue = data[0];
5496                         [[fallthrough]];
5497                     case JSCallMode::CALL_ARG0:
5498                     case JSCallMode::DEPRECATED_CALL_ARG0:
5499                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue });
5500                         Jump(&exit);
5501                         break;
5502                     case JSCallMode::CALL_THIS_ARG1:
5503                         thisValue = data[1];
5504                         [[fallthrough]];
5505                     case JSCallMode::CALL_ARG1:
5506                     case JSCallMode::DEPRECATED_CALL_ARG1:
5507                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue, data[0] });
5508                         Jump(&exit);
5509                         break;
5510                     case JSCallMode::CALL_THIS_ARG2:
5511                         thisValue = data[2];
5512                         [[fallthrough]];
5513                     case JSCallMode::CALL_ARG2:
5514                     case JSCallMode::DEPRECATED_CALL_ARG2:
5515                         result = CallOptimized(glue, code,
5516                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
5517                         Jump(&exit);
5518                         break;
5519                     case JSCallMode::CALL_THIS_ARG3:
5520                         thisValue = data[3];
5521                         [[fallthrough]];
5522                     case JSCallMode::CALL_ARG3:
5523                     case JSCallMode::DEPRECATED_CALL_ARG3:
5524                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue,
5525                             data[0], data[1], data[2] });
5526                         Jump(&exit);
5527                         break;
5528                     case JSCallMode::CALL_THIS_WITH_ARGV:
5529                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5530                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5531                         thisValue = data[2]; // 2: this input
5532                         [[fallthrough]];
5533                     case JSCallMode::CALL_WITH_ARGV:
5534                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5535                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
5536                             { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
5537                         Jump(&exit);
5538                         break;
5539                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5540                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5541                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
5542                             { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
5543                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5544                         Jump(&exit);
5545                         break;
5546                     case JSCallMode::CALL_GETTER:
5547                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, data[0] });
5548                         Jump(&exit);
5549                         break;
5550                     case JSCallMode::CALL_SETTER:
5551                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, data[0], data[1] });
5552                         Jump(&exit);
5553                         break;
5554                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5555                         result = CallOptimized(glue, code,
5556                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5557                         Jump(&exit);
5558                         break;
5559                     default:
5560                         LOG_ECMA(FATAL) << "this branch is unreachable";
5561                         UNREACHABLE();
5562                 }
5563             }
5564             Bind(&slowCallBridge);
5565             {
5566                 switch (mode) {
5567                     case JSCallMode::CALL_THIS_ARG0:
5568                         thisValue = data[0];
5569                         [[fallthrough]];
5570                     case JSCallMode::CALL_ARG0:
5571                     case JSCallMode::DEPRECATED_CALL_ARG0:
5572                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5573                             { glue, realNumArgs, func, newTarget, thisValue});
5574                         Jump(&exit);
5575                         break;
5576                     case JSCallMode::CALL_THIS_ARG1:
5577                         thisValue = data[1];
5578                         [[fallthrough]];
5579                     case JSCallMode::CALL_ARG1:
5580                     case JSCallMode::DEPRECATED_CALL_ARG1:
5581                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5582                             { glue, realNumArgs, func, newTarget, thisValue, data[0] });
5583                         Jump(&exit);
5584                         break;
5585                     case JSCallMode::CALL_THIS_ARG2:
5586                         thisValue = data[2];
5587                         [[fallthrough]];
5588                     case JSCallMode::CALL_ARG2:
5589                     case JSCallMode::DEPRECATED_CALL_ARG2:
5590                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5591                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
5592                         Jump(&exit);
5593                         break;
5594                     case JSCallMode::CALL_THIS_ARG3:
5595                         thisValue = data[3];
5596                         [[fallthrough]];
5597                     case JSCallMode::CALL_ARG3:
5598                     case JSCallMode::DEPRECATED_CALL_ARG3:
5599                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5600                             { glue, realNumArgs, func, newTarget, thisValue,
5601                             data[0], data[1], data[2] }); // 2: args2
5602                         Jump(&exit);
5603                         break;
5604                     case JSCallMode::CALL_THIS_WITH_ARGV:
5605                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5606                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5607                         thisValue = data[2]; // 2: this input
5608                         [[fallthrough]];
5609                     case JSCallMode::CALL_WITH_ARGV:
5610                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5611                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgVAndPushUndefined),
5612                             { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
5613                         Jump(&exit);
5614                         break;
5615                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5616                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5617                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgVAndPushUndefined),
5618                             { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
5619                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5620                         Jump(&exit);
5621                         break;
5622                     case JSCallMode::CALL_GETTER:
5623                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5624                             { glue, realNumArgs, func, newTarget, data[0]});
5625                         Jump(&exit);
5626                         break;
5627                     case JSCallMode::CALL_SETTER:
5628                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5629                             { glue, realNumArgs, func, newTarget, data[0], data[1]});
5630                         Jump(&exit);
5631                         break;
5632                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5633                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5634                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5635                         Jump(&exit);
5636                         break;
5637                     default:
5638                         LOG_ECMA(FATAL) << "this branch is unreachable";
5639                         UNREACHABLE();
5640                 }
5641             }
5642         }
5643 
5644         Bind(&methodNotAot);
5645         if (jumpSize != 0) {
5646             SaveJumpSizeIfNeeded(glue, jumpSize);
5647         }
5648         SaveHotnessCounterIfNeeded(glue, sp, hotnessCounter, mode);
5649         switch (mode) {
5650             case JSCallMode::CALL_THIS_ARG0:
5651                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg0AndDispatch),
5652                     { glue, sp, func, method, callField, data[0] });
5653                 Return();
5654                 break;
5655             case JSCallMode::CALL_ARG0:
5656             case JSCallMode::DEPRECATED_CALL_ARG0:
5657                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg0AndDispatch),
5658                     { glue, sp, func, method, callField });
5659                 Return();
5660                 break;
5661             case JSCallMode::CALL_THIS_ARG1:
5662                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg1AndDispatch),
5663                     { glue, sp, func, method, callField, data[0], data[1] });
5664                 Return();
5665                 break;
5666             case JSCallMode::CALL_ARG1:
5667             case JSCallMode::DEPRECATED_CALL_ARG1:
5668                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg1AndDispatch),
5669                     { glue, sp, func, method, callField, data[0] });
5670                 Return();
5671                 break;
5672             case JSCallMode::CALL_THIS_ARG2:
5673                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs2AndDispatch),
5674                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
5675                 Return();
5676                 break;
5677             case JSCallMode::CALL_ARG2:
5678             case JSCallMode::DEPRECATED_CALL_ARG2:
5679                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs2AndDispatch),
5680                     { glue, sp, func, method, callField, data[0], data[1] });
5681                 Return();
5682                 break;
5683             case JSCallMode::CALL_THIS_ARG3:
5684                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs3AndDispatch),
5685                     { glue, sp, func, method, callField, data[0], data[1], data[2], data[3] });
5686                 Return();
5687                 break;
5688             case JSCallMode::CALL_ARG3:
5689             case JSCallMode::DEPRECATED_CALL_ARG3:
5690                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs3AndDispatch),
5691                     { glue, sp, func, method, callField, data[0], data[1], data[2] }); // 2: args2
5692                 Return();
5693                 break;
5694             case JSCallMode::CALL_WITH_ARGV:
5695             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5696                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatch),
5697                     { glue, sp, func, method, callField, data[0], data[1] });
5698                 Return();
5699                 break;
5700             case JSCallMode::CALL_THIS_WITH_ARGV:
5701             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5702                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisRangeAndDispatch),
5703                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
5704                 Return();
5705                 break;
5706             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5707             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5708                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatch),
5709                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
5710                 Return();
5711                 break;
5712             case JSCallMode::CALL_GETTER:
5713                 result = CallNGCRuntime(glue, RTSTUB_ID(CallGetter),
5714                     { glue, func, method, callField, data[0] });
5715                 Jump(&exit);
5716                 break;
5717             case JSCallMode::CALL_SETTER:
5718                 result = CallNGCRuntime(glue, RTSTUB_ID(CallSetter),
5719                     { glue, func, method, callField, data[1], data[0] });
5720                 Jump(&exit);
5721                 break;
5722             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5723                 result = CallNGCRuntime(glue, RTSTUB_ID(CallContainersArgs3),
5724                     { glue, func, method, callField, data[1], data[2], data[3], data[0] });
5725                 Jump(&exit);
5726                 break;
5727             case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5728                 result = CallNGCRuntime(glue, RTSTUB_ID(CallReturnWithArgv),
5729                     { glue, func, method, callField, data[0], data[1], data[2] });
5730                 Jump(&exit);
5731                 break;
5732             default:
5733                 LOG_ECMA(FATAL) << "this branch is unreachable";
5734                 UNREACHABLE();
5735         }
5736     }
5737     Bind(&exit);
5738     auto ret = *result;
5739     env->SubCfgExit();
5740     return ret;
5741 }
5742 
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)5743 void StubBuilder::CallFastPath(GateRef glue, GateRef nativeCode, GateRef func, GateRef thisValue,
5744     GateRef actualNumArgs, GateRef callField, GateRef method, Label* notFastBuiltins, Label* exit, Variable* result,
5745     std::initializer_list<GateRef> args, JSCallMode mode)
5746 {
5747     auto env = GetEnvironment();
5748     auto data = std::begin(args);
5749     Label isFastBuiltins(env);
5750     GateRef numArgs = ZExtInt32ToPtr(actualNumArgs);
5751     GateRef isFastBuiltinsMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsFastBuiltinBit::START_BIT);
5752     Branch(Int64NotEqual(Int64And(callField, isFastBuiltinsMask), Int64(0)), &isFastBuiltins, notFastBuiltins);
5753     Bind(&isFastBuiltins);
5754     {
5755         GateRef builtinId = GetBuiltinId(method);
5756         GateRef ret;
5757         switch (mode) {
5758             case JSCallMode::CALL_THIS_ARG0:
5759                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue, numArgs,
5760                     Undefined(), Undefined(), Undefined()});
5761                 break;
5762             case JSCallMode::CALL_THIS_ARG1:
5763                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(),
5764                                                           thisValue, numArgs, data[0], Undefined(), Undefined() });
5765                 break;
5766             case JSCallMode::CALL_THIS_ARG2:
5767                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
5768                                                           numArgs, data[0], data[1], Undefined() });
5769                 break;
5770             case JSCallMode::CALL_THIS_ARG3:
5771                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
5772                                                           numArgs, data[0], data[1], data[2] });
5773                 break;
5774             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5775             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5776                 ret = DispatchBuiltinsWithArgv(glue, builtinId, { glue, nativeCode, func, func, thisValue,
5777                                                                   numArgs, data[1] });
5778                 break;
5779             default:
5780                 LOG_ECMA(FATAL) << "this branch is unreachable";
5781                 UNREACHABLE();
5782         }
5783         result->WriteVariable(ret);
5784         Jump(exit);
5785     }
5786     Bind(notFastBuiltins);
5787 }
5788 
TryStringOrSymbolToElementIndex(GateRef glue,GateRef key)5789 GateRef StubBuilder::TryStringOrSymbolToElementIndex(GateRef glue, GateRef key)
5790 {
5791     auto env = GetEnvironment();
5792     Label entry(env);
5793     env->SubCfgEntry(&entry);
5794     Label exit(env);
5795     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
5796 
5797     Label keyNotSymbol(env);
5798     Branch(IsSymbol(key), &exit, &keyNotSymbol);
5799     Bind(&keyNotSymbol);
5800 
5801     Label greatThanZero(env);
5802     Label inRange(env);
5803     auto len = GetLengthFromString(key);
5804     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
5805     Bind(&greatThanZero);
5806     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
5807     Bind(&inRange);
5808     {
5809         Label isUtf8(env);
5810         Branch(IsUtf16String(key), &exit, &isUtf8);
5811         Bind(&isUtf8);
5812         GateRef data = GetNormalStringData(FlattenString(glue, key));
5813         DEFVARIABLE(c, VariableType::INT32(), Int32(0));
5814         c = ZExtInt8ToInt32(Load(VariableType::INT8(), data));
5815         Label isDigitZero(env);
5816         Label notDigitZero(env);
5817         Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
5818         Bind(&isDigitZero);
5819         {
5820             Label lengthIsOne(env);
5821             Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
5822             Bind(&lengthIsOne);
5823             {
5824                 result = Int32(0);
5825                 Jump(&exit);
5826             }
5827         }
5828         Bind(&notDigitZero);
5829         {
5830             Label isDigit(env);
5831             Label notIsDigit(env);
5832             DEFVARIABLE(i, VariableType::INT32(), Int32(1));
5833             DEFVARIABLE(n, VariableType::INT32(), Int32Sub(*c, Int32('0')));
5834 
5835             Branch(IsDigit(*c), &isDigit, &notIsDigit);
5836             Label loopHead(env);
5837             Label loopEnd(env);
5838             Label afterLoop(env);
5839             Bind(&isDigit);
5840             Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
5841             LoopBegin(&loopHead);
5842             {
5843                 c = ZExtInt8ToInt32(Load(VariableType::INT8(), data, ZExtInt32ToPtr(*i)));
5844                 Label isDigit2(env);
5845                 Label notDigit2(env);
5846                 Branch(IsDigit(*c), &isDigit2, &notDigit2);
5847                 Bind(&isDigit2);
5848                 {
5849                     // 10 means the base of digit is 10.
5850                     n = Int32Add(Int32Mul(*n, Int32(10)),
5851                                  Int32Sub(*c, Int32('0')));
5852                     i = Int32Add(*i, Int32(1));
5853                     Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
5854                 }
5855                 Bind(&notDigit2);
5856                 {
5857                     Label hasPoint(env);
5858                     Branch(Int32Equal(*c, Int32('.')), &hasPoint, &exit);
5859                     Bind(&hasPoint);
5860                     {
5861                         result = Int32(-2); // -2:return -2 means should goto slow path
5862                         Jump(&exit);
5863                     }
5864                 }
5865             }
5866             Bind(&loopEnd);
5867             LoopEnd(&loopHead);
5868             Bind(&afterLoop);
5869             {
5870                 Label lessThanMaxIndex(env);
5871                 Branch(Int32UnsignedLessThan(*n, Int32(JSObject::MAX_ELEMENT_INDEX)),
5872                        &lessThanMaxIndex, &exit);
5873                 Bind(&lessThanMaxIndex);
5874                 {
5875                     result = *n;
5876                     Jump(&exit);
5877                 }
5878             }
5879             Bind(&notIsDigit);
5880             {
5881                 Label isNegative(env);
5882                 Branch(Int32Equal(*c, Int32('-')), &isNegative, &exit);
5883                 Bind(&isNegative);
5884                 {
5885                     result = Int32(-2); // -2:return -2 means should goto slow path
5886                     Jump(&exit);
5887                 }
5888             }
5889         }
5890     }
5891     Bind(&exit);
5892     auto ret = *result;
5893     env->SubCfgExit();
5894     return ret;
5895 }
5896 
GetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef jsType)5897 GateRef StubBuilder::GetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder,
5898                                                 GateRef key, GateRef jsType)
5899 {
5900     auto env = GetEnvironment();
5901     Label entry(env);
5902     env->SubCfgEntry(&entry);
5903     Label exit(env);
5904     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5905 
5906     Label notOnProtoChain(env);
5907     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
5908     Bind(&notOnProtoChain);
5909 
5910     auto negativeZero = GetGlobalConstantValue(
5911         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
5912     Label isNegativeZero(env);
5913     Label notNegativeZero(env);
5914     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
5915     Bind(&isNegativeZero);
5916     {
5917         result = Undefined();
5918         Jump(&exit);
5919     }
5920     Bind(&notNegativeZero);
5921     {
5922         GateRef index = TryStringOrSymbolToElementIndex(glue, key);
5923         Label validIndex(env);
5924         Label notValidIndex(env);
5925         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
5926         Bind(&validIndex);
5927         {
5928             TypedArrayStubBuilder typedArrayStubBuilder(this);
5929             result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, holder, index, jsType);
5930             Jump(&exit);
5931         }
5932         Bind(&notValidIndex);
5933         {
5934             Label returnNull(env);
5935             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
5936             Bind(&returnNull);
5937             {
5938                 result = Null();
5939                 Jump(&exit);
5940             }
5941         }
5942     }
5943 
5944     Bind(&exit);
5945     auto ret = *result;
5946     env->SubCfgExit();
5947     return ret;
5948 }
5949 
SetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef value,GateRef jsType)5950 GateRef StubBuilder::SetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder, GateRef key,
5951                                                 GateRef value, GateRef jsType)
5952 {
5953     auto env = GetEnvironment();
5954     Label entry(env);
5955     env->SubCfgEntry(&entry);
5956     Label exit(env);
5957     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5958     Label notOnProtoChain(env);
5959     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
5960     Bind(&notOnProtoChain);
5961 
5962     auto negativeZero = GetGlobalConstantValue(
5963         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
5964     Label isNegativeZero(env);
5965     Label notNegativeZero(env);
5966     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
5967     Bind(&isNegativeZero);
5968     {
5969         Label isObj(env);
5970         Label notObj(env);
5971         Branch(IsEcmaObject(value), &isObj, &notObj);
5972         Bind(&isObj);
5973         {
5974             result = Null();
5975             Jump(&exit);
5976         }
5977         Bind(&notObj);
5978         result = Undefined();
5979         Jump(&exit);
5980     }
5981     Bind(&notNegativeZero);
5982     {
5983         GateRef index = TryStringOrSymbolToElementIndex(glue, key);
5984         Label validIndex(env);
5985         Label notValidIndex(env);
5986         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
5987         Bind(&validIndex);
5988         {
5989             result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
5990                 { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType) });
5991             Jump(&exit);
5992         }
5993         Bind(&notValidIndex);
5994         {
5995             Label returnNull(env);
5996             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
5997             Bind(&returnNull);
5998             {
5999                 result = Null();
6000                 Jump(&exit);
6001             }
6002         }
6003     }
6004 
6005     Bind(&exit);
6006     auto ret = *result;
6007     env->SubCfgExit();
6008     return ret;
6009 }
6010 
Assert(int messageId,int line,GateRef glue,GateRef condition,Label * nextLabel)6011 void StubBuilder::Assert(int messageId, int line, GateRef glue, GateRef condition, Label *nextLabel)
6012 {
6013     auto env = GetEnvironment();
6014     Label ok(env);
6015     Label notOk(env);
6016     Branch(condition, &ok, &notOk);
6017     Bind(&ok);
6018     {
6019         Jump(nextLabel);
6020     }
6021     Bind(&notOk);
6022     {
6023         FatalPrint(glue, { Int32(messageId), Int32(line) });
6024         Jump(nextLabel);
6025     }
6026 }
6027 
FlattenString(GateRef glue,GateRef str)6028 GateRef StubBuilder::FlattenString(GateRef glue, GateRef str)
6029 {
6030     auto env = GetEnvironment();
6031     Label entry(env);
6032     env->SubCfgEntry(&entry);
6033     Label exit(env);
6034     DEFVARIABLE(result, VariableType::JS_POINTER(), str);
6035     Label isTreeString(env);
6036     Branch(IsTreeString(str), &isTreeString, &exit);
6037     Bind(&isTreeString);
6038     {
6039         Label isFlat(env);
6040         Label notFlat(env);
6041         Branch(TreeStringIsFlat(str), &isFlat, &notFlat);
6042         Bind(&isFlat);
6043         {
6044             result = GetFirstFromTreeString(str);
6045             Jump(&exit);
6046         }
6047         Bind(&notFlat);
6048         {
6049             result = CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str });
6050             Jump(&exit);
6051         }
6052     }
6053     Bind(&exit);
6054     auto ret = *result;
6055     env->SubCfgExit();
6056     return ret;
6057 }
6058 
GetNormalStringData(GateRef str)6059 GateRef StubBuilder::GetNormalStringData(GateRef str)
6060 {
6061     auto env = GetEnvironment();
6062     Label entry(env);
6063     env->SubCfgEntry(&entry);
6064     Label exit(env);
6065     Label isConstantString(env);
6066     Label isLineString(env);
6067     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
6068     Branch(IsConstantString(str), &isConstantString, &isLineString);
6069     Bind(&isConstantString);
6070     {
6071         GateRef address = PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET));
6072         result = Load(VariableType::JS_ANY(), address, IntPtr(0));
6073         Jump(&exit);
6074     }
6075     Bind(&isLineString);
6076     {
6077         result = PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET));
6078         Jump(&exit);
6079     }
6080     Bind(&exit);
6081     auto ret = *result;
6082     env->SubCfgExit();
6083     return ret;
6084 }
6085 
FlattenString(GateRef str,Variable * flatStr,Label * fastPath,Label * slowPath)6086 void StubBuilder::FlattenString(GateRef str, Variable *flatStr, Label *fastPath, Label *slowPath)
6087 {
6088     auto env = GetEnvironment();
6089     Label notLineString(env);
6090     Label exit(env);
6091     DEFVARIABLE(result, VariableType::JS_POINTER(), str);
6092     Branch(BoolOr(IsLineString(str), IsConstantString(str)), &exit, &notLineString);
6093     Bind(&notLineString);
6094     {
6095         Label isTreeString(env);
6096         Branch(IsTreeString(str), &isTreeString, &exit);
6097         Bind(&isTreeString);
6098         {
6099             Label isFlat(env);
6100             Branch(TreeStringIsFlat(str), &isFlat, slowPath);
6101             Bind(&isFlat);
6102             {
6103                 result = GetFirstFromTreeString(str);
6104                 Jump(&exit);
6105             }
6106         }
6107     }
6108     Bind(&exit);
6109     {
6110         flatStr->WriteVariable(*result);
6111         Jump(fastPath);
6112     }
6113 }
6114 
ToNumber(GateRef glue,GateRef tagged)6115 GateRef StubBuilder::ToNumber(GateRef glue, GateRef tagged)
6116 {
6117     auto env = GetEnvironment();
6118     Label entry(env);
6119     env->SubCfgEntry(&entry);
6120     Label exit(env);
6121     Label isNumber(env);
6122     Label notNumber(env);
6123     Label defaultLabel(env);
6124     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
6125     Branch(TaggedIsNumber(tagged), &isNumber, &notNumber);
6126     Bind(&isNumber);
6127     {
6128         result = tagged;
6129         Jump(&exit);
6130     }
6131     Bind(&notNumber);
6132     {
6133         Label returnNan(env);
6134         Label notNan(env);
6135         Label returnNumber1(env);
6136         Label notNumber1(env);
6137         Label returnNumber0(env);
6138         auto isHole = TaggedIsHole(tagged);
6139         auto isUndefined = TaggedIsUndefined(tagged);
6140         Branch(BoolOr(isHole, isUndefined), &returnNan, &notNan);
6141         Bind(&returnNan);
6142         {
6143             result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
6144             Jump(&exit);
6145         }
6146         Bind(&notNan);
6147         Branch(TaggedIsTrue(tagged), &returnNumber1, &notNumber1);
6148         Bind(&returnNumber1);
6149         {
6150             result = Int64ToTaggedPtr(Int32(1));
6151             Jump(&exit);
6152         }
6153         Bind(&notNumber1);
6154         auto isFalse = TaggedIsFalse(tagged);
6155         auto isNull = TaggedIsNull(tagged);
6156         Branch(BoolOr(isFalse, isNull), &returnNumber0, &defaultLabel);
6157         Bind(&returnNumber0);
6158         {
6159             result = Int64ToTaggedPtr(Int32(0));
6160             Jump(&exit);
6161         }
6162         Bind(&defaultLabel);
6163         {
6164             CallRuntime(glue, RTSTUB_ID(OtherToNumber), { tagged });
6165             Jump(&exit);
6166         }
6167     }
6168     Bind(&exit);
6169     auto ret = *result;
6170     env->SubCfgExit();
6171     return ret;
6172 }
6173 
GetLengthOfJsArray(GateRef glue,GateRef array)6174 GateRef StubBuilder::GetLengthOfJsArray(GateRef glue, GateRef array)
6175 {
6176     auto env = GetEnvironment();
6177     Label entry(env);
6178     env->SubCfgEntry(&entry);
6179     Label exit(env);
6180     Label isInt(env);
6181     Label notInt(env);
6182     Label notDouble(env);
6183     Label isDouble(env);
6184     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
6185     GateRef len = Load(VariableType::JS_ANY(), array, IntPtr(JSArray::LENGTH_OFFSET));
6186     Branch(TaggedIsInt(len), &isInt, &notInt);
6187     Bind(&isInt);
6188     {
6189         result = TaggedGetInt(len);
6190         Jump(&exit);
6191     }
6192     Bind(&notInt);
6193     {
6194         Branch(TaggedIsDouble(len), &isDouble, &notDouble);
6195         Bind(&isDouble);
6196         {
6197             result = DoubleToInt(glue, GetDoubleOfTDouble(len));
6198             Jump(&exit);
6199         }
6200         Bind(&notDouble);
6201         {
6202             FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
6203             Jump(&exit);
6204         }
6205     }
6206     Bind(&exit);
6207     auto ret = *result;
6208     env->SubCfgExit();
6209     return ret;
6210 }
6211 
CreateListFromArrayLike(GateRef glue,GateRef arrayObj)6212 GateRef StubBuilder::CreateListFromArrayLike(GateRef glue, GateRef arrayObj)
6213 {
6214     auto env = GetEnvironment();
6215     Label entry(env);
6216     env->SubCfgEntry(&entry);
6217     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
6218     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
6219     Label exit(env);
6220 
6221     // 3. If Type(obj) is Object, throw a TypeError exception.
6222     Label targetIsHeapObject(env);
6223     Label targetIsEcmaObject(env);
6224     Label targetNotEcmaObject(env);
6225     Branch(TaggedIsHeapObject(arrayObj), &targetIsHeapObject, &targetNotEcmaObject);
6226     Bind(&targetIsHeapObject);
6227     Branch(TaggedObjectIsEcmaObject(arrayObj), &targetIsEcmaObject, &targetNotEcmaObject);
6228     Bind(&targetNotEcmaObject);
6229     {
6230         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
6231         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
6232         Jump(&exit);
6233     }
6234     Bind(&targetIsEcmaObject);
6235     {
6236         // 4. Let len be ToLength(Get(obj, "length")).
6237         GateRef lengthString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
6238                                                       ConstantIndex::LENGTH_STRING_INDEX);
6239         GateRef value = FastGetPropertyByName(glue, arrayObj, lengthString, ProfileOperation());
6240         GateRef number = ToLength(glue, value);
6241         // 5. ReturnIfAbrupt(len).
6242         Label isPendingException1(env);
6243         Label noPendingException1(env);
6244         Branch(HasPendingException(glue), &isPendingException1, &noPendingException1);
6245         Bind(&isPendingException1);
6246         {
6247             Jump(&exit);
6248         }
6249         Bind(&noPendingException1);
6250         {
6251             Label indexInRange(env);
6252             Label indexOutRange(env);
6253             GateRef doubleLen = GetDoubleOfTNumber(number);
6254             Branch(DoubleGreaterThan(doubleLen, Double(JSObject::MAX_ELEMENT_INDEX)), &indexOutRange, &indexInRange);
6255             Bind(&indexOutRange);
6256             {
6257                 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(LenGreaterThanMax));
6258                 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
6259                 Jump(&exit);
6260             }
6261             Bind(&indexInRange);
6262             {
6263                 GateRef int32Len = DoubleToInt(glue, doubleLen);
6264                 // 6. Let list be an empty List.
6265                 NewObjectStubBuilder newBuilder(this);
6266                 GateRef array = newBuilder.NewTaggedArray(glue, int32Len);
6267                 Label targetIsTypeArray(env);
6268                 Label targetNotTypeArray(env);
6269                 Branch(IsTypedArray(arrayObj), &targetIsTypeArray, &targetNotTypeArray);
6270                 Bind(&targetIsTypeArray);
6271                 {
6272                     TypedArrayStubBuilder arrayStubBuilder(this);
6273                     arrayStubBuilder.FastCopyElementToArray(glue, arrayObj, array);
6274                     // c. ReturnIfAbrupt(next).
6275                     Label isPendingException2(env);
6276                     Label noPendingException2(env);
6277                     Branch(HasPendingException(glue), &isPendingException2, &noPendingException2);
6278                     Bind(&isPendingException2);
6279                     {
6280                         Jump(&exit);
6281                     }
6282                     Bind(&noPendingException2);
6283                     {
6284                         res = array;
6285                         Jump(&exit);
6286                     }
6287                 }
6288                 Bind(&targetNotTypeArray);
6289                 // 8. Repeat while index < len
6290                 Label loopHead(env);
6291                 Label loopEnd(env);
6292                 Label afterLoop(env);
6293                 Label isPendingException3(env);
6294                 Label noPendingException3(env);
6295                 Label storeValue(env);
6296                 Jump(&loopHead);
6297                 LoopBegin(&loopHead);
6298                 {
6299                     Branch(Int32UnsignedLessThan(*index, int32Len), &storeValue, &afterLoop);
6300                     Bind(&storeValue);
6301                     {
6302                         GateRef next = FastGetPropertyByIndex(glue, arrayObj, *index, ProfileOperation());
6303                         // c. ReturnIfAbrupt(next).
6304                         Branch(HasPendingException(glue), &isPendingException3, &noPendingException3);
6305                         Bind(&isPendingException3);
6306                         {
6307                             Jump(&exit);
6308                         }
6309                         Bind(&noPendingException3);
6310                         SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, next);
6311                         index = Int32Add(*index, Int32(1));
6312                         Jump(&loopEnd);
6313                     }
6314                 }
6315                 Bind(&loopEnd);
6316                 LoopEnd(&loopHead);
6317                 Bind(&afterLoop);
6318                 {
6319                     res = array;
6320                     Jump(&exit);
6321                 }
6322             }
6323         }
6324     }
6325     Bind(&exit);
6326     GateRef ret = *res;
6327     env->SubCfgExit();
6328     return ret;
6329 }
6330 
ToLength(GateRef glue,GateRef target)6331 GateRef StubBuilder::ToLength(GateRef glue, GateRef target)
6332 {
6333     auto env = GetEnvironment();
6334     Label subentry(env);
6335     env->SubCfgEntry(&subentry);
6336     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
6337     Label exit(env);
6338 
6339     GateRef number = ToNumber(glue, target);
6340     Label isPendingException(env);
6341     Label noPendingException(env);
6342     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
6343     Bind(&isPendingException);
6344     {
6345         Jump(&exit);
6346     }
6347     Bind(&noPendingException);
6348     {
6349         GateRef num = GetDoubleOfTNumber(number);
6350         Label targetLessThanZero(env);
6351         Label targetGreaterThanZero(env);
6352         Label targetLessThanSafeNumber(env);
6353         Label targetGreaterThanSafeNumber(env);
6354         Branch(DoubleLessThan(num, Double(0.0)), &targetLessThanZero, &targetGreaterThanZero);
6355         Bind(&targetLessThanZero);
6356         {
6357             res = DoubleToTaggedDoublePtr(Double(0.0));
6358             Jump(&exit);
6359         }
6360         Bind(&targetGreaterThanZero);
6361         Branch(DoubleGreaterThan(num, Double(SAFE_NUMBER)), &targetGreaterThanSafeNumber, &targetLessThanSafeNumber);
6362         Bind(&targetGreaterThanSafeNumber);
6363         {
6364             res = DoubleToTaggedDoublePtr(Double(SAFE_NUMBER));
6365             Jump(&exit);
6366         }
6367         Bind(&targetLessThanSafeNumber);
6368         {
6369             res = number;
6370             Jump(&exit);
6371         }
6372     }
6373     Bind(&exit);
6374     auto ret = *res;
6375     env->SubCfgExit();
6376     return ret;
6377 }
6378 
TaggedGetNumber(GateRef x)6379 GateRef StubBuilder::TaggedGetNumber(GateRef x)
6380 {
6381     auto env = GetEnvironment();
6382     Label subentry(env);
6383     Label exit(env);
6384     env->SubCfgEntry(&subentry);
6385 
6386     Label targetIsInt(env);
6387     Label targetIsDouble(env);
6388     DEFVAlUE(number, env_, VariableType::FLOAT64(), Double(0));
6389     Branch(TaggedIsInt(x), &targetIsInt, &targetIsDouble);
6390     Bind(&targetIsInt);
6391     {
6392         number = ChangeInt32ToFloat64(TaggedGetInt(x));
6393         Jump(&exit);
6394     }
6395     Bind(&targetIsDouble);
6396     {
6397         number = GetDoubleOfTDouble(x);
6398         Jump(&exit);
6399     }
6400     Bind(&exit);
6401     GateRef ret = *number;
6402     env->SubCfgExit();
6403     return ret;
6404 }
6405 
HasStableElements(GateRef glue,GateRef obj)6406 GateRef StubBuilder::HasStableElements(GateRef glue, GateRef obj)
6407 {
6408     auto env = GetEnvironment();
6409     Label subentry(env);
6410     env->SubCfgEntry(&subentry);
6411     DEFVARIABLE(result, VariableType::BOOL(), False());
6412     Label exit(env);
6413     Label targetIsHeapObject(env);
6414     Label targetIsStableElements(env);
6415 
6416     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
6417     Bind(&targetIsHeapObject);
6418     {
6419         GateRef jsHclass = LoadHClass(obj);
6420         Branch(IsStableElements(jsHclass), &targetIsStableElements, &exit);
6421         Bind(&targetIsStableElements);
6422         {
6423             GateRef guardiansOffset = IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
6424             GateRef guardians = Load(VariableType::JS_ANY(), glue, guardiansOffset);
6425             Label targetIsTaggedTrue(env);
6426             Label targetIsTaggedFalse(env);
6427             Branch(TaggedIsTrue(guardians), &targetIsTaggedTrue, &targetIsTaggedFalse);
6428             Bind(&targetIsTaggedTrue);
6429             {
6430                 result = True();
6431                 Jump(&exit);
6432             }
6433             Bind(&targetIsTaggedFalse);
6434             {
6435                 result = False();
6436                 Jump(&exit);
6437             }
6438         }
6439     }
6440     Bind(&exit);
6441     auto res = *result;
6442     env->SubCfgExit();
6443     return res;
6444 }
6445 
IsStableJSArguments(GateRef glue,GateRef obj)6446 GateRef StubBuilder::IsStableJSArguments(GateRef glue, GateRef obj)
6447 {
6448     auto env = GetEnvironment();
6449     Label subentry(env);
6450     env->SubCfgEntry(&subentry);
6451     DEFVARIABLE(result, VariableType::BOOL(), False());
6452     Label exit(env);
6453     Label targetIsHeapObject(env);
6454     Label targetIsStableArguments(env);
6455 
6456     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
6457     Bind(&targetIsHeapObject);
6458     {
6459         GateRef jsHclass = LoadHClass(obj);
6460         Branch(IsStableArguments(jsHclass), &targetIsStableArguments, &exit);
6461         Bind(&targetIsStableArguments);
6462         {
6463             GateRef guardiansOffset = IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
6464             GateRef guardians = Load(VariableType::JS_ANY(), glue, guardiansOffset);
6465 
6466             Label targetIsTaggedTrue(env);
6467             Label targetIsTaggedFalse(env);
6468             Branch(TaggedIsTrue(guardians), &targetIsTaggedTrue, &targetIsTaggedFalse);
6469             Bind(&targetIsTaggedTrue);
6470             {
6471                 result = True();
6472                 Jump(&exit);
6473             }
6474             Bind(&targetIsTaggedFalse);
6475             {
6476                 result = False();
6477                 Jump(&exit);
6478             }
6479         }
6480     }
6481     Bind(&exit);
6482     auto res = *result;
6483     env->SubCfgExit();
6484     return res;
6485 }
6486 
IsStableJSArray(GateRef glue,GateRef obj)6487 GateRef StubBuilder::IsStableJSArray(GateRef glue, GateRef obj)
6488 {
6489     auto env = GetEnvironment();
6490     Label subentry(env);
6491     env->SubCfgEntry(&subentry);
6492     DEFVARIABLE(result, VariableType::BOOL(), False());
6493     Label exit(env);
6494     Label targetIsHeapObject(env);
6495     Label targetIsStableArray(env);
6496 
6497     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
6498     Bind(&targetIsHeapObject);
6499     {
6500         GateRef jsHclass = LoadHClass(obj);
6501         Branch(IsStableArray(jsHclass), &targetIsStableArray, &exit);
6502         Bind(&targetIsStableArray);
6503         {
6504             GateRef guardiansOffset = IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
6505             GateRef guardians = Load(VariableType::JS_ANY(), glue, guardiansOffset);
6506 
6507             Label targetIsTaggedTrue(env);
6508             Label targetIsTaggedFalse(env);
6509             Branch(TaggedIsTrue(guardians), &targetIsTaggedTrue, &targetIsTaggedFalse);
6510             Bind(&targetIsTaggedTrue);
6511             {
6512                 result = True();
6513                 Jump(&exit);
6514             }
6515             Bind(&targetIsTaggedFalse);
6516             {
6517                 result = False();
6518                 Jump(&exit);
6519             }
6520         }
6521     }
6522     Bind(&exit);
6523     auto res = *result;
6524     env->SubCfgExit();
6525     return res;
6526 }
6527 
UpdateProfileTypeInfo(GateRef glue,GateRef jsFunc)6528 GateRef StubBuilder::UpdateProfileTypeInfo(GateRef glue, GateRef jsFunc)
6529 {
6530     auto env = GetEnvironment();
6531     Label entry(env);
6532     env->SubCfgEntry(&entry);
6533     Label needUpdate(env);
6534     Label exit(env);
6535     DEFVARIABLE(profileTypeInfo, VariableType::JS_POINTER(), GetProfileTypeInfo(jsFunc));
6536     Branch(TaggedIsUndefined(*profileTypeInfo), &needUpdate, &exit);
6537     Bind(&needUpdate);
6538     {
6539         profileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounter), { jsFunc });
6540         Jump(&exit);
6541     }
6542     Bind(&exit);
6543     auto ret = *profileTypeInfo;
6544     env->SubCfgExit();
6545     return ret;
6546 }
6547 }  // namespace panda::ecmascript::kungfu
6548