• 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     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1856     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
1857     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
1858     Jump(&loopHead);
1859     LoopBegin(&loopHead);
1860     {
1861         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
1862         Bind(&handlerIsInt);
1863         {
1864             GateRef handlerInfo = GetInt32OfTInt(*handler);
1865             Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
1866             Bind(&handlerInfoIsField);
1867             {
1868                 result = StoreField(glue, receiver, value, handlerInfo, callback);
1869                 Jump(&exit);
1870             }
1871             Bind(&handlerInfoNotField);
1872             {
1873                 GateRef accessor = LoadFromField(*holder, handlerInfo);
1874                 result = CallSetterHelper(glue, receiver, accessor, value, callback);
1875                 Jump(&exit);
1876             }
1877         }
1878         Bind(&handlerNotInt);
1879         {
1880             Branch(TaggedIsTransitionHandler(*handler), &handlerIsTransitionHandler, &handlerNotTransitionHandler);
1881             Bind(&handlerIsTransitionHandler);
1882             {
1883                 result = StoreWithTransition(glue, receiver, value, *handler, callback);
1884                 Jump(&exit);
1885             }
1886             Bind(&handlerNotTransitionHandler);
1887             {
1888                 Branch(TaggedIsTransWithProtoHandler(*handler), &handlerIsTransWithProtoHandler,
1889                     &handlerNotTransWithProtoHandler);
1890                 Bind(&handlerIsTransWithProtoHandler);
1891                 {
1892                     GateRef cellValue = GetProtoCell(*handler);
1893                     Branch(GetHasChanged(cellValue), &cellHasChanged, &cellNotChanged);
1894                     Bind(&cellNotChanged);
1895                     {
1896                         result = StoreWithTransition(glue, receiver, value, *handler, callback, true);
1897                         Jump(&exit);
1898                     }
1899                 }
1900                 Bind(&handlerNotTransWithProtoHandler);
1901                 {
1902                     Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
1903                     Bind(&handlerNotPrototypeHandler);
1904                     {
1905                         Branch(TaggedIsPropertyBox(*handler), &handlerIsPropertyBox, &handlerNotPropertyBox);
1906                         Bind(&handlerIsPropertyBox);
1907                         StoreGlobal(glue, value, *handler);
1908                         Jump(&exit);
1909                     }
1910                 }
1911             }
1912         }
1913         Bind(&handlerIsPrototypeHandler);
1914         {
1915             GateRef cellValue = GetProtoCell(*handler);
1916             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1917             Bind(&loopEnd);
1918             {
1919                 holder = GetPrototypeHandlerHolder(*handler);
1920                 handler = GetPrototypeHandlerHandlerInfo(*handler);
1921                 LoopEnd(&loopHead);
1922             }
1923         }
1924         Bind(&handlerNotPropertyBox);
1925         {
1926             Branch(TaggedIsStoreTSHandler(*handler), &handlerIsStoreTSHandler, &handlerNotStoreTSHandler);
1927             Bind(&handlerIsStoreTSHandler);
1928             {
1929                 GateRef cellValue = GetProtoCell(*handler);
1930                 Branch(GetHasChanged(cellValue), &cellHasChanged, &aotCellNotChanged);
1931                 Bind(&aotCellNotChanged);
1932                 {
1933                     holder = GetStoreTSHandlerHolder(*handler);
1934                     handler = GetStoreTSHandlerHandlerInfo(*handler);
1935                     GateRef handlerInfo = GetInt32OfTInt(*handler);
1936                     Branch(IsField(handlerInfo), &aotHandlerInfoIsField, &aotHandlerInfoNotField);
1937                     Bind(&aotHandlerInfoIsField);
1938                     {
1939                         result = StoreField(glue, receiver, value, handlerInfo, callback);
1940                         Jump(&exit);
1941                     }
1942                     Bind(&aotHandlerInfoNotField);
1943                     {
1944                         GateRef accessor = LoadFromField(*holder, handlerInfo);
1945                         result = CallSetterHelper(glue, receiver, accessor, value, callback);
1946                         Jump(&exit);
1947                     }
1948                 }
1949             }
1950             Bind(&handlerNotStoreTSHandler);
1951             Jump(&exit);
1952         }
1953         Bind(&cellHasChanged);
1954         {
1955             result = Hole();
1956             Jump(&exit);
1957         }
1958     }
1959     Bind(&exit);
1960     auto ret = *result;
1961     env->SubCfgExit();
1962     return ret;
1963 }
1964 
StoreField(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback)1965 GateRef StubBuilder::StoreField(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
1966     ProfileOperation callback)
1967 {
1968     auto env = GetEnvironment();
1969     Label entry(env);
1970     env->SubCfgEntry(&entry);
1971     ProfilerStubBuilder(env).UpdatePropAttrIC(glue, receiver, value, handler, callback);
1972     Label exit(env);
1973     Label handlerIsInlinedProperty(env);
1974     Label handlerNotInlinedProperty(env);
1975     GateRef index = HandlerBaseGetOffset(handler);
1976     GateRef rep = HandlerBaseGetRep(handler);
1977     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1978     Label repChange(env);
1979     Branch(HandlerBaseIsInlinedProperty(handler), &handlerIsInlinedProperty, &handlerNotInlinedProperty);
1980     Bind(&handlerIsInlinedProperty);
1981     {
1982         GateRef toOffset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
1983         SetValueWithRep(glue, receiver, toOffset, value, rep, &repChange);
1984         Jump(&exit);
1985     }
1986     Bind(&handlerNotInlinedProperty);
1987     {
1988         GateRef array = GetPropertiesArray(receiver);
1989         SetValueToTaggedArrayWithRep(glue, array, index, value, rep, &repChange);
1990         Jump(&exit);
1991     }
1992     Bind(&repChange);
1993     {
1994         result = Hole();
1995         Jump(&exit);
1996     }
1997 
1998     Bind(&exit);
1999     auto ret = *result;
2000     env->SubCfgExit();
2001     return ret;
2002 }
2003 
StoreWithTransition(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback,bool withPrototype)2004 GateRef StubBuilder::StoreWithTransition(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
2005                                          ProfileOperation callback, bool withPrototype)
2006 {
2007     auto env = GetEnvironment();
2008     Label entry(env);
2009     env->SubCfgEntry(&entry);
2010     Label exit(env);
2011 
2012     Label handlerInfoIsInlinedProps(env);
2013     Label handlerInfoNotInlinedProps(env);
2014     Label indexMoreCapacity(env);
2015     Label indexLessCapacity(env);
2016     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2017     GateRef newHClass;
2018     GateRef handlerInfo;
2019     if (withPrototype) {
2020         newHClass = GetTransWithProtoHClass(handler);
2021         handlerInfo = GetInt32OfTInt(GetTransWithProtoHandlerInfo(handler));
2022     } else {
2023         newHClass = GetTransitionHClass(handler);
2024         handlerInfo = GetInt32OfTInt(GetTransitionHandlerInfo(handler));
2025     }
2026 
2027     StoreHClass(glue, receiver, newHClass);
2028     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
2029     Bind(&handlerInfoNotInlinedProps);
2030     {
2031         ProfilerStubBuilder(env).UpdatePropAttrIC(glue, receiver, value, handlerInfo, callback);
2032         Label repChange(env);
2033         GateRef array = GetPropertiesArray(receiver);
2034         GateRef capacity = GetLengthOfTaggedArray(array);
2035         GateRef index = HandlerBaseGetOffset(handlerInfo);
2036         Branch(Int32GreaterThanOrEqual(index, capacity), &indexMoreCapacity, &indexLessCapacity);
2037         Bind(&indexMoreCapacity);
2038         {
2039             CallRuntime(glue,
2040                         RTSTUB_ID(PropertiesSetValue),
2041                         { receiver, value, array, IntToTaggedInt(capacity),
2042                           IntToTaggedInt(index) });
2043             Jump(&exit);
2044         }
2045         Bind(&indexLessCapacity);
2046         {
2047             GateRef rep = HandlerBaseGetRep(handlerInfo);
2048             GateRef base = PtrAdd(array, IntPtr(TaggedArray::DATA_OFFSET));
2049             GateRef toIndex = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
2050             SetValueWithRep(glue, base, toIndex, value, rep, &repChange);
2051             Jump(&exit);
2052         }
2053         Bind(&repChange);
2054         {
2055             result = Hole();
2056             Jump(&exit);
2057         }
2058     }
2059     Bind(&handlerInfoIsInlinedProps);
2060     {
2061         result = StoreField(glue, receiver, value, handlerInfo, callback);
2062         Jump(&exit);
2063     }
2064     Bind(&exit);
2065     auto ret = *result;
2066     env->SubCfgExit();
2067     return ret;
2068 }
2069 
StoreGlobal(GateRef glue,GateRef value,GateRef cell)2070 GateRef StubBuilder::StoreGlobal(GateRef glue, GateRef value, GateRef cell)
2071 {
2072     auto env = GetEnvironment();
2073     Label entry(env);
2074     env->SubCfgEntry(&entry);
2075     Label exit(env);
2076     Label cellIsInvalid(env);
2077     Label cellNotInvalid(env);
2078     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2079     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
2080     Bind(&cellIsInvalid);
2081     {
2082         Jump(&exit);
2083     }
2084     Bind(&cellNotInvalid);
2085     {
2086         Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value);
2087         result = Undefined();
2088         Jump(&exit);
2089     }
2090     Bind(&exit);
2091     auto ret = *result;
2092     env->SubCfgExit();
2093     return ret;
2094 }
2095 
2096 template<typename DictionaryT>
GetAttributesFromDictionary(GateRef elements,GateRef entry)2097 GateRef StubBuilder::GetAttributesFromDictionary(GateRef elements, GateRef entry)
2098 {
2099     GateRef arrayIndex =
2100     Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2101              Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2102     GateRef attributesIndex =
2103         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_DETAILS_INDEX));
2104     auto attrValue = GetValueFromTaggedArray(elements, attributesIndex);
2105     return GetInt32OfTInt(attrValue);
2106 }
2107 
2108 template<typename DictionaryT>
GetValueFromDictionary(GateRef elements,GateRef entry)2109 GateRef StubBuilder::GetValueFromDictionary(GateRef elements, GateRef entry)
2110 {
2111     GateRef arrayIndex =
2112         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2113                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2114     GateRef valueIndex =
2115         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_VALUE_INDEX));
2116     return GetValueFromTaggedArray(elements, valueIndex);
2117 }
2118 
2119 template<typename DictionaryT>
GetKeyFromDictionary(GateRef elements,GateRef entry)2120 GateRef StubBuilder::GetKeyFromDictionary(GateRef elements, GateRef entry)
2121 {
2122     auto env = GetEnvironment();
2123     Label subentry(env);
2124     env->SubCfgEntry(&subentry);
2125     Label exit(env);
2126     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2127     Label ltZero(env);
2128     Label notLtZero(env);
2129     Label gtLength(env);
2130     Label notGtLength(env);
2131     GateRef dictionaryLength =
2132         Load(VariableType::INT32(), elements, IntPtr(TaggedArray::LENGTH_OFFSET));
2133     GateRef arrayIndex =
2134         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2135                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2136     Branch(Int32LessThan(arrayIndex, Int32(0)), &ltZero, &notLtZero);
2137     Bind(&ltZero);
2138     Jump(&exit);
2139     Bind(&notLtZero);
2140     Branch(Int32GreaterThan(arrayIndex, dictionaryLength), &gtLength, &notGtLength);
2141     Bind(&gtLength);
2142     Jump(&exit);
2143     Bind(&notGtLength);
2144     result = GetValueFromTaggedArray(elements, arrayIndex);
2145     Jump(&exit);
2146     Bind(&exit);
2147     auto ret = *result;
2148     env->SubCfgExit();
2149     return ret;
2150 }
2151 
UpdateValueAndAttributes(GateRef glue,GateRef elements,GateRef index,GateRef value,GateRef attr)2152 inline void StubBuilder::UpdateValueAndAttributes(GateRef glue, GateRef elements, GateRef index,
2153                                                   GateRef value, GateRef attr)
2154 {
2155     GateRef arrayIndex =
2156         Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
2157                  Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
2158     GateRef valueIndex =
2159         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
2160     GateRef attributesIndex =
2161         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_DETAILS_INDEX));
2162     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
2163     GateRef attroffset =
2164         PtrMul(ZExtInt32ToPtr(attributesIndex), IntPtr(JSTaggedValue::TaggedTypeSize()));
2165     GateRef dataOffset = PtrAdd(attroffset, IntPtr(TaggedArray::DATA_OFFSET));
2166     Store(VariableType::INT64(), glue, elements, dataOffset, IntToTaggedInt(attr));
2167 }
2168 
UpdateValueInDict(GateRef glue,GateRef elements,GateRef index,GateRef value)2169 inline void StubBuilder::UpdateValueInDict(GateRef glue, GateRef elements, GateRef index, GateRef value)
2170 {
2171     GateRef arrayIndex = Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
2172         Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
2173     GateRef valueIndex = Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
2174     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
2175 }
2176 
GetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,ProfileOperation callback)2177 GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, ProfileOperation callback)
2178 {
2179     auto env = GetEnvironment();
2180     Label entry(env);
2181     env->SubCfgEntry(&entry);
2182     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2183     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2184     Label exit(env);
2185     Label loopHead(env);
2186     Label loopEnd(env);
2187     Label loopExit(env);
2188     Label afterLoop(env);
2189     Jump(&loopHead);
2190     LoopBegin(&loopHead);
2191     {
2192         GateRef hclass = LoadHClass(*holder);
2193         GateRef jsType = GetObjectType(hclass);
2194         Label isSpecialIndexed(env);
2195         Label notSpecialIndexed(env);
2196         Branch(IsSpecialIndexedObj(jsType), &isSpecialIndexed, &notSpecialIndexed);
2197         Bind(&isSpecialIndexed);
2198         {
2199             // TypeArray
2200             Label isFastTypeArray(env);
2201             Label notFastTypeArray(env);
2202             Label notTypedArrayProto(env);
2203             Branch(Int32Equal(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY))), &exit, &notTypedArrayProto);
2204             Bind(&notTypedArrayProto);
2205             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2206             Bind(&isFastTypeArray);
2207             {
2208                 TypedArrayStubBuilder typedArrayStubBuilder(this);
2209                 result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, *holder, index, jsType);
2210                 Jump(&exit);
2211             }
2212             Bind(&notFastTypeArray);
2213 
2214             Label isSpecialContainer(env);
2215             Label notSpecialContainer(env);
2216             // Add SpecialContainer
2217             Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
2218             Bind(&isSpecialContainer);
2219             {
2220                 result = GetContainerProperty(glue, *holder, index, jsType);
2221                 Jump(&exit);
2222             }
2223             Bind(&notSpecialContainer);
2224             {
2225                 result = Hole();
2226                 Jump(&exit);
2227             }
2228         }
2229         Bind(&notSpecialIndexed);
2230         {
2231             GateRef elements = GetElementsArray(*holder);
2232             Label isDictionaryElement(env);
2233             Label notDictionaryElement(env);
2234             Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2235             Bind(&notDictionaryElement);
2236             {
2237                 Label lessThanLength(env);
2238                 Label notLessThanLength(env);
2239                 Branch(Int32UnsignedLessThan(index, GetLengthOfTaggedArray(elements)),
2240                        &lessThanLength, &notLessThanLength);
2241                 Bind(&lessThanLength);
2242                 {
2243                     Label notHole(env);
2244                     Label isHole(env);
2245                     GateRef value = GetValueFromTaggedArray(elements, index);
2246                     callback.ProfileObjLayoutByLoad(receiver);
2247                     Branch(TaggedIsNotHole(value), &notHole, &isHole);
2248                     Bind(&notHole);
2249                     {
2250                         result = value;
2251                         Jump(&exit);
2252                     }
2253                     Bind(&isHole);
2254                     {
2255                         Jump(&loopExit);
2256                     }
2257                 }
2258                 Bind(&notLessThanLength);
2259                 {
2260                     result = Hole();
2261                     Jump(&exit);
2262                 }
2263             }
2264             Bind(&isDictionaryElement);
2265             {
2266                 GateRef entryA = FindElementFromNumberDictionary(glue, elements, index);
2267                 Label notNegtiveOne(env);
2268                 Label negtiveOne(env);
2269                 Branch(Int32NotEqual(entryA, Int32(-1)), &notNegtiveOne, &negtiveOne);
2270                 Bind(&notNegtiveOne);
2271                 {
2272                     GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, entryA);
2273                     GateRef value = GetValueFromDictionary<NumberDictionary>(elements, entryA);
2274                     Label isAccessor(env);
2275                     Label notAccessor(env);
2276                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2277                     Bind(&isAccessor);
2278                     {
2279                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2280                         Jump(&exit);
2281                     }
2282                     Bind(&notAccessor);
2283                     {
2284                         result = value;
2285                         Jump(&exit);
2286                     }
2287                 }
2288                 Bind(&negtiveOne);
2289                 Jump(&loopExit);
2290             }
2291             Bind(&loopExit);
2292             {
2293                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2294                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2295             }
2296         }
2297         Bind(&loopEnd);
2298         LoopEnd(&loopHead);
2299         Bind(&afterLoop);
2300         {
2301             result = Undefined();
2302             Jump(&exit);
2303         }
2304     }
2305     Bind(&exit);
2306     auto ret = *result;
2307     env->SubCfgExit();
2308     return ret;
2309 }
2310 
GetPropertyByValue(GateRef glue,GateRef receiver,GateRef keyValue,ProfileOperation callback)2311 GateRef StubBuilder::GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue, ProfileOperation callback)
2312 {
2313     auto env = GetEnvironment();
2314     Label entry(env);
2315     env->SubCfgEntry(&entry);
2316     DEFVARIABLE(key, VariableType::JS_ANY(), keyValue);
2317     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2318     Label isNumberOrStringSymbol(env);
2319     Label notNumber(env);
2320     Label isStringOrSymbol(env);
2321     Label notStringOrSymbol(env);
2322     Label exit(env);
2323 
2324     Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, &notNumber);
2325     Bind(&notNumber);
2326     {
2327         Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, &notStringOrSymbol);
2328         Bind(&notStringOrSymbol);
2329         {
2330             result = Hole();
2331             Jump(&exit);
2332         }
2333     }
2334     Bind(&isNumberOrStringSymbol);
2335     {
2336         GateRef index64 = TryToElementsIndex(glue, *key);
2337         Label validIndex(env);
2338         Label notValidIndex(env);
2339         Label greaterThanInt32Max(env);
2340         Label notGreaterThanInt32Max(env);
2341         Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
2342         Bind(&greaterThanInt32Max);
2343         {
2344             Jump(&exit);
2345         }
2346         Bind(&notGreaterThanInt32Max);
2347         GateRef index = TruncInt64ToInt32(index64);
2348         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
2349         Bind(&validIndex);
2350         {
2351             result = GetPropertyByIndex(glue, receiver, index, callback);
2352             Jump(&exit);
2353         }
2354         Bind(&notValidIndex);
2355         {
2356             Label notNumber1(env);
2357             Label getByName(env);
2358             Branch(TaggedIsNumber(*key), &exit, &notNumber1);
2359             Bind(&notNumber1);
2360             {
2361                 Label isString(env);
2362                 Label notString(env);
2363                 Label isInternalString(env);
2364                 Label notIntenalString(env);
2365                 Branch(TaggedIsString(*key), &isString, &notString);
2366                 Bind(&isString);
2367                 {
2368                     Branch(IsInternalString(*key), &isInternalString, &notIntenalString);
2369                     Bind(&isInternalString);
2370                     Jump(&getByName);
2371                     Bind(&notIntenalString);
2372                     {
2373                         key = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *key });
2374                         Jump(&getByName);
2375                     }
2376                 }
2377                 Bind(&notString);
2378                 {
2379                     Jump(&getByName);
2380                 }
2381             }
2382             Bind(&getByName);
2383             {
2384                 result = GetPropertyByName(glue, receiver, *key, callback);
2385                 Jump(&exit);
2386             }
2387         }
2388     }
2389     Bind(&exit);
2390     auto ret = *result;
2391     env->SubCfgExit();
2392     return ret;
2393 }
2394 
GetPropertyByName(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback)2395 GateRef StubBuilder::GetPropertyByName(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
2396 {
2397     auto env = GetEnvironment();
2398     Label entry(env);
2399     env->SubCfgEntry(&entry);
2400     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2401     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2402     Label exit(env);
2403     Label loopHead(env);
2404     Label loopEnd(env);
2405     Label loopExit(env);
2406     Label afterLoop(env);
2407     Jump(&loopHead);
2408     LoopBegin(&loopHead);
2409     {
2410         GateRef hclass = LoadHClass(*holder);
2411         GateRef jsType = GetObjectType(hclass);
2412         Label isSIndexObj(env);
2413         Label notSIndexObj(env);
2414         Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2415         Bind(&isSIndexObj);
2416         {
2417             // TypeArray
2418             Label isFastTypeArray(env);
2419             Label notFastTypeArray(env);
2420             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2421             Bind(&isFastTypeArray);
2422             {
2423                 result = GetTypeArrayPropertyByName(glue, receiver, *holder, key, jsType);
2424                 Label isNull(env);
2425                 Label notNull(env);
2426                 Branch(TaggedIsNull(*result), &isNull, &notNull);
2427                 Bind(&isNull);
2428                 {
2429                     result = Hole();
2430                     Jump(&exit);
2431                 }
2432                 Bind(&notNull);
2433                 Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2434             }
2435             Bind(&notFastTypeArray);
2436             {
2437                 result = Hole();
2438                 Jump(&exit);
2439             }
2440         }
2441         Bind(&notSIndexObj);
2442         {
2443             Label isDicMode(env);
2444             Label notDicMode(env);
2445             Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2446             Bind(&notDicMode);
2447             {
2448                 GateRef layOutInfo = GetLayoutFromHClass(hclass);
2449                 GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2450                 // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2451                 GateRef entryA = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2452                 Label hasEntry(env);
2453                 Label noEntry(env);
2454                 // if branch condition : entry != -1
2455                 Branch(Int32NotEqual(entryA, Int32(-1)), &hasEntry, &noEntry);
2456                 Bind(&hasEntry);
2457                 {
2458                     // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2459                     GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entryA);
2460                     GateRef attr = GetInt32OfTInt(propAttr);
2461                     GateRef value = JSObjectGetProperty(*holder, hclass, attr);
2462                     Label isPropertyBox(env);
2463                     Label notPropertyBox(env);
2464                     Branch(TaggedIsPropertyBox(value), &isPropertyBox, &notPropertyBox);
2465                     Bind(&isPropertyBox);
2466                     {
2467                         result = GetValueFromPropertyBox(value);
2468                         Jump(&exit);
2469                     }
2470                     Bind(&notPropertyBox);
2471                     Label isAccessor(env);
2472                     Label notAccessor(env);
2473                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2474                     Bind(&isAccessor);
2475                     {
2476                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2477                         Jump(&exit);
2478                     }
2479                     Bind(&notAccessor);
2480                     {
2481                         Label notHole(env);
2482                         Branch(TaggedIsHole(value), &noEntry, &notHole);
2483                         Bind(&notHole);
2484                         {
2485                             result = value;
2486                             Jump(&exit);
2487                         }
2488                     }
2489                 }
2490                 Bind(&noEntry);
2491                 {
2492                     Jump(&loopExit);
2493                 }
2494             }
2495             Bind(&isDicMode);
2496             {
2497                 GateRef array = GetPropertiesArray(*holder);
2498                 // int entry = dict->FindEntry(key)
2499                 GateRef entryB = FindEntryFromNameDictionary(glue, array, key);
2500                 Label notNegtiveOne(env);
2501                 Label negtiveOne(env);
2502                 // if branch condition : entry != -1
2503                 Branch(Int32NotEqual(entryB, Int32(-1)), &notNegtiveOne, &negtiveOne);
2504                 Bind(&notNegtiveOne);
2505                 {
2506                     // auto value = dict->GetValue(entry)
2507                     GateRef attr = GetAttributesFromDictionary<NameDictionary>(array, entryB);
2508                     // auto attr = dict->GetAttributes(entry)
2509                     GateRef value = GetValueFromDictionary<NameDictionary>(array, entryB);
2510                     Label isAccessor1(env);
2511                     Label notAccessor1(env);
2512                     Branch(IsAccessor(attr), &isAccessor1, &notAccessor1);
2513                     Bind(&isAccessor1);
2514                     {
2515                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2516                         Jump(&exit);
2517                     }
2518                     Bind(&notAccessor1);
2519                     {
2520                         result = value;
2521                         Jump(&exit);
2522                     }
2523                 }
2524                 Bind(&negtiveOne);
2525                 Jump(&loopExit);
2526             }
2527             Bind(&loopExit);
2528             {
2529                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2530                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2531             }
2532         }
2533         Bind(&loopEnd);
2534         LoopEnd(&loopHead);
2535         Bind(&afterLoop);
2536         {
2537             result = Undefined();
2538             Jump(&exit);
2539         }
2540     }
2541     Bind(&exit);
2542     auto ret = *result;
2543     env->SubCfgExit();
2544     return ret;
2545 }
2546 
CopyAllHClass(GateRef glue,GateRef dstHClass,GateRef srcHClass)2547 void StubBuilder::CopyAllHClass(GateRef glue, GateRef dstHClass, GateRef srcHClass)
2548 {
2549     auto env = GetEnvironment();
2550     Label entry(env);
2551     env->SubCfgEntry(&entry);
2552     auto proto = GetPrototypeFromHClass(srcHClass);
2553     SetPrototypeToHClass(VariableType::JS_POINTER(), glue, dstHClass, proto);
2554     SetBitFieldToHClass(glue, dstHClass, GetBitFieldFromHClass(srcHClass));
2555     SetIsAllTaggedProp(glue, dstHClass, GetIsAllTaggedPropFromHClass(srcHClass));
2556     SetNumberOfPropsToHClass(glue, dstHClass, GetNumberOfPropsFromHClass(srcHClass));
2557     SetTransitionsToHClass(VariableType::INT64(), glue, dstHClass, Undefined());
2558     SetProtoChangeDetailsToHClass(VariableType::INT64(), glue, dstHClass, Null());
2559     SetEnumCacheToHClass(VariableType::INT64(), glue, dstHClass, Null());
2560     SetLayoutToHClass(VariableType::JS_POINTER(), glue, dstHClass, GetLayoutFromHClass(srcHClass));
2561     env->SubCfgExit();
2562     return;
2563 }
2564 
TransitionForRepChange(GateRef glue,GateRef receiver,GateRef key,GateRef attr)2565 void StubBuilder::TransitionForRepChange(GateRef glue, GateRef receiver, GateRef key, GateRef attr)
2566 {
2567     auto env = GetEnvironment();
2568     Label subEntry(env);
2569     env->SubCfgEntry(&subEntry);
2570     GateRef hclass = LoadHClass(receiver);
2571     GateRef type = GetObjectType(hclass);
2572     GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass),
2573                             Int32(JSTaggedValue::TaggedTypeSize()));
2574     GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass);
2575     GateRef newJshclass = CallRuntime(glue, RTSTUB_ID(NewEcmaHClass),
2576         { IntToTaggedInt(size), IntToTaggedInt(type),
2577           IntToTaggedInt(inlineProps) });
2578     CopyAllHClass(glue, newJshclass, hclass);
2579     CallRuntime(glue, RTSTUB_ID(CopyAndUpdateObjLayout),
2580                 { hclass, newJshclass, key, IntToTaggedInt(attr) });
2581 #if ECMASCRIPT_ENABLE_IC
2582     NotifyHClassChanged(glue, hclass, newJshclass);
2583 #endif
2584     StoreHClass(glue, receiver, newJshclass);
2585     env->SubCfgExit();
2586 }
2587 
TransitToElementsKind(GateRef glue,GateRef receiver,GateRef value,GateRef kind)2588 void StubBuilder::TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind)
2589 {
2590     auto env = GetEnvironment();
2591     Label subEntry(env);
2592     env->SubCfgEntry(&subEntry);
2593     Label exit(env);
2594 
2595     GateRef hclass = LoadHClass(receiver);
2596     GateRef elementsKind = GetElementsKindFromHClass(hclass);
2597 
2598     Label isNoneDefault(env);
2599     Branch(Int32Equal(elementsKind, Int32(static_cast<int32_t>(ElementsKind::GENERIC))), &exit, &isNoneDefault);
2600     Bind(&isNoneDefault);
2601     {
2602         GateRef newKind = TaggedToElementKind(value);
2603         newKind = Int32Or(newKind, kind);
2604         newKind = Int32Or(newKind, elementsKind);
2605         Label change(env);
2606         Branch(Int32Equal(elementsKind, newKind), &exit, &change);
2607         Bind(&change);
2608         {
2609             CallRuntime(glue, RTSTUB_ID(UpdateHClassForElementsKind), { receiver, newKind });
2610             Jump(&exit);
2611         }
2612     }
2613 
2614     Bind(&exit);
2615     env->SubCfgExit();
2616 }
2617 
FindTransitions(GateRef glue,GateRef receiver,GateRef hclass,GateRef key,GateRef metaData)2618 GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, GateRef key, GateRef metaData)
2619 {
2620     auto env = GetEnvironment();
2621     Label entry(env);
2622     env->SubCfgEntry(&entry);
2623     Label exit(env);
2624     GateRef transitionOffset = IntPtr(JSHClass::TRANSTIONS_OFFSET);
2625     GateRef transition = Load(VariableType::JS_POINTER(), hclass, transitionOffset);
2626     DEFVARIABLE(result, VariableType::JS_ANY(), transition);
2627 
2628     Label notUndefined(env);
2629     Branch(Equal(transition, Undefined()), &exit, &notUndefined);
2630     Bind(&notUndefined);
2631     {
2632         Label isWeak(env);
2633         Label notWeak(env);
2634         Branch(TaggedIsWeak(transition), &isWeak, &notWeak);
2635         Bind(&isWeak);
2636         {
2637             GateRef transitionHClass = LoadObjectFromWeakRef(transition);
2638             GateRef propNums = GetNumberOfPropsFromHClass(transitionHClass);
2639             GateRef last = Int32Sub(propNums, Int32(1));
2640             GateRef layoutInfo = GetLayoutFromHClass(transitionHClass);
2641             GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last);
2642             GateRef cachedAttr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(layoutInfo, last));
2643             GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr);
2644             Label keyMatch(env);
2645             Label isMatch(env);
2646             Label notMatch(env);
2647             Branch(Equal(cachedKey, key), &keyMatch, &notMatch);
2648             Bind(&keyMatch);
2649             {
2650                 Branch(Int32Equal(metaData, cachedMetaData), &isMatch, &notMatch);
2651                 Bind(&isMatch);
2652                 {
2653 #if ECMASCRIPT_ENABLE_IC
2654                     NotifyHClassChanged(glue, hclass, transitionHClass);
2655 #endif
2656                     StoreHClass(glue, receiver, transitionHClass);
2657                     Jump(&exit);
2658                 }
2659             }
2660             Bind(&notMatch);
2661             {
2662                 result = Undefined();
2663                 Jump(&exit);
2664             }
2665         }
2666         Bind(&notWeak);
2667         {
2668             // need to find from dictionary
2669             GateRef entryA = FindEntryFromTransitionDictionary(glue, transition, key, metaData);
2670             Label isFound(env);
2671             Label notFound(env);
2672             Branch(Int32NotEqual(entryA, Int32(-1)), &isFound, &notFound);
2673             Bind(&isFound);
2674             auto value = GetValueFromDictionary<TransitionsDictionary>(transition, entryA);
2675             Label valueUndefined(env);
2676             Label valueNotUndefined(env);
2677             Branch(Int64NotEqual(value, Undefined()), &valueNotUndefined,
2678                 &valueUndefined);
2679             Bind(&valueNotUndefined);
2680             {
2681                 GateRef newHClass = LoadObjectFromWeakRef(value);
2682                 result = newHClass;
2683 #if ECMASCRIPT_ENABLE_IC
2684                 NotifyHClassChanged(glue, hclass, newHClass);
2685 #endif
2686                 StoreHClass(glue, receiver, newHClass);
2687                 Jump(&exit);
2688                 Bind(&notFound);
2689                 result = Undefined();
2690                 Jump(&exit);
2691             }
2692             Bind(&valueUndefined);
2693             {
2694                 result = Undefined();
2695                 Jump(&exit);
2696             }
2697         }
2698     }
2699     Bind(&exit);
2700     auto ret = *result;
2701     env->SubCfgExit();
2702     return ret;
2703 }
2704 
SetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,GateRef value,bool useOwn,ProfileOperation callback)2705 GateRef StubBuilder::SetPropertyByIndex(
2706     GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn, ProfileOperation callback)
2707 {
2708     auto env = GetEnvironment();
2709     Label entry(env);
2710     env->SubCfgEntry(&entry);
2711     DEFVARIABLE(returnValue, VariableType::JS_ANY(), Hole());
2712     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2713     Label exit(env);
2714     Label ifEnd(env);
2715     Label loopHead(env);
2716     Label loopEnd(env);
2717     Label loopExit(env);
2718     Label afterLoop(env);
2719     Label isJsCOWArray(env);
2720     Label isNotJsCOWArray(env);
2721     Label setElementsArray(env);
2722     if (!useOwn) {
2723         Jump(&loopHead);
2724         LoopBegin(&loopHead);
2725     }
2726     GateRef hclass = LoadHClass(*holder);
2727     GateRef jsType = GetObjectType(hclass);
2728     Label isSpecialIndex(env);
2729     Label notSpecialIndex(env);
2730     Branch(IsSpecialIndexedObj(jsType), &isSpecialIndex, &notSpecialIndex);
2731     Bind(&isSpecialIndex);
2732     {
2733         // TypeArray
2734         Label isFastTypeArray(env);
2735         Label notFastTypeArray(env);
2736         Label checkIsOnPrototypeChain(env);
2737         Label notTypedArrayProto(env);
2738         Branch(Int32Equal(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY))), &exit, &notTypedArrayProto);
2739         Bind(&notTypedArrayProto);
2740         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2741         Bind(&isFastTypeArray);
2742         {
2743             Branch(Equal(*holder, receiver), &checkIsOnPrototypeChain, &exit);
2744             Bind(&checkIsOnPrototypeChain);
2745             {
2746                 returnValue = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
2747                     { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType)});
2748                 Jump(&exit);
2749             }
2750         }
2751         Bind(&notFastTypeArray);
2752         returnValue = Hole();
2753         Jump(&exit);
2754     }
2755     Bind(&notSpecialIndex);
2756     {
2757         GateRef elements = GetElementsArray(*holder);
2758         Label isDictionaryElement(env);
2759         Label notDictionaryElement(env);
2760         Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2761         Bind(&notDictionaryElement);
2762         {
2763             Label isReceiver(env);
2764             if (useOwn) {
2765                 Branch(Equal(*holder, receiver), &isReceiver, &ifEnd);
2766             } else {
2767                 Branch(Equal(*holder, receiver), &isReceiver, &afterLoop);
2768             }
2769             Bind(&isReceiver);
2770             {
2771                 GateRef length = GetLengthOfTaggedArray(elements);
2772                 Label inRange(env);
2773                 if (useOwn) {
2774                     Branch(Int64LessThan(index, length), &inRange, &ifEnd);
2775                 } else {
2776                     Branch(Int64LessThan(index, length), &inRange, &loopExit);
2777                 }
2778                 Bind(&inRange);
2779                 {
2780                     GateRef value1 = GetValueFromTaggedArray(elements, index);
2781                     Label notHole(env);
2782                     if (useOwn) {
2783                         Branch(Int64NotEqual(value1, Hole()), &notHole, &ifEnd);
2784                     } else {
2785                         Branch(Int64NotEqual(value1, Hole()), &notHole, &loopExit);
2786                     }
2787                     Bind(&notHole);
2788                     {
2789                         Branch(IsJsCOWArray(*holder), &isJsCOWArray, &isNotJsCOWArray);
2790                         Bind(&isJsCOWArray);
2791                         {
2792                             GateRef newElements = CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {*holder});
2793                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, newElements, index, value);
2794                             TransitToElementsKind(
2795                                 glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
2796                             callback.ProfileObjLayoutByStore(receiver);
2797                             returnValue = Undefined();
2798                             Jump(&exit);
2799                         }
2800                         Bind(&isNotJsCOWArray);
2801                         {
2802                             Jump(&setElementsArray);
2803                         }
2804                         Bind(&setElementsArray);
2805                         {
2806                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
2807                             TransitToElementsKind(
2808                                 glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
2809                             callback.ProfileObjLayoutByStore(receiver);
2810                             returnValue = Undefined();
2811                             Jump(&exit);
2812                         }
2813                     }
2814                 }
2815             }
2816         }
2817         Bind(&isDictionaryElement);
2818         {
2819             returnValue = Hole();
2820             Jump(&exit);
2821         }
2822     }
2823     if (useOwn) {
2824         Bind(&ifEnd);
2825     } else {
2826         Bind(&loopExit);
2827         {
2828             holder = GetPrototypeFromHClass(LoadHClass(*holder));
2829             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2830         }
2831         Bind(&loopEnd);
2832         LoopEnd(&loopHead);
2833         Bind(&afterLoop);
2834     }
2835     Label isExtensible(env);
2836     Label notExtensible(env);
2837     Branch(IsExtensible(receiver), &isExtensible, &notExtensible);
2838     Bind(&isExtensible);
2839     {
2840         GateRef result = CallRuntime(glue, RTSTUB_ID(AddElementInternal),
2841             { receiver, IntToTaggedInt(index), value,
2842             IntToTaggedInt(Int32(PropertyAttributes::GetDefaultAttributes())) });
2843         Label success(env);
2844         Label failed(env);
2845         Branch(TaggedIsTrue(result), &success, &failed);
2846         Bind(&success);
2847         {
2848             callback.ProfileObjLayoutByStore(receiver);
2849             returnValue = Undefined();
2850             Jump(&exit);
2851         }
2852         Bind(&failed);
2853         {
2854             returnValue = Exception();
2855             Jump(&exit);
2856         }
2857     }
2858     Bind(&notExtensible);
2859     {
2860         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
2861         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2862         returnValue = Exception();
2863         Jump(&exit);
2864     }
2865     Bind(&exit);
2866     auto ret = *returnValue;
2867     env->SubCfgExit();
2868     return ret;
2869 }
2870 
SetPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn,ProfileOperation callback)2871 GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn,
2872     ProfileOperation callback)
2873 {
2874     auto env = GetEnvironment();
2875     Label entryPass(env);
2876     env->SubCfgEntry(&entryPass);
2877     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2878     DEFVARIABLE(holder, VariableType::JS_POINTER(), receiver);
2879     DEFVARIABLE(receiverHoleEntry, VariableType::INT32(), Int32(-1));
2880     Label exit(env);
2881     Label ifEnd(env);
2882     Label loopHead(env);
2883     Label loopEnd(env);
2884     Label loopExit(env);
2885     Label afterLoop(env);
2886     if (!useOwn) {
2887         // a do-while loop
2888         Jump(&loopHead);
2889         LoopBegin(&loopHead);
2890     }
2891     // auto *hclass = holder.GetTaggedObject()->GetClass()
2892     // JSType jsType = hclass->GetObjectType()
2893     GateRef hclass = LoadHClass(*holder);
2894     GateRef jsType = GetObjectType(hclass);
2895     Label isSIndexObj(env);
2896     Label notSIndexObj(env);
2897     // if branch condition : IsSpecialIndexedObj(jsType)
2898     Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2899     Bind(&isSIndexObj);
2900     {
2901         Label isFastTypeArray(env);
2902         Label notFastTypeArray(env);
2903         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2904         Bind(&isFastTypeArray);
2905         {
2906             result = SetTypeArrayPropertyByName(glue, receiver, *holder, key, value, jsType);
2907             Label isNull(env);
2908             Label notNull(env);
2909             Branch(TaggedIsNull(*result), &isNull, &notNull);
2910             Bind(&isNull);
2911             {
2912                 result = Hole();
2913                 Jump(&exit);
2914             }
2915             Bind(&notNull);
2916             Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2917         }
2918         Bind(&notFastTypeArray);
2919 
2920         Label isSpecialContainer(env);
2921         Label notSpecialContainer(env);
2922         // Add SpecialContainer
2923         Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
2924         Bind(&isSpecialContainer);
2925         {
2926             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotSetPropertyOnContainer));
2927             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2928             result = Exception();
2929             Jump(&exit);
2930         }
2931         Bind(&notSpecialContainer);
2932         {
2933             result = Hole();
2934             Jump(&exit);
2935         }
2936     }
2937     Bind(&notSIndexObj);
2938     {
2939         Label isDicMode(env);
2940         Label notDicMode(env);
2941         // if branch condition : LIKELY(!hclass->IsDictionaryMode())
2942         Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2943         Bind(&notDicMode);
2944         {
2945             // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject())
2946             GateRef layOutInfo = GetLayoutFromHClass(hclass);
2947             // int propsNumber = hclass->NumberOfPropsFromHClass()
2948             GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2949             // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2950             GateRef entry = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2951             Label hasEntry(env);
2952             // if branch condition : entry != -1
2953             if (useOwn) {
2954                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &ifEnd);
2955             } else {
2956                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &loopExit);
2957             }
2958             Bind(&hasEntry);
2959             {
2960                 // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2961                 GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry);
2962                 GateRef attr = GetInt32OfTInt(propAttr);
2963                 Label isAccessor(env);
2964                 Label notAccessor(env);
2965                 Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2966                 Bind(&isAccessor);
2967                 {
2968                     // auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr)
2969                     GateRef accessor = JSObjectGetProperty(*holder, hclass, attr);
2970                     Label shouldCall(env);
2971                     // ShouldCallSetter(receiver, *holder, accessor, attr)
2972                     Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &notAccessor);
2973                     Bind(&shouldCall);
2974                     {
2975                         result = CallSetterHelper(glue, receiver, accessor, value, callback);
2976                         Jump(&exit);
2977                     }
2978                 }
2979                 Bind(&notAccessor);
2980                 {
2981                     Label writable(env);
2982                     Label notWritable(env);
2983                     Branch(IsWritable(attr), &writable, &notWritable);
2984                     Bind(&notWritable);
2985                     {
2986                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
2987                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
2988                         result = Exception();
2989                         Jump(&exit);
2990                     }
2991                     Bind(&writable);
2992                     {
2993                         Label isTS(env);
2994                         Label notTS(env);
2995                         Branch(IsTSHClass(hclass), &isTS, &notTS);
2996                         Bind(&isTS);
2997                         {
2998                             GateRef attrVal = JSObjectGetProperty(*holder, hclass, attr);
2999                             Label attrValIsHole(env);
3000                             Branch(TaggedIsHole(attrVal), &attrValIsHole, &notTS);
3001                             Bind(&attrValIsHole);
3002                             {
3003                                 Label storeReceiverHoleEntry(env);
3004                                 Label noNeedStore(env);
3005                                 GateRef checkReceiverHoleEntry = Int32Equal(*receiverHoleEntry, Int32(-1));
3006                                 GateRef checkHolderEqualsRecv = Equal(*holder, receiver);
3007                                 Branch(BoolAnd(checkReceiverHoleEntry, checkHolderEqualsRecv),
3008                                     &storeReceiverHoleEntry, &noNeedStore);
3009                                 Bind(&storeReceiverHoleEntry);
3010                                 {
3011                                     receiverHoleEntry = entry;
3012                                     Jump(&noNeedStore);
3013                                 }
3014                                 Bind(&noNeedStore);
3015                                 if (useOwn) {
3016                                     Jump(&ifEnd);
3017                                 } else {
3018                                     Jump(&loopExit);
3019                                 }
3020                             }
3021                         }
3022                         Bind(&notTS);
3023                         Label holdEqualsRecv(env);
3024                         if (useOwn) {
3025                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &ifEnd);
3026                         } else {
3027                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &afterLoop);
3028                         }
3029                         Bind(&holdEqualsRecv);
3030                         {
3031                             // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value)
3032                             // return JSTaggedValue::Undefined()
3033                             JSObjectSetProperty(glue, *holder, hclass, attr, key, value);
3034                             ProfilerStubBuilder(env).UpdatePropAttrWithValue(
3035                                 glue, *holder, layOutInfo, attr, entry, value, callback);
3036                             result = Undefined();
3037                             Jump(&exit);
3038                         }
3039                     }
3040                 }
3041             }
3042         }
3043         Bind(&isDicMode);
3044         {
3045             GateRef array = GetPropertiesArray(*holder);
3046             // int entry = dict->FindEntry(key)
3047             GateRef entry1 = FindEntryFromNameDictionary(glue, array, key);
3048             Label notNegtiveOne(env);
3049             // if branch condition : entry != -1
3050             if (useOwn) {
3051                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &ifEnd);
3052             } else {
3053                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &loopExit);
3054             }
3055             Bind(&notNegtiveOne);
3056             {
3057                 // auto attr = dict->GetAttributes(entry)
3058                 GateRef attr1 = GetAttributesFromDictionary<NameDictionary>(array, entry1);
3059                 Label isAccessor1(env);
3060                 Label notAccessor1(env);
3061                 // if branch condition : UNLIKELY(attr.IsAccessor())
3062                 Branch(IsAccessor(attr1), &isAccessor1, &notAccessor1);
3063                 Bind(&isAccessor1);
3064                 {
3065                     // auto accessor = dict->GetValue(entry)
3066                     GateRef accessor1 = GetValueFromDictionary<NameDictionary>(array, entry1);
3067                     Label shouldCall1(env);
3068                     Branch(ShouldCallSetter(receiver, *holder, accessor1, attr1), &shouldCall1, &notAccessor1);
3069                     Bind(&shouldCall1);
3070                     {
3071                         result = CallSetterHelper(glue, receiver, accessor1, value, callback);
3072                         Jump(&exit);
3073                     }
3074                 }
3075                 Bind(&notAccessor1);
3076                 {
3077                     Label writable1(env);
3078                     Label notWritable1(env);
3079                     Branch(IsWritable(attr1), &writable1, &notWritable1);
3080                     Bind(&notWritable1);
3081                     {
3082                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
3083                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3084                         result = Exception();
3085                         Jump(&exit);
3086                     }
3087                     Bind(&writable1);
3088                     {
3089                         Label holdEqualsRecv1(env);
3090                         if (useOwn) {
3091                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &ifEnd);
3092                         } else {
3093                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &afterLoop);
3094                         }
3095                         Bind(&holdEqualsRecv1);
3096                         {
3097                             // dict->UpdateValue(thread, entry, value)
3098                             // return JSTaggedValue::Undefined()
3099                             UpdateValueInDict(glue, array, entry1, value);
3100                             result = Undefined();
3101                             Jump(&exit);
3102                         }
3103                     }
3104                 }
3105             }
3106         }
3107     }
3108     if (useOwn) {
3109         Bind(&ifEnd);
3110     } else {
3111         Bind(&loopExit);
3112         {
3113             // holder = hclass->GetPrototype()
3114             holder = GetPrototypeFromHClass(LoadHClass(*holder));
3115             // loop condition for a do-while loop
3116             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
3117         }
3118         Bind(&loopEnd);
3119         LoopEnd(&loopHead);
3120         Bind(&afterLoop);
3121     }
3122 
3123     Label holeEntryNotNegtiveOne(env);
3124     Label holeEntryIfEnd(env);
3125     Branch(Int32NotEqual(*receiverHoleEntry, Int32(-1)), &holeEntryNotNegtiveOne, &holeEntryIfEnd);
3126     Bind(&holeEntryNotNegtiveOne);
3127     {
3128         GateRef receiverHClass = LoadHClass(receiver);
3129         GateRef receiverLayoutInfo = GetLayoutFromHClass(receiverHClass);
3130         GateRef holePropAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry);
3131         GateRef holeAttr = GetInt32OfTInt(holePropAttr);
3132         JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, key, value);
3133         ProfilerStubBuilder(env).UpdatePropAttrWithValue(
3134             glue, receiver, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback);
3135         result = Undefined();
3136         Jump(&exit);
3137     }
3138     Bind(&holeEntryIfEnd);
3139 
3140     Label extensible(env);
3141     Label inextensible(env);
3142     Branch(IsExtensible(receiver), &extensible, &inextensible);
3143     Bind(&inextensible);
3144     {
3145         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
3146         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3147         result = Exception();
3148         Jump(&exit);
3149     }
3150     Bind(&extensible);
3151     {
3152         result = AddPropertyByName(glue, receiver, key, value,
3153             Int32(PropertyAttributes::GetDefaultAttributes()), callback);
3154         Jump(&exit);
3155     }
3156     Bind(&exit);
3157     auto ret = *result;
3158     env->SubCfgExit();
3159     return ret;
3160 }
3161 
SetPropertyByValue(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn,ProfileOperation callback)3162 GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn,
3163     ProfileOperation callback)
3164 {
3165     auto env = GetEnvironment();
3166     Label subEntry1(env);
3167     env->SubCfgEntry(&subEntry1);
3168     DEFVARIABLE(varKey, VariableType::JS_ANY(), key);
3169     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3170     Label isNumberOrStringSymbol(env);
3171     Label notNumber(env);
3172     Label isStringOrSymbol(env);
3173     Label notStringOrSymbol(env);
3174     Label exit(env);
3175     Branch(TaggedIsNumber(*varKey), &isNumberOrStringSymbol, &notNumber);
3176     Bind(&notNumber);
3177     {
3178         Branch(TaggedIsStringOrSymbol(*varKey), &isNumberOrStringSymbol, &notStringOrSymbol);
3179         Bind(&notStringOrSymbol);
3180         {
3181             result = Hole();
3182             Jump(&exit);
3183         }
3184     }
3185     Bind(&isNumberOrStringSymbol);
3186     {
3187         GateRef index64 = TryToElementsIndex(glue, *varKey);
3188         Label validIndex(env);
3189         Label notValidIndex(env);
3190         Label greaterThanInt32Max(env);
3191         Label notGreaterThanInt32Max(env);
3192         Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
3193         Bind(&greaterThanInt32Max);
3194         {
3195             Jump(&exit);
3196         }
3197         Bind(&notGreaterThanInt32Max);
3198         GateRef index = TruncInt64ToInt32(index64);
3199         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
3200         Bind(&validIndex);
3201         {
3202             result = SetPropertyByIndex(glue, receiver, index, value, useOwn, callback);
3203             Jump(&exit);
3204         }
3205         Bind(&notValidIndex);
3206         {
3207             Label isNumber1(env);
3208             Label notNumber1(env);
3209             Label setByName(env);
3210             Branch(TaggedIsNumber(*varKey), &isNumber1, &notNumber1);
3211             Bind(&isNumber1);
3212             {
3213                 result = Hole();
3214                 Jump(&exit);
3215             }
3216             Bind(&notNumber1);
3217             {
3218                 Label isString(env);
3219                 Label notIntenalString(env);
3220                 Branch(TaggedIsString(*varKey), &isString, &setByName);
3221                 Bind(&isString);
3222                 {
3223                     Branch(IsInternalString(*varKey), &setByName, &notIntenalString);
3224                     Bind(&notIntenalString);
3225                     {
3226                         varKey = CallRuntime(glue, RTSTUB_ID(NewInternalString), { *varKey });
3227                         Jump(&setByName);
3228                     }
3229                 }
3230             }
3231             Bind(&setByName);
3232             {
3233                 result = SetPropertyByName(glue, receiver, *varKey, value, useOwn, callback);
3234                 Jump(&exit);
3235             }
3236         }
3237     }
3238     Bind(&exit);
3239     auto ret = *result;
3240     env->SubCfgExit();
3241     return ret;
3242 }
3243 
NotifyHClassChanged(GateRef glue,GateRef oldHClass,GateRef newHClass)3244 void StubBuilder::NotifyHClassChanged(GateRef glue, GateRef oldHClass, GateRef newHClass)
3245 {
3246     auto env = GetEnvironment();
3247     Label entry(env);
3248     env->SubCfgEntry(&entry);
3249     Label exit(env);
3250     Label isProtoType(env);
3251     Branch(IsProtoTypeHClass(oldHClass), &isProtoType, &exit);
3252     Bind(&isProtoType);
3253     {
3254         Label notEqualHClass(env);
3255         Branch(Equal(oldHClass, newHClass), &exit, &notEqualHClass);
3256         Bind(&notEqualHClass);
3257         {
3258             SetIsProtoTypeToHClass(glue, newHClass, True());
3259             CallRuntime(glue, RTSTUB_ID(NoticeThroughChainAndRefreshUser), { oldHClass, newHClass });
3260             Jump(&exit);
3261         }
3262     }
3263     Bind(&exit);
3264     env->SubCfgExit();
3265     return;
3266 }
3267 
GetContainerProperty(GateRef glue,GateRef receiver,GateRef index,GateRef jsType)3268 GateRef StubBuilder::GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType)
3269 {
3270     auto env = GetEnvironment();
3271     Label entry(env);
3272     env->SubCfgEntry(&entry);
3273     Label exit(env);
3274     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3275 
3276     Label isDefaultLabel(env);
3277     Label noDefaultLabel(env);
3278     Branch(IsSpecialContainer(jsType), &noDefaultLabel, &isDefaultLabel);
3279     Bind(&noDefaultLabel);
3280     {
3281         result = JSAPIContainerGet(glue, receiver, index);
3282         Jump(&exit);
3283     }
3284     Bind(&isDefaultLabel);
3285     {
3286         Jump(&exit);
3287     }
3288     Bind(&exit);
3289 
3290     auto ret = *result;
3291     env->SubCfgExit();
3292     return ret;
3293 }
3294 
FastTypeOf(GateRef glue,GateRef obj)3295 GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj)
3296 {
3297     auto env = GetEnvironment();
3298     Label entry(env);
3299     env->SubCfgEntry(&entry);
3300     Label exit(env);
3301 
3302     GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
3303         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
3304     GateRef undefinedIndex = GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX);
3305     GateRef gConstUndefinedStr = Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
3306     DEFVARIABLE(result, VariableType::JS_POINTER(), gConstUndefinedStr);
3307     Label objIsTrue(env);
3308     Label objNotTrue(env);
3309     Label defaultLabel(env);
3310     GateRef gConstBooleanStr = Load(VariableType::JS_POINTER(), gConstAddr,
3311         GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX));
3312     Branch(TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
3313     Bind(&objIsTrue);
3314     {
3315         result = gConstBooleanStr;
3316         Jump(&exit);
3317     }
3318     Bind(&objNotTrue);
3319     {
3320         Label objIsFalse(env);
3321         Label objNotFalse(env);
3322         Branch(TaggedIsFalse(obj), &objIsFalse, &objNotFalse);
3323         Bind(&objIsFalse);
3324         {
3325             result = gConstBooleanStr;
3326             Jump(&exit);
3327         }
3328         Bind(&objNotFalse);
3329         {
3330             Label objIsNull(env);
3331             Label objNotNull(env);
3332             Branch(TaggedIsNull(obj), &objIsNull, &objNotNull);
3333             Bind(&objIsNull);
3334             {
3335                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3336                     GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
3337                 Jump(&exit);
3338             }
3339             Bind(&objNotNull);
3340             {
3341                 Label objIsUndefined(env);
3342                 Label objNotUndefined(env);
3343                 Branch(TaggedIsUndefined(obj), &objIsUndefined, &objNotUndefined);
3344                 Bind(&objIsUndefined);
3345                 {
3346                     result = Load(VariableType::JS_POINTER(), gConstAddr,
3347                         GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX));
3348                     Jump(&exit);
3349                 }
3350                 Bind(&objNotUndefined);
3351                 Jump(&defaultLabel);
3352             }
3353         }
3354     }
3355     Bind(&defaultLabel);
3356     {
3357         Label objIsHeapObject(env);
3358         Label objNotHeapObject(env);
3359         Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject);
3360         Bind(&objIsHeapObject);
3361         {
3362             Label objIsString(env);
3363             Label objNotString(env);
3364             Branch(IsString(obj), &objIsString, &objNotString);
3365             Bind(&objIsString);
3366             {
3367                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3368                     GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX));
3369                 Jump(&exit);
3370             }
3371             Bind(&objNotString);
3372             {
3373                 Label objIsSymbol(env);
3374                 Label objNotSymbol(env);
3375                 Branch(IsSymbol(obj), &objIsSymbol, &objNotSymbol);
3376                 Bind(&objIsSymbol);
3377                 {
3378                     result = Load(VariableType::JS_POINTER(), gConstAddr,
3379                         GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX));
3380                     Jump(&exit);
3381                 }
3382                 Bind(&objNotSymbol);
3383                 {
3384                     Label objIsCallable(env);
3385                     Label objNotCallable(env);
3386                     Branch(IsCallable(obj), &objIsCallable, &objNotCallable);
3387                     Bind(&objIsCallable);
3388                     {
3389                         result = Load(VariableType::JS_POINTER(), gConstAddr,
3390                             GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX));
3391                         Jump(&exit);
3392                     }
3393                     Bind(&objNotCallable);
3394                     {
3395                         Label objIsBigInt(env);
3396                         Label objNotBigInt(env);
3397                         Branch(TaggedObjectIsBigInt(obj), &objIsBigInt, &objNotBigInt);
3398                         Bind(&objIsBigInt);
3399                         {
3400                             result = Load(VariableType::JS_POINTER(), gConstAddr,
3401                                 GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX));
3402                             Jump(&exit);
3403                         }
3404                         Bind(&objNotBigInt);
3405                         {
3406                             result = Load(VariableType::JS_POINTER(), gConstAddr,
3407                                 GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
3408                             Jump(&exit);
3409                         }
3410                     }
3411                 }
3412             }
3413         }
3414         Bind(&objNotHeapObject);
3415         {
3416             Label objIsNum(env);
3417             Label objNotNum(env);
3418             Branch(TaggedIsNumber(obj), &objIsNum, &objNotNum);
3419             Bind(&objIsNum);
3420             {
3421                 result = Load(VariableType::JS_POINTER(), gConstAddr,
3422                     GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX));
3423                 Jump(&exit);
3424             }
3425             Bind(&objNotNum);
3426             Jump(&exit);
3427         }
3428     }
3429     Bind(&exit);
3430     auto ret = *result;
3431     env->SubCfgExit();
3432     return ret;
3433 }
3434 
InstanceOf(GateRef glue,GateRef object,GateRef target,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)3435 GateRef StubBuilder::InstanceOf(
3436     GateRef glue, GateRef object, GateRef target, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
3437 {
3438     auto env = GetEnvironment();
3439     Label entry(env);
3440     env->SubCfgEntry(&entry);
3441     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3442     Label exit(env);
3443 
3444     // 1.If Type(target) is not Object, throw a TypeError exception.
3445     Label targetIsHeapObject(env);
3446     Label targetIsEcmaObject(env);
3447     Label targetNotEcmaObject(env);
3448     Branch(TaggedIsHeapObject(target), &targetIsHeapObject, &targetNotEcmaObject);
3449     Bind(&targetIsHeapObject);
3450     Branch(TaggedObjectIsEcmaObject(target), &targetIsEcmaObject, &targetNotEcmaObject);
3451     Bind(&targetNotEcmaObject);
3452     {
3453         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
3454         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3455         result = Exception();
3456         Jump(&exit);
3457     }
3458     Bind(&targetIsEcmaObject);
3459     {
3460         // 2.Let instOfHandler be GetMethod(target, @@hasInstance).
3461         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3462         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3463         GateRef hasInstanceSymbol = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
3464                                                       GlobalEnv::HASINSTANCE_SYMBOL_INDEX);
3465         GateRef instof = GetMethod(glue, target, hasInstanceSymbol, profileTypeInfo, slotId);
3466 
3467         // 3.ReturnIfAbrupt(instOfHandler).
3468         Label isPendingException(env);
3469         Label noPendingException(env);
3470         Branch(HasPendingException(glue), &isPendingException, &noPendingException);
3471         Bind(&isPendingException);
3472         {
3473             result = Exception();
3474             Jump(&exit);
3475         }
3476         Bind(&noPendingException);
3477 
3478         // 4.If instOfHandler is not undefined, then
3479         Label instOfNotUndefined(env);
3480         Label instOfIsUndefined(env);
3481         Label fastPath(env);
3482         Label targetNotCallable(env);
3483         Branch(TaggedIsUndefined(instof), &instOfIsUndefined, &instOfNotUndefined);
3484         Bind(&instOfNotUndefined);
3485         {
3486             TryFastHasInstance(glue, instof, target, object, &fastPath, &exit, &result, callback);
3487         }
3488         Bind(&instOfIsUndefined);
3489         {
3490             // 5.If IsCallable(target) is false, throw a TypeError exception.
3491             Branch(IsCallable(target), &fastPath, &targetNotCallable);
3492             Bind(&targetNotCallable);
3493             {
3494                 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
3495                 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3496                 result = Exception();
3497                 Jump(&exit);
3498             }
3499         }
3500         Bind(&fastPath);
3501         {
3502             // 6.Return ? OrdinaryHasInstance(target, object).
3503             result = OrdinaryHasInstance(glue, target, object);
3504             Jump(&exit);
3505         }
3506     }
3507     Bind(&exit);
3508     auto ret = *result;
3509     env->SubCfgExit();
3510     return ret;
3511 }
3512 
TryFastHasInstance(GateRef glue,GateRef instof,GateRef target,GateRef object,Label * fastPath,Label * exit,Variable * result,ProfileOperation callback)3513 void StubBuilder::TryFastHasInstance(GateRef glue, GateRef instof, GateRef target, GateRef object, Label *fastPath,
3514                                      Label *exit, Variable *result, ProfileOperation callback)
3515 {
3516     auto env = GetEnvironment();
3517 
3518     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3519     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3520     GateRef function = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::HASINSTANCE_FUNCTION_INDEX);
3521 
3522     Label slowPath(env);
3523     Label tryFastPath(env);
3524     GateRef isEqual = IntPtrEqual(instof, function);
3525     Branch(isEqual, &tryFastPath, &slowPath);
3526     Bind(&tryFastPath);
3527     Jump(fastPath);
3528     Bind(&slowPath);
3529     {
3530         GateRef retValue = JSCallDispatch(glue, instof, Int32(1), 0, Circuit::NullGate(),
3531                                           JSCallMode::CALL_SETTER, { target, object }, callback);
3532         result->WriteVariable(FastToBoolean(retValue));
3533         Jump(exit);
3534     }
3535 }
3536 
GetMethod(GateRef glue,GateRef obj,GateRef key,GateRef profileTypeInfo,GateRef slotId)3537 GateRef StubBuilder::GetMethod(GateRef glue, GateRef obj, GateRef key, GateRef profileTypeInfo, GateRef slotId)
3538 {
3539     auto env = GetEnvironment();
3540     Label entry(env);
3541     env->SubCfgEntry(&entry);
3542     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3543     Label exit(env);
3544 
3545     StringIdInfo info;
3546     AccessObjectStubBuilder builder(this);
3547     GateRef value = builder.LoadObjByName(glue, obj, key, info, profileTypeInfo, slotId, ProfileOperation());
3548 
3549     Label isPendingException(env);
3550     Label noPendingException(env);
3551     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
3552     Bind(&isPendingException);
3553     {
3554         result = Exception();
3555         Jump(&exit);
3556     }
3557     Bind(&noPendingException);
3558     Label valueIsUndefinedOrNull(env);
3559     Label valueNotUndefinedOrNull(env);
3560     Branch(TaggedIsUndefinedOrNull(value), &valueIsUndefinedOrNull, &valueNotUndefinedOrNull);
3561     Bind(&valueIsUndefinedOrNull);
3562     {
3563         result = Undefined();
3564         Jump(&exit);
3565     }
3566     Bind(&valueNotUndefinedOrNull);
3567     {
3568         Label valueIsCallable(env);
3569         Label valueNotCallable(env);
3570         Branch(IsCallable(value), &valueIsCallable, &valueNotCallable);
3571         Bind(&valueNotCallable);
3572         {
3573             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(NonCallable));
3574             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3575             result = Exception();
3576             Jump(&exit);
3577         }
3578         Bind(&valueIsCallable);
3579         {
3580             result = value;
3581             Jump(&exit);
3582         }
3583     }
3584     Bind(&exit);
3585     auto ret = *result;
3586     env->SubCfgExit();
3587     return ret;
3588 }
3589 
FastGetPropertyByName(GateRef glue,GateRef obj,GateRef key,ProfileOperation callback)3590 GateRef StubBuilder::FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback)
3591 {
3592     auto env = GetEnvironment();
3593     Label entry(env);
3594     env->SubCfgEntry(&entry);
3595     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3596     Label exit(env);
3597     Label checkResult(env);
3598     Label fastpath(env);
3599     Label slowpath(env);
3600 
3601     Branch(TaggedIsHeapObject(obj), &fastpath, &slowpath);
3602     Bind(&fastpath);
3603     {
3604         result = GetPropertyByName(glue, obj, key, callback);
3605         Branch(TaggedIsHole(*result), &slowpath, &exit);
3606     }
3607     Bind(&slowpath);
3608     {
3609         result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
3610                              { Undefined(), obj, key, Int64ToTaggedPtr(Int32(0)) });
3611         Jump(&exit);
3612     }
3613     Bind(&exit);
3614     auto ret = *result;
3615     env->SubCfgExit();
3616     return ret;
3617 }
3618 
FastGetPropertyByIndex(GateRef glue,GateRef obj,GateRef index,ProfileOperation callback)3619 GateRef StubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback)
3620 {
3621     auto env = GetEnvironment();
3622     Label entry(env);
3623     env->SubCfgEntry(&entry);
3624     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3625     Label exit(env);
3626     Label fastPath(env);
3627     Label slowPath(env);
3628 
3629     Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath);
3630     Bind(&fastPath);
3631     {
3632         result = GetPropertyByIndex(glue, obj, index, callback);
3633         Label notHole(env);
3634         Branch(TaggedIsHole(*result), &slowPath, &exit);
3635     }
3636     Bind(&slowPath);
3637     {
3638         result = CallRuntime(glue, RTSTUB_ID(LdObjByIndex),
3639             { obj, IntToTaggedInt(index), TaggedFalse(), Undefined() });
3640         Jump(&exit);
3641     }
3642     Bind(&exit);
3643     auto ret = *result;
3644     env->SubCfgExit();
3645     return ret;
3646 }
3647 
OrdinaryHasInstance(GateRef glue,GateRef target,GateRef obj)3648 GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj)
3649 {
3650     auto env = GetEnvironment();
3651     Label entry(env);
3652     env->SubCfgEntry(&entry);
3653     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3654     Label exit(env);
3655     DEFVARIABLE(object, VariableType::JS_ANY(), obj);
3656 
3657     // 1. If IsCallable(C) is false, return false.
3658     Label targetIsCallable(env);
3659     Label targetNotCallable(env);
3660     Branch(IsCallable(target), &targetIsCallable, &targetNotCallable);
3661     Bind(&targetNotCallable);
3662     {
3663         result = TaggedFalse();
3664         Jump(&exit);
3665     }
3666     Bind(&targetIsCallable);
3667     {
3668         // 2. If C has a [[BoundTargetFunction]] internal slot, then
3669         //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
3670         //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
3671         Label targetIsBoundFunction(env);
3672         Label targetNotBoundFunction(env);
3673         Branch(IsBoundFunction(target), &targetIsBoundFunction, &targetNotBoundFunction);
3674         Bind(&targetIsBoundFunction);
3675         {
3676             GateRef boundTarget = Load(VariableType::JS_ANY(), target, IntPtr(JSBoundFunction::BOUND_TARGET_OFFSET));
3677             result = CallRuntime(glue, RTSTUB_ID(InstanceOf), { obj, boundTarget });
3678             Jump(&exit);
3679         }
3680         Bind(&targetNotBoundFunction);
3681         {
3682             // 3. If Type(O) is not Object, return false
3683             Label objIsHeapObject(env);
3684             Label objIsEcmaObject(env);
3685             Label objNotEcmaObject(env);
3686             Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotEcmaObject);
3687             Bind(&objIsHeapObject);
3688             Branch(TaggedObjectIsEcmaObject(obj), &objIsEcmaObject, &objNotEcmaObject);
3689             Bind(&objNotEcmaObject);
3690             {
3691                 result = TaggedFalse();
3692                 Jump(&exit);
3693             }
3694             Bind(&objIsEcmaObject);
3695             {
3696                 // 4. Let P be Get(C, "prototype").
3697                 auto prototypeString = GetGlobalConstantValue(
3698                     VariableType::JS_POINTER(), glue, ConstantIndex::PROTOTYPE_STRING_INDEX);
3699 
3700                 GateRef constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation());
3701 
3702                 // 5. ReturnIfAbrupt(P).
3703                 // no throw exception, so needn't return
3704                 Label isPendingException(env);
3705                 Label noPendingException(env);
3706                 Branch(HasPendingException(glue), &isPendingException, &noPendingException);
3707                 Bind(&isPendingException);
3708                 {
3709                     result = Exception();
3710                     Jump(&exit);
3711                 }
3712                 Bind(&noPendingException);
3713 
3714                 // 6. If Type(P) is not Object, throw a TypeError exception.
3715                 Label constructorPrototypeIsHeapObject(env);
3716                 Label constructorPrototypeIsEcmaObject(env);
3717                 Label constructorPrototypeNotEcmaObject(env);
3718                 Branch(TaggedIsHeapObject(constructorPrototype), &constructorPrototypeIsHeapObject,
3719                     &constructorPrototypeNotEcmaObject);
3720                 Bind(&constructorPrototypeIsHeapObject);
3721                 Branch(TaggedObjectIsEcmaObject(constructorPrototype), &constructorPrototypeIsEcmaObject,
3722                     &constructorPrototypeNotEcmaObject);
3723                 Bind(&constructorPrototypeNotEcmaObject);
3724                 {
3725                     GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
3726                     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3727                     result = Exception();
3728                     Jump(&exit);
3729                 }
3730                 Bind(&constructorPrototypeIsEcmaObject);
3731                 {
3732                     // 7. Repeat
3733                     //    a.Let O be O.[[GetPrototypeOf]]().
3734                     //    b.ReturnIfAbrupt(O).
3735                     //    c.If O is null, return false.
3736                     //    d.If SameValue(P, O) is true, return true.
3737                     Label loopHead(env);
3738                     Label loopEnd(env);
3739                     Label afterLoop(env);
3740                     Label strictEqual1(env);
3741                     Label notStrictEqual1(env);
3742                     Label shouldReturn(env);
3743                     Label shouldContinue(env);
3744 
3745                     Branch(TaggedIsNull(*object), &afterLoop, &loopHead);
3746                     LoopBegin(&loopHead);
3747                     {
3748                         GateRef isEqual = SameValue(glue, *object, constructorPrototype);
3749 
3750                         Branch(isEqual, &strictEqual1, &notStrictEqual1);
3751                         Bind(&strictEqual1);
3752                         {
3753                             result = TaggedTrue();
3754                             Jump(&exit);
3755                         }
3756                         Bind(&notStrictEqual1);
3757                         {
3758                             object = GetPrototype(glue, *object);
3759 
3760                             Branch(HasPendingException(glue), &shouldReturn, &shouldContinue);
3761                             Bind(&shouldReturn);
3762                             {
3763                                 result = Exception();
3764                                 Jump(&exit);
3765                             }
3766                         }
3767                         Bind(&shouldContinue);
3768                         Branch(TaggedIsNull(*object), &afterLoop, &loopEnd);
3769                     }
3770                     Bind(&loopEnd);
3771                     LoopEnd(&loopHead);
3772                     Bind(&afterLoop);
3773                     {
3774                         result = TaggedFalse();
3775                         Jump(&exit);
3776                     }
3777                 }
3778             }
3779         }
3780     }
3781     Bind(&exit);
3782     auto ret = *result;
3783     env->SubCfgExit();
3784     return ret;
3785 }
3786 
GetPrototype(GateRef glue,GateRef object)3787 GateRef StubBuilder::GetPrototype(GateRef glue, GateRef object)
3788 {
3789     auto env = GetEnvironment();
3790     Label entry(env);
3791     env->SubCfgEntry(&entry);
3792     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3793     Label exit(env);
3794     Label objectIsHeapObject(env);
3795     Label objectIsEcmaObject(env);
3796     Label objectNotEcmaObject(env);
3797 
3798     Branch(TaggedIsHeapObject(object), &objectIsHeapObject, &objectNotEcmaObject);
3799     Bind(&objectIsHeapObject);
3800     Branch(TaggedObjectIsEcmaObject(object), &objectIsEcmaObject, &objectNotEcmaObject);
3801     Bind(&objectNotEcmaObject);
3802     {
3803         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotGetNotEcmaObject));
3804         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3805         result = Exception();
3806         Jump(&exit);
3807     }
3808     Bind(&objectIsEcmaObject);
3809     {
3810         Label objectIsJsProxy(env);
3811         Label objectNotIsJsProxy(env);
3812         Branch(IsJsProxy(object), &objectIsJsProxy, &objectNotIsJsProxy);
3813         Bind(&objectIsJsProxy);
3814         {
3815             result = CallRuntime(glue, RTSTUB_ID(CallGetPrototype), { object });
3816             Jump(&exit);
3817         }
3818         Bind(&objectNotIsJsProxy);
3819         {
3820             result = GetPrototypeFromHClass(LoadHClass(object));
3821             Jump(&exit);
3822         }
3823     }
3824     Bind(&exit);
3825     auto ret = *result;
3826     env->SubCfgExit();
3827     return ret;
3828 }
3829 
SameValue(GateRef glue,GateRef left,GateRef right)3830 GateRef StubBuilder::SameValue(GateRef glue, GateRef left, GateRef right)
3831 {
3832     auto env = GetEnvironment();
3833     Label entry(env);
3834     env->SubCfgEntry(&entry);
3835     DEFVARIABLE(result, VariableType::BOOL(), False());
3836     Label exit(env);
3837     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
3838     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
3839     Label strictEqual(env);
3840     Label stringEqualCheck(env);
3841     Label stringCompare(env);
3842     Label bigIntEqualCheck(env);
3843     Label numberEqualCheck1(env);
3844 
3845     Branch(Equal(left, right), &strictEqual, &numberEqualCheck1);
3846     Bind(&strictEqual);
3847     {
3848         result = True();
3849         Jump(&exit);
3850     }
3851     Bind(&numberEqualCheck1);
3852     {
3853         Label leftIsNumber(env);
3854         Label leftIsNotNumber(env);
3855         Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
3856         Bind(&leftIsNumber);
3857         {
3858             Label rightIsNumber(env);
3859             Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
3860             Bind(&rightIsNumber);
3861             {
3862                 Label numberEqualCheck2(env);
3863                 Label leftIsInt(env);
3864                 Label leftNotInt(env);
3865                 Label getRight(env);
3866                 Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
3867                 Bind(&leftIsInt);
3868                 {
3869                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
3870                     Jump(&getRight);
3871                 }
3872                 Bind(&leftNotInt);
3873                 {
3874                     doubleLeft = GetDoubleOfTDouble(left);
3875                     Jump(&getRight);
3876                 }
3877                 Bind(&getRight);
3878                 {
3879                     Label rightIsInt(env);
3880                     Label rightNotInt(env);
3881                     Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
3882                     Bind(&rightIsInt);
3883                     {
3884                         doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
3885                         Jump(&numberEqualCheck2);
3886                     }
3887                     Bind(&rightNotInt);
3888                     {
3889                         doubleRight = GetDoubleOfTDouble(right);
3890                         Jump(&numberEqualCheck2);
3891                     }
3892                 }
3893                 Bind(&numberEqualCheck2);
3894                 {
3895                     Label boolAndCheck(env);
3896                     Label signbitCheck(env);
3897                     Branch(DoubleEqual(*doubleLeft, *doubleRight), &signbitCheck, &boolAndCheck);
3898                     Bind(&signbitCheck);
3899                     {
3900                         GateRef leftEncoding = CastDoubleToInt64(*doubleLeft);
3901                         GateRef RightEncoding = CastDoubleToInt64(*doubleRight);
3902                         Label leftIsMinusZero(env);
3903                         Label leftNotMinusZero(env);
3904                         Branch(Int64Equal(leftEncoding, Int64(base::MINUS_ZERO_BITS)),
3905                             &leftIsMinusZero, &leftNotMinusZero);
3906                         Bind(&leftIsMinusZero);
3907                         {
3908                             Label rightIsMinusZero(env);
3909                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &rightIsMinusZero, &exit);
3910                             Bind(&rightIsMinusZero);
3911                             {
3912                                 result = True();
3913                                 Jump(&exit);
3914                             }
3915                         }
3916                         Bind(&leftNotMinusZero);
3917                         {
3918                             Label rightNotMinusZero(env);
3919                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &exit, &rightNotMinusZero);
3920                             Bind(&rightNotMinusZero);
3921                             {
3922                                 result = True();
3923                                 Jump(&exit);
3924                             }
3925                         }
3926                     }
3927                     Bind(&boolAndCheck);
3928                     {
3929                         result = BoolAnd(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight));
3930                         Jump(&exit);
3931                     }
3932                 }
3933             }
3934         }
3935         Bind(&leftIsNotNumber);
3936         Branch(TaggedIsNumber(right), &exit, &stringEqualCheck);
3937         Bind(&stringEqualCheck);
3938         Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
3939         Bind(&stringCompare);
3940         {
3941             result = FastStringEqual(glue, left, right);
3942             Jump(&exit);
3943         }
3944         Bind(&bigIntEqualCheck);
3945         {
3946             Label leftIsBigInt(env);
3947             Label leftIsNotBigInt(env);
3948             Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
3949             Bind(&leftIsBigInt);
3950             {
3951                 Label rightIsBigInt(env);
3952                 Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
3953                 Bind(&rightIsBigInt);
3954                 result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
3955                 Jump(&exit);
3956             }
3957         }
3958     }
3959     Bind(&exit);
3960     auto ret = *result;
3961     env->SubCfgExit();
3962     return ret;
3963 }
3964 
FastStringEqual(GateRef glue,GateRef left,GateRef right)3965 GateRef StubBuilder::FastStringEqual(GateRef glue, GateRef left, GateRef right)
3966 {
3967     auto env = GetEnvironment();
3968     Label entry(env);
3969     env->SubCfgEntry(&entry);
3970     DEFVARIABLE(result, VariableType::BOOL(), False());
3971     Label exit(env);
3972     Label lengthCompare(env);
3973     Label hashcodeCompare(env);
3974     Label contentsCompare(env);
3975 
3976     Branch(Int32Equal(ZExtInt1ToInt32(IsUtf16String(left)), ZExtInt1ToInt32(IsUtf16String(right))),
3977         &lengthCompare, &exit);
3978 
3979     Bind(&lengthCompare);
3980     Branch(Int32Equal(GetLengthFromString(left), GetLengthFromString(right)), &hashcodeCompare,
3981         &exit);
3982 
3983     Bind(&hashcodeCompare);
3984     Label leftNotNeg(env);
3985     GateRef leftHash = TryGetHashcodeFromString(left);
3986     GateRef rightHash = TryGetHashcodeFromString(right);
3987     Branch(Int64Equal(leftHash, Int64(-1)), &contentsCompare, &leftNotNeg);
3988     Bind(&leftNotNeg);
3989     {
3990         Label rightNotNeg(env);
3991         Branch(Int64Equal(rightHash, Int64(-1)), &contentsCompare, &rightNotNeg);
3992         Bind(&rightNotNeg);
3993         Branch(Int64Equal(leftHash, rightHash), &contentsCompare, &exit);
3994     }
3995 
3996     Bind(&contentsCompare);
3997     {
3998         GateRef stringEqual = CallRuntime(glue, RTSTUB_ID(StringEqual), { left, right });
3999         result = Equal(stringEqual, TaggedTrue());
4000         Jump(&exit);
4001     }
4002 
4003     Bind(&exit);
4004     auto ret = *result;
4005     env->SubCfgExit();
4006     return ret;
4007 }
4008 
FastStrictEqual(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)4009 GateRef StubBuilder::FastStrictEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
4010 {
4011     auto env = GetEnvironment();
4012     Label entry(env);
4013     env->SubCfgEntry(&entry);
4014     DEFVARIABLE(result, VariableType::BOOL(), False());
4015     Label strictEqual(env);
4016     Label leftIsNumber(env);
4017     Label leftIsNotNumber(env);
4018     Label sameVariableCheck(env);
4019     Label stringEqualCheck(env);
4020     Label stringCompare(env);
4021     Label bigIntEqualCheck(env);
4022     Label exit(env);
4023     Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
4024     Bind(&leftIsNumber);
4025     {
4026         Label rightIsNumber(env);
4027         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4028         Bind(&rightIsNumber);
4029         {
4030             DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
4031             DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
4032             DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::IntType()));
4033             Label leftIsInt(env);
4034             Label leftNotInt(env);
4035             Label getRight(env);
4036             Label numberEqualCheck(env);
4037 
4038             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
4039             Bind(&leftIsInt);
4040             {
4041                 doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4042                 Jump(&getRight);
4043             }
4044             Bind(&leftNotInt);
4045             {
4046                 curType = Int32(PGOSampleType::DoubleType());
4047                 doubleLeft = GetDoubleOfTDouble(left);
4048                 Jump(&getRight);
4049             }
4050             Bind(&getRight);
4051             {
4052                 Label rightIsInt(env);
4053                 Label rightNotInt(env);
4054                 Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
4055                 Bind(&rightIsInt);
4056                 {
4057                     GateRef type = Int32(PGOSampleType::IntType());
4058                     COMBINE_TYPE_CALL_BACK(curType, type);
4059                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4060                     Jump(&numberEqualCheck);
4061                 }
4062                 Bind(&rightNotInt);
4063                 {
4064                     GateRef type = Int32(PGOSampleType::DoubleType());
4065                     COMBINE_TYPE_CALL_BACK(curType, type);
4066                     doubleRight = GetDoubleOfTDouble(right);
4067                     Jump(&numberEqualCheck);
4068                 }
4069             }
4070             Bind(&numberEqualCheck);
4071             {
4072                 Label doubleEqualCheck(env);
4073                 Branch(BoolOr(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight)), &exit, &doubleEqualCheck);
4074                 Bind(&doubleEqualCheck);
4075                 {
4076                     result = DoubleEqual(*doubleLeft, *doubleRight);
4077                     Jump(&exit);
4078                 }
4079             }
4080         }
4081     }
4082     Bind(&leftIsNotNumber);
4083     Branch(TaggedIsNumber(right), &exit, &sameVariableCheck);
4084     Bind(&sameVariableCheck);
4085     Branch(Equal(left, right), &strictEqual, &stringEqualCheck);
4086     Bind(&stringEqualCheck);
4087     Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
4088     Bind(&stringCompare);
4089     {
4090         callback.ProfileOpType(Int32(PGOSampleType::StringType()));
4091         result = FastStringEqual(glue, left, right);
4092         Jump(&exit);
4093     }
4094     Bind(&bigIntEqualCheck);
4095     {
4096         Label leftIsBigInt(env);
4097         Label leftIsNotBigInt(env);
4098         Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
4099         Bind(&leftIsBigInt);
4100         {
4101             Label rightIsBigInt(env);
4102             Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
4103             Bind(&rightIsBigInt);
4104             callback.ProfileOpType(Int32(PGOSampleType::BigIntType()));
4105             result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
4106             Jump(&exit);
4107         }
4108     }
4109     Bind(&strictEqual);
4110     {
4111         callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
4112         result = True();
4113         Jump(&exit);
4114     }
4115     Bind(&exit);
4116     auto ret = *result;
4117     env->SubCfgExit();
4118     return ret;
4119 }
4120 
FastEqual(GateRef left,GateRef right,ProfileOperation callback)4121 GateRef StubBuilder::FastEqual(GateRef left, GateRef right, ProfileOperation callback)
4122 {
4123     auto env = GetEnvironment();
4124     Label entry(env);
4125     env->SubCfgEntry(&entry);
4126     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4127     Label leftEqualRight(env);
4128     Label leftNotEqualRight(env);
4129     Label exit(env);
4130     Branch(Equal(left, right), &leftEqualRight, &leftNotEqualRight);
4131     Bind(&leftEqualRight);
4132     {
4133         Label leftIsDouble(env);
4134         Label leftNotDoubleOrLeftNotNan(env);
4135         Branch(TaggedIsDouble(left), &leftIsDouble, &leftNotDoubleOrLeftNotNan);
4136         Bind(&leftIsDouble);
4137         {
4138             callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
4139             GateRef doubleLeft = GetDoubleOfTDouble(left);
4140             Label leftIsNan(env);
4141             Label leftIsNotNan(env);
4142             Branch(DoubleIsNAN(doubleLeft), &leftIsNan, &leftIsNotNan);
4143             Bind(&leftIsNan);
4144             {
4145                 result = TaggedFalse();
4146                 Jump(&exit);
4147             }
4148             Bind(&leftIsNotNan);
4149             {
4150                 result = TaggedTrue();
4151                 Jump(&exit);
4152             }
4153         }
4154         Bind(&leftNotDoubleOrLeftNotNan);
4155         {
4156             // Collect the type of left value
4157             result = TaggedTrue();
4158             Label leftIsInt(env);
4159             Label leftIsNotInt(env);
4160             Branch(TaggedIsInt(left), &leftIsInt, &leftIsNotInt);
4161             Bind(&leftIsInt);
4162             {
4163                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4164                 Jump(&exit);
4165             }
4166             Bind(&leftIsNotInt);
4167             {
4168                 callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
4169                 Jump(&exit);
4170             }
4171         }
4172     }
4173     Bind(&leftNotEqualRight);
4174     {
4175         Label leftIsNumber(env);
4176         Label leftNotNumberOrLeftNotIntOrRightNotInt(env);
4177         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrLeftNotIntOrRightNotInt);
4178         Bind(&leftIsNumber);
4179         {
4180             Label leftIsInt(env);
4181             Branch(TaggedIsInt(left), &leftIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
4182             Bind(&leftIsInt);
4183             {
4184                 Label rightIsInt(env);
4185                 Branch(TaggedIsInt(right), &rightIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
4186                 Bind(&rightIsInt);
4187                 {
4188                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4189                     result = TaggedFalse();
4190                     Jump(&exit);
4191                 }
4192             }
4193         }
4194         Bind(&leftNotNumberOrLeftNotIntOrRightNotInt);
4195         {
4196             DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
4197             Label rightIsUndefinedOrNull(env);
4198             Label leftOrRightNotUndefinedOrNull(env);
4199             Branch(TaggedIsUndefinedOrNull(right), &rightIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull);
4200             Bind(&rightIsUndefinedOrNull);
4201             {
4202                 curType = Int32(PGOSampleType::UndefineOrNullType());
4203                 Label leftIsHeapObject(env);
4204                 Label leftNotHeapObject(env);
4205                 Branch(TaggedIsHeapObject(left), &leftIsHeapObject, &leftNotHeapObject);
4206                 Bind(&leftIsHeapObject);
4207                 {
4208                     GateRef type = Int32(PGOSampleType::HeapObjectType());
4209                     COMBINE_TYPE_CALL_BACK(curType, type);
4210                     result = TaggedFalse();
4211                     Jump(&exit);
4212                 }
4213                 Bind(&leftNotHeapObject);
4214                 {
4215                     Label leftIsUndefinedOrNull(env);
4216                     Branch(TaggedIsUndefinedOrNull(left), &leftIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull);
4217                     Bind(&leftIsUndefinedOrNull);
4218                     {
4219                         callback.ProfileOpType(*curType);
4220                         result = TaggedTrue();
4221                         Jump(&exit);
4222                     }
4223                 }
4224             }
4225             Bind(&leftOrRightNotUndefinedOrNull);
4226             {
4227                 Label leftIsBool(env);
4228                 Label leftNotBoolOrRightNotSpecial(env);
4229                 Branch(TaggedIsBoolean(left), &leftIsBool, &leftNotBoolOrRightNotSpecial);
4230                 Bind(&leftIsBool);
4231                 {
4232                     curType = Int32(PGOSampleType::BooleanType());
4233                     Label rightIsSpecial(env);
4234                     Branch(TaggedIsSpecial(right), &rightIsSpecial, &leftNotBoolOrRightNotSpecial);
4235                     Bind(&rightIsSpecial);
4236                     {
4237                         GateRef type = Int32(PGOSampleType::SpecialType());
4238                         COMBINE_TYPE_CALL_BACK(curType, type);
4239                         result = TaggedFalse();
4240                         Jump(&exit);
4241                     }
4242                 }
4243                 Bind(&leftNotBoolOrRightNotSpecial);
4244                 {
4245                     callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
4246                     Jump(&exit);
4247                 }
4248             }
4249         }
4250     }
4251     Bind(&exit);
4252     auto ret = *result;
4253     env->SubCfgExit();
4254     return ret;
4255 }
4256 
FastToBoolean(GateRef value)4257 GateRef StubBuilder::FastToBoolean(GateRef value)
4258 {
4259     auto env = GetEnvironment();
4260     Label entry(env);
4261     env->SubCfgEntry(&entry);
4262     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4263     Label exit(env);
4264 
4265     Label isSpecial(env);
4266     Label notSpecial(env);
4267     Label isNumber(env);
4268     Label isInt(env);
4269     Label isDouble(env);
4270     Label notNumber(env);
4271     Label notNan(env);
4272     Label isString(env);
4273     Label notString(env);
4274     Label isBigint(env);
4275     Label lengthIsOne(env);
4276     Label returnTrue(env);
4277     Label returnFalse(env);
4278 
4279     Branch(TaggedIsSpecial(value), &isSpecial, &notSpecial);
4280     Bind(&isSpecial);
4281     {
4282         Branch(TaggedIsTrue(value), &returnTrue, &returnFalse);
4283     }
4284     Bind(&notSpecial);
4285     {
4286         Branch(TaggedIsNumber(value), &isNumber, &notNumber);
4287         Bind(&notNumber);
4288         {
4289             Branch(IsString(value), &isString, &notString);
4290             Bind(&isString);
4291             {
4292                 auto len = GetLengthFromString(value);
4293                 Branch(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue);
4294             }
4295             Bind(&notString);
4296             Branch(TaggedObjectIsBigInt(value), &isBigint, &returnTrue);
4297             Bind(&isBigint);
4298             {
4299                 auto len = Load(VariableType::INT32(), value, IntPtr(BigInt::LENGTH_OFFSET));
4300                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &returnTrue);
4301                 Bind(&lengthIsOne);
4302                 {
4303                     auto data = PtrAdd(value, IntPtr(BigInt::DATA_OFFSET));
4304                     auto data0 = Load(VariableType::INT32(), data, Int32(0));
4305                     Branch(Int32Equal(data0, Int32(0)), &returnFalse, &returnTrue);
4306                 }
4307             }
4308         }
4309         Bind(&isNumber);
4310         {
4311             Branch(TaggedIsInt(value), &isInt, &isDouble);
4312             Bind(&isInt);
4313             {
4314                 auto intValue = GetInt32OfTInt(value);
4315                 Branch(Int32Equal(intValue, Int32(0)), &returnFalse, &returnTrue);
4316             }
4317             Bind(&isDouble);
4318             {
4319                 auto doubleValue = GetDoubleOfTDouble(value);
4320                 Branch(DoubleIsNAN(doubleValue), &returnFalse, &notNan);
4321                 Bind(&notNan);
4322                 Branch(DoubleEqual(doubleValue, Double(0.0)), &returnFalse, &returnTrue);
4323             }
4324         }
4325     }
4326     Bind(&returnTrue);
4327     {
4328         result = TaggedTrue();
4329         Jump(&exit);
4330     }
4331     Bind(&returnFalse);
4332     {
4333         result = TaggedFalse();
4334         Jump(&exit);
4335     }
4336 
4337     Bind(&exit);
4338     auto ret = *result;
4339     env->SubCfgExit();
4340     return ret;
4341 }
4342 
FastDiv(GateRef left,GateRef right,ProfileOperation callback)4343 GateRef StubBuilder::FastDiv(GateRef left, GateRef right, ProfileOperation callback)
4344 {
4345     auto env = GetEnvironment();
4346     Label entry(env);
4347     env->SubCfgEntry(&entry);
4348     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4349     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4350     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4351     DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
4352     Label leftIsNumber(env);
4353     Label leftNotNumberOrRightNotNumber(env);
4354     Label leftIsNumberAndRightIsNumber(env);
4355     Label leftIsDoubleAndRightIsDouble(env);
4356     Label exit(env);
4357     Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
4358     Bind(&leftIsNumber);
4359     {
4360         Label rightIsNumber(env);
4361         Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
4362         Bind(&rightIsNumber);
4363         {
4364             Label leftIsInt(env);
4365             Label leftNotInt(env);
4366             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
4367             Bind(&leftIsInt);
4368             {
4369                 Label rightIsInt(env);
4370                 Label bailout(env);
4371                 Branch(TaggedIsInt(right), &rightIsInt, &bailout);
4372                 Bind(&rightIsInt);
4373                 {
4374                     result = FastIntDiv(left, right, &bailout, callback);
4375                     Jump(&exit);
4376                 }
4377                 Bind(&bailout);
4378                 {
4379                     curType = Int32(PGOSampleType::IntOverFlowType());
4380                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4381                     Jump(&leftIsNumberAndRightIsNumber);
4382                 }
4383             }
4384             Bind(&leftNotInt);
4385             {
4386                 curType = Int32(PGOSampleType::DoubleType());
4387                 doubleLeft = GetDoubleOfTDouble(left);
4388                 Jump(&leftIsNumberAndRightIsNumber);
4389             }
4390         }
4391     }
4392     Bind(&leftNotNumberOrRightNotNumber);
4393     {
4394         Jump(&exit);
4395     }
4396     Bind(&leftIsNumberAndRightIsNumber);
4397     {
4398         Label rightIsInt(env);
4399         Label rightNotInt(env);
4400         Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
4401         Bind(&rightIsInt);
4402         {
4403             GateRef type = Int32(PGOSampleType::IntType());
4404             COMBINE_TYPE_CALL_BACK(curType, type);
4405             doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4406             Jump(&leftIsDoubleAndRightIsDouble);
4407         }
4408         Bind(&rightNotInt);
4409         {
4410             GateRef type = Int32(PGOSampleType::DoubleType());
4411             COMBINE_TYPE_CALL_BACK(curType, type);
4412             doubleRight = GetDoubleOfTDouble(right);
4413             Jump(&leftIsDoubleAndRightIsDouble);
4414         }
4415     }
4416     Bind(&leftIsDoubleAndRightIsDouble);
4417     {
4418         Label rightIsZero(env);
4419         Label rightNotZero(env);
4420         Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZero, &rightNotZero);
4421         Bind(&rightIsZero);
4422         {
4423             Label leftIsZero(env);
4424             Label leftNotZero(env);
4425             Label leftIsZeroOrNan(env);
4426             Label leftNotZeroAndNotNan(env);
4427             Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZero, &leftNotZero);
4428             Bind(&leftIsZero);
4429             {
4430                 Jump(&leftIsZeroOrNan);
4431             }
4432             Bind(&leftNotZero);
4433             {
4434                 Label leftIsNan(env);
4435                 Branch(DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan);
4436                 Bind(&leftIsNan);
4437                 {
4438                     Jump(&leftIsZeroOrNan);
4439                 }
4440             }
4441             Bind(&leftIsZeroOrNan);
4442             {
4443                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
4444                 Jump(&exit);
4445             }
4446             Bind(&leftNotZeroAndNotNan);
4447             {
4448                 GateRef intLeftTmp = CastDoubleToInt64(*doubleLeft);
4449                 GateRef intRightTmp = CastDoubleToInt64(*doubleRight);
4450                 GateRef flagBit = Int64And(Int64Xor(intLeftTmp, intRightTmp), Int64(base::DOUBLE_SIGN_MASK));
4451                 GateRef tmpResult = Int64Xor(flagBit, CastDoubleToInt64(Double(base::POSITIVE_INFINITY)));
4452                 result = DoubleToTaggedDoublePtr(CastInt64ToFloat64(tmpResult));
4453                 Jump(&exit);
4454             }
4455         }
4456         Bind(&rightNotZero);
4457         {
4458             result = DoubleToTaggedDoublePtr(DoubleDiv(*doubleLeft, *doubleRight));
4459             Jump(&exit);
4460         }
4461     }
4462     Bind(&exit);
4463     auto ret = *result;
4464     env->SubCfgExit();
4465     return ret;
4466 }
4467 
FastBinaryOp(GateRef left,GateRef right,const BinaryOperation & intOp,const BinaryOperation & floatOp,ProfileOperation callback)4468 GateRef StubBuilder::FastBinaryOp(GateRef left, GateRef right,
4469                                   const BinaryOperation& intOp,
4470                                   const BinaryOperation& floatOp,
4471                                   ProfileOperation callback)
4472 {
4473     auto env = GetEnvironment();
4474     Label entry(env);
4475     env->SubCfgEntry(&entry);
4476     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4477     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4478     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4479 
4480     Label exit(env);
4481     Label doFloatOp(env);
4482     Label doIntOp(env);
4483     Label leftIsNumber(env);
4484     Label rightIsNumber(env);
4485     Label leftIsIntRightIsDouble(env);
4486     Label rightIsInt(env);
4487     Label rightIsDouble(env);
4488 
4489     Branch(TaggedIsNumber(left), &leftIsNumber, &exit);
4490     Bind(&leftIsNumber);
4491     {
4492         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4493         Bind(&rightIsNumber);
4494         {
4495             Label leftIsInt(env);
4496             Label leftIsDouble(env);
4497             Branch(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
4498             Bind(&leftIsInt);
4499             {
4500                 Branch(TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
4501                 Bind(&leftIsIntRightIsDouble);
4502                 {
4503                     callback.ProfileOpType(Int32(PGOSampleType::NumberType()));
4504                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4505                     doubleRight = GetDoubleOfTDouble(right);
4506                     Jump(&doFloatOp);
4507                 }
4508             }
4509             Bind(&leftIsDouble);
4510             {
4511                 Branch(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
4512                 Bind(&rightIsInt);
4513                 {
4514                     callback.ProfileOpType(Int32(PGOSampleType::NumberType()));
4515                     doubleLeft = GetDoubleOfTDouble(left);
4516                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4517                     Jump(&doFloatOp);
4518                 }
4519                 Bind(&rightIsDouble);
4520                 {
4521                     callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
4522                     doubleLeft = GetDoubleOfTDouble(left);
4523                     doubleRight = GetDoubleOfTDouble(right);
4524                     Jump(&doFloatOp);
4525                 }
4526             }
4527         }
4528     }
4529     Bind(&doIntOp);
4530     {
4531         result = intOp(env, left, right);
4532         Jump(&exit);
4533     }
4534     Bind(&doFloatOp);
4535     {
4536         result = floatOp(env, *doubleLeft, *doubleRight);
4537         Jump(&exit);
4538     }
4539     Bind(&exit);
4540     auto ret = *result;
4541     env->SubCfgExit();
4542     return ret;
4543 }
4544 
4545 template<OpCode Op>
FastAddSubAndMul(GateRef left,GateRef right,ProfileOperation callback)4546 GateRef StubBuilder::FastAddSubAndMul(GateRef left, GateRef right, ProfileOperation callback)
4547 {
4548     auto intOperation = [=](Environment *env, GateRef left, GateRef right) {
4549         Label entry(env);
4550         env->SubCfgEntry(&entry);
4551         DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4552         Label exit(env);
4553         Label overflow(env);
4554         Label notOverflow(env);
4555         auto res = BinaryOpWithOverflow<Op, MachineType::I32>(GetInt32OfTInt(left), GetInt32OfTInt(right));
4556         GateRef condition = env->GetBuilder()->ExtractValue(MachineType::I1, res, Int32(1));
4557         Branch(condition, &overflow, &notOverflow);
4558         Bind(&overflow);
4559         {
4560             auto doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4561             auto doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4562             auto ret = BinaryOp<Op, MachineType::F64>(doubleLeft, doubleRight);
4563             result = DoubleToTaggedDoublePtr(ret);
4564             callback.ProfileOpType(Int32(PGOSampleType::IntOverFlowType()));
4565             Jump(&exit);
4566         }
4567         Bind(&notOverflow);
4568         {
4569             res = env->GetBuilder()->ExtractValue(MachineType::I32, res, Int32(0));
4570             if (Op == OpCode::MUL) {
4571                 Label resultIsZero(env);
4572                 Label returnNegativeZero(env);
4573                 Label returnResult(env);
4574                 Branch(Int32Equal(res, Int32(0)), &resultIsZero, &returnResult);
4575                 Bind(&resultIsZero);
4576                 GateRef leftNegative = Int32LessThan(GetInt32OfTInt(left), Int32(0));
4577                 GateRef rightNegative = Int32LessThan(GetInt32OfTInt(right), Int32(0));
4578                 Branch(BoolOr(leftNegative, rightNegative), &returnNegativeZero, &returnResult);
4579                 Bind(&returnNegativeZero);
4580                 result = DoubleToTaggedDoublePtr(Double(-0.0));
4581                 callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
4582                 Jump(&exit);
4583                 Bind(&returnResult);
4584                 result = IntToTaggedPtr(res);
4585                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4586                 Jump(&exit);
4587             } else {
4588                 result = IntToTaggedPtr(res);
4589                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4590                 Jump(&exit);
4591             }
4592         }
4593         Bind(&exit);
4594         auto ret = *result;
4595         env->SubCfgExit();
4596         return ret;
4597     };
4598     auto floatOperation = [=]([[maybe_unused]] Environment *env, GateRef left, GateRef right) {
4599         auto res = BinaryOp<Op, MachineType::F64>(left, right);
4600         return DoubleToTaggedDoublePtr(res);
4601     };
4602     return FastBinaryOp(left, right, intOperation, floatOperation, callback);
4603 }
4604 
FastIntDiv(GateRef left,GateRef right,Label * bailout,ProfileOperation callback)4605 GateRef StubBuilder::FastIntDiv(GateRef left, GateRef right, Label *bailout, ProfileOperation callback)
4606 {
4607     auto env = GetEnvironment();
4608     Label entry(env);
4609     env->SubCfgEntry(&entry);
4610     DEFVARIABLE(intResult, VariableType::INT32(), Int32(0));
4611 
4612     GateRef intLeft = GetInt32OfTInt(left);
4613     GateRef intRight = GetInt32OfTInt(right);
4614     Label exit(env);
4615     Label rightIsNotZero(env);
4616     Branch(Int32Equal(intRight, Int32(0)), bailout, &rightIsNotZero);
4617     Bind(&rightIsNotZero);
4618     {
4619         Label leftIsZero(env);
4620         Label leftIsNotZero(env);
4621         Branch(Int32Equal(intLeft, Int32(0)), &leftIsZero, &leftIsNotZero);
4622         Bind(&leftIsZero);
4623         {
4624             Branch(Int32LessThan(intRight, Int32(0)), bailout, &leftIsNotZero);
4625         }
4626         Bind(&leftIsNotZero);
4627         {
4628             intResult = Int32Div(intLeft, intRight);
4629             GateRef truncated = Int32Mul(*intResult, intRight);
4630             Branch(Equal(intLeft, truncated), &exit, bailout);
4631         }
4632     }
4633     Bind(&exit);
4634     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4635     auto ret = IntToTaggedPtr(*intResult);
4636     env->SubCfgExit();
4637     return ret;
4638 }
4639 
FastAdd(GateRef left,GateRef right,ProfileOperation callback)4640 GateRef StubBuilder::FastAdd(GateRef left, GateRef right, ProfileOperation callback)
4641 {
4642     return FastAddSubAndMul<OpCode::ADD>(left, right, callback);
4643 }
4644 
FastSub(GateRef left,GateRef right,ProfileOperation callback)4645 GateRef StubBuilder::FastSub(GateRef left, GateRef right, ProfileOperation callback)
4646 {
4647     return FastAddSubAndMul<OpCode::SUB>(left, right, callback);
4648 }
4649 
FastMul(GateRef left,GateRef right,ProfileOperation callback)4650 GateRef StubBuilder::FastMul(GateRef left, GateRef right, ProfileOperation callback)
4651 {
4652     return FastAddSubAndMul<OpCode::MUL>(left, right, callback);
4653 }
4654 
FastMod(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)4655 GateRef StubBuilder::FastMod(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
4656 {
4657     auto env = GetEnvironment();
4658     Label entry(env);
4659     env->SubCfgEntry(&entry);
4660     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4661     DEFVARIABLE(intLeft, VariableType::INT32(), Int32(0));
4662     DEFVARIABLE(intRight, VariableType::INT32(), Int32(0));
4663     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
4664     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
4665     Label leftIsInt(env);
4666     Label leftNotIntOrRightNotInt(env);
4667     Label exit(env);
4668     Branch(TaggedIsInt(left), &leftIsInt, &leftNotIntOrRightNotInt);
4669     Bind(&leftIsInt);
4670     {
4671         Label rightIsInt(env);
4672         Branch(TaggedIsInt(right), &rightIsInt, &leftNotIntOrRightNotInt);
4673         Bind(&rightIsInt);
4674         {
4675             intLeft = GetInt32OfTInt(left);
4676             intRight = GetInt32OfTInt(right);
4677             Label leftGreaterZero(env);
4678             Branch(Int32GreaterThanOrEqual(*intLeft, Int32(0)), &leftGreaterZero, &leftNotIntOrRightNotInt);
4679             Bind(&leftGreaterZero);
4680             {
4681                 Label rightGreaterZero(env);
4682                 Branch(Int32GreaterThan(*intRight, Int32(0)), &rightGreaterZero, &leftNotIntOrRightNotInt);
4683                 Bind(&rightGreaterZero);
4684                 {
4685                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
4686                     result = IntToTaggedPtr(Int32Mod(*intLeft, *intRight));
4687                     Jump(&exit);
4688                 }
4689             }
4690         }
4691     }
4692     Bind(&leftNotIntOrRightNotInt);
4693     {
4694         Label leftIsNumber(env);
4695         Label leftNotNumberOrRightNotNumber(env);
4696         Label leftIsNumberAndRightIsNumber(env);
4697         Label leftIsDoubleAndRightIsDouble(env);
4698         DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
4699         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
4700         Bind(&leftIsNumber);
4701         {
4702             Label rightIsNumber(env);
4703             Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
4704             Bind(&rightIsNumber);
4705             {
4706                 Label leftIsInt1(env);
4707                 Label leftNotInt1(env);
4708                 Branch(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
4709                 Bind(&leftIsInt1);
4710                 {
4711                     curType = Int32(PGOSampleType::IntType());
4712                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4713                     Jump(&leftIsNumberAndRightIsNumber);
4714                 }
4715                 Bind(&leftNotInt1);
4716                 {
4717                     curType = Int32(PGOSampleType::DoubleType());
4718                     doubleLeft = GetDoubleOfTDouble(left);
4719                     Jump(&leftIsNumberAndRightIsNumber);
4720                 }
4721             }
4722         }
4723         Bind(&leftNotNumberOrRightNotNumber);
4724         {
4725             Jump(&exit);
4726         }
4727         Bind(&leftIsNumberAndRightIsNumber);
4728         {
4729             Label rightIsInt1(env);
4730             Label rightNotInt1(env);
4731             Branch(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
4732             Bind(&rightIsInt1);
4733             {
4734                 GateRef type = Int32(PGOSampleType::IntType());
4735                 COMBINE_TYPE_CALL_BACK(curType, type);
4736                 doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4737                 Jump(&leftIsDoubleAndRightIsDouble);
4738             }
4739             Bind(&rightNotInt1);
4740             {
4741                 GateRef type = Int32(PGOSampleType::DoubleType());
4742                 COMBINE_TYPE_CALL_BACK(curType, type);
4743                 doubleRight = GetDoubleOfTDouble(right);
4744                 Jump(&leftIsDoubleAndRightIsDouble);
4745             }
4746         }
4747         Bind(&leftIsDoubleAndRightIsDouble);
4748         {
4749             Label rightNotZero(env);
4750             Label rightIsZeroOrNanOrLeftIsNanOrInf(env);
4751             Label rightNotZeroAndNanAndLeftNotNanAndInf(env);
4752             Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotZero);
4753             Bind(&rightNotZero);
4754             {
4755                 Label rightNotNan(env);
4756                 Branch(DoubleIsNAN(*doubleRight), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotNan);
4757                 Bind(&rightNotNan);
4758                 {
4759                     Label leftNotNan(env);
4760                     Branch(DoubleIsNAN(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &leftNotNan);
4761                     Bind(&leftNotNan);
4762                     {
4763                         Branch(DoubleIsINF(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf,
4764                             &rightNotZeroAndNanAndLeftNotNanAndInf);
4765                     }
4766                 }
4767             }
4768             Bind(&rightIsZeroOrNanOrLeftIsNanOrInf);
4769             {
4770                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
4771                 Jump(&exit);
4772             }
4773             Bind(&rightNotZeroAndNanAndLeftNotNanAndInf);
4774             {
4775                 Label leftNotZero(env);
4776                 Label leftIsZeroOrRightIsInf(env);
4777                 Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZeroOrRightIsInf, &leftNotZero);
4778                 Bind(&leftNotZero);
4779                 {
4780                     Label rightNotInf(env);
4781                     Branch(DoubleIsINF(*doubleRight), &leftIsZeroOrRightIsInf, &rightNotInf);
4782                     Bind(&rightNotInf);
4783                     {
4784                         result = DoubleToTaggedDoublePtr(CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
4785                             { *doubleLeft, *doubleRight }));
4786                         Jump(&exit);
4787                     }
4788                 }
4789                 Bind(&leftIsZeroOrRightIsInf);
4790                 {
4791                     result = DoubleToTaggedDoublePtr(*doubleLeft);
4792                     Jump(&exit);
4793                 }
4794             }
4795         }
4796     }
4797     Bind(&exit);
4798     auto ret = *result;
4799     env->SubCfgExit();
4800     return ret;
4801 }
4802 
GetGlobalOwnProperty(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback)4803 GateRef StubBuilder::GetGlobalOwnProperty(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
4804 {
4805     auto env = GetEnvironment();
4806     Label entryLabel(env);
4807     env->SubCfgEntry(&entryLabel);
4808     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4809     GateRef properties = GetPropertiesFromJSObject(receiver);
4810     GateRef entry = FindEntryFromNameDictionary(glue, properties, key);
4811     Label notNegtiveOne(env);
4812     Label exit(env);
4813     Branch(Int32NotEqual(entry, Int32(-1)), &notNegtiveOne, &exit);
4814     Bind(&notNegtiveOne);
4815     {
4816         result = GetValueFromGlobalDictionary(properties, entry);
4817         Label callGetter(env);
4818         Branch(TaggedIsAccessor(*result), &callGetter, &exit);
4819         Bind(&callGetter);
4820         {
4821             result = CallGetterHelper(glue, receiver, receiver, *result, callback);
4822             Jump(&exit);
4823         }
4824     }
4825     Bind(&exit);
4826     auto ret = *result;
4827     env->SubCfgExit();
4828     return ret;
4829 }
4830 
GetConstPoolFromFunction(GateRef jsFunc)4831 GateRef StubBuilder::GetConstPoolFromFunction(GateRef jsFunc)
4832 {
4833     return env_->GetBuilder()->GetConstPoolFromFunction(jsFunc);
4834 }
4835 
GetStringFromConstPool(GateRef glue,GateRef constpool,GateRef index)4836 GateRef StubBuilder::GetStringFromConstPool(GateRef glue, GateRef constpool, GateRef index)
4837 {
4838     GateRef module = Circuit::NullGate();
4839     GateRef hirGate = Circuit::NullGate();
4840     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::STRING);
4841 }
4842 
GetMethodFromConstPool(GateRef glue,GateRef constpool,GateRef index)4843 GateRef StubBuilder::GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index)
4844 {
4845     GateRef module = Circuit::NullGate();
4846     GateRef hirGate = Circuit::NullGate();
4847     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::METHOD);
4848 }
4849 
GetArrayLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)4850 GateRef StubBuilder::GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
4851 {
4852     GateRef hirGate = Circuit::NullGate();
4853     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index,
4854                                                       ConstPoolType::ARRAY_LITERAL);
4855 }
4856 
GetObjectLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)4857 GateRef StubBuilder::GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
4858 {
4859     GateRef hirGate = Circuit::NullGate();
4860     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index,
4861                                                       ConstPoolType::OBJECT_LITERAL);
4862 }
4863 
4864 // return elements
BuildArgumentsListFastElements(GateRef glue,GateRef arrayObj)4865 GateRef StubBuilder::BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj)
4866 {
4867     auto env = GetEnvironment();
4868     Label subentry(env);
4869     env->SubCfgEntry(&subentry);
4870     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
4871     Label exit(env);
4872     Label hasStableElements(env);
4873     Label targetIsStableJSArguments(env);
4874     Label targetNotStableJSArguments(env);
4875     Label targetIsInt(env);
4876     Label hClassEqual(env);
4877     Label targetIsStableJSArray(env);
4878     Label targetNotStableJSArray(env);
4879 
4880     Branch(HasStableElements(glue, arrayObj), &hasStableElements, &exit);
4881     Bind(&hasStableElements);
4882     {
4883         Branch(IsStableJSArguments(glue, arrayObj), &targetIsStableJSArguments, &targetNotStableJSArguments);
4884         Bind(&targetIsStableJSArguments);
4885         {
4886             GateRef hClass = LoadHClass(arrayObj);
4887             GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
4888             GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
4889             GateRef argmentsClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
4890                                                       GlobalEnv::ARGUMENTS_CLASS);
4891             Branch(Int32Equal(hClass, argmentsClass), &hClassEqual, &exit);
4892             Bind(&hClassEqual);
4893             {
4894                 GateRef PropertyInlinedPropsOffset = IntPtr(JSArguments::LENGTH_INLINE_PROPERTY_INDEX);
4895                 GateRef result = GetPropertyInlinedProps(arrayObj, hClass, PropertyInlinedPropsOffset);
4896                 Branch(TaggedIsInt(result), &targetIsInt, &exit);
4897                 Bind(&targetIsInt);
4898                 {
4899                     res = GetElementsArray(arrayObj);
4900                     Jump(&exit);
4901                 }
4902             }
4903         }
4904         Bind(&targetNotStableJSArguments);
4905         {
4906             Branch(IsStableJSArray(glue, arrayObj), &targetIsStableJSArray, &targetNotStableJSArray);
4907             Bind(&targetIsStableJSArray);
4908             {
4909                 res = GetElementsArray(arrayObj);
4910                 Jump(&exit);
4911             }
4912             Bind(&targetNotStableJSArray);
4913             {
4914                 FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
4915                 Jump(&exit);
4916             }
4917         }
4918     }
4919     Bind(&exit);
4920     auto ret = *res;
4921     env->SubCfgExit();
4922     return ret;
4923 }
4924 
MakeArgListWithHole(GateRef glue,GateRef argv,GateRef length)4925 GateRef StubBuilder::MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length)
4926 {
4927     auto env = GetEnvironment();
4928     Label subentry(env);
4929     env->SubCfgEntry(&subentry);
4930     DEFVARIABLE(res, VariableType::INT32(), length);
4931     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
4932     Label exit(env);
4933 
4934     GateRef argsLength = GetLengthOfTaggedArray(argv);
4935 
4936     Label lengthGreaterThanArgsLength(env);
4937     Label lengthLessThanArgsLength(env);
4938     Branch(Int32GreaterThan(length, argsLength), &lengthGreaterThanArgsLength, &lengthLessThanArgsLength);
4939     Bind(&lengthGreaterThanArgsLength);
4940     {
4941         res = argsLength;
4942         Jump(&lengthLessThanArgsLength);
4943     }
4944     Bind(&lengthLessThanArgsLength);
4945     {
4946         Label loopHead(env);
4947         Label loopEnd(env);
4948         Label afterLoop(env);
4949         Label targetIsHole(env);
4950         Label targetNotHole(env);
4951         Branch(Int32UnsignedLessThan(*i, *res), &loopHead, &afterLoop);
4952         LoopBegin(&loopHead);
4953         {
4954             GateRef value = GetValueFromTaggedArray(argv, *i);
4955             Branch(TaggedIsHole(value), &targetIsHole, &targetNotHole);
4956             Bind(&targetIsHole);
4957             {
4958                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argv, *i, Undefined());
4959                 Jump(&targetNotHole);
4960             }
4961             Bind(&targetNotHole);
4962             i = Int32Add(*i, Int32(1));
4963             Branch(Int32UnsignedLessThan(*i, *res), &loopEnd, &afterLoop);
4964         }
4965         Bind(&loopEnd);
4966         LoopEnd(&loopHead);
4967         Bind(&afterLoop);
4968         {
4969             res = length;
4970             Jump(&exit);
4971         }
4972     }
4973     Bind(&exit);
4974     auto ret = *res;
4975     env->SubCfgExit();
4976     return ret;
4977 }
4978 
JSAPIContainerGet(GateRef glue,GateRef receiver,GateRef index)4979 GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index)
4980 {
4981     auto env = GetEnvironment();
4982     Label entry(env);
4983     env->SubCfgEntry(&entry);
4984     Label exit(env);
4985     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4986 
4987     GateRef lengthOffset = IntPtr(panda::ecmascript::JSAPIArrayList::LENGTH_OFFSET);
4988     GateRef length = GetInt32OfTInt(Load(VariableType::INT64(), receiver, lengthOffset));
4989     Label isVailedIndex(env);
4990     Label notValidIndex(env);
4991     Branch(BoolAnd(Int32GreaterThanOrEqual(index, Int32(0)),
4992         Int32UnsignedLessThan(index, length)), &isVailedIndex, &notValidIndex);
4993     Bind(&isVailedIndex);
4994     {
4995         GateRef elements = GetElementsArray(receiver);
4996         result = GetValueFromTaggedArray(elements, index);
4997         Jump(&exit);
4998     }
4999     Bind(&notValidIndex);
5000     {
5001         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(GetPropertyOutOfBounds));
5002         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
5003         result = Exception();
5004         Jump(&exit);
5005     }
5006 
5007     Bind(&exit);
5008     auto ret = *result;
5009     env->SubCfgExit();
5010     return ret;
5011 }
5012 
DoubleToInt(GateRef glue,GateRef x)5013 GateRef StubBuilder::DoubleToInt(GateRef glue, GateRef x)
5014 {
5015     auto env = GetEnvironment();
5016     Label entry(env);
5017     env->SubCfgEntry(&entry);
5018     Label exit(env);
5019     Label overflow(env);
5020 
5021     GateRef xInt = ChangeFloat64ToInt32(x);
5022     DEFVARIABLE(result, VariableType::INT32(), xInt);
5023 
5024     if (env->IsAmd64()) {
5025         // 0x80000000: amd64 overflow return value
5026         Branch(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit);
5027     } else {
5028         GateRef xInt64 = CastDoubleToInt64(x);
5029         // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
5030         GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
5031         exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
5032         exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
5033         GateRef bits = Int32(base::INT32_BITS - 1);
5034         // exp < 32 - 1
5035         Branch(Int32LessThan(exp, bits), &exit, &overflow);
5036     }
5037     Bind(&overflow);
5038     {
5039         result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), { x });
5040         Jump(&exit);
5041     }
5042     Bind(&exit);
5043     auto ret = *result;
5044     env->SubCfgExit();
5045     return ret;
5046 }
5047 
ReturnExceptionIfAbruptCompletion(GateRef glue)5048 void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue)
5049 {
5050     auto env = GetEnvironment();
5051     Label entry(env);
5052     env->SubCfgEntry(&entry);
5053     Label exit(env);
5054     Label hasPendingException(env);
5055     GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env->IsArch32Bit()));
5056     GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset);
5057     Branch(TaggedIsNotHole(exception), &hasPendingException, &exit);
5058     Bind(&hasPendingException);
5059     Return(Exception());
5060     Bind(&exit);
5061     env->SubCfgExit();
5062     return;
5063 }
5064 
GetHashcodeFromString(GateRef glue,GateRef value)5065 GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
5066 {
5067     auto env = GetEnvironment();
5068     Label subentry(env);
5069     env->SubCfgEntry(&subentry);
5070     Label noRawHashcode(env);
5071     Label exit(env);
5072     DEFVARIABLE(hashcode, VariableType::INT32(), Int32(0));
5073     hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::HASHCODE_OFFSET));
5074     Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
5075     Bind(&noRawHashcode);
5076     {
5077         hashcode = GetInt32OfTInt(CallRuntime(glue, RTSTUB_ID(ComputeHashcode), { value }));
5078         Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
5079         Jump(&exit);
5080     }
5081     Bind(&exit);
5082     auto ret = *hashcode;
5083     env->SubCfgExit();
5084     return ret;
5085 }
5086 
ConstructorCheck(GateRef glue,GateRef ctor,GateRef outPut,GateRef thisObj)5087 GateRef StubBuilder::ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut, GateRef thisObj)
5088 {
5089     auto env = GetEnvironment();
5090     Label entryPass(env);
5091     Label exit(env);
5092     env->SubCfgEntry(&entryPass);
5093     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
5094     Label isHeapObject(env);
5095     Label isEcmaObj(env);
5096     Label notEcmaObj(env);
5097     Branch(TaggedIsHeapObject(outPut), &isHeapObject, &notEcmaObj);
5098     Bind(&isHeapObject);
5099     Branch(TaggedObjectIsEcmaObject(outPut), &isEcmaObj, &notEcmaObj);
5100     Bind(&isEcmaObj);
5101     {
5102         result = outPut;
5103         Jump(&exit);
5104     }
5105     Bind(&notEcmaObj);
5106     {
5107         Label ctorIsBase(env);
5108         Label ctorNotBase(env);
5109         Branch(IsBase(ctor), &ctorIsBase, &ctorNotBase);
5110         Bind(&ctorIsBase);
5111         {
5112             result = thisObj;
5113             Jump(&exit);
5114         }
5115         Bind(&ctorNotBase);
5116         {
5117             Label throwExeption(env);
5118             Label returnObj(env);
5119             Branch(TaggedIsUndefined(outPut), &returnObj, &throwExeption);
5120             Bind(&returnObj);
5121             result = thisObj;
5122             Jump(&exit);
5123             Bind(&throwExeption);
5124             {
5125                 CallRuntime(glue, RTSTUB_ID(ThrowNonConstructorException), {});
5126                 Jump(&exit);
5127             }
5128         }
5129     }
5130     Bind(&exit);
5131     auto ret = *result;
5132     env->SubCfgExit();
5133     return ret;
5134 }
5135 
JSCallDispatch(GateRef glue,GateRef func,GateRef actualNumArgs,GateRef jumpSize,GateRef hotnessCounter,JSCallMode mode,std::initializer_list<GateRef> args,ProfileOperation callback)5136 GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize,
5137                                     GateRef hotnessCounter, JSCallMode mode, std::initializer_list<GateRef> args,
5138                                     ProfileOperation callback)
5139 {
5140     auto env = GetEnvironment();
5141     Label entryPass(env);
5142     Label exit(env);
5143     env->SubCfgEntry(&entryPass);
5144     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
5145     // 1. call initialize
5146     Label funcIsHeapObject(env);
5147     Label funcIsCallable(env);
5148     Label funcNotCallable(env);
5149     // save pc
5150     SavePcIfNeeded(glue);
5151     GateRef bitfield = 0;
5152 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
5153     CallNGCRuntime(glue, RTSTUB_ID(StartCallTimer), { glue, func, False()});
5154 #endif
5155     Branch(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable);
5156     Bind(&funcIsHeapObject);
5157     GateRef hclass = LoadHClass(func);
5158     bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
5159     Branch(IsCallableFromBitField(bitfield), &funcIsCallable, &funcNotCallable);
5160     Bind(&funcNotCallable);
5161     {
5162         CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {});
5163         Jump(&exit);
5164     }
5165     Bind(&funcIsCallable);
5166     GateRef method = GetMethodFromJSFunction(func);
5167     GateRef callField = GetCallFieldFromMethod(method);
5168     GateRef isNativeMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsNativeBit::START_BIT);
5169 
5170     // 2. call dispatch
5171     Label methodIsNative(env);
5172     Label methodNotNative(env);
5173     Branch(Int64NotEqual(Int64And(callField, isNativeMask), Int64(0)), &methodIsNative, &methodNotNative);
5174     auto data = std::begin(args);
5175     Label notFastBuiltinsArg0(env);
5176     Label notFastBuiltinsArg1(env);
5177     Label notFastBuiltinsArg2(env);
5178     Label notFastBuiltinsArg3(env);
5179     Label notFastBuiltins(env);
5180     // 3. call native
5181     Bind(&methodIsNative);
5182     {
5183         GateRef nativeCode = Load(VariableType::NATIVE_POINTER(), method,
5184             IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
5185         GateRef newTarget = Undefined();
5186         GateRef thisValue = Undefined();
5187         GateRef numArgs = Int32Add(actualNumArgs, Int32(NUM_MANDATORY_JSFUNC_ARGS));
5188         switch (mode) {
5189             case JSCallMode::CALL_THIS_ARG0: {
5190                 thisValue = data[0];
5191                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5192                     method, &notFastBuiltinsArg0, &exit, &result, args, mode);
5193                 Bind(&notFastBuiltinsArg0);
5194                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5195                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
5196                 break;
5197             }
5198             case JSCallMode::CALL_ARG0:
5199             case JSCallMode::DEPRECATED_CALL_ARG0:
5200                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5201                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
5202                 break;
5203             case JSCallMode::CALL_THIS_ARG1: {
5204                 thisValue = data[1];
5205                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5206                     method, &notFastBuiltinsArg1, &exit, &result, args, mode);
5207                 Bind(&notFastBuiltinsArg1);
5208                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5209                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
5210                 break;
5211             }
5212             case JSCallMode::CALL_ARG1:
5213             case JSCallMode::DEPRECATED_CALL_ARG1:
5214                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5215                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
5216                 break;
5217             case JSCallMode::CALL_THIS_ARG2: {
5218                 thisValue = data[2];
5219                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5220                     method, &notFastBuiltinsArg2, &exit, &result, args, mode);
5221                 Bind(&notFastBuiltinsArg2);
5222                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5223                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
5224                 break;
5225             }
5226             case JSCallMode::CALL_ARG2:
5227             case JSCallMode::DEPRECATED_CALL_ARG2:
5228                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5229                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
5230                 break;
5231             case JSCallMode::CALL_THIS_ARG3: {
5232                 thisValue = data[3];
5233                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5234                     method, &notFastBuiltinsArg3, &exit, &result, args, mode);
5235                 Bind(&notFastBuiltinsArg3);
5236                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5237                     { nativeCode, glue, numArgs, func,
5238                         newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
5239                 break;
5240             }
5241             case JSCallMode::CALL_ARG3:
5242             case JSCallMode::DEPRECATED_CALL_ARG3:
5243                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5244                     { nativeCode, glue, numArgs, func,
5245                       newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
5246                 break;
5247             case JSCallMode::CALL_THIS_WITH_ARGV:
5248             case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5249             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV: {
5250                 thisValue = data[2]; // 2: this input
5251                 [[fallthrough]];
5252             }
5253             case JSCallMode::CALL_WITH_ARGV:
5254             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5255                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatchNative),
5256                     { glue, nativeCode, func, thisValue, data[0], data[1] });
5257                 break;
5258             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5259             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV: {
5260                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
5261                     method, &notFastBuiltins, &exit, &result, args, mode);
5262                 Bind(&notFastBuiltins);
5263                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatchNative),
5264                     { glue, nativeCode, func, data[2], data[0], data[1] });
5265                 break;
5266             }
5267             case JSCallMode::CALL_GETTER:
5268                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5269                     { nativeCode, glue, numArgs, func, newTarget, data[0] });
5270                 break;
5271             case JSCallMode::CALL_SETTER:
5272                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5273                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1] });
5274                 break;
5275             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5276                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
5277                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5278                 break;
5279             default:
5280                 LOG_ECMA(FATAL) << "this branch is unreachable";
5281                 UNREACHABLE();
5282         }
5283         Jump(&exit);
5284     }
5285     // 4. call nonNative
5286     Bind(&methodNotNative);
5287 
5288     callback.ProfileCall(func);
5289     Label funcIsClassConstructor(env);
5290     Label funcNotClassConstructor(env);
5291     Label methodNotAot(env);
5292     if (!AssemblerModule::IsCallNew(mode)) {
5293         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &funcNotClassConstructor);
5294         Bind(&funcIsClassConstructor);
5295         {
5296             CallRuntime(glue, RTSTUB_ID(ThrowCallConstructorException), {});
5297             Jump(&exit);
5298         }
5299         Bind(&funcNotClassConstructor);
5300     } else {
5301         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &methodNotAot);
5302         Bind(&funcIsClassConstructor);
5303     }
5304     GateRef sp = 0;
5305     if (env->IsAsmInterp()) {
5306         sp = Argument(static_cast<size_t>(InterpreterHandlerInputs::SP));
5307     }
5308     Label methodisAot(env);
5309     Label methodIsFastCall(env);
5310     Label methodNotFastCall(env);
5311     Label fastCall(env);
5312     Label fastCallBridge(env);
5313     Label slowCall(env);
5314     Label slowCallBridge(env);
5315     {
5316         GateRef newTarget = Undefined();
5317         GateRef thisValue = Undefined();
5318         GateRef realNumArgs = Int64Add(ZExtInt32ToInt64(actualNumArgs), Int64(NUM_MANDATORY_JSFUNC_ARGS));
5319         Branch(CanFastCallWithBitField(bitfield), &methodIsFastCall, &methodNotFastCall);
5320         Bind(&methodIsFastCall);
5321         {
5322             GateRef expectedNum = Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
5323                 Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
5324             GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
5325             Branch(Int64LessThanOrEqual(expectedArgc, realNumArgs), &fastCall, &fastCallBridge);
5326             Bind(&fastCall);
5327             {
5328                 GateRef code = GetAotCodeAddr(method);
5329                 switch (mode) {
5330                     case JSCallMode::CALL_THIS_ARG0:
5331                         thisValue = data[0];
5332                         [[fallthrough]];
5333                     case JSCallMode::CALL_ARG0:
5334                     case JSCallMode::DEPRECATED_CALL_ARG0:
5335                         result = FastCallOptimized(glue, code, { glue, func, thisValue});
5336                         Jump(&exit);
5337                         break;
5338                     case JSCallMode::CALL_THIS_ARG1:
5339                         thisValue = data[1];
5340                         [[fallthrough]];
5341                     case JSCallMode::CALL_ARG1:
5342                     case JSCallMode::DEPRECATED_CALL_ARG1:
5343                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0] });
5344                         Jump(&exit);
5345                         break;
5346                     case JSCallMode::CALL_THIS_ARG2:
5347                         thisValue = data[2];
5348                         [[fallthrough]];
5349                     case JSCallMode::CALL_ARG2:
5350                     case JSCallMode::DEPRECATED_CALL_ARG2:
5351                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0], data[1] });
5352                         Jump(&exit);
5353                         break;
5354                     case JSCallMode::CALL_THIS_ARG3:
5355                         thisValue = data[3];
5356                         [[fallthrough]];
5357                     case JSCallMode::CALL_ARG3:
5358                     case JSCallMode::DEPRECATED_CALL_ARG3:
5359                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0], data[1], data[2] });
5360                         Jump(&exit);
5361                         break;
5362                     case JSCallMode::CALL_THIS_WITH_ARGV:
5363                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5364                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5365                         thisValue = data[2]; // 2: this input
5366                         [[fallthrough]];
5367                     case JSCallMode::CALL_WITH_ARGV:
5368                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5369                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgV),
5370                             { glue, func, thisValue, ZExtInt32ToInt64(actualNumArgs), data[1] });
5371                         Jump(&exit);
5372                         break;
5373                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5374                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5375                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgV),
5376                             { glue, func, data[2], ZExtInt32ToInt64(actualNumArgs), data[1]});
5377                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5378                         Jump(&exit);
5379                         break;
5380                     case JSCallMode::CALL_GETTER:
5381                         result = FastCallOptimized(glue, code, { glue, func, data[0] });
5382                         Jump(&exit);
5383                         break;
5384                     case JSCallMode::CALL_SETTER:
5385                         result = FastCallOptimized(glue, code, { glue, func, data[0], data[1] });
5386                         Jump(&exit);
5387                         break;
5388                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5389                         result = FastCallOptimized(glue, code, { glue, func, data[0], data[1], data[2], data[3] });
5390                         Jump(&exit);
5391                         break;
5392                     default:
5393                         LOG_ECMA(FATAL) << "this branch is unreachable";
5394                         UNREACHABLE();
5395                 }
5396             }
5397             Bind(&fastCallBridge);
5398             {
5399                 switch (mode) {
5400                     case JSCallMode::CALL_THIS_ARG0:
5401                         thisValue = data[0];
5402                         [[fallthrough]];
5403                     case JSCallMode::CALL_ARG0:
5404                     case JSCallMode::DEPRECATED_CALL_ARG0:
5405                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5406                             { glue, realNumArgs, func, newTarget, thisValue});
5407                         Jump(&exit);
5408                         break;
5409                     case JSCallMode::CALL_THIS_ARG1:
5410                         thisValue = data[1];
5411                         [[fallthrough]];
5412                     case JSCallMode::CALL_ARG1:
5413                     case JSCallMode::DEPRECATED_CALL_ARG1:
5414                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5415                             { glue, realNumArgs, func, newTarget, thisValue, data[0] });
5416                         Jump(&exit);
5417                         break;
5418                     case JSCallMode::CALL_THIS_ARG2:
5419                         thisValue = data[2];
5420                         [[fallthrough]];
5421                     case JSCallMode::CALL_ARG2:
5422                     case JSCallMode::DEPRECATED_CALL_ARG2:
5423                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5424                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
5425                         Jump(&exit);
5426                         break;
5427                     case JSCallMode::CALL_THIS_ARG3:
5428                         thisValue = data[3];
5429                         [[fallthrough]];
5430                     case JSCallMode::CALL_ARG3:
5431                     case JSCallMode::DEPRECATED_CALL_ARG3:
5432                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5433                             { glue, realNumArgs, func, newTarget, thisValue,
5434                             data[0], data[1], data[2] }); // 2: args2
5435                         Jump(&exit);
5436                         break;
5437                     case JSCallMode::CALL_THIS_WITH_ARGV:
5438                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5439                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5440                         thisValue = data[2]; // 2: this input
5441                         [[fallthrough]];
5442                     case JSCallMode::CALL_WITH_ARGV:
5443                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5444                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgVAndPushUndefined),
5445                             { glue, func, thisValue, ZExtInt32ToInt64(actualNumArgs), data[1], expectedNum });
5446                         Jump(&exit);
5447                         break;
5448                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5449                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5450                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgVAndPushUndefined),
5451                             { glue, func, data[2], ZExtInt32ToInt64(actualNumArgs), data[1], expectedNum });
5452                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5453                         Jump(&exit);
5454                         break;
5455                     case JSCallMode::CALL_GETTER:
5456                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5457                             { glue, realNumArgs, func, newTarget, data[0]});
5458                         Jump(&exit);
5459                         break;
5460                     case JSCallMode::CALL_SETTER:
5461                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5462                             { glue, realNumArgs, func, newTarget, data[0], data[1]});
5463                         Jump(&exit);
5464                         break;
5465                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5466                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
5467                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5468                         Jump(&exit);
5469                         break;
5470                     default:
5471                         LOG_ECMA(FATAL) << "this branch is unreachable";
5472                         UNREACHABLE();
5473                 }
5474             }
5475         }
5476 
5477         Bind(&methodNotFastCall);
5478         Branch(IsOptimizedWithBitField(bitfield), &methodisAot, &methodNotAot);
5479         Bind(&methodisAot);
5480         {
5481             GateRef expectedNum = Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
5482                 Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
5483             GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
5484             Branch(Int64LessThanOrEqual(expectedArgc, realNumArgs), &slowCall, &slowCallBridge);
5485             Bind(&slowCall);
5486             {
5487                 GateRef code = GetAotCodeAddr(method);
5488                 switch (mode) {
5489                     case JSCallMode::CALL_THIS_ARG0:
5490                         thisValue = data[0];
5491                         [[fallthrough]];
5492                     case JSCallMode::CALL_ARG0:
5493                     case JSCallMode::DEPRECATED_CALL_ARG0:
5494                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue });
5495                         Jump(&exit);
5496                         break;
5497                     case JSCallMode::CALL_THIS_ARG1:
5498                         thisValue = data[1];
5499                         [[fallthrough]];
5500                     case JSCallMode::CALL_ARG1:
5501                     case JSCallMode::DEPRECATED_CALL_ARG1:
5502                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue, data[0] });
5503                         Jump(&exit);
5504                         break;
5505                     case JSCallMode::CALL_THIS_ARG2:
5506                         thisValue = data[2];
5507                         [[fallthrough]];
5508                     case JSCallMode::CALL_ARG2:
5509                     case JSCallMode::DEPRECATED_CALL_ARG2:
5510                         result = CallOptimized(glue, code,
5511                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
5512                         Jump(&exit);
5513                         break;
5514                     case JSCallMode::CALL_THIS_ARG3:
5515                         thisValue = data[3];
5516                         [[fallthrough]];
5517                     case JSCallMode::CALL_ARG3:
5518                     case JSCallMode::DEPRECATED_CALL_ARG3:
5519                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue,
5520                             data[0], data[1], data[2] });
5521                         Jump(&exit);
5522                         break;
5523                     case JSCallMode::CALL_THIS_WITH_ARGV:
5524                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5525                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5526                         thisValue = data[2]; // 2: this input
5527                         [[fallthrough]];
5528                     case JSCallMode::CALL_WITH_ARGV:
5529                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5530                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
5531                             { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
5532                         Jump(&exit);
5533                         break;
5534                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5535                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5536                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
5537                             { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
5538                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5539                         Jump(&exit);
5540                         break;
5541                     case JSCallMode::CALL_GETTER:
5542                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, data[0] });
5543                         Jump(&exit);
5544                         break;
5545                     case JSCallMode::CALL_SETTER:
5546                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, data[0], data[1] });
5547                         Jump(&exit);
5548                         break;
5549                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5550                         result = CallOptimized(glue, code,
5551                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5552                         Jump(&exit);
5553                         break;
5554                     default:
5555                         LOG_ECMA(FATAL) << "this branch is unreachable";
5556                         UNREACHABLE();
5557                 }
5558             }
5559             Bind(&slowCallBridge);
5560             {
5561                 switch (mode) {
5562                     case JSCallMode::CALL_THIS_ARG0:
5563                         thisValue = data[0];
5564                         [[fallthrough]];
5565                     case JSCallMode::CALL_ARG0:
5566                     case JSCallMode::DEPRECATED_CALL_ARG0:
5567                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5568                             { glue, realNumArgs, func, newTarget, thisValue});
5569                         Jump(&exit);
5570                         break;
5571                     case JSCallMode::CALL_THIS_ARG1:
5572                         thisValue = data[1];
5573                         [[fallthrough]];
5574                     case JSCallMode::CALL_ARG1:
5575                     case JSCallMode::DEPRECATED_CALL_ARG1:
5576                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5577                             { glue, realNumArgs, func, newTarget, thisValue, data[0] });
5578                         Jump(&exit);
5579                         break;
5580                     case JSCallMode::CALL_THIS_ARG2:
5581                         thisValue = data[2];
5582                         [[fallthrough]];
5583                     case JSCallMode::CALL_ARG2:
5584                     case JSCallMode::DEPRECATED_CALL_ARG2:
5585                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5586                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
5587                         Jump(&exit);
5588                         break;
5589                     case JSCallMode::CALL_THIS_ARG3:
5590                         thisValue = data[3];
5591                         [[fallthrough]];
5592                     case JSCallMode::CALL_ARG3:
5593                     case JSCallMode::DEPRECATED_CALL_ARG3:
5594                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5595                             { glue, realNumArgs, func, newTarget, thisValue,
5596                             data[0], data[1], data[2] }); // 2: args2
5597                         Jump(&exit);
5598                         break;
5599                     case JSCallMode::CALL_THIS_WITH_ARGV:
5600                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5601                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5602                         thisValue = data[2]; // 2: this input
5603                         [[fallthrough]];
5604                     case JSCallMode::CALL_WITH_ARGV:
5605                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5606                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgVAndPushUndefined),
5607                             { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
5608                         Jump(&exit);
5609                         break;
5610                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5611                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5612                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgVAndPushUndefined),
5613                             { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
5614                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
5615                         Jump(&exit);
5616                         break;
5617                     case JSCallMode::CALL_GETTER:
5618                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5619                             { glue, realNumArgs, func, newTarget, data[0]});
5620                         Jump(&exit);
5621                         break;
5622                     case JSCallMode::CALL_SETTER:
5623                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5624                             { glue, realNumArgs, func, newTarget, data[0], data[1]});
5625                         Jump(&exit);
5626                         break;
5627                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5628                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
5629                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
5630                         Jump(&exit);
5631                         break;
5632                     default:
5633                         LOG_ECMA(FATAL) << "this branch is unreachable";
5634                         UNREACHABLE();
5635                 }
5636             }
5637         }
5638 
5639         Bind(&methodNotAot);
5640         if (jumpSize != 0) {
5641             SaveJumpSizeIfNeeded(glue, jumpSize);
5642         }
5643         SaveHotnessCounterIfNeeded(glue, sp, hotnessCounter, mode);
5644         switch (mode) {
5645             case JSCallMode::CALL_THIS_ARG0:
5646                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg0AndDispatch),
5647                     { glue, sp, func, method, callField, data[0] });
5648                 Return();
5649                 break;
5650             case JSCallMode::CALL_ARG0:
5651             case JSCallMode::DEPRECATED_CALL_ARG0:
5652                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg0AndDispatch),
5653                     { glue, sp, func, method, callField });
5654                 Return();
5655                 break;
5656             case JSCallMode::CALL_THIS_ARG1:
5657                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg1AndDispatch),
5658                     { glue, sp, func, method, callField, data[0], data[1] });
5659                 Return();
5660                 break;
5661             case JSCallMode::CALL_ARG1:
5662             case JSCallMode::DEPRECATED_CALL_ARG1:
5663                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg1AndDispatch),
5664                     { glue, sp, func, method, callField, data[0] });
5665                 Return();
5666                 break;
5667             case JSCallMode::CALL_THIS_ARG2:
5668                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs2AndDispatch),
5669                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
5670                 Return();
5671                 break;
5672             case JSCallMode::CALL_ARG2:
5673             case JSCallMode::DEPRECATED_CALL_ARG2:
5674                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs2AndDispatch),
5675                     { glue, sp, func, method, callField, data[0], data[1] });
5676                 Return();
5677                 break;
5678             case JSCallMode::CALL_THIS_ARG3:
5679                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs3AndDispatch),
5680                     { glue, sp, func, method, callField, data[0], data[1], data[2], data[3] });
5681                 Return();
5682                 break;
5683             case JSCallMode::CALL_ARG3:
5684             case JSCallMode::DEPRECATED_CALL_ARG3:
5685                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs3AndDispatch),
5686                     { glue, sp, func, method, callField, data[0], data[1], data[2] }); // 2: args2
5687                 Return();
5688                 break;
5689             case JSCallMode::CALL_WITH_ARGV:
5690             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
5691                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatch),
5692                     { glue, sp, func, method, callField, data[0], data[1] });
5693                 Return();
5694                 break;
5695             case JSCallMode::CALL_THIS_WITH_ARGV:
5696             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
5697                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisRangeAndDispatch),
5698                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
5699                 Return();
5700                 break;
5701             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5702             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5703                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatch),
5704                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
5705                 Return();
5706                 break;
5707             case JSCallMode::CALL_GETTER:
5708                 result = CallNGCRuntime(glue, RTSTUB_ID(CallGetter),
5709                     { glue, func, method, callField, data[0] });
5710                 Jump(&exit);
5711                 break;
5712             case JSCallMode::CALL_SETTER:
5713                 result = CallNGCRuntime(glue, RTSTUB_ID(CallSetter),
5714                     { glue, func, method, callField, data[1], data[0] });
5715                 Jump(&exit);
5716                 break;
5717             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
5718                 result = CallNGCRuntime(glue, RTSTUB_ID(CallContainersArgs3),
5719                     { glue, func, method, callField, data[1], data[2], data[3], data[0] });
5720                 Jump(&exit);
5721                 break;
5722             case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
5723                 result = CallNGCRuntime(glue, RTSTUB_ID(CallReturnWithArgv),
5724                     { glue, func, method, callField, data[0], data[1], data[2] });
5725                 Jump(&exit);
5726                 break;
5727             default:
5728                 LOG_ECMA(FATAL) << "this branch is unreachable";
5729                 UNREACHABLE();
5730         }
5731     }
5732     Bind(&exit);
5733     auto ret = *result;
5734     env->SubCfgExit();
5735     return ret;
5736 }
5737 
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)5738 void StubBuilder::CallFastPath(GateRef glue, GateRef nativeCode, GateRef func, GateRef thisValue,
5739     GateRef actualNumArgs, GateRef callField, GateRef method, Label* notFastBuiltins, Label* exit, Variable* result,
5740     std::initializer_list<GateRef> args, JSCallMode mode)
5741 {
5742     auto env = GetEnvironment();
5743     auto data = std::begin(args);
5744     Label isFastBuiltins(env);
5745     GateRef numArgs = ZExtInt32ToPtr(actualNumArgs);
5746     GateRef isFastBuiltinsMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsFastBuiltinBit::START_BIT);
5747     Branch(Int64NotEqual(Int64And(callField, isFastBuiltinsMask), Int64(0)), &isFastBuiltins, notFastBuiltins);
5748     Bind(&isFastBuiltins);
5749     {
5750         GateRef builtinId = GetBuiltinId(method);
5751         GateRef ret;
5752         switch (mode) {
5753             case JSCallMode::CALL_THIS_ARG0:
5754                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue, numArgs,
5755                     Undefined(), Undefined(), Undefined()});
5756                 break;
5757             case JSCallMode::CALL_THIS_ARG1:
5758                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(),
5759                                                           thisValue, numArgs, data[0], Undefined(), Undefined() });
5760                 break;
5761             case JSCallMode::CALL_THIS_ARG2:
5762                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
5763                                                           numArgs, data[0], data[1], Undefined() });
5764                 break;
5765             case JSCallMode::CALL_THIS_ARG3:
5766                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
5767                                                           numArgs, data[0], data[1], data[2] });
5768                 break;
5769             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
5770             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
5771                 ret = DispatchBuiltinsWithArgv(glue, builtinId, { glue, nativeCode, func, func, thisValue,
5772                                                                   numArgs, data[1] });
5773                 break;
5774             default:
5775                 LOG_ECMA(FATAL) << "this branch is unreachable";
5776                 UNREACHABLE();
5777         }
5778         result->WriteVariable(ret);
5779         Jump(exit);
5780     }
5781     Bind(notFastBuiltins);
5782 }
5783 
TryStringOrSymbolToElementIndex(GateRef glue,GateRef key)5784 GateRef StubBuilder::TryStringOrSymbolToElementIndex(GateRef glue, GateRef key)
5785 {
5786     auto env = GetEnvironment();
5787     Label entry(env);
5788     env->SubCfgEntry(&entry);
5789     Label exit(env);
5790     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
5791 
5792     Label keyNotSymbol(env);
5793     Branch(IsSymbol(key), &exit, &keyNotSymbol);
5794     Bind(&keyNotSymbol);
5795 
5796     Label greatThanZero(env);
5797     Label inRange(env);
5798     auto len = GetLengthFromString(key);
5799     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
5800     Bind(&greatThanZero);
5801     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
5802     Bind(&inRange);
5803     {
5804         Label isUtf8(env);
5805         Branch(IsUtf16String(key), &exit, &isUtf8);
5806         Bind(&isUtf8);
5807         GateRef data = GetNormalStringData(FlattenString(glue, key));
5808         DEFVARIABLE(c, VariableType::INT32(), Int32(0));
5809         c = ZExtInt8ToInt32(Load(VariableType::INT8(), data));
5810         Label isDigitZero(env);
5811         Label notDigitZero(env);
5812         Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
5813         Bind(&isDigitZero);
5814         {
5815             Label lengthIsOne(env);
5816             Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
5817             Bind(&lengthIsOne);
5818             {
5819                 result = Int32(0);
5820                 Jump(&exit);
5821             }
5822         }
5823         Bind(&notDigitZero);
5824         {
5825             Label isDigit(env);
5826             Label notIsDigit(env);
5827             DEFVARIABLE(i, VariableType::INT32(), Int32(1));
5828             DEFVARIABLE(n, VariableType::INT32(), Int32Sub(*c, Int32('0')));
5829 
5830             Branch(IsDigit(*c), &isDigit, &notIsDigit);
5831             Label loopHead(env);
5832             Label loopEnd(env);
5833             Label afterLoop(env);
5834             Bind(&isDigit);
5835             Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
5836             LoopBegin(&loopHead);
5837             {
5838                 c = ZExtInt8ToInt32(Load(VariableType::INT8(), data, ZExtInt32ToPtr(*i)));
5839                 Label isDigit2(env);
5840                 Label notDigit2(env);
5841                 Branch(IsDigit(*c), &isDigit2, &notDigit2);
5842                 Bind(&isDigit2);
5843                 {
5844                     // 10 means the base of digit is 10.
5845                     n = Int32Add(Int32Mul(*n, Int32(10)),
5846                                  Int32Sub(*c, Int32('0')));
5847                     i = Int32Add(*i, Int32(1));
5848                     Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
5849                 }
5850                 Bind(&notDigit2);
5851                 {
5852                     Label hasPoint(env);
5853                     Branch(Int32Equal(*c, Int32('.')), &hasPoint, &exit);
5854                     Bind(&hasPoint);
5855                     {
5856                         result = Int32(-2); // -2:return -2 means should goto slow path
5857                         Jump(&exit);
5858                     }
5859                 }
5860             }
5861             Bind(&loopEnd);
5862             LoopEnd(&loopHead);
5863             Bind(&afterLoop);
5864             {
5865                 Label lessThanMaxIndex(env);
5866                 Branch(Int32UnsignedLessThan(*n, Int32(JSObject::MAX_ELEMENT_INDEX)),
5867                        &lessThanMaxIndex, &exit);
5868                 Bind(&lessThanMaxIndex);
5869                 {
5870                     result = *n;
5871                     Jump(&exit);
5872                 }
5873             }
5874             Bind(&notIsDigit);
5875             {
5876                 Label isNegative(env);
5877                 Branch(Int32Equal(*c, Int32('-')), &isNegative, &exit);
5878                 Bind(&isNegative);
5879                 {
5880                     result = Int32(-2); // -2:return -2 means should goto slow path
5881                     Jump(&exit);
5882                 }
5883             }
5884         }
5885     }
5886     Bind(&exit);
5887     auto ret = *result;
5888     env->SubCfgExit();
5889     return ret;
5890 }
5891 
GetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef jsType)5892 GateRef StubBuilder::GetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder,
5893                                                 GateRef key, GateRef jsType)
5894 {
5895     auto env = GetEnvironment();
5896     Label entry(env);
5897     env->SubCfgEntry(&entry);
5898     Label exit(env);
5899     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5900 
5901     Label notOnProtoChain(env);
5902     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
5903     Bind(&notOnProtoChain);
5904 
5905     auto negativeZero = GetGlobalConstantValue(
5906         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
5907     Label isNegativeZero(env);
5908     Label notNegativeZero(env);
5909     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
5910     Bind(&isNegativeZero);
5911     {
5912         result = Undefined();
5913         Jump(&exit);
5914     }
5915     Bind(&notNegativeZero);
5916     {
5917         GateRef index = TryStringOrSymbolToElementIndex(glue, key);
5918         Label validIndex(env);
5919         Label notValidIndex(env);
5920         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
5921         Bind(&validIndex);
5922         {
5923             TypedArrayStubBuilder typedArrayStubBuilder(this);
5924             result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, holder, index, jsType);
5925             Jump(&exit);
5926         }
5927         Bind(&notValidIndex);
5928         {
5929             Label returnNull(env);
5930             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
5931             Bind(&returnNull);
5932             {
5933                 result = Null();
5934                 Jump(&exit);
5935             }
5936         }
5937     }
5938 
5939     Bind(&exit);
5940     auto ret = *result;
5941     env->SubCfgExit();
5942     return ret;
5943 }
5944 
SetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef value,GateRef jsType)5945 GateRef StubBuilder::SetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder, GateRef key,
5946                                                 GateRef value, GateRef jsType)
5947 {
5948     auto env = GetEnvironment();
5949     Label entry(env);
5950     env->SubCfgEntry(&entry);
5951     Label exit(env);
5952     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5953     Label notOnProtoChain(env);
5954     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
5955     Bind(&notOnProtoChain);
5956 
5957     auto negativeZero = GetGlobalConstantValue(
5958         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
5959     Label isNegativeZero(env);
5960     Label notNegativeZero(env);
5961     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
5962     Bind(&isNegativeZero);
5963     {
5964         Label isObj(env);
5965         Label notObj(env);
5966         Branch(IsEcmaObject(value), &isObj, &notObj);
5967         Bind(&isObj);
5968         {
5969             result = Null();
5970             Jump(&exit);
5971         }
5972         Bind(&notObj);
5973         result = Undefined();
5974         Jump(&exit);
5975     }
5976     Bind(&notNegativeZero);
5977     {
5978         GateRef index = TryStringOrSymbolToElementIndex(glue, key);
5979         Label validIndex(env);
5980         Label notValidIndex(env);
5981         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
5982         Bind(&validIndex);
5983         {
5984             result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
5985                 { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType) });
5986             Jump(&exit);
5987         }
5988         Bind(&notValidIndex);
5989         {
5990             Label returnNull(env);
5991             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
5992             Bind(&returnNull);
5993             {
5994                 result = Null();
5995                 Jump(&exit);
5996             }
5997         }
5998     }
5999 
6000     Bind(&exit);
6001     auto ret = *result;
6002     env->SubCfgExit();
6003     return ret;
6004 }
6005 
Assert(int messageId,int line,GateRef glue,GateRef condition,Label * nextLabel)6006 void StubBuilder::Assert(int messageId, int line, GateRef glue, GateRef condition, Label *nextLabel)
6007 {
6008     auto env = GetEnvironment();
6009     Label ok(env);
6010     Label notOk(env);
6011     Branch(condition, &ok, &notOk);
6012     Bind(&ok);
6013     {
6014         Jump(nextLabel);
6015     }
6016     Bind(&notOk);
6017     {
6018         FatalPrint(glue, { Int32(messageId), Int32(line) });
6019         Jump(nextLabel);
6020     }
6021 }
6022 
FlattenString(GateRef glue,GateRef str)6023 GateRef StubBuilder::FlattenString(GateRef glue, GateRef str)
6024 {
6025     auto env = GetEnvironment();
6026     Label entry(env);
6027     env->SubCfgEntry(&entry);
6028     Label exit(env);
6029     DEFVARIABLE(result, VariableType::JS_POINTER(), str);
6030     Label isTreeString(env);
6031     Branch(IsTreeString(str), &isTreeString, &exit);
6032     Bind(&isTreeString);
6033     {
6034         Label isFlat(env);
6035         Label notFlat(env);
6036         Branch(TreeStringIsFlat(str), &isFlat, &notFlat);
6037         Bind(&isFlat);
6038         {
6039             result = GetFirstFromTreeString(str);
6040             Jump(&exit);
6041         }
6042         Bind(&notFlat);
6043         {
6044             result = CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str });
6045             Jump(&exit);
6046         }
6047     }
6048     Bind(&exit);
6049     auto ret = *result;
6050     env->SubCfgExit();
6051     return ret;
6052 }
6053 
GetNormalStringData(GateRef str)6054 GateRef StubBuilder::GetNormalStringData(GateRef str)
6055 {
6056     auto env = GetEnvironment();
6057     Label entry(env);
6058     env->SubCfgEntry(&entry);
6059     Label exit(env);
6060     Label isConstantString(env);
6061     Label isLineString(env);
6062     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
6063     Branch(IsConstantString(str), &isConstantString, &isLineString);
6064     Bind(&isConstantString);
6065     {
6066         GateRef address = PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET));
6067         result = Load(VariableType::JS_ANY(), address, IntPtr(0));
6068         Jump(&exit);
6069     }
6070     Bind(&isLineString);
6071     {
6072         result = PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET));
6073         Jump(&exit);
6074     }
6075     Bind(&exit);
6076     auto ret = *result;
6077     env->SubCfgExit();
6078     return ret;
6079 }
6080 
FlattenString(GateRef str,Variable * flatStr,Label * fastPath,Label * slowPath)6081 void StubBuilder::FlattenString(GateRef str, Variable *flatStr, Label *fastPath, Label *slowPath)
6082 {
6083     auto env = GetEnvironment();
6084     Label notLineString(env);
6085     Label exit(env);
6086     DEFVARIABLE(result, VariableType::JS_POINTER(), str);
6087     Branch(BoolOr(IsLineString(str), IsConstantString(str)), &exit, &notLineString);
6088     Bind(&notLineString);
6089     {
6090         Label isTreeString(env);
6091         Branch(IsTreeString(str), &isTreeString, &exit);
6092         Bind(&isTreeString);
6093         {
6094             Label isFlat(env);
6095             Branch(TreeStringIsFlat(str), &isFlat, slowPath);
6096             Bind(&isFlat);
6097             {
6098                 result = GetFirstFromTreeString(str);
6099                 Jump(&exit);
6100             }
6101         }
6102     }
6103     Bind(&exit);
6104     {
6105         flatStr->WriteVariable(*result);
6106         Jump(fastPath);
6107     }
6108 }
6109 
ToNumber(GateRef glue,GateRef tagged)6110 GateRef StubBuilder::ToNumber(GateRef glue, GateRef tagged)
6111 {
6112     auto env = GetEnvironment();
6113     Label entry(env);
6114     env->SubCfgEntry(&entry);
6115     Label exit(env);
6116     Label isNumber(env);
6117     Label notNumber(env);
6118     Label defaultLabel(env);
6119     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
6120     Branch(TaggedIsNumber(tagged), &isNumber, &notNumber);
6121     Bind(&isNumber);
6122     {
6123         result = tagged;
6124         Jump(&exit);
6125     }
6126     Bind(&notNumber);
6127     {
6128         Label returnNan(env);
6129         Label notNan(env);
6130         Label returnNumber1(env);
6131         Label notNumber1(env);
6132         Label returnNumber0(env);
6133         auto isHole = TaggedIsHole(tagged);
6134         auto isUndefined = TaggedIsUndefined(tagged);
6135         Branch(BoolOr(isHole, isUndefined), &returnNan, &notNan);
6136         Bind(&returnNan);
6137         {
6138             result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
6139             Jump(&exit);
6140         }
6141         Bind(&notNan);
6142         Branch(TaggedIsTrue(tagged), &returnNumber1, &notNumber1);
6143         Bind(&returnNumber1);
6144         {
6145             result = Int64ToTaggedPtr(Int32(1));
6146             Jump(&exit);
6147         }
6148         Bind(&notNumber1);
6149         auto isFalse = TaggedIsFalse(tagged);
6150         auto isNull = TaggedIsNull(tagged);
6151         Branch(BoolOr(isFalse, isNull), &returnNumber0, &defaultLabel);
6152         Bind(&returnNumber0);
6153         {
6154             result = Int64ToTaggedPtr(Int32(0));
6155             Jump(&exit);
6156         }
6157         Bind(&defaultLabel);
6158         {
6159             CallRuntime(glue, RTSTUB_ID(OtherToNumber), { tagged });
6160             Jump(&exit);
6161         }
6162     }
6163     Bind(&exit);
6164     auto ret = *result;
6165     env->SubCfgExit();
6166     return ret;
6167 }
6168 
GetLengthOfJsArray(GateRef glue,GateRef array)6169 GateRef StubBuilder::GetLengthOfJsArray(GateRef glue, GateRef array)
6170 {
6171     auto env = GetEnvironment();
6172     Label entry(env);
6173     env->SubCfgEntry(&entry);
6174     Label exit(env);
6175     Label isInt(env);
6176     Label notInt(env);
6177     Label notDouble(env);
6178     Label isDouble(env);
6179     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
6180     GateRef len = Load(VariableType::JS_ANY(), array, IntPtr(JSArray::LENGTH_OFFSET));
6181     Branch(TaggedIsInt(len), &isInt, &notInt);
6182     Bind(&isInt);
6183     {
6184         result = TaggedGetInt(len);
6185         Jump(&exit);
6186     }
6187     Bind(&notInt);
6188     {
6189         Branch(TaggedIsDouble(len), &isDouble, &notDouble);
6190         Bind(&isDouble);
6191         {
6192             result = DoubleToInt(glue, GetDoubleOfTDouble(len));
6193             Jump(&exit);
6194         }
6195         Bind(&notDouble);
6196         {
6197             FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
6198             Jump(&exit);
6199         }
6200     }
6201     Bind(&exit);
6202     auto ret = *result;
6203     env->SubCfgExit();
6204     return ret;
6205 }
6206 
CreateListFromArrayLike(GateRef glue,GateRef arrayObj)6207 GateRef StubBuilder::CreateListFromArrayLike(GateRef glue, GateRef arrayObj)
6208 {
6209     auto env = GetEnvironment();
6210     Label entry(env);
6211     env->SubCfgEntry(&entry);
6212     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
6213     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
6214     Label exit(env);
6215 
6216     // 3. If Type(obj) is Object, throw a TypeError exception.
6217     Label targetIsHeapObject(env);
6218     Label targetIsEcmaObject(env);
6219     Label targetNotEcmaObject(env);
6220     Branch(TaggedIsHeapObject(arrayObj), &targetIsHeapObject, &targetNotEcmaObject);
6221     Bind(&targetIsHeapObject);
6222     Branch(TaggedObjectIsEcmaObject(arrayObj), &targetIsEcmaObject, &targetNotEcmaObject);
6223     Bind(&targetNotEcmaObject);
6224     {
6225         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
6226         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
6227         Jump(&exit);
6228     }
6229     Bind(&targetIsEcmaObject);
6230     {
6231         // 4. Let len be ToLength(Get(obj, "length")).
6232         GateRef lengthString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
6233                                                       ConstantIndex::LENGTH_STRING_INDEX);
6234         GateRef value = FastGetPropertyByName(glue, arrayObj, lengthString, ProfileOperation());
6235         GateRef number = ToLength(glue, value);
6236         // 5. ReturnIfAbrupt(len).
6237         Label isPendingException1(env);
6238         Label noPendingException1(env);
6239         Branch(HasPendingException(glue), &isPendingException1, &noPendingException1);
6240         Bind(&isPendingException1);
6241         {
6242             Jump(&exit);
6243         }
6244         Bind(&noPendingException1);
6245         {
6246             Label indexInRange(env);
6247             Label indexOutRange(env);
6248             GateRef doubleLen = GetDoubleOfTNumber(number);
6249             Branch(DoubleGreaterThan(doubleLen, Double(JSObject::MAX_ELEMENT_INDEX)), &indexOutRange, &indexInRange);
6250             Bind(&indexOutRange);
6251             {
6252                 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(LenGreaterThanMax));
6253                 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
6254                 Jump(&exit);
6255             }
6256             Bind(&indexInRange);
6257             {
6258                 GateRef int32Len = DoubleToInt(glue, doubleLen);
6259                 // 6. Let list be an empty List.
6260                 NewObjectStubBuilder newBuilder(this);
6261                 GateRef array = newBuilder.NewTaggedArray(glue, int32Len);
6262                 Label targetIsTypeArray(env);
6263                 Label targetNotTypeArray(env);
6264                 Branch(IsTypedArray(arrayObj), &targetIsTypeArray, &targetNotTypeArray);
6265                 Bind(&targetIsTypeArray);
6266                 {
6267                     TypedArrayStubBuilder arrayStubBuilder(this);
6268                     arrayStubBuilder.FastCopyElementToArray(glue, arrayObj, array);
6269                     // c. ReturnIfAbrupt(next).
6270                     Label isPendingException2(env);
6271                     Label noPendingException2(env);
6272                     Branch(HasPendingException(glue), &isPendingException2, &noPendingException2);
6273                     Bind(&isPendingException2);
6274                     {
6275                         Jump(&exit);
6276                     }
6277                     Bind(&noPendingException2);
6278                     {
6279                         res = array;
6280                         Jump(&exit);
6281                     }
6282                 }
6283                 Bind(&targetNotTypeArray);
6284                 // 8. Repeat while index < len
6285                 Label loopHead(env);
6286                 Label loopEnd(env);
6287                 Label afterLoop(env);
6288                 Label isPendingException3(env);
6289                 Label noPendingException3(env);
6290                 Label storeValue(env);
6291                 Jump(&loopHead);
6292                 LoopBegin(&loopHead);
6293                 {
6294                     Branch(Int32UnsignedLessThan(*index, int32Len), &storeValue, &afterLoop);
6295                     Bind(&storeValue);
6296                     {
6297                         GateRef next = FastGetPropertyByIndex(glue, arrayObj, *index, ProfileOperation());
6298                         // c. ReturnIfAbrupt(next).
6299                         Branch(HasPendingException(glue), &isPendingException3, &noPendingException3);
6300                         Bind(&isPendingException3);
6301                         {
6302                             Jump(&exit);
6303                         }
6304                         Bind(&noPendingException3);
6305                         SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, next);
6306                         index = Int32Add(*index, Int32(1));
6307                         Jump(&loopEnd);
6308                     }
6309                 }
6310                 Bind(&loopEnd);
6311                 LoopEnd(&loopHead);
6312                 Bind(&afterLoop);
6313                 {
6314                     res = array;
6315                     Jump(&exit);
6316                 }
6317             }
6318         }
6319     }
6320     Bind(&exit);
6321     GateRef ret = *res;
6322     env->SubCfgExit();
6323     return ret;
6324 }
6325 
ToLength(GateRef glue,GateRef target)6326 GateRef StubBuilder::ToLength(GateRef glue, GateRef target)
6327 {
6328     auto env = GetEnvironment();
6329     Label subentry(env);
6330     env->SubCfgEntry(&subentry);
6331     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
6332     Label exit(env);
6333 
6334     GateRef number = ToNumber(glue, target);
6335     Label isPendingException(env);
6336     Label noPendingException(env);
6337     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
6338     Bind(&isPendingException);
6339     {
6340         Jump(&exit);
6341     }
6342     Bind(&noPendingException);
6343     {
6344         GateRef num = GetDoubleOfTNumber(number);
6345         Label targetLessThanZero(env);
6346         Label targetGreaterThanZero(env);
6347         Label targetLessThanSafeNumber(env);
6348         Label targetGreaterThanSafeNumber(env);
6349         Branch(DoubleLessThan(num, Double(0.0)), &targetLessThanZero, &targetGreaterThanZero);
6350         Bind(&targetLessThanZero);
6351         {
6352             res = DoubleToTaggedDoublePtr(Double(0.0));
6353             Jump(&exit);
6354         }
6355         Bind(&targetGreaterThanZero);
6356         Branch(DoubleGreaterThan(num, Double(SAFE_NUMBER)), &targetGreaterThanSafeNumber, &targetLessThanSafeNumber);
6357         Bind(&targetGreaterThanSafeNumber);
6358         {
6359             res = DoubleToTaggedDoublePtr(Double(SAFE_NUMBER));
6360             Jump(&exit);
6361         }
6362         Bind(&targetLessThanSafeNumber);
6363         {
6364             res = number;
6365             Jump(&exit);
6366         }
6367     }
6368     Bind(&exit);
6369     auto ret = *res;
6370     env->SubCfgExit();
6371     return ret;
6372 }
6373 
TaggedGetNumber(GateRef x)6374 GateRef StubBuilder::TaggedGetNumber(GateRef x)
6375 {
6376     auto env = GetEnvironment();
6377     Label subentry(env);
6378     Label exit(env);
6379     env->SubCfgEntry(&subentry);
6380 
6381     Label targetIsInt(env);
6382     Label targetIsDouble(env);
6383     DEFVAlUE(number, env_, VariableType::FLOAT64(), Double(0));
6384     Branch(TaggedIsInt(x), &targetIsInt, &targetIsDouble);
6385     Bind(&targetIsInt);
6386     {
6387         number = ChangeInt32ToFloat64(TaggedGetInt(x));
6388         Jump(&exit);
6389     }
6390     Bind(&targetIsDouble);
6391     {
6392         number = GetDoubleOfTDouble(x);
6393         Jump(&exit);
6394     }
6395     Bind(&exit);
6396     GateRef ret = *number;
6397     env->SubCfgExit();
6398     return ret;
6399 }
6400 
HasStableElements(GateRef glue,GateRef obj)6401 GateRef StubBuilder::HasStableElements(GateRef glue, GateRef obj)
6402 {
6403     auto env = GetEnvironment();
6404     Label subentry(env);
6405     env->SubCfgEntry(&subentry);
6406     DEFVARIABLE(result, VariableType::BOOL(), False());
6407     Label exit(env);
6408     Label targetIsHeapObject(env);
6409     Label targetIsStableElements(env);
6410 
6411     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
6412     Bind(&targetIsHeapObject);
6413     {
6414         GateRef jsHclass = LoadHClass(obj);
6415         Branch(IsStableElements(jsHclass), &targetIsStableElements, &exit);
6416         Bind(&targetIsStableElements);
6417         {
6418             GateRef guardiansOffset = IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
6419             GateRef guardians = Load(VariableType::JS_ANY(), glue, guardiansOffset);
6420             Label targetIsTaggedTrue(env);
6421             Label targetIsTaggedFalse(env);
6422             Branch(TaggedIsTrue(guardians), &targetIsTaggedTrue, &targetIsTaggedFalse);
6423             Bind(&targetIsTaggedTrue);
6424             {
6425                 result = True();
6426                 Jump(&exit);
6427             }
6428             Bind(&targetIsTaggedFalse);
6429             {
6430                 result = False();
6431                 Jump(&exit);
6432             }
6433         }
6434     }
6435     Bind(&exit);
6436     auto res = *result;
6437     env->SubCfgExit();
6438     return res;
6439 }
6440 
IsStableJSArguments(GateRef glue,GateRef obj)6441 GateRef StubBuilder::IsStableJSArguments(GateRef glue, GateRef obj)
6442 {
6443     auto env = GetEnvironment();
6444     Label subentry(env);
6445     env->SubCfgEntry(&subentry);
6446     DEFVARIABLE(result, VariableType::BOOL(), False());
6447     Label exit(env);
6448     Label targetIsHeapObject(env);
6449     Label targetIsStableArguments(env);
6450 
6451     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
6452     Bind(&targetIsHeapObject);
6453     {
6454         GateRef jsHclass = LoadHClass(obj);
6455         Branch(IsStableArguments(jsHclass), &targetIsStableArguments, &exit);
6456         Bind(&targetIsStableArguments);
6457         {
6458             GateRef guardiansOffset = IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
6459             GateRef guardians = Load(VariableType::JS_ANY(), glue, guardiansOffset);
6460 
6461             Label targetIsTaggedTrue(env);
6462             Label targetIsTaggedFalse(env);
6463             Branch(TaggedIsTrue(guardians), &targetIsTaggedTrue, &targetIsTaggedFalse);
6464             Bind(&targetIsTaggedTrue);
6465             {
6466                 result = True();
6467                 Jump(&exit);
6468             }
6469             Bind(&targetIsTaggedFalse);
6470             {
6471                 result = False();
6472                 Jump(&exit);
6473             }
6474         }
6475     }
6476     Bind(&exit);
6477     auto res = *result;
6478     env->SubCfgExit();
6479     return res;
6480 }
6481 
IsStableJSArray(GateRef glue,GateRef obj)6482 GateRef StubBuilder::IsStableJSArray(GateRef glue, GateRef obj)
6483 {
6484     auto env = GetEnvironment();
6485     Label subentry(env);
6486     env->SubCfgEntry(&subentry);
6487     DEFVARIABLE(result, VariableType::BOOL(), False());
6488     Label exit(env);
6489     Label targetIsHeapObject(env);
6490     Label targetIsStableArray(env);
6491 
6492     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
6493     Bind(&targetIsHeapObject);
6494     {
6495         GateRef jsHclass = LoadHClass(obj);
6496         Branch(IsStableArray(jsHclass), &targetIsStableArray, &exit);
6497         Bind(&targetIsStableArray);
6498         {
6499             GateRef guardiansOffset = IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
6500             GateRef guardians = Load(VariableType::JS_ANY(), glue, guardiansOffset);
6501 
6502             Label targetIsTaggedTrue(env);
6503             Label targetIsTaggedFalse(env);
6504             Branch(TaggedIsTrue(guardians), &targetIsTaggedTrue, &targetIsTaggedFalse);
6505             Bind(&targetIsTaggedTrue);
6506             {
6507                 result = True();
6508                 Jump(&exit);
6509             }
6510             Bind(&targetIsTaggedFalse);
6511             {
6512                 result = False();
6513                 Jump(&exit);
6514             }
6515         }
6516     }
6517     Bind(&exit);
6518     auto res = *result;
6519     env->SubCfgExit();
6520     return res;
6521 }
6522 
UpdateProfileTypeInfo(GateRef glue,GateRef jsFunc)6523 GateRef StubBuilder::UpdateProfileTypeInfo(GateRef glue, GateRef jsFunc)
6524 {
6525     auto env = GetEnvironment();
6526     Label entry(env);
6527     env->SubCfgEntry(&entry);
6528     Label needUpdate(env);
6529     Label exit(env);
6530     DEFVARIABLE(profileTypeInfo, VariableType::JS_POINTER(), GetProfileTypeInfo(jsFunc));
6531     Branch(TaggedIsUndefined(*profileTypeInfo), &needUpdate, &exit);
6532     Bind(&needUpdate);
6533     {
6534         profileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounter), { jsFunc });
6535         Jump(&exit);
6536     }
6537     Bind(&exit);
6538     auto ret = *profileTypeInfo;
6539     env->SubCfgExit();
6540     return ret;
6541 }
6542 }  // namespace panda::ecmascript::kungfu
6543