• 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/assembler/assembler.h"
17 #include "ecmascript/compiler/circuit_builder_helper.h"
18 #include "ecmascript/compiler/share_gate_meta_data.h"
19 #include "ecmascript/compiler/stub_builder-inl.h"
20 #include "ecmascript/compiler/assembler_module.h"
21 #include "ecmascript/compiler/access_object_stub_builder.h"
22 #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
23 #include "ecmascript/compiler/interpreter_stub.h"
24 #include "ecmascript/compiler/llvm_ir_builder.h"
25 #include "ecmascript/compiler/new_object_stub_builder.h"
26 #include "ecmascript/compiler/profiler_stub_builder.h"
27 #include "ecmascript/compiler/rt_call_signature.h"
28 #include "ecmascript/compiler/typed_array_stub_builder.h"
29 #include "ecmascript/global_env_constants.h"
30 #include "ecmascript/ic/properties_cache.h"
31 #include "ecmascript/js_api/js_api_arraylist.h"
32 #include "ecmascript/js_api/js_api_vector.h"
33 #include "ecmascript/js_object.h"
34 #include "ecmascript/js_primitive_ref.h"
35 #include "ecmascript/js_arguments.h"
36 #include "ecmascript/mem/remembered_set.h"
37 #include "ecmascript/message_string.h"
38 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
39 #include "ecmascript/property_attributes.h"
40 #include "ecmascript/tagged_dictionary.h"
41 #include "ecmascript/tagged_hash_table.h"
42 
43 namespace panda::ecmascript::kungfu {
Jump(Label * label)44 void StubBuilder::Jump(Label *label)
45 {
46     ASSERT(label);
47     auto currentLabel = env_->GetCurrentLabel();
48     auto currentControl = currentLabel->GetControl();
49     auto jump = env_->GetBuilder()->Goto(currentControl);
50     currentLabel->SetControl(jump);
51     label->AppendPredecessor(currentLabel);
52     label->MergeControl(currentLabel->GetControl());
53     env_->SetCurrentLabel(nullptr);
54 }
55 
Branch(GateRef condition,Label * trueLabel,Label * falseLabel)56 void StubBuilder::Branch(GateRef condition, Label *trueLabel, Label *falseLabel)
57 {
58     auto currentLabel = env_->GetCurrentLabel();
59     auto currentControl = currentLabel->GetControl();
60     GateRef ifBranch = env_->GetBuilder()->Branch(currentControl, condition);
61     currentLabel->SetControl(ifBranch);
62     GateRef ifTrue = env_->GetBuilder()->IfTrue(ifBranch);
63     trueLabel->AppendPredecessor(env_->GetCurrentLabel());
64     trueLabel->MergeControl(ifTrue);
65     GateRef ifFalse = env_->GetBuilder()->IfFalse(ifBranch);
66     falseLabel->AppendPredecessor(env_->GetCurrentLabel());
67     falseLabel->MergeControl(ifFalse);
68     env_->SetCurrentLabel(nullptr);
69 }
70 
Switch(GateRef index,Label * defaultLabel,int64_t * keysValue,Label * keysLabel,int numberOfKeys)71 void StubBuilder::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys)
72 {
73     auto currentLabel = env_->GetCurrentLabel();
74     auto currentControl = currentLabel->GetControl();
75     GateRef switchBranch = env_->GetBuilder()->SwitchBranch(currentControl, index, numberOfKeys);
76     currentLabel->SetControl(switchBranch);
77     for (int i = 0; i < numberOfKeys; i++) {
78         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
79         GateRef switchCase = env_->GetBuilder()->SwitchCase(switchBranch, keysValue[i]);
80         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
81         keysLabel[i].AppendPredecessor(currentLabel);
82         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
83         keysLabel[i].MergeControl(switchCase);
84     }
85 
86     GateRef defaultCase = env_->GetBuilder()->DefaultCase(switchBranch);
87     defaultLabel->AppendPredecessor(currentLabel);
88     defaultLabel->MergeControl(defaultCase);
89     env_->SetCurrentLabel(nullptr);
90 }
91 
LoopBegin(Label * loopHead)92 void StubBuilder::LoopBegin(Label *loopHead)
93 {
94     ASSERT(loopHead);
95     auto loopControl = env_->GetBuilder()->LoopBegin(loopHead->GetControl());
96     loopHead->SetControl(loopControl);
97     loopHead->SetPreControl(loopControl);
98     loopHead->Bind();
99     env_->SetCurrentLabel(loopHead);
100 }
101 
LoopEnd(Label * loopHead)102 void StubBuilder::LoopEnd(Label *loopHead)
103 {
104     ASSERT(loopHead);
105     auto currentLabel = env_->GetCurrentLabel();
106     auto currentControl = currentLabel->GetControl();
107     auto loopend = env_->GetBuilder()->LoopEnd(currentControl);
108     currentLabel->SetControl(loopend);
109     loopHead->AppendPredecessor(currentLabel);
110     loopHead->MergeControl(loopend);
111     loopHead->Seal();
112     loopHead->MergeAllControl();
113     loopHead->MergeAllDepend();
114     env_->SetCurrentLabel(nullptr);
115 }
116 
MatchTrackType(GateRef trackType,GateRef value,Label * executeSetProp,Label * typeMismatch)117 void StubBuilder::MatchTrackType(GateRef trackType, GateRef value, Label *executeSetProp, Label *typeMismatch)
118 {
119     auto *env = GetEnvironment();
120     Label isNumber(env);
121     Label checkBoolean(env);
122     Label isBoolean(env);
123     Label checkString(env);
124     Label isString(env);
125     Label checkJSShared(env);
126     Label isJSShared(env);
127     Label checkJSNone(env);
128     Label isJSNone(env);
129     Label exit(env);
130     DEFVARIABLE(result, VariableType::BOOL(), False());
131     Branch(Equal(trackType, Int32(static_cast<int32_t>(TrackType::NUMBER))), &isNumber, &checkBoolean);
132     Bind(&isNumber);
133     {
134         result = TaggedIsNumber(value);
135         Jump(&exit);
136     }
137     Bind(&checkBoolean);
138     {
139         Branch(Equal(trackType, Int32(static_cast<int32_t>(TrackType::BOOLEAN))), &isBoolean, &checkString);
140         Bind(&isBoolean);
141         {
142             result = TaggedIsBoolean(value);
143             Jump(&exit);
144         }
145     }
146     Bind(&checkString);
147     {
148         Branch(Equal(trackType, Int32(static_cast<int32_t>(TrackType::STRING))), &isString, &checkJSShared);
149         Bind(&isString);
150         {
151             result = BoolOr(TaggedIsString(value), TaggedIsNull(value));
152             Jump(&exit);
153         }
154     }
155     Bind(&checkJSShared);
156     {
157         Branch(Equal(trackType, Int32(static_cast<int32_t>(TrackType::SENDABLE))), &isJSShared, &checkJSNone);
158         Bind(&isJSShared);
159         {
160             result = BoolOr(TaggedIsShared(value), TaggedIsNull(value));
161             Jump(&exit);
162         }
163     }
164     Bind(&checkJSNone);
165     {
166         Branch(Equal(trackType, Int32(static_cast<int32_t>(TrackType::NONE))), &isJSNone, &exit);
167         Bind(&isJSNone);
168         {
169             // bypass none type
170             result = True();
171             Jump(&exit);
172         }
173     }
174     Bind(&exit);
175     Branch(*result, executeSetProp, typeMismatch);
176 }
177 
178 // FindElementWithCache in ecmascript/layout_info-inl.h
FindElementWithCache(GateRef glue,GateRef layoutInfo,GateRef hclass,GateRef key,GateRef propsNum)179 GateRef StubBuilder::FindElementWithCache(GateRef glue, GateRef layoutInfo, GateRef hclass,
180     GateRef key, GateRef propsNum)
181 {
182     auto env = GetEnvironment();
183     Label subEntry(env);
184     env->SubCfgEntry(&subEntry);
185     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
186     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
187     Label exit(env);
188     Label notExceedUpper(env);
189     Label exceedUpper(env);
190     // 9 : Builtins Object properties number is nine
191     Branch(Int32LessThanOrEqual(propsNum, Int32(9)), &notExceedUpper, &exceedUpper);
192     Bind(&notExceedUpper);
193     {
194         Label loopHead(env);
195         Label loopEnd(env);
196         Label afterLoop(env);
197         Jump(&loopHead);
198         LoopBegin(&loopHead);
199         {
200             Label propsNumIsZero(env);
201             Label propsNumNotZero(env);
202             Branch(Int32Equal(propsNum, Int32(0)), &propsNumIsZero, &propsNumNotZero);
203             Bind(&propsNumIsZero);
204             Jump(&afterLoop);
205             Bind(&propsNumNotZero);
206             GateRef elementAddr = GetPropertiesAddrFromLayoutInfo(layoutInfo);
207             GateRef keyInProperty = Load(VariableType::JS_ANY(), elementAddr,
208                                          PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(panda::ecmascript::Properties))));
209             Label equal(env);
210             Label notEqual(env);
211             Label afterEqualCon(env);
212             Branch(Equal(keyInProperty, key), &equal, &notEqual);
213             Bind(&equal);
214             result = *i;
215             Jump(&exit);
216             Bind(&notEqual);
217             Jump(&afterEqualCon);
218             Bind(&afterEqualCon);
219             i = Int32Add(*i, Int32(1));
220             Branch(Int32UnsignedLessThan(*i, propsNum), &loopEnd, &afterLoop);
221             Bind(&loopEnd);
222             LoopEnd(&loopHead);
223         }
224         Bind(&afterLoop);
225         result = Int32(-1);
226         Jump(&exit);
227     }
228     Bind(&exceedUpper);
229     result = CallNGCRuntime(glue, RTSTUB_ID(FindElementWithCache), { glue, hclass, key, propsNum });
230     Jump(&exit);
231     Bind(&exit);
232     auto ret = *result;
233     env->SubCfgExit();
234     return ret;
235 }
236 
FindElementFromNumberDictionary(GateRef glue,GateRef elements,GateRef index)237 GateRef StubBuilder::FindElementFromNumberDictionary(GateRef glue, GateRef elements, GateRef index)
238 {
239     auto env = GetEnvironment();
240     Label subentry(env);
241     env->SubCfgEntry(&subentry);
242     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
243     Label exit(env);
244     GateRef capcityoffset =
245         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
246                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
247     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
248     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
249                                            PtrAdd(dataoffset, capcityoffset)));
250     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
251     GateRef len = Int32(sizeof(int) / sizeof(uint8_t));
252     GateRef hash = CallRuntime(glue, RTSTUB_ID(GetHash32),
253         { IntToTaggedInt(index), IntToTaggedInt(len) });
254     DEFVARIABLE(entry, VariableType::INT32(),
255         Int32And(TruncInt64ToInt32(ChangeTaggedPointerToInt64(hash)), Int32Sub(capacity, Int32(1))));
256     Label loopHead(env);
257     Label loopEnd(env);
258     Label afterLoop(env);
259     Jump(&loopHead);
260     LoopBegin(&loopHead);
261     GateRef element = GetKeyFromDictionary<NumberDictionary>(elements, *entry);
262     Label isHole(env);
263     Label notHole(env);
264     Branch(TaggedIsHole(element), &isHole, &notHole);
265     Bind(&isHole);
266     Jump(&loopEnd);
267     Bind(&notHole);
268     Label isUndefined(env);
269     Label notUndefined(env);
270     Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
271     Bind(&isUndefined);
272     result = Int32(-1);
273     Jump(&exit);
274     Bind(&notUndefined);
275     Label isMatch(env);
276     Label notMatch(env);
277     Branch(Int32Equal(index, GetInt32OfTInt(element)), &isMatch, &notMatch);
278     Bind(&isMatch);
279     result = *entry;
280     Jump(&exit);
281     Bind(&notMatch);
282     Jump(&loopEnd);
283     Bind(&loopEnd);
284     entry = GetNextPositionForHash(*entry, *count, capacity);
285     count = Int32Add(*count, Int32(1));
286     LoopEnd(&loopHead);
287     Bind(&exit);
288     auto ret = *result;
289     env->SubCfgExit();
290     return ret;
291 }
292 
293 // int TaggedHashTable<Derived>::FindEntry(const JSTaggedValue &key) in tagged_hash_table.h
FindEntryFromNameDictionary(GateRef glue,GateRef elements,GateRef key)294 GateRef StubBuilder::FindEntryFromNameDictionary(GateRef glue, GateRef elements, GateRef key)
295 {
296     auto env = GetEnvironment();
297     Label funcEntry(env);
298     env->SubCfgEntry(&funcEntry);
299     Label exit(env);
300     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
301     GateRef capcityoffset =
302         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
303                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
304     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
305     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
306                                            PtrAdd(dataoffset, capcityoffset)));
307     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
308     DEFVARIABLE(hash, VariableType::INT32(), Int32(0));
309     // NameDictionary::hash
310     Label isSymbol(env);
311     Label notSymbol(env);
312     Label loopHead(env);
313     Label loopEnd(env);
314     Label afterLoop(env);
315     Label beforeDefineHash(env);
316     Branch(IsSymbol(key), &isSymbol, &notSymbol);
317     Bind(&isSymbol);
318     {
319         hash = GetInt32OfTInt(Load(VariableType::INT64(), key,
320             IntPtr(JSSymbol::HASHFIELD_OFFSET)));
321         Jump(&beforeDefineHash);
322     }
323     Bind(&notSymbol);
324     {
325         Label isString(env);
326         Label notString(env);
327         Branch(IsString(key), &isString, &notString);
328         Bind(&isString);
329         {
330             hash = GetHashcodeFromString(glue, key);
331             Jump(&beforeDefineHash);
332         }
333         Bind(&notString);
334         {
335             Jump(&beforeDefineHash);
336         }
337     }
338     Bind(&beforeDefineHash);
339     // GetFirstPosition(hash, size)
340     DEFVARIABLE(entry, VariableType::INT32(), Int32And(*hash, Int32Sub(capacity, Int32(1))));
341     Jump(&loopHead);
342     LoopBegin(&loopHead);
343     {
344         GateRef element = GetKeyFromDictionary<NameDictionary>(elements, *entry);
345         Label isHole(env);
346         Label notHole(env);
347         Branch(TaggedIsHole(element), &isHole, &notHole);
348         {
349             Bind(&isHole);
350             {
351                 Jump(&loopEnd);
352             }
353             Bind(&notHole);
354             {
355                 Label isUndefined(env);
356                 Label notUndefined(env);
357                 Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
358                 {
359                     Bind(&isUndefined);
360                     {
361                         result = Int32(-1);
362                         Jump(&exit);
363                     }
364                     Bind(&notUndefined);
365                     {
366                         Label isMatch(env);
367                         Label notMatch(env);
368                         Branch(Equal(key, element), &isMatch, &notMatch);
369                         {
370                             Bind(&isMatch);
371                             {
372                                 result = *entry;
373                                 Jump(&exit);
374                             }
375                             Bind(&notMatch);
376                             {
377                                 Jump(&loopEnd);
378                             }
379                         }
380                     }
381                 }
382             }
383         }
384         Bind(&loopEnd);
385         {
386             entry = GetNextPositionForHash(*entry, *count, capacity);
387             count = Int32Add(*count, Int32(1));
388             LoopEnd(&loopHead);
389         }
390     }
391     Bind(&exit);
392     auto ret = *result;
393     env->SubCfgExit();
394     return ret;
395 }
396 
IsMatchInTransitionDictionary(GateRef element,GateRef key,GateRef metaData,GateRef attr)397 GateRef StubBuilder::IsMatchInTransitionDictionary(GateRef element, GateRef key, GateRef metaData, GateRef attr)
398 {
399     return BoolAnd(Equal(element, key), Int32Equal(metaData, attr));
400 }
401 
402 // metaData is int32 type
FindEntryFromTransitionDictionary(GateRef glue,GateRef elements,GateRef key,GateRef metaData)403 GateRef StubBuilder::FindEntryFromTransitionDictionary(GateRef glue, GateRef elements, GateRef key, GateRef metaData)
404 {
405     auto env = GetEnvironment();
406     Label funcEntry(env);
407     env->SubCfgEntry(&funcEntry);
408     Label exit(env);
409     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
410     GateRef capcityoffset =
411         PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()),
412                IntPtr(TaggedHashTable<NumberDictionary>::SIZE_INDEX));
413     GateRef dataoffset = IntPtr(TaggedArray::DATA_OFFSET);
414     GateRef capacity = GetInt32OfTInt(Load(VariableType::INT64(), elements,
415                                            PtrAdd(dataoffset, capcityoffset)));
416     DEFVARIABLE(count, VariableType::INT32(), Int32(1));
417     DEFVARIABLE(hash, VariableType::INT32(), Int32(0));
418     // TransitionDictionary::hash
419     Label isSymbol(env);
420     Label notSymbol(env);
421     Label loopHead(env);
422     Label loopEnd(env);
423     Label afterLoop(env);
424     Label beforeDefineHash(env);
425     Branch(IsSymbol(key), &isSymbol, &notSymbol);
426     Bind(&isSymbol);
427     {
428         hash = GetInt32OfTInt(Load(VariableType::INT64(), key,
429             IntPtr(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET)));
430         Jump(&beforeDefineHash);
431     }
432     Bind(&notSymbol);
433     {
434         Label isString(env);
435         Label notString(env);
436         Branch(IsString(key), &isString, &notString);
437         Bind(&isString);
438         {
439             hash = GetHashcodeFromString(glue, key);
440             Jump(&beforeDefineHash);
441         }
442         Bind(&notString);
443         {
444             Jump(&beforeDefineHash);
445         }
446     }
447     Bind(&beforeDefineHash);
448     hash = Int32Add(*hash, metaData);
449     // GetFirstPosition(hash, size)
450     DEFVARIABLE(entry, VariableType::INT32(), Int32And(*hash, Int32Sub(capacity, Int32(1))));
451     Jump(&loopHead);
452     LoopBegin(&loopHead);
453     {
454         GateRef element = GetKeyFromDictionary<TransitionsDictionary>(elements, *entry);
455         Label isHole(env);
456         Label notHole(env);
457         Branch(TaggedIsHole(element), &isHole, &notHole);
458         {
459             Bind(&isHole);
460             {
461                 Jump(&loopEnd);
462             }
463             Bind(&notHole);
464             {
465                 Label isUndefined(env);
466                 Label notUndefined(env);
467                 Branch(TaggedIsUndefined(element), &isUndefined, &notUndefined);
468                 {
469                     Bind(&isUndefined);
470                     {
471                         result = Int32(-1);
472                         Jump(&exit);
473                     }
474                     Bind(&notUndefined);
475                     {
476                         Label isMatch(env);
477                         Label notMatch(env);
478                         Branch(
479                             IsMatchInTransitionDictionary(element, key, metaData,
480                                 GetAttributesFromDictionary<TransitionsDictionary>(elements, *entry)),
481                             &isMatch, &notMatch);
482                         {
483                             Bind(&isMatch);
484                             {
485                                 result = *entry;
486                                 Jump(&exit);
487                             }
488                             Bind(&notMatch);
489                             {
490                                 Jump(&loopEnd);
491                             }
492                         }
493                     }
494                 }
495             }
496         }
497         Bind(&loopEnd);
498         {
499             entry = GetNextPositionForHash(*entry, *count, capacity);
500             count = Int32Add(*count, Int32(1));
501             LoopEnd(&loopHead);
502         }
503     }
504     Bind(&exit);
505     auto ret = *result;
506     env->SubCfgExit();
507     return ret;
508 }
509 
JSObjectGetProperty(GateRef obj,GateRef hclass,GateRef attr)510 GateRef StubBuilder::JSObjectGetProperty(GateRef obj, GateRef hclass, GateRef attr)
511 {
512     auto env = GetEnvironment();
513     Label entry(env);
514     env->SubCfgEntry(&entry);
515     Label exit(env);
516     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
517     Label inlinedProp(env);
518     Label notInlinedProp(env);
519     Label post(env);
520     GateRef attrOffset = GetOffsetFieldInPropAttr(attr);
521     GateRef rep = GetRepInPropAttr(attr);
522     Branch(IsInlinedProperty(attr), &inlinedProp, &notInlinedProp);
523     {
524         Bind(&inlinedProp);
525         {
526             result = GetPropertyInlinedProps(obj, hclass, attrOffset);
527             Jump(&post);
528         }
529         Bind(&notInlinedProp);
530         {
531             // compute outOfLineProp offset, get it and return
532             GateRef array =
533                 Load(VariableType::INT64(), obj, IntPtr(JSObject::PROPERTIES_OFFSET));
534             result = GetValueFromTaggedArray(array, Int32Sub(attrOffset,
535                 GetInlinedPropertiesFromHClass(hclass)));
536             Jump(&post);
537         }
538     }
539     Bind(&post);
540     {
541         Label nonDoubleToTagged(env);
542         Label doubleToTagged(env);
543         Branch(IsDoubleRepInPropAttr(rep), &doubleToTagged, &nonDoubleToTagged);
544         Bind(&doubleToTagged);
545         {
546             result = TaggedPtrToTaggedDoublePtr(*result);
547             Jump(&exit);
548         }
549         Bind(&nonDoubleToTagged);
550         {
551             Label intToTagged(env);
552             Branch(IsIntRepInPropAttr(rep), &intToTagged, &exit);
553             Bind(&intToTagged);
554             {
555                 result = TaggedPtrToTaggedIntPtr(*result);
556                 Jump(&exit);
557             }
558         }
559     }
560     Bind(&exit);
561     auto ret = *result;
562     env->SubCfgExit();
563     return ret;
564 }
565 
JSObjectSetProperty(GateRef glue,GateRef obj,GateRef hclass,GateRef attr,GateRef key,GateRef value)566 void StubBuilder::JSObjectSetProperty(
567     GateRef glue, GateRef obj, GateRef hclass, GateRef attr, GateRef key, GateRef value)
568 {
569     auto env = GetEnvironment();
570     Label subEntry(env);
571     env->SubCfgEntry(&subEntry);
572     Label exit(env);
573     Label inlinedProp(env);
574     Label notInlinedProp(env);
575     GateRef attrIndex = GetOffsetFieldInPropAttr(attr);
576     Branch(IsInlinedProperty(attr), &inlinedProp, &notInlinedProp);
577     {
578         Bind(&inlinedProp);
579         {
580             GateRef offset = GetInlinedPropOffsetFromHClass(hclass, attrIndex);
581             SetValueWithAttr(glue, obj, offset, key, value, attr);
582             Jump(&exit);
583         }
584         Bind(&notInlinedProp);
585         {
586             // compute outOfLineProp offset, get it and return
587             GateRef array = Load(VariableType::JS_POINTER(), obj,
588                                  IntPtr(JSObject::PROPERTIES_OFFSET));
589             GateRef offset = Int32Sub(attrIndex, GetInlinedPropertiesFromHClass(hclass));
590             SetValueToTaggedArrayWithAttr(glue, array, offset, key, value, attr);
591             Jump(&exit);
592         }
593     }
594     Bind(&exit);
595     env->SubCfgExit();
596     return;
597 }
598 
ComputeNonInlinedFastPropsCapacity(GateRef glue,GateRef oldLength,GateRef maxNonInlinedFastPropsCapacity)599 GateRef StubBuilder::ComputeNonInlinedFastPropsCapacity(GateRef glue, GateRef oldLength,
600                                                         GateRef maxNonInlinedFastPropsCapacity)
601 {
602     auto env = GetEnvironment();
603     Label subEntry(env);
604     env->SubCfgEntry(&subEntry);
605     Label exit(env);
606     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
607     GateRef propertiesStep = Load(VariableType::INT32(), glue,
608         IntPtr(JSThread::GlueData::GetPropertiesGrowStepOffset(env->Is32Bit())));
609     GateRef newL = Int32Add(oldLength, propertiesStep);
610     Label reachMax(env);
611     Label notReachMax(env);
612     Branch(Int32GreaterThan(newL, maxNonInlinedFastPropsCapacity), &reachMax, &notReachMax);
613     {
614         Bind(&reachMax);
615         result = maxNonInlinedFastPropsCapacity;
616         Jump(&exit);
617         Bind(&notReachMax);
618         result = newL;
619         Jump(&exit);
620     }
621     Bind(&exit);
622     auto ret = *result;
623     env->SubCfgExit();
624     return ret;
625 }
626 
ComputeElementCapacity(GateRef oldLength)627 GateRef StubBuilder::ComputeElementCapacity(GateRef oldLength)
628 {
629     auto env = GetEnvironment();
630     Label subEntry(env);
631     env->SubCfgEntry(&subEntry);
632     Label exit(env);
633     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
634     GateRef newL = Int32Add(oldLength, Int32LSR(oldLength, Int32(1)));
635     Label reachMin(env);
636     Label notReachMin(env);
637     Branch(Int32GreaterThan(newL, Int32(JSObject::MIN_ELEMENTS_LENGTH)), &reachMin, &notReachMin);
638     {
639         Bind(&reachMin);
640         result = newL;
641         Jump(&exit);
642         Bind(&notReachMin);
643         result = Int32(JSObject::MIN_ELEMENTS_LENGTH);
644         Jump(&exit);
645     }
646     Bind(&exit);
647     auto ret = *result;
648     env->SubCfgExit();
649     return ret;
650 }
651 
CallGetterHelper(GateRef glue,GateRef receiver,GateRef holder,GateRef accessor,ProfileOperation callback)652 GateRef StubBuilder::CallGetterHelper(
653     GateRef glue, GateRef receiver, GateRef holder, GateRef accessor, ProfileOperation callback)
654 {
655     auto env = GetEnvironment();
656     Label subEntry(env);
657     env->SubCfgEntry(&subEntry);
658     Label exit(env);
659     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
660 
661     Label isInternal(env);
662     Label notInternal(env);
663     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
664     Bind(&isInternal);
665     {
666         Label arrayLength(env);
667         Label tryContinue(env);
668         auto lengthAccessor = GetGlobalConstantValue(
669             VariableType::JS_POINTER(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
670         Branch(Equal(accessor, lengthAccessor), &arrayLength, &tryContinue);
671         Bind(&arrayLength);
672         {
673             auto length = Load(VariableType::INT32(), holder, IntPtr(JSArray::LENGTH_OFFSET));
674             // TaggedInt supports up to INT32_MAX.
675             // If length is greater than Int32_MAX, needs to be converted to TaggedDouble.
676             auto condition = Int32UnsignedGreaterThan(length, Int32(INT32_MAX));
677             Label overflow(env);
678             Label notOverflow(env);
679             Branch(condition, &overflow, &notOverflow);
680             Bind(&overflow);
681             {
682                 result = DoubleToTaggedDoublePtr(ChangeUInt32ToFloat64(length));
683                 Jump(&exit);
684             }
685             Bind(&notOverflow);
686             {
687                 result = IntToTaggedPtr(length);
688                 Jump(&exit);
689             }
690         }
691         Bind(&tryContinue);
692         result = CallRuntime(glue, RTSTUB_ID(CallInternalGetter), { accessor, holder });
693         Jump(&exit);
694     }
695     Bind(&notInternal);
696     {
697         auto getter = Load(VariableType::JS_ANY(), accessor,
698                            IntPtr(AccessorData::GETTER_OFFSET));
699         Label objIsUndefined(env);
700         Label objNotUndefined(env);
701         Branch(TaggedIsUndefined(getter), &objIsUndefined, &objNotUndefined);
702         // if getter is undefined, return undefiend
703         Bind(&objIsUndefined);
704         {
705             result = Undefined();
706             Jump(&exit);
707         }
708         Bind(&objNotUndefined);
709         {
710             auto retValue = JSCallDispatch(glue, getter, Int32(0), 0, Circuit::NullGate(),
711                                            JSCallMode::CALL_GETTER, { receiver }, callback);
712             Label noPendingException(env);
713             Branch(HasPendingException(glue), &exit, &noPendingException);
714             Bind(&noPendingException);
715             {
716                 result = retValue;
717                 Jump(&exit);
718             }
719         }
720     }
721     Bind(&exit);
722     auto ret = *result;
723     env->SubCfgExit();
724     return ret;
725 }
726 
CallSetterHelper(GateRef glue,GateRef receiver,GateRef accessor,GateRef value,ProfileOperation callback)727 GateRef StubBuilder::CallSetterHelper(
728     GateRef glue, GateRef receiver, GateRef accessor, GateRef value, ProfileOperation callback)
729 {
730     auto env = GetEnvironment();
731     Label subEntry(env);
732     env->SubCfgEntry(&subEntry);
733     Label exit(env);
734     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
735 
736     Label isInternal(env);
737     Label notInternal(env);
738     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
739     Bind(&isInternal);
740     {
741         result = CallRuntime(glue, RTSTUB_ID(CallInternalSetter), { receiver, accessor, value });
742         Jump(&exit);
743     }
744     Bind(&notInternal);
745     {
746         auto setter = Load(VariableType::JS_ANY(), accessor,
747                            IntPtr(AccessorData::SETTER_OFFSET));
748         Label objIsUndefined(env);
749         Label objNotUndefined(env);
750         Branch(TaggedIsUndefined(setter), &objIsUndefined, &objNotUndefined);
751         Bind(&objIsUndefined);
752         {
753             CallRuntime(glue, RTSTUB_ID(ThrowSetterIsUndefinedException), {});
754             result = Exception();
755             Jump(&exit);
756         }
757         Bind(&objNotUndefined);
758         {
759             auto retValue = JSCallDispatch(glue, setter, Int32(1), 0, Circuit::NullGate(),
760                                            JSCallMode::CALL_SETTER, { receiver, value }, callback);
761             Label noPendingException(env);
762             Branch(HasPendingException(glue), &exit, &noPendingException);
763             Bind(&noPendingException);
764             {
765                 result = retValue;
766                 Jump(&exit);
767             }
768         }
769     }
770     Bind(&exit);
771     auto ret = *result;
772     env->SubCfgExit();
773     return ret;
774 }
775 
ShouldCallSetter(GateRef receiver,GateRef holder,GateRef accessor,GateRef attr)776 GateRef StubBuilder::ShouldCallSetter(GateRef receiver, GateRef holder, GateRef accessor, GateRef attr)
777 {
778     auto env = GetEnvironment();
779     Label subEntry(env);
780     env->SubCfgEntry(&subEntry);
781     Label exit(env);
782     DEFVARIABLE(result, VariableType::BOOL(), True());
783     Label isInternal(env);
784     Label notInternal(env);
785     Branch(IsAccessorInternal(accessor), &isInternal, &notInternal);
786     Bind(&isInternal);
787     {
788         Label receiverEqualsHolder(env);
789         Label receiverNotEqualsHolder(env);
790         Branch(Equal(receiver, holder), &receiverEqualsHolder, &receiverNotEqualsHolder);
791         Bind(&receiverEqualsHolder);
792         {
793             result = IsWritable(attr);
794             Jump(&exit);
795         }
796         Bind(&receiverNotEqualsHolder);
797         {
798             result = False();
799             Jump(&exit);
800         }
801     }
802     Bind(&notInternal);
803     {
804         result = True();
805         Jump(&exit);
806     }
807     Bind(&exit);
808     auto ret = *result;
809     env->SubCfgExit();
810     return ret;
811 }
812 
JSHClassAddProperty(GateRef glue,GateRef receiver,GateRef key,GateRef attr)813 void StubBuilder::JSHClassAddProperty(GateRef glue, GateRef receiver, GateRef key, GateRef attr)
814 {
815     auto env = GetEnvironment();
816     Label subEntry(env);
817     env->SubCfgEntry(&subEntry);
818     Label exit(env);
819     GateRef hclass = LoadHClass(receiver);
820     GateRef metaData = GetPropertyMetaDataFromAttr(attr);
821     GateRef newClass = FindTransitions(glue, receiver, hclass, key, metaData);
822     Label findHClass(env);
823     Label notFindHClass(env);
824     Branch(Equal(newClass, Undefined()), &notFindHClass, &findHClass);
825     Bind(&findHClass);
826     {
827         Jump(&exit);
828     }
829     Bind(&notFindHClass);
830     {
831         GateRef type = GetObjectType(hclass);
832         GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass),
833                                 Int32(JSTaggedValue::TaggedTypeSize()));
834         GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass);
835         GateRef newJshclass = CallRuntime(glue, RTSTUB_ID(NewEcmaHClass),
836             { IntToTaggedInt(size), IntToTaggedInt(type),
837               IntToTaggedInt(inlineProps) });
838         CopyAllHClass(glue, newJshclass, hclass);
839         CallRuntime(glue, RTSTUB_ID(UpdateLayOutAndAddTransition),
840                     { hclass, newJshclass, key, IntToTaggedInt(attr) });
841 #if ECMASCRIPT_ENABLE_IC
842         NotifyHClassChanged(glue, hclass, newJshclass);
843 #endif
844         StoreHClass(glue, receiver, newJshclass);
845         // Because we currently only supports Fast ElementsKind
846         CallRuntime(glue, RTSTUB_ID(TryRestoreElementsKind), { receiver, newJshclass });
847         Jump(&exit);
848     }
849     Bind(&exit);
850     env->SubCfgExit();
851     return;
852 }
853 
854 // if condition:(objHandle->IsJSArray() || objHandle->IsTypedArray()) &&
855 //      keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()
SetHasConstructorCondition(GateRef glue,GateRef receiver,GateRef key)856 GateRef StubBuilder::SetHasConstructorCondition(GateRef glue, GateRef receiver, GateRef key)
857 {
858     GateRef gConstOffset = Load(VariableType::JS_ANY(), glue,
859         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
860 
861     GateRef gCtorStr = Load(VariableType::JS_ANY(),
862         gConstOffset,
863         Int64Mul(Int64(sizeof(JSTaggedValue)),
864             Int64(static_cast<uint64_t>(ConstantIndex::CONSTRUCTOR_STRING_INDEX))));
865     GateRef isCtorStr = Equal(key, gCtorStr);
866     return BoolAnd(BoolOr(IsJsArray(receiver), IsTypedArray(receiver)), isCtorStr);
867 }
868 
869 // Note: set return exit node
AddPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef propertyAttributes,ProfileOperation callback)870 GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value,
871                                        GateRef propertyAttributes, ProfileOperation callback)
872 {
873     auto env = GetEnvironment();
874     Label subentry(env);
875     env->SubCfgEntry(&subentry);
876     Label exit(env);
877     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
878     Label setHasCtor(env);
879     Label notSetHasCtor(env);
880     Label afterCtorCon(env);
881     GateRef hclass = LoadHClass(receiver);
882     Branch(SetHasConstructorCondition(glue, receiver, key), &setHasCtor, &notSetHasCtor);
883     {
884         Bind(&setHasCtor);
885         SetHasConstructorToHClass(glue, hclass, Int32(1));
886         Jump(&afterCtorCon);
887         Bind(&notSetHasCtor);
888         Jump(&afterCtorCon);
889     }
890     Bind(&afterCtorCon);
891     // 0x111 : default attribute for property: writable, enumerable, configurable
892     DEFVARIABLE(attr, VariableType::INT32(), propertyAttributes);
893     GateRef numberOfProps = GetNumberOfPropsFromHClass(hclass);
894     GateRef inlinedProperties = GetInlinedPropertiesFromHClass(hclass);
895     Label hasUnusedInProps(env);
896     Label noUnusedInProps(env);
897     Label afterInPropsCon(env);
898     Branch(Int32UnsignedLessThan(numberOfProps, inlinedProperties), &hasUnusedInProps, &noUnusedInProps);
899     {
900         Bind(&noUnusedInProps);
901         Jump(&afterInPropsCon);
902         Bind(&hasUnusedInProps);
903         {
904             attr = SetOffsetFieldInPropAttr(*attr, numberOfProps);
905             attr = SetIsInlinePropsFieldInPropAttr(*attr, Int32(1)); // 1: set inInlineProps true
906             attr = SetTaggedRepInPropAttr(*attr);
907             attr = ProfilerStubBuilder(env).UpdateTrackTypeInPropAttr(*attr, value, callback);
908             JSHClassAddProperty(glue, receiver, key, *attr);
909             GateRef newHclass = LoadHClass(receiver);
910             GateRef newLayoutInfo = GetLayoutFromHClass(newHclass);
911             GateRef offset = GetInlinedPropOffsetFromHClass(hclass, numberOfProps);
912             attr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(newLayoutInfo, numberOfProps));
913             SetValueWithAttr(glue, receiver, offset, key, value, *attr);
914             result = Undefined();
915             Jump(&exit);
916         }
917     }
918     Bind(&afterInPropsCon);
919     DEFVARIABLE(array, VariableType::JS_POINTER(), GetPropertiesArray(receiver));
920     DEFVARIABLE(length, VariableType::INT32(), GetLengthOfTaggedArray(*array));
921     Label lenIsZero(env);
922     Label lenNotZero(env);
923     Label afterLenCon(env);
924     Branch(Int32Equal(*length, Int32(0)), &lenIsZero, &lenNotZero);
925     {
926         Bind(&lenIsZero);
927         {
928             length = Int32(JSObject::MIN_PROPERTIES_LENGTH);
929             array = CallRuntime(glue, RTSTUB_ID(NewTaggedArray), { IntToTaggedInt(*length) });
930             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array);
931             Jump(&afterLenCon);
932         }
933         Bind(&lenNotZero);
934         Jump(&afterLenCon);
935     }
936     Bind(&afterLenCon);
937     Label isDictMode(env);
938     Label notDictMode(env);
939     Branch(IsDictionaryMode(*array), &isDictMode, &notDictMode);
940     {
941         Bind(&isDictMode);
942         {
943             GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent),
944                                       {receiver, *array, key, value, IntToTaggedInt(*attr), TaggedFalse()});
945             SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res);
946             Jump(&exit);
947         }
948         Bind(&notDictMode);
949         {
950             attr = SetIsInlinePropsFieldInPropAttr(*attr, Int32(0));
951             GateRef outProps = Int32Sub(numberOfProps, inlinedProperties);
952             Label ChangeToDict(env);
953             Label notChangeToDict(env);
954             Label afterDictChangeCon(env);
955             Branch(Int32GreaterThanOrEqual(numberOfProps, Int32(PropertyAttributes::MAX_FAST_PROPS_CAPACITY)),
956                 &ChangeToDict, &notChangeToDict);
957             {
958                 Bind(&ChangeToDict);
959                 {
960                     attr = SetDictionaryOrderFieldInPropAttr(*attr,
961                         Int32(PropertyAttributes::MAX_FAST_PROPS_CAPACITY));
962                     GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent),
963                         { receiver, *array, key, value, IntToTaggedInt(*attr), TaggedTrue() });
964                     SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res);
965                     result = Undefined();
966                     Jump(&exit);
967                 }
968                 Bind(&notChangeToDict);
969                 Jump(&afterDictChangeCon);
970             }
971             Bind(&afterDictChangeCon);
972             Label isArrayFull(env);
973             Label arrayNotFull(env);
974             Label afterArrLenCon(env);
975             Branch(Int32Equal(*length, outProps), &isArrayFull, &arrayNotFull);
976             {
977                 Bind(&isArrayFull);
978                 {
979                     GateRef maxNonInlinedFastPropsCapacity =
980                         Int32Sub(Int32(PropertyAttributes::MAX_FAST_PROPS_CAPACITY), inlinedProperties);
981                     GateRef capacity = ComputeNonInlinedFastPropsCapacity(glue, *length,
982                         maxNonInlinedFastPropsCapacity);
983                     array = CallRuntime(glue, RTSTUB_ID(CopyArray),
984                         { *array, IntToTaggedInt(*length), IntToTaggedInt(capacity) });
985                     SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, *array);
986                     Jump(&afterArrLenCon);
987                 }
988                 Bind(&arrayNotFull);
989                 Jump(&afterArrLenCon);
990             }
991             Bind(&afterArrLenCon);
992             {
993                 attr = SetOffsetFieldInPropAttr(*attr, numberOfProps);
994                 attr = SetTaggedRepInPropAttr(*attr);
995                 attr = ProfilerStubBuilder(env).UpdateTrackTypeInPropAttr(*attr, value, callback);
996                 JSHClassAddProperty(glue, receiver, key, *attr);
997                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, *array, outProps, value);
998                 Jump(&exit);
999             }
1000         }
1001     }
1002     Bind(&exit);
1003     auto ret = *result;
1004     env->SubCfgExit();
1005     return ret;
1006 }
1007 
ThrowTypeAndReturn(GateRef glue,int messageId,GateRef val)1008 void StubBuilder::ThrowTypeAndReturn(GateRef glue, int messageId, GateRef val)
1009 {
1010     GateRef msgIntId = Int32(messageId);
1011     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(msgIntId) });
1012     Return(val);
1013 }
1014 
TaggedToRepresentation(GateRef value)1015 GateRef StubBuilder::TaggedToRepresentation(GateRef value)
1016 {
1017     auto env = GetEnvironment();
1018     Label entry(env);
1019     env->SubCfgEntry(&entry);
1020     Label exit(env);
1021     DEFVARIABLE(resultRep, VariableType::INT64(),
1022                 Int64(static_cast<int32_t>(Representation::TAGGED)));
1023     Label isInt(env);
1024     Label notInt(env);
1025 
1026     Branch(TaggedIsInt(value), &isInt, &notInt);
1027     Bind(&isInt);
1028     {
1029         resultRep = Int64(static_cast<int32_t>(Representation::INT));
1030         Jump(&exit);
1031     }
1032     Bind(&notInt);
1033     {
1034         Label isDouble(env);
1035         Label notDouble(env);
1036         Branch(TaggedIsDouble(value), &isDouble, &notDouble);
1037         Bind(&isDouble);
1038         {
1039             resultRep = Int64(static_cast<int32_t>(Representation::DOUBLE));
1040             Jump(&exit);
1041         }
1042         Bind(&notDouble);
1043         {
1044             resultRep = Int64(static_cast<int32_t>(Representation::TAGGED));
1045             Jump(&exit);
1046         }
1047     }
1048     Bind(&exit);
1049     auto ret = *resultRep;
1050     env->SubCfgExit();
1051     return ret;
1052 }
1053 
TaggedToElementKind(GateRef value)1054 GateRef StubBuilder::TaggedToElementKind(GateRef value)
1055 {
1056     auto env = GetEnvironment();
1057     Label entry(env);
1058     env->SubCfgEntry(&entry);
1059     Label exit(env);
1060 
1061     DEFVARIABLE(result, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::TAGGED)));
1062     Label isHole(env);
1063     Label isNotHole(env);
1064     Branch(TaggedIsHole(value), &isHole, &isNotHole);
1065     Bind(&isHole);
1066     {
1067         result = Int32(static_cast<int32_t>(ElementsKind::HOLE));
1068         Jump(&exit);
1069     }
1070     Bind(&isNotHole);
1071     {
1072         Label isInt(env);
1073         Label isNotInt(env);
1074         Branch(TaggedIsInt(value), &isInt, &isNotInt);
1075         Bind(&isInt);
1076         {
1077             result = Int32(static_cast<int32_t>(ElementsKind::INT));
1078             Jump(&exit);
1079         }
1080         Bind(&isNotInt);
1081         {
1082             Label isObject(env);
1083             Label isDouble(env);
1084             Branch(TaggedIsObject(value), &isObject, &isDouble);
1085             Bind(&isDouble);
1086             {
1087                 result = Int32(static_cast<int32_t>(ElementsKind::NUMBER));
1088                 Jump(&exit);
1089             }
1090             Bind(&isObject);
1091             {
1092                 Label isHeapObject(env);
1093                 Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
1094                 Bind(&isHeapObject);
1095                 {
1096                     Label isString(env);
1097                     Label isNonString(env);
1098                     Branch(TaggedIsString(value), &isString, &isNonString);
1099                     Bind(&isString);
1100                     {
1101                         result = Int32(static_cast<int32_t>(ElementsKind::STRING));
1102                         Jump(&exit);
1103                     }
1104                     Bind(&isNonString);
1105                     {
1106                         result = Int32(static_cast<int32_t>(ElementsKind::OBJECT));
1107                         Jump(&exit);
1108                     }
1109                 }
1110             }
1111         }
1112     }
1113     Bind(&exit);
1114     auto ret = *result;
1115     env->SubCfgExit();
1116     return ret;
1117 }
1118 
Store(VariableType type,GateRef glue,GateRef base,GateRef offset,GateRef value,MemoryOrder order)1119 void StubBuilder::Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value, MemoryOrder order)
1120 {
1121     if (!env_->IsAsmInterp()) {
1122         env_->GetBuilder()->Store(type, glue, base, offset, value, order);
1123     } else {
1124         auto depend = env_->GetCurrentLabel()->GetDepend();
1125         GateRef ptr = PtrAdd(base, offset);
1126         auto bit = LoadStoreAccessor::ToValue(order);
1127         GateRef result = env_->GetCircuit()->NewGate(
1128             env_->GetCircuit()->Store(bit), MachineType::NOVALUE,
1129             { depend, value, ptr }, type.GetGateType());
1130         env_->GetCurrentLabel()->SetDepend(result);
1131         if (type == VariableType::JS_POINTER() || type == VariableType::JS_ANY()) {
1132             auto env = GetEnvironment();
1133             Label entry(env);
1134             env->SubCfgEntry(&entry);
1135             Label exit(env);
1136             Label isHeapObject(env);
1137 
1138             Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
1139             Bind(&isHeapObject);
1140             {
1141                 CallNGCRuntime(glue, RTSTUB_ID(StoreBarrier), { glue, base, offset, value });
1142                 Jump(&exit);
1143             }
1144             Bind(&exit);
1145             env->SubCfgExit();
1146         }
1147     }
1148 }
1149 
SetValueWithAttr(GateRef glue,GateRef obj,GateRef offset,GateRef key,GateRef value,GateRef attr)1150 void StubBuilder::SetValueWithAttr(GateRef glue, GateRef obj, GateRef offset, GateRef key, GateRef value, GateRef attr)
1151 {
1152     auto env = GetEnvironment();
1153     Label entry(env);
1154     env->SubCfgEntry(&entry);
1155 
1156     Label exit(env);
1157     Label repChange(env);
1158     GateRef rep = GetRepInPropAttr(attr);
1159     SetValueWithRep(glue, obj, offset, value, rep, &repChange);
1160     Jump(&exit);
1161     Bind(&repChange);
1162     {
1163         attr = SetTaggedRepInPropAttr(attr);
1164         TransitionForRepChange(glue, obj, key, attr);
1165         Store(VariableType::JS_ANY(), glue, obj, offset, value);
1166         Jump(&exit);
1167     }
1168     Bind(&exit);
1169     env->SubCfgExit();
1170 }
1171 
SetValueWithRep(GateRef glue,GateRef obj,GateRef offset,GateRef value,GateRef rep,Label * repChange)1172 void StubBuilder::SetValueWithRep(
1173     GateRef glue, GateRef obj, GateRef offset, GateRef value, GateRef rep, Label *repChange)
1174 {
1175     auto env = GetEnvironment();
1176     Label entry(env);
1177     env->SubCfgEntry(&entry);
1178 
1179     Label exit(env);
1180     Label repIsDouble(env);
1181     Label repIsNonDouble(env);
1182     Branch(IsDoubleRepInPropAttr(rep), &repIsDouble, &repIsNonDouble);
1183     Bind(&repIsDouble);
1184     {
1185         Label valueIsInt(env);
1186         Label valueIsNotInt(env);
1187         Branch(TaggedIsInt(value), &valueIsInt, &valueIsNotInt);
1188         Bind(&valueIsInt);
1189         {
1190             GateRef result = GetDoubleOfTInt(value);
1191             Store(VariableType::FLOAT64(), glue, obj, offset, result);
1192             Jump(&exit);
1193         }
1194         Bind(&valueIsNotInt);
1195         {
1196             Label valueIsObject(env);
1197             Label valueIsDouble(env);
1198             Branch(TaggedIsObject(value), &valueIsObject, &valueIsDouble);
1199             Bind(&valueIsDouble);
1200             {
1201                 // TaggedDouble to double
1202                 GateRef result = GetDoubleOfTDouble(value);
1203                 Store(VariableType::FLOAT64(), glue, obj, offset, result);
1204                 Jump(&exit);
1205             }
1206             Bind(&valueIsObject);
1207             {
1208                 Jump(repChange);
1209             }
1210         }
1211     }
1212     Bind(&repIsNonDouble);
1213     {
1214         Label repIsInt(env);
1215         Label repIsTagged(env);
1216         Branch(IsIntRepInPropAttr(rep), &repIsInt, &repIsTagged);
1217         Bind(&repIsInt);
1218         {
1219             Label valueIsInt(env);
1220             Label valueIsNotInt(env);
1221             Branch(TaggedIsInt(value), &valueIsInt, &valueIsNotInt);
1222             Bind(&valueIsInt);
1223             {
1224                 GateRef result = GetInt32OfTInt(value);
1225                 Store(VariableType::INT32(), glue, obj, offset, result);
1226                 Jump(&exit);
1227             }
1228             Bind(&valueIsNotInt);
1229             {
1230                 Jump(repChange);
1231             }
1232         }
1233         Bind(&repIsTagged);
1234         {
1235             Store(VariableType::JS_ANY(), glue, obj, offset, value);
1236             Jump(&exit);
1237         }
1238     }
1239 
1240     Bind(&exit);
1241     env->SubCfgExit();
1242     return;
1243 }
1244 
1245 
SetValueWithBarrier(GateRef glue,GateRef obj,GateRef offset,GateRef value)1246 void StubBuilder::SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value)
1247 {
1248     auto env = GetEnvironment();
1249     Label entry(env);
1250     env->SubCfgEntry(&entry);
1251     Label exit(env);
1252     Label isVailedIndex(env);
1253     Label notValidIndex(env);
1254 
1255     // ObjectAddressToRange function may cause obj is not an object. GC may not mark this obj.
1256     GateRef objectRegion = ObjectAddressToRange(obj);
1257     GateRef valueRegion = ObjectAddressToRange(value);
1258     GateRef slotAddr = PtrAdd(TaggedCastToIntPtr(obj), offset);
1259     GateRef objectNotInYoung = BoolNot(InYoungGeneration(objectRegion));
1260     GateRef valueRegionInYoung = InYoungGeneration(valueRegion);
1261     Branch(BoolAnd(objectNotInYoung, valueRegionInYoung), &isVailedIndex, &notValidIndex);
1262     Bind(&isVailedIndex);
1263     {
1264         GateRef loadOffset = IntPtr(Region::PackedData::GetOldToNewSetOffset(env_->Is32Bit()));
1265         auto oldToNewSet = Load(VariableType::NATIVE_POINTER(), objectRegion, loadOffset);
1266         Label isNullPtr(env);
1267         Label notNullPtr(env);
1268         Branch(IntPtrEuqal(oldToNewSet, IntPtr(0)), &isNullPtr, &notNullPtr);
1269         Bind(&notNullPtr);
1270         {
1271             // (slotAddr - this) >> TAGGED_TYPE_SIZE_LOG
1272             GateRef bitOffsetPtr = IntPtrLSR(PtrSub(slotAddr, objectRegion), IntPtr(TAGGED_TYPE_SIZE_LOG));
1273             GateRef bitOffset = TruncPtrToInt32(bitOffsetPtr);
1274             GateRef bitPerWordLog2 = Int32(GCBitset::BIT_PER_WORD_LOG2);
1275             GateRef bytePerWord = Int32(GCBitset::BYTE_PER_WORD);
1276             // bitOffset >> BIT_PER_WORD_LOG2
1277             GateRef index = Int32LSR(bitOffset, bitPerWordLog2);
1278             GateRef byteIndex = Int32Mul(index, bytePerWord);
1279             // bitset_[index] |= mask;
1280             GateRef bitsetData = PtrAdd(oldToNewSet, IntPtr(RememberedSet::GCBITSET_DATA_OFFSET));
1281             GateRef oldsetValue = Load(VariableType::INT32(), bitsetData, byteIndex);
1282             GateRef newmapValue = Int32Or(oldsetValue, GetBitMask(bitOffset));
1283 
1284             Store(VariableType::INT32(), glue, bitsetData, byteIndex, newmapValue);
1285             Jump(&notValidIndex);
1286         }
1287         Bind(&isNullPtr);
1288         {
1289             CallNGCRuntime(glue, RTSTUB_ID(InsertOldToNewRSet), { glue, obj, offset });
1290             Jump(&notValidIndex);
1291         }
1292     }
1293     Bind(&notValidIndex);
1294     {
1295         Label marking(env);
1296         bool isArch32 = GetEnvironment()->Is32Bit();
1297         GateRef stateBitFieldAddr = Int64Add(glue,
1298                                              Int64(JSThread::GlueData::GetStateBitFieldOffset(isArch32)));
1299         GateRef stateBitField = Load(VariableType::INT64(), stateBitFieldAddr, Int64(0));
1300         // mask: 1 << JSThread::CONCURRENT_MARKING_BITFIELD_NUM - 1
1301         GateRef markingBitMask = Int64Sub(
1302             Int64LSL(Int64(1), Int64(JSThread::CONCURRENT_MARKING_BITFIELD_NUM)), Int64(1));
1303         GateRef state = Int64And(stateBitField, markingBitMask);
1304         Branch(Int64Equal(state, Int64(static_cast<int64_t>(MarkStatus::READY_TO_MARK))), &exit, &marking);
1305 
1306         Bind(&marking);
1307         CallNGCRuntime(
1308             glue,
1309             RTSTUB_ID(MarkingBarrier), { glue, obj, offset, value });
1310         Jump(&exit);
1311     }
1312     Bind(&exit);
1313     env->SubCfgExit();
1314 }
1315 
TaggedIsBigInt(GateRef obj)1316 GateRef StubBuilder::TaggedIsBigInt(GateRef obj)
1317 {
1318     auto env = GetEnvironment();
1319     Label entry(env);
1320     env->SubCfgEntry(&entry);
1321     Label exit(env);
1322     Label isHeapObject(env);
1323     DEFVARIABLE(result, VariableType::BOOL(), False());
1324     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
1325     Bind(&isHeapObject);
1326     {
1327         result = Int32Equal(GetObjectType(LoadHClass(obj)),
1328                             Int32(static_cast<int32_t>(JSType::BIGINT)));
1329         Jump(&exit);
1330     }
1331     Bind(&exit);
1332     auto ret = *result;
1333     env->SubCfgExit();
1334     return ret;
1335 }
1336 
TaggedIsPropertyBox(GateRef obj)1337 GateRef StubBuilder::TaggedIsPropertyBox(GateRef obj)
1338 {
1339     auto env = GetEnvironment();
1340     Label entry(env);
1341     env->SubCfgEntry(&entry);
1342     Label exit(env);
1343     Label isHeapObject(env);
1344     DEFVARIABLE(result, VariableType::BOOL(), False());
1345     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
1346     Bind(&isHeapObject);
1347     {
1348         GateRef type = GetObjectType(LoadHClass(obj));
1349         result = Int32Equal(type, Int32(static_cast<int32_t>(JSType::PROPERTY_BOX)));
1350         Jump(&exit);
1351     }
1352     Bind(&exit);
1353     auto ret = *result;
1354     env->SubCfgExit();
1355     return ret;
1356 }
1357 
TaggedIsAccessor(GateRef x)1358 GateRef StubBuilder::TaggedIsAccessor(GateRef x)
1359 {
1360     auto env = GetEnvironment();
1361     Label entry(env);
1362     env->SubCfgEntry(&entry);
1363     Label exit(env);
1364     Label isHeapObject(env);
1365     DEFVARIABLE(result, VariableType::BOOL(), False());
1366     Branch(TaggedIsHeapObject(x), &isHeapObject, &exit);
1367     Bind(&isHeapObject);
1368     {
1369         GateRef type = GetObjectType(LoadHClass(x));
1370         result = BoolOr(Int32Equal(type, Int32(static_cast<int32_t>(JSType::ACCESSOR_DATA))),
1371                         Int32Equal(type, Int32(static_cast<int32_t>(JSType::INTERNAL_ACCESSOR))));
1372         Jump(&exit);
1373     }
1374     Bind(&exit);
1375     auto ret = *result;
1376     env->SubCfgExit();
1377     return ret;
1378 }
1379 
IsUtf16String(GateRef string)1380 GateRef StubBuilder::IsUtf16String(GateRef string)
1381 {
1382     // compressedStringsEnabled fixed to true constant
1383     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1384     return Int32Equal(
1385         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
1386         Int32(EcmaString::STRING_UNCOMPRESSED));
1387 }
1388 
IsUtf8String(GateRef string)1389 GateRef StubBuilder::IsUtf8String(GateRef string)
1390 {
1391     // compressedStringsEnabled fixed to true constant
1392     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1393     return Int32Equal(
1394         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
1395         Int32(EcmaString::STRING_COMPRESSED));
1396 }
1397 
IsInternalString(GateRef string)1398 GateRef StubBuilder::IsInternalString(GateRef string)
1399 {
1400     // compressedStringsEnabled fixed to true constant
1401     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
1402     return Int32NotEqual(
1403         Int32And(len, Int32(EcmaString::STRING_INTERN_BIT)),
1404         Int32(0));
1405 }
1406 
IsDigit(GateRef ch)1407 GateRef StubBuilder::IsDigit(GateRef ch)
1408 {
1409     return BoolAnd(Int32LessThanOrEqual(ch, Int32('9')),
1410         Int32GreaterThanOrEqual(ch, Int32('0')));
1411 }
1412 
TryToGetInteger(GateRef string,Variable * num,Label * success,Label * failed)1413 void StubBuilder::TryToGetInteger(GateRef string, Variable *num, Label *success, Label *failed)
1414 {
1415     auto env = GetEnvironment();
1416     Label exit(env);
1417     Label inRange(env);
1418     Label isInteger(env);
1419 
1420     GateRef len = GetLengthFromString(string);
1421     Branch(Int32LessThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &inRange, failed);
1422     Bind(&inRange);
1423     {
1424         Branch(IsIntegerString(string), &isInteger, failed);
1425         Bind(&isInteger);
1426         {
1427             GateRef integerNum = ZExtInt32ToInt64(GetRawHashFromString(string));
1428             num->WriteVariable(integerNum);
1429             Jump(success);
1430         }
1431     }
1432 }
1433 
StringToElementIndex(GateRef glue,GateRef string)1434 GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string)
1435 {
1436     auto env = GetEnvironment();
1437     Label entry(env);
1438     env->SubCfgEntry(&entry);
1439     Label exit(env);
1440     DEFVARIABLE(result, VariableType::INT64(), Int64(-1));
1441     Label greatThanZero(env);
1442     Label inRange(env);
1443     Label flattenFastPath(env);
1444     auto len = GetLengthFromString(string);
1445     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
1446     Bind(&greatThanZero);
1447     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
1448     Bind(&inRange);
1449     {
1450         Label isUtf8(env);
1451         GateRef isUtf16String = IsUtf16String(string);
1452         Branch(isUtf16String, &exit, &isUtf8);
1453         Bind(&isUtf8);
1454         {
1455             Label getFailed(env);
1456             TryToGetInteger(string, &result, &exit, &getFailed);
1457             Bind(&getFailed);
1458             DEFVARIABLE(c, VariableType::INT32(), Int32(0));
1459             FlatStringStubBuilder thisFlat(this);
1460             thisFlat.FlattenString(glue, string, &flattenFastPath);
1461             Bind(&flattenFastPath);
1462             StringInfoGateRef stringInfoGate(&thisFlat);
1463             GateRef dataUtf8 = GetNormalStringData(stringInfoGate);
1464             c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf8));
1465             Label isDigitZero(env);
1466             Label notDigitZero(env);
1467             Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
1468             Bind(&isDigitZero);
1469             {
1470                 Label lengthIsOne(env);
1471                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
1472                 Bind(&lengthIsOne);
1473                 {
1474                     result = Int64(0);
1475                     Jump(&exit);
1476                 }
1477             }
1478             Bind(&notDigitZero);
1479             {
1480                 Label isDigit(env);
1481                 DEFVARIABLE(i, VariableType::INT32(), Int32(1));
1482                 DEFVARIABLE(n, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(*c), Int64('0')));
1483                 Branch(IsDigit(*c), &isDigit, &exit);
1484                 Label loopHead(env);
1485                 Label loopEnd(env);
1486                 Label afterLoop(env);
1487                 Bind(&isDigit);
1488                 Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
1489                 LoopBegin(&loopHead);
1490                 {
1491                     c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf8, ZExtInt32ToPtr(*i)));
1492                     Label isDigit2(env);
1493                     Label notDigit2(env);
1494                     Branch(IsDigit(*c), &isDigit2, &notDigit2);
1495                     Bind(&isDigit2);
1496                     {
1497                         // 10 means the base of digit is 10.
1498                         n = Int64Add(Int64Mul(*n, Int64(10)), Int64Sub(ZExtInt32ToInt64(*c), Int64('0')));
1499                         i = Int32Add(*i, Int32(1));
1500                         Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
1501                     }
1502                     Bind(&notDigit2);
1503                     Jump(&exit);
1504                 }
1505                 Bind(&loopEnd);
1506                 LoopEnd(&loopHead);
1507                 Bind(&afterLoop);
1508                 {
1509                     Label lessThanMaxIndex(env);
1510                     Branch(Int64LessThan(*n, Int64(JSObject::MAX_ELEMENT_INDEX)),
1511                            &lessThanMaxIndex, &exit);
1512                     Bind(&lessThanMaxIndex);
1513                     {
1514                         result = *n;
1515                         Jump(&exit);
1516                     }
1517                 }
1518             }
1519         }
1520     }
1521     Bind(&exit);
1522     auto ret = *result;
1523     env->SubCfgExit();
1524     return ret;
1525 }
1526 
TryToElementsIndex(GateRef glue,GateRef key)1527 GateRef StubBuilder::TryToElementsIndex(GateRef glue, GateRef key)
1528 {
1529     auto env = GetEnvironment();
1530     Label entry(env);
1531     env->SubCfgEntry(&entry);
1532     Label exit(env);
1533     Label isKeyInt(env);
1534     Label notKeyInt(env);
1535 
1536     DEFVARIABLE(resultKey, VariableType::INT64(), Int64(-1));
1537     Branch(TaggedIsInt(key), &isKeyInt, &notKeyInt);
1538     Bind(&isKeyInt);
1539     {
1540         resultKey = GetInt64OfTInt(key);
1541         Jump(&exit);
1542     }
1543     Bind(&notKeyInt);
1544     {
1545         Label isString(env);
1546         Label notString(env);
1547         Branch(TaggedIsString(key), &isString, &notString);
1548         Bind(&isString);
1549         {
1550             resultKey = StringToElementIndex(glue, key);
1551             Jump(&exit);
1552         }
1553         Bind(&notString);
1554         {
1555             Label isDouble(env);
1556             Branch(TaggedIsDouble(key), &isDouble, &exit);
1557             Bind(&isDouble);
1558             {
1559                 GateRef number = GetDoubleOfTDouble(key);
1560                 GateRef integer = ChangeFloat64ToInt32(number);
1561                 Label isEqual(env);
1562                 Branch(DoubleEqual(number, ChangeInt32ToFloat64(integer)), &isEqual, &exit);
1563                 Bind(&isEqual);
1564                 {
1565                     resultKey = SExtInt32ToInt64(integer);
1566                     Jump(&exit);
1567                 }
1568             }
1569         }
1570     }
1571     Bind(&exit);
1572     auto ret = *resultKey;
1573     env->SubCfgExit();
1574     return ret;
1575 }
1576 
LdGlobalRecord(GateRef glue,GateRef key)1577 GateRef StubBuilder::LdGlobalRecord(GateRef glue, GateRef key)
1578 {
1579     auto env = GetEnvironment();
1580     Label entry(env);
1581     env->SubCfgEntry(&entry);
1582     Label exit(env);
1583 
1584     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1585     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1586     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1587     GateRef globalRecord = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::GLOBAL_RECORD);
1588     GateRef recordEntry = FindEntryFromNameDictionary(glue, globalRecord, key);
1589     Label foundInGlobalRecord(env);
1590     Branch(Int32NotEqual(recordEntry, Int32(-1)), &foundInGlobalRecord, &exit);
1591     Bind(&foundInGlobalRecord);
1592     {
1593         result = GetBoxFromGlobalDictionary(globalRecord, recordEntry);
1594         Jump(&exit);
1595     }
1596     Bind(&exit);
1597     auto ret = *result;
1598     env->SubCfgExit();
1599     return ret;
1600 }
1601 
LoadFromField(GateRef receiver,GateRef handlerInfo)1602 GateRef StubBuilder::LoadFromField(GateRef receiver, GateRef handlerInfo)
1603 {
1604     auto env = GetEnvironment();
1605     Label entry(env);
1606     env->SubCfgEntry(&entry);
1607     Label exit(env);
1608     Label handlerInfoIsInlinedProps(env);
1609     Label handlerInfoNotInlinedProps(env);
1610     Label handlerPost(env);
1611     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1612     GateRef index = HandlerBaseGetOffset(handlerInfo);
1613     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
1614     Bind(&handlerInfoIsInlinedProps);
1615     {
1616         result = Load(VariableType::JS_ANY(), receiver, PtrMul(ZExtInt32ToPtr(index),
1617             IntPtr(JSTaggedValue::TaggedTypeSize())));
1618         Jump(&handlerPost);
1619     }
1620     Bind(&handlerInfoNotInlinedProps);
1621     {
1622         result = GetValueFromTaggedArray(GetPropertiesArray(receiver), index);
1623         Jump(&handlerPost);
1624     }
1625     Bind(&handlerPost);
1626     {
1627         Label nonDoubleToTagged(env);
1628         Label doubleToTagged(env);
1629         GateRef rep = HandlerBaseGetRep(handlerInfo);
1630         Branch(IsDoubleRepInPropAttr(rep), &doubleToTagged, &nonDoubleToTagged);
1631         Bind(&doubleToTagged);
1632         {
1633             result = TaggedPtrToTaggedDoublePtr(*result);
1634             Jump(&exit);
1635         }
1636         Bind(&nonDoubleToTagged);
1637         {
1638             Label intToTagged(env);
1639             Branch(IsIntRepInPropAttr(rep), &intToTagged, &exit);
1640             Bind(&intToTagged);
1641             {
1642                 result = TaggedPtrToTaggedIntPtr(*result);
1643                 Jump(&exit);
1644             }
1645         }
1646     }
1647     Bind(&exit);
1648     auto ret = *result;
1649     env->SubCfgExit();
1650     return ret;
1651 }
1652 
LoadGlobal(GateRef cell)1653 GateRef StubBuilder::LoadGlobal(GateRef cell)
1654 {
1655     auto env = GetEnvironment();
1656     Label entry(env);
1657     env->SubCfgEntry(&entry);
1658     Label exit(env);
1659     Label cellIsInvalid(env);
1660     Label cellNotInvalid(env);
1661     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1662     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
1663     Bind(&cellIsInvalid);
1664     {
1665         Jump(&exit);
1666     }
1667     Bind(&cellNotInvalid);
1668     {
1669         result = GetValueFromPropertyBox(cell);
1670         Jump(&exit);
1671     }
1672     Bind(&exit);
1673     auto ret = *result;
1674     env->SubCfgExit();
1675     return ret;
1676 }
1677 
CheckPolyHClass(GateRef cachedValue,GateRef hclass)1678 GateRef StubBuilder::CheckPolyHClass(GateRef cachedValue, GateRef hclass)
1679 {
1680     auto env = GetEnvironment();
1681     Label entry(env);
1682     env->SubCfgEntry(&entry);
1683     Label exit(env);
1684     Label loopHead(env);
1685     Label loopEnd(env);
1686     Label iLessLength(env);
1687     Label hasHclass(env);
1688     Label cachedValueNotWeak(env);
1689     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1690     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1691     Branch(TaggedIsWeak(cachedValue), &exit, &cachedValueNotWeak);
1692     Bind(&cachedValueNotWeak);
1693     {
1694         GateRef length = GetLengthOfTaggedArray(cachedValue);
1695         Jump(&loopHead);
1696         LoopBegin(&loopHead);
1697         {
1698             Branch(Int32UnsignedLessThan(*i, length), &iLessLength, &exit);
1699             Bind(&iLessLength);
1700             {
1701                 GateRef element = GetValueFromTaggedArray(cachedValue, *i);
1702                 Branch(Equal(LoadObjectFromWeakRef(element), hclass), &hasHclass, &loopEnd);
1703                 Bind(&hasHclass);
1704                 result = GetValueFromTaggedArray(cachedValue,
1705                                                  Int32Add(*i, Int32(1)));
1706                 Jump(&exit);
1707             }
1708             Bind(&loopEnd);
1709             i = Int32Add(*i, Int32(2));  // 2 means one ic, two slot
1710             LoopEnd(&loopHead);
1711         }
1712     }
1713     Bind(&exit);
1714     auto ret = *result;
1715     env->SubCfgExit();
1716     return ret;
1717 }
1718 
LoadICWithHandler(GateRef glue,GateRef receiver,GateRef argHolder,GateRef argHandler,ProfileOperation callback)1719 GateRef StubBuilder::LoadICWithHandler(
1720     GateRef glue, GateRef receiver, GateRef argHolder, GateRef argHandler, ProfileOperation callback)
1721 {
1722     auto env = GetEnvironment();
1723     Label entry(env);
1724     env->SubCfgEntry(&entry);
1725     Label exit(env);
1726     Label handlerIsInt(env);
1727     Label handlerNotInt(env);
1728     Label handlerInfoIsField(env);
1729     Label handlerInfoNotField(env);
1730     Label handlerInfoIsNonExist(env);
1731     Label handlerInfoNotNonExist(env);
1732     Label handlerInfoIsString(env);
1733     Label handlerInfoNotString(env);
1734     Label handlerInfoIsStringLength(env);
1735     Label handlerInfoNotStringLength(env);
1736     Label handlerIsPrototypeHandler(env);
1737     Label handlerNotPrototypeHandler(env);
1738     Label cellHasChanged(env);
1739     Label loopHead(env);
1740     Label loopEnd(env);
1741     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
1742     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
1743     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
1744 
1745     Jump(&loopHead);
1746     LoopBegin(&loopHead);
1747     {
1748         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
1749         Bind(&handlerIsInt);
1750         {
1751             GateRef handlerInfo = GetInt32OfTInt(*handler);
1752             Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
1753             Bind(&handlerInfoIsField);
1754             {
1755                 Label receiverIsNumber(env);
1756                 Label receiverNotNumber(env);
1757                 Branch(TaggedIsNumber(receiver), &receiverIsNumber, &receiverNotNumber);
1758                 Bind(&receiverIsNumber);
1759                 {
1760                     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1761                     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1762                     auto numberProto = GetGlobalEnvValue(VariableType::JS_ANY(),
1763                         glueGlobalEnv, GlobalEnv::NUMBER_PROTOTYPE_INDEX);
1764                     result = LoadFromField(numberProto, handlerInfo);
1765                     Jump(&exit);
1766                 }
1767                 Bind(&receiverNotNumber);
1768                 {
1769                     result = LoadFromField(*holder, handlerInfo);
1770                     Jump(&exit);
1771                 }
1772             }
1773             Bind(&handlerInfoNotField);
1774             {
1775                 Branch(IsStringElement(handlerInfo), &handlerInfoIsString, &handlerInfoNotString);
1776                 Bind(&handlerInfoIsString);
1777                 {
1778                     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1779                     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1780                     auto stringProto = GetGlobalEnvValue(VariableType::JS_ANY(),
1781                         glueGlobalEnv, GlobalEnv::STRING_PROTOTYPE_INDEX);
1782                     result = LoadFromField(stringProto, handlerInfo);
1783                     Jump(&exit);
1784                 }
1785                 Bind(&handlerInfoNotString);
1786                 {
1787                     Branch(IsNonExist(handlerInfo), &handlerInfoIsNonExist, &handlerInfoNotNonExist);
1788                     Bind(&handlerInfoIsNonExist);
1789                     Jump(&exit);
1790                     Bind(&handlerInfoNotNonExist);
1791                     {
1792                         Branch(IsStringLength(handlerInfo), &handlerInfoIsStringLength, &handlerInfoNotStringLength);
1793                         Bind(&handlerInfoNotStringLength);
1794                         {
1795                             // string or number hasaccessor
1796                             Label holderIsString(env);
1797                             Label holderNotString(env);
1798                             Label holderIsNumber(env);
1799                             Label holderNotNumber(env);
1800                             Branch(TaggedIsString(*holder), &holderIsString, &holderNotString);
1801                             Bind(&holderIsString);
1802                             {
1803                                 GateRef glueGlobalEnvOffset =
1804                                     IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1805                                 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(),
1806                                     glue, glueGlobalEnvOffset);
1807                                 holder = GetGlobalEnvValue(VariableType::JS_ANY(),
1808                                     glueGlobalEnv, GlobalEnv::STRING_PROTOTYPE_INDEX);
1809                                 Jump(&exit);
1810                             }
1811                             Bind(&holderNotString);
1812                             Branch(TaggedIsNumber(*holder), &holderIsNumber, &holderNotNumber);
1813                             Bind(&holderIsNumber);
1814                             {
1815                                 GateRef glueGlobalEnvOffset =
1816                                     IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1817                                 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(),
1818                                     glue, glueGlobalEnvOffset);
1819                                 holder = GetGlobalEnvValue(VariableType::JS_ANY(),
1820                                     glueGlobalEnv, GlobalEnv::NUMBER_PROTOTYPE_INDEX);
1821                                 Jump(&exit);
1822                             }
1823                             Bind(&holderNotNumber);
1824                             GateRef accessor = LoadFromField(*holder, handlerInfo);
1825                             result = CallGetterHelper(glue, receiver, *holder, accessor, callback);
1826                             Jump(&exit);
1827                         }
1828                         Bind(&handlerInfoIsStringLength);
1829                         {
1830                             result = IntToTaggedPtr(GetLengthFromString(receiver));
1831                             Jump(&exit);
1832                         }
1833                     }
1834                 }
1835             }
1836         }
1837         Bind(&handlerNotInt);
1838         Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
1839         Bind(&handlerIsPrototypeHandler);
1840         {
1841             GateRef cellValue = GetProtoCell(*handler);
1842             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
1843             Bind(&cellHasChanged);
1844             {
1845                 result = Hole();
1846                 Jump(&exit);
1847             }
1848             Bind(&loopEnd);
1849             holder = GetPrototypeHandlerHolder(*handler);
1850             handler = GetPrototypeHandlerHandlerInfo(*handler);
1851             LoopEnd(&loopHead);
1852         }
1853     }
1854     Bind(&handlerNotPrototypeHandler);
1855     result = LoadGlobal(*handler);
1856     Jump(&exit);
1857 
1858     Bind(&exit);
1859     auto ret = *result;
1860     env->SubCfgExit();
1861     return ret;
1862 }
1863 
LoadElement(GateRef glue,GateRef receiver,GateRef key)1864 GateRef StubBuilder::LoadElement(GateRef glue, GateRef receiver, GateRef key)
1865 {
1866     auto env = GetEnvironment();
1867     Label entry(env);
1868     env->SubCfgEntry(&entry);
1869     Label exit(env);
1870     Label indexLessZero(env);
1871     Label indexNotLessZero(env);
1872     Label lengthLessIndex(env);
1873     Label lengthNotLessIndex(env);
1874     Label greaterThanInt32Max(env);
1875     Label notGreaterThanInt32Max(env);
1876     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1877     GateRef index64 = TryToElementsIndex(glue, key);
1878     Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
1879     Bind(&greaterThanInt32Max);
1880     {
1881         Jump(&exit);
1882     }
1883     Bind(&notGreaterThanInt32Max);
1884     GateRef index = TruncInt64ToInt32(index64);
1885     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1886     Bind(&indexLessZero);
1887     {
1888         Jump(&exit);
1889     }
1890     Bind(&indexNotLessZero);
1891     {
1892         GateRef elements = GetElementsArray(receiver);
1893         Branch(Int32LessThanOrEqual(GetLengthOfTaggedArray(elements), index), &lengthLessIndex, &lengthNotLessIndex);
1894         Bind(&lengthLessIndex);
1895         Jump(&exit);
1896         Bind(&lengthNotLessIndex);
1897         result = GetTaggedValueWithElementsKind(receiver, index);
1898         Jump(&exit);
1899     }
1900     Bind(&exit);
1901     auto ret = *result;
1902     env->SubCfgExit();
1903     return ret;
1904 }
1905 
LoadStringElement(GateRef glue,GateRef receiver,GateRef key)1906 GateRef StubBuilder::LoadStringElement(GateRef glue, GateRef receiver, GateRef key)
1907 {
1908     auto env = GetEnvironment();
1909     Label entry(env);
1910     env->SubCfgEntry(&entry);
1911     Label exit(env);
1912     Label indexLessZero(env);
1913     Label indexNotLessZero(env);
1914     Label lengthLessIndex(env);
1915     Label lengthNotLessIndex(env);
1916     Label greaterThanInt32Max(env);
1917     Label notGreaterThanInt32Max(env);
1918     Label flattenFastPath(env);
1919 
1920     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1921     GateRef index64 = TryToElementsIndex(glue, key);
1922     Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
1923     Bind(&greaterThanInt32Max);
1924     {
1925         Jump(&exit);
1926     }
1927     Bind(&notGreaterThanInt32Max);
1928     GateRef index = TruncInt64ToInt32(index64);
1929     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1930     Bind(&indexLessZero);
1931     {
1932         Jump(&exit);
1933     }
1934     Bind(&indexNotLessZero);
1935     {
1936         FlatStringStubBuilder thisFlat(this);
1937         thisFlat.FlattenString(glue, receiver, &flattenFastPath);
1938         Bind(&flattenFastPath);
1939         Branch(Int32LessThanOrEqual(GetLengthFromString(receiver), index), &lengthLessIndex, &lengthNotLessIndex);
1940         Bind(&lengthLessIndex);
1941         Jump(&exit);
1942         Bind(&lengthNotLessIndex);
1943         BuiltinsStringStubBuilder stringBuilder(this);
1944         StringInfoGateRef stringInfoGate(&thisFlat);
1945         result = stringBuilder.CreateFromEcmaString(glue, index, stringInfoGate);
1946         Jump(&exit);
1947     }
1948     Bind(&exit);
1949     auto ret = *result;
1950     env->SubCfgExit();
1951     return ret;
1952 }
1953 
ICStoreElement(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef handler)1954 GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef handler)
1955 {
1956     auto env = GetEnvironment();
1957     Label entry(env);
1958     env->SubCfgEntry(&entry);
1959     Label exit(env);
1960     Label indexLessZero(env);
1961     Label indexNotLessZero(env);
1962     Label handlerInfoIsTypedArray(env);
1963     Label handerInfoNotTypedArray(env);
1964     Label handerInfoIsJSArray(env);
1965     Label handerInfoNotJSArray(env);
1966     Label isJsCOWArray(env);
1967     Label isNotJsCOWArray(env);
1968     Label setElementsLength(env);
1969     Label indexGreaterLength(env);
1970     Label indexGreaterCapacity(env);
1971     Label callRuntime(env);
1972     Label storeElement(env);
1973     Label handlerIsInt(env);
1974     Label handlerNotInt(env);
1975     Label cellHasChanged(env);
1976     Label cellHasNotChanged(env);
1977     Label loopHead(env);
1978     Label loopEnd(env);
1979     Label greaterThanInt32Max(env);
1980     Label notGreaterThanInt32Max(env);
1981     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1982     DEFVARIABLE(varHandler, VariableType::JS_ANY(), handler);
1983     GateRef index64 = TryToElementsIndex(glue, key);
1984     Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
1985     Bind(&greaterThanInt32Max);
1986     {
1987         Jump(&exit);
1988     }
1989     Bind(&notGreaterThanInt32Max);
1990     GateRef index = TruncInt64ToInt32(index64);
1991     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
1992     Bind(&indexLessZero);
1993     {
1994         Jump(&exit);
1995     }
1996     Bind(&indexNotLessZero);
1997     {
1998         Jump(&loopHead);
1999         LoopBegin(&loopHead);
2000         Branch(TaggedIsInt(*varHandler), &handlerIsInt, &handlerNotInt);
2001         Bind(&handlerIsInt);
2002         {
2003             GateRef handlerInfo = GetInt32OfTInt(*varHandler);
2004             Branch(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArray, &handerInfoNotTypedArray);
2005             Bind(&handlerInfoIsTypedArray);
2006             {
2007                 GateRef hclass = LoadHClass(receiver);
2008                 GateRef jsType = GetObjectType(hclass);
2009                 TypedArrayStubBuilder typedArrayBuilder(this);
2010                 result = typedArrayBuilder.StoreTypedArrayElement(glue, receiver, index64, value, jsType);
2011                 Jump(&exit);
2012             }
2013             Bind(&handerInfoNotTypedArray);
2014             Branch(HandlerBaseIsJSArray(handlerInfo), &handerInfoIsJSArray, &handerInfoNotJSArray);
2015             Bind(&handerInfoIsJSArray);
2016             {
2017                 Branch(IsJsCOWArray(receiver), &isJsCOWArray, &isNotJsCOWArray);
2018                 Bind(&isJsCOWArray);
2019                 {
2020                     CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {receiver});
2021                     Jump(&setElementsLength);
2022                 }
2023                 Bind(&isNotJsCOWArray);
2024                 {
2025                     Jump(&setElementsLength);
2026                 }
2027                 Bind(&setElementsLength);
2028                 {
2029                     GateRef oldLength = GetArrayLength(receiver);
2030                     Branch(Int32GreaterThanOrEqual(index, oldLength), &indexGreaterLength, &handerInfoNotJSArray);
2031                     Bind(&indexGreaterLength);
2032                     Store(VariableType::INT32(), glue, receiver,
2033                         IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET),
2034                         Int32Add(index, Int32(1)));
2035                 }
2036                 Jump(&handerInfoNotJSArray);
2037             }
2038             Bind(&handerInfoNotJSArray);
2039             {
2040                 GateRef elements = GetElementsArray(receiver);
2041                 GateRef capacity = GetLengthOfTaggedArray(elements);
2042                 Branch(Int32GreaterThanOrEqual(index, capacity), &callRuntime, &storeElement);
2043                 Bind(&callRuntime);
2044                 {
2045                     result = CallRuntime(glue,
2046                         RTSTUB_ID(TaggedArraySetValue),
2047                         { receiver, value, elements, IntToTaggedInt(index),
2048                           IntToTaggedInt(capacity) });
2049                     Label transition(env);
2050                     Branch(TaggedIsHole(*result), &exit, &transition);
2051                     Bind(&transition);
2052                     {
2053                         Label hole(env);
2054                         Label notHole(env);
2055                         DEFVARIABLE(kind, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::NONE)));
2056                         Branch(Int32GreaterThan(index, capacity), &hole, &notHole);
2057                         Bind(&hole);
2058                         {
2059                             kind = Int32(static_cast<int32_t>(ElementsKind::HOLE));
2060                             Jump(&notHole);
2061                         }
2062                         Bind(&notHole);
2063                         {
2064                             SetValueWithElementsKind(glue, receiver, value, index, Boolean(true), *kind);
2065                             Jump(&exit);
2066                         }
2067                     }
2068                 }
2069                 Bind(&storeElement);
2070                 {
2071                     SetValueWithElementsKind(glue, receiver, value, index, Boolean(true),
2072                                              Int32(static_cast<int32_t>(ElementsKind::NONE)));
2073                     result = Undefined();
2074                     Jump(&exit);
2075                 }
2076             }
2077         }
2078         Bind(&handlerNotInt);
2079         {
2080             GateRef cellValue = GetProtoCell(*varHandler);
2081             Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
2082             Bind(&cellHasChanged);
2083             {
2084                 Jump(&exit);
2085             }
2086             Bind(&loopEnd);
2087             {
2088                 varHandler = GetPrototypeHandlerHandlerInfo(*varHandler);
2089                 LoopEnd(&loopHead);
2090             }
2091         }
2092     }
2093     Bind(&exit);
2094     auto ret = *result;
2095     env->SubCfgExit();
2096     return ret;
2097 }
2098 
GetArrayLength(GateRef object)2099 GateRef StubBuilder::GetArrayLength(GateRef object)
2100 {
2101     GateRef lengthOffset = IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET);
2102     GateRef result = Load(VariableType::INT32(), object, lengthOffset);
2103     return result;
2104 }
2105 
SetArrayLength(GateRef glue,GateRef object,GateRef len)2106 void StubBuilder::SetArrayLength(GateRef glue, GateRef object, GateRef len)
2107 {
2108     GateRef lengthOffset = IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET);
2109     Store(VariableType::INT32(), glue, object, lengthOffset, len);
2110 }
2111 
StoreICWithHandler(GateRef glue,GateRef receiver,GateRef argHolder,GateRef value,GateRef argHandler,ProfileOperation callback)2112 GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder,
2113                                         GateRef value, GateRef argHandler, ProfileOperation callback)
2114 {
2115     auto env = GetEnvironment();
2116     Label entry(env);
2117     env->SubCfgEntry(&entry);
2118     Label exit(env);
2119     Label handlerIsInt(env);
2120     Label handlerNotInt(env);
2121     Label handlerInfoIsField(env);
2122     Label handlerInfoNotField(env);
2123     Label isShared(env);
2124     Label notShared(env);
2125     Label prepareIntHandlerLoop(env);
2126     Label handlerIsTransitionHandler(env);
2127     Label handlerNotTransitionHandler(env);
2128     Label handlerIsTransWithProtoHandler(env);
2129     Label handlerNotTransWithProtoHandler(env);
2130     Label handlerIsPrototypeHandler(env);
2131     Label handlerNotPrototypeHandler(env);
2132     Label handlerIsPropertyBox(env);
2133     Label handlerNotPropertyBox(env);
2134     Label handlerIsStoreTSHandler(env);
2135     Label handlerNotStoreTSHandler(env);
2136     Label aotHandlerInfoIsField(env);
2137     Label aotHandlerInfoNotField(env);
2138     Label cellHasChanged(env);
2139     Label cellNotChanged(env);
2140     Label aotCellNotChanged(env);
2141     Label loopHead(env);
2142     Label loopEnd(env);
2143     Label JumpLoopHead(env);
2144     Label cellNotNull(env);
2145     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2146     DEFVARIABLE(holder, VariableType::JS_ANY(), argHolder);
2147     DEFVARIABLE(handler, VariableType::JS_ANY(), argHandler);
2148     Jump(&loopHead);
2149     LoopBegin(&loopHead);
2150     {
2151         Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt);
2152         Bind(&handlerIsInt);
2153         {
2154             GateRef handlerInfo = GetInt32OfTInt(*handler);
2155             Branch(IsNonSharedStoreField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField);
2156             Bind(&handlerInfoIsField);
2157             {
2158                 result = StoreField(glue, receiver, value, handlerInfo, callback);
2159                 Jump(&exit);
2160             }
2161             Bind(&handlerInfoNotField);
2162             {
2163                 Branch(IsStoreShared(handlerInfo), &isShared, &notShared);
2164                 Bind(&isShared);
2165                 {
2166                     GateRef trackType = GetTrackTypeFromHandler(handlerInfo);
2167                     MatchTrackType(&result, glue, trackType, value, &prepareIntHandlerLoop, &exit);
2168                     Bind(&prepareIntHandlerLoop);
2169                     {
2170                         handler = IntToTaggedPtr(ClearSharedStoreKind(handlerInfo));
2171                         Jump(&JumpLoopHead);
2172                     }
2173                 }
2174                 Bind(&notShared);
2175                 GateRef accessor = LoadFromField(*holder, handlerInfo);
2176                 result = CallSetterHelper(glue, receiver, accessor, value, callback);
2177                 Jump(&exit);
2178             }
2179         }
2180         Bind(&handlerNotInt);
2181         {
2182             Branch(TaggedIsTransitionHandler(*handler), &handlerIsTransitionHandler, &handlerNotTransitionHandler);
2183             Bind(&handlerIsTransitionHandler);
2184             {
2185                 result = StoreWithTransition(glue, receiver, value, *handler, callback);
2186                 Jump(&exit);
2187             }
2188             Bind(&handlerNotTransitionHandler);
2189             {
2190                 Branch(TaggedIsTransWithProtoHandler(*handler), &handlerIsTransWithProtoHandler,
2191                     &handlerNotTransWithProtoHandler);
2192                 Bind(&handlerIsTransWithProtoHandler);
2193                 {
2194                     GateRef cellValue = GetProtoCell(*handler);
2195                     Branch(GetHasChanged(cellValue), &cellHasChanged, &cellNotChanged);
2196                     Bind(&cellNotChanged);
2197                     {
2198                         result = StoreWithTransition(glue, receiver, value, *handler, callback, true);
2199                         Jump(&exit);
2200                     }
2201                 }
2202                 Bind(&handlerNotTransWithProtoHandler);
2203                 {
2204                     Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler);
2205                     Bind(&handlerNotPrototypeHandler);
2206                     {
2207                         Branch(TaggedIsPropertyBox(*handler), &handlerIsPropertyBox, &handlerNotPropertyBox);
2208                         Bind(&handlerIsPropertyBox);
2209                         StoreGlobal(glue, value, *handler);
2210                         Jump(&exit);
2211                     }
2212                 }
2213             }
2214         }
2215         Bind(&handlerIsPrototypeHandler);
2216         {
2217             GateRef cellValue = GetProtoCell(*handler);
2218             Branch(TaggedIsNull(cellValue), &cellHasChanged, &cellNotNull);
2219             Bind(&cellNotNull);
2220             {
2221                 Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd);
2222             }
2223             Bind(&loopEnd);
2224             {
2225                 holder = GetPrototypeHandlerHolder(*handler);
2226                 handler = GetPrototypeHandlerHandlerInfo(*handler);
2227                 Jump(&JumpLoopHead);
2228             }
2229         }
2230         Bind(&handlerNotPropertyBox);
2231         {
2232             Branch(TaggedIsStoreTSHandler(*handler), &handlerIsStoreTSHandler, &handlerNotStoreTSHandler);
2233             Bind(&handlerIsStoreTSHandler);
2234             {
2235                 GateRef cellValue = GetProtoCell(*handler);
2236                 Branch(GetHasChanged(cellValue), &cellHasChanged, &aotCellNotChanged);
2237                 Bind(&aotCellNotChanged);
2238                 {
2239                     holder = GetStoreTSHandlerHolder(*handler);
2240                     handler = GetStoreTSHandlerHandlerInfo(*handler);
2241                     GateRef handlerInfo = GetInt32OfTInt(*handler);
2242                     Branch(IsField(handlerInfo), &aotHandlerInfoIsField, &aotHandlerInfoNotField);
2243                     Bind(&aotHandlerInfoIsField);
2244                     {
2245                         result = StoreField(glue, receiver, value, handlerInfo, callback);
2246                         Jump(&exit);
2247                     }
2248                     Bind(&aotHandlerInfoNotField);
2249                     {
2250                         GateRef accessor = LoadFromField(*holder, handlerInfo);
2251                         result = CallSetterHelper(glue, receiver, accessor, value, callback);
2252                         Jump(&exit);
2253                     }
2254                 }
2255             }
2256             Bind(&handlerNotStoreTSHandler);
2257             Jump(&exit);
2258         }
2259         Bind(&cellHasChanged);
2260         {
2261             result = Hole();
2262             Jump(&exit);
2263         }
2264         Bind(&JumpLoopHead);
2265         {
2266             LoopEnd(&loopHead);
2267         }
2268     }
2269     Bind(&exit);
2270     auto ret = *result;
2271     env->SubCfgExit();
2272     return ret;
2273 }
2274 
StoreField(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback)2275 GateRef StubBuilder::StoreField(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
2276     ProfileOperation callback)
2277 {
2278     auto env = GetEnvironment();
2279     Label entry(env);
2280     env->SubCfgEntry(&entry);
2281     ProfilerStubBuilder(env).UpdatePropAttrIC(glue, receiver, value, handler, callback);
2282     Label exit(env);
2283     Label handlerIsInlinedProperty(env);
2284     Label handlerNotInlinedProperty(env);
2285     GateRef index = HandlerBaseGetOffset(handler);
2286     GateRef rep = HandlerBaseGetRep(handler);
2287     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2288     Label repChange(env);
2289     Branch(HandlerBaseIsInlinedProperty(handler), &handlerIsInlinedProperty, &handlerNotInlinedProperty);
2290     Bind(&handlerIsInlinedProperty);
2291     {
2292         GateRef toOffset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
2293         SetValueWithRep(glue, receiver, toOffset, value, rep, &repChange);
2294         Jump(&exit);
2295     }
2296     Bind(&handlerNotInlinedProperty);
2297     {
2298         GateRef array = GetPropertiesArray(receiver);
2299         SetValueToTaggedArrayWithRep(glue, array, index, value, rep, &repChange);
2300         Jump(&exit);
2301     }
2302     Bind(&repChange);
2303     {
2304         result = Hole();
2305         Jump(&exit);
2306     }
2307 
2308     Bind(&exit);
2309     auto ret = *result;
2310     env->SubCfgExit();
2311     return ret;
2312 }
2313 
StoreWithTransition(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback,bool withPrototype)2314 GateRef StubBuilder::StoreWithTransition(GateRef glue, GateRef receiver, GateRef value, GateRef handler,
2315                                          ProfileOperation callback, bool withPrototype)
2316 {
2317     auto env = GetEnvironment();
2318     Label entry(env);
2319     env->SubCfgEntry(&entry);
2320     Label exit(env);
2321 
2322     Label handlerInfoIsInlinedProps(env);
2323     Label handlerInfoNotInlinedProps(env);
2324     Label indexMoreCapacity(env);
2325     Label indexLessCapacity(env);
2326     Label capacityIsZero(env);
2327     Label capacityNotZero(env);
2328     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2329     GateRef newHClass;
2330     GateRef handlerInfo;
2331     if (withPrototype) {
2332         newHClass = GetTransWithProtoHClass(handler);
2333         handlerInfo = GetInt32OfTInt(GetTransWithProtoHandlerInfo(handler));
2334     } else {
2335         newHClass = GetTransitionHClass(handler);
2336         handlerInfo = GetInt32OfTInt(GetTransitionHandlerInfo(handler));
2337     }
2338 
2339     GateRef oldHClass = LoadHClass(receiver);
2340     GateRef prototype = GetPrototypeFromHClass(oldHClass);
2341     StorePrototype(glue, newHClass, prototype);
2342     StoreHClass(glue, receiver, newHClass);
2343     // Because we currently only supports Fast ElementsKind
2344     CallRuntime(glue, RTSTUB_ID(TryRestoreElementsKind), { receiver, newHClass });
2345     Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps);
2346     Bind(&handlerInfoNotInlinedProps);
2347     {
2348         ProfilerStubBuilder(env).UpdatePropAttrIC(glue, receiver, value, handlerInfo, callback);
2349         Label repChange(env);
2350         GateRef array = GetPropertiesArray(receiver);
2351         GateRef capacity = GetLengthOfTaggedArray(array);
2352         GateRef index = HandlerBaseGetOffset(handlerInfo);
2353         Branch(Int32GreaterThanOrEqual(index, capacity), &indexMoreCapacity, &indexLessCapacity);
2354         Bind(&indexMoreCapacity);
2355         {
2356             NewObjectStubBuilder newBuilder(this);
2357             Branch(Int32Equal(capacity, Int32(0)), &capacityIsZero, &capacityNotZero);
2358             Bind(&capacityIsZero);
2359             {
2360                 GateRef properties = newBuilder.NewTaggedArray(glue, Int32(JSObject::MIN_PROPERTIES_LENGTH));
2361                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, properties, index, value);
2362                 SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, properties);
2363                 Jump(&exit);
2364             }
2365             Bind(&capacityNotZero);
2366             {
2367                 GateRef inlinedProperties = GetInlinedPropertiesFromHClass(newHClass);
2368                 GateRef maxNonInlinedFastPropsCapacity =
2369                                 Int32Sub(Int32(PropertyAttributes::MAX_FAST_PROPS_CAPACITY), inlinedProperties);
2370                 GateRef newLen = ComputeNonInlinedFastPropsCapacity(glue, capacity, maxNonInlinedFastPropsCapacity);
2371                 GateRef properties = newBuilder.CopyArray(glue, array, capacity, newLen);
2372                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, properties, index, value);
2373                 SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, properties);
2374                 Jump(&exit);
2375             }
2376         }
2377         Bind(&indexLessCapacity);
2378         {
2379             GateRef rep = HandlerBaseGetRep(handlerInfo);
2380             GateRef base = PtrAdd(array, IntPtr(TaggedArray::DATA_OFFSET));
2381             GateRef toIndex = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
2382             SetValueWithRep(glue, base, toIndex, value, rep, &repChange);
2383             Jump(&exit);
2384         }
2385         Bind(&repChange);
2386         {
2387             result = Hole();
2388             Jump(&exit);
2389         }
2390     }
2391     Bind(&handlerInfoIsInlinedProps);
2392     {
2393         result = StoreField(glue, receiver, value, handlerInfo, callback);
2394         Jump(&exit);
2395     }
2396     Bind(&exit);
2397     auto ret = *result;
2398     env->SubCfgExit();
2399     return ret;
2400 }
2401 
StoreGlobal(GateRef glue,GateRef value,GateRef cell)2402 GateRef StubBuilder::StoreGlobal(GateRef glue, GateRef value, GateRef cell)
2403 {
2404     auto env = GetEnvironment();
2405     Label entry(env);
2406     env->SubCfgEntry(&entry);
2407     Label exit(env);
2408     Label cellIsInvalid(env);
2409     Label cellNotInvalid(env);
2410     Label cellIsAccessorData(env);
2411     Label cellIsNotAccessorData(env);
2412     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2413     Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid);
2414     Bind(&cellIsInvalid);
2415     {
2416         Jump(&exit);
2417     }
2418     Bind(&cellNotInvalid);
2419     Branch(IsAccessorPropertyBox(cell), &cellIsAccessorData, &cellIsNotAccessorData);
2420     Bind(&cellIsAccessorData);
2421     {
2422         Jump(&exit);
2423     }
2424     Bind(&cellIsNotAccessorData);
2425     {
2426         Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value);
2427         result = Undefined();
2428         Jump(&exit);
2429     }
2430     Bind(&exit);
2431     auto ret = *result;
2432     env->SubCfgExit();
2433     return ret;
2434 }
2435 
2436 template<typename DictionaryT>
GetAttributesFromDictionary(GateRef elements,GateRef entry)2437 GateRef StubBuilder::GetAttributesFromDictionary(GateRef elements, GateRef entry)
2438 {
2439     GateRef arrayIndex =
2440     Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2441              Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2442     GateRef attributesIndex =
2443         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_DETAILS_INDEX));
2444     auto attrValue = GetValueFromTaggedArray(elements, attributesIndex);
2445     return GetInt32OfTInt(attrValue);
2446 }
2447 
2448 template<typename DictionaryT>
GetValueFromDictionary(GateRef elements,GateRef entry)2449 GateRef StubBuilder::GetValueFromDictionary(GateRef elements, GateRef entry)
2450 {
2451     GateRef arrayIndex =
2452         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2453                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2454     GateRef valueIndex =
2455         Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_VALUE_INDEX));
2456     return GetValueFromTaggedArray(elements, valueIndex);
2457 }
2458 
2459 template<typename DictionaryT>
GetKeyFromDictionary(GateRef elements,GateRef entry)2460 GateRef StubBuilder::GetKeyFromDictionary(GateRef elements, GateRef entry)
2461 {
2462     auto env = GetEnvironment();
2463     Label subentry(env);
2464     env->SubCfgEntry(&subentry);
2465     Label exit(env);
2466     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
2467     Label ltZero(env);
2468     Label notLtZero(env);
2469     Label gtLength(env);
2470     Label notGtLength(env);
2471     GateRef dictionaryLength =
2472         Load(VariableType::INT32(), elements, IntPtr(TaggedArray::LENGTH_OFFSET));
2473     GateRef arrayIndex =
2474         Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2475                  Int32Mul(entry, Int32(DictionaryT::ENTRY_SIZE)));
2476     Branch(Int32LessThan(arrayIndex, Int32(0)), &ltZero, &notLtZero);
2477     Bind(&ltZero);
2478     Jump(&exit);
2479     Bind(&notLtZero);
2480     Branch(Int32GreaterThan(arrayIndex, dictionaryLength), &gtLength, &notGtLength);
2481     Bind(&gtLength);
2482     Jump(&exit);
2483     Bind(&notGtLength);
2484     result = GetValueFromTaggedArray(elements, arrayIndex);
2485     Jump(&exit);
2486     Bind(&exit);
2487     auto ret = *result;
2488     env->SubCfgExit();
2489     return ret;
2490 }
2491 
UpdateValueAndAttributes(GateRef glue,GateRef elements,GateRef index,GateRef value,GateRef attr)2492 inline void StubBuilder::UpdateValueAndAttributes(GateRef glue, GateRef elements, GateRef index,
2493                                                   GateRef value, GateRef attr)
2494 {
2495     GateRef arrayIndex =
2496         Int32Add(Int32(NameDictionary::TABLE_HEADER_SIZE),
2497                  Int32Mul(index, Int32(NameDictionary::ENTRY_SIZE)));
2498     GateRef valueIndex =
2499         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_VALUE_INDEX));
2500     GateRef attributesIndex =
2501         Int32Add(arrayIndex, Int32(NameDictionary::ENTRY_DETAILS_INDEX));
2502     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
2503     GateRef attroffset =
2504         PtrMul(ZExtInt32ToPtr(attributesIndex), IntPtr(JSTaggedValue::TaggedTypeSize()));
2505     GateRef dataOffset = PtrAdd(attroffset, IntPtr(TaggedArray::DATA_OFFSET));
2506     Store(VariableType::INT64(), glue, elements, dataOffset, IntToTaggedInt(attr));
2507 }
2508 
2509 template<typename DictionaryT>
UpdateValueInDict(GateRef glue,GateRef elements,GateRef index,GateRef value)2510 inline void StubBuilder::UpdateValueInDict(GateRef glue, GateRef elements, GateRef index, GateRef value)
2511 {
2512     GateRef arrayIndex = Int32Add(Int32(DictionaryT::TABLE_HEADER_SIZE),
2513         Int32Mul(index, Int32(DictionaryT::ENTRY_SIZE)));
2514     GateRef valueIndex = Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_VALUE_INDEX));
2515     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, valueIndex, value);
2516 }
2517 
GetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,ProfileOperation callback)2518 GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, ProfileOperation callback)
2519 {
2520     auto env = GetEnvironment();
2521     Label entry(env);
2522     env->SubCfgEntry(&entry);
2523     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2524     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2525     Label exit(env);
2526     Label loopHead(env);
2527     Label loopEnd(env);
2528     Label loopExit(env);
2529     Label afterLoop(env);
2530     Jump(&loopHead);
2531     LoopBegin(&loopHead);
2532     {
2533         GateRef hclass = LoadHClass(*holder);
2534         GateRef jsType = GetObjectType(hclass);
2535         Label isSpecialIndexed(env);
2536         Label notSpecialIndexed(env);
2537         Branch(IsSpecialIndexedObj(jsType), &isSpecialIndexed, &notSpecialIndexed);
2538         Bind(&isSpecialIndexed);
2539         {
2540             // TypeArray
2541             Label isFastTypeArray(env);
2542             Label notFastTypeArray(env);
2543             Label notTypedArrayProto(env);
2544             Branch(Int32Equal(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY))), &exit, &notTypedArrayProto);
2545             Bind(&notTypedArrayProto);
2546             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2547             Bind(&isFastTypeArray);
2548             {
2549                 TypedArrayStubBuilder typedArrayStubBuilder(this);
2550                 result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, *holder, index, jsType);
2551                 Jump(&exit);
2552             }
2553             Bind(&notFastTypeArray);
2554 
2555             Label isSpecialContainer(env);
2556             Label notSpecialContainer(env);
2557             // Add SpecialContainer
2558             Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
2559             Bind(&isSpecialContainer);
2560             {
2561                 result = GetContainerProperty(glue, *holder, index, jsType);
2562                 Jump(&exit);
2563             }
2564             Bind(&notSpecialContainer);
2565             {
2566                 result = Hole();
2567                 Jump(&exit);
2568             }
2569         }
2570         Bind(&notSpecialIndexed);
2571         {
2572             GateRef elements = GetElementsArray(*holder);
2573             Label isDictionaryElement(env);
2574             Label notDictionaryElement(env);
2575             Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
2576             Bind(&notDictionaryElement);
2577             {
2578                 Label lessThanLength(env);
2579                 Label notLessThanLength(env);
2580                 Branch(Int32UnsignedLessThan(index, GetLengthOfTaggedArray(elements)),
2581                        &lessThanLength, &notLessThanLength);
2582                 Bind(&lessThanLength);
2583                 {
2584                     DEFVARIABLE(value, VariableType::JS_ANY(), Hole());
2585                     Label notHole(env);
2586                     Label isHole(env);
2587                     value = GetTaggedValueWithElementsKind(*holder, index);
2588                     Branch(TaggedIsNotHole(*value), &notHole, &isHole);
2589                     Bind(&notHole);
2590                     {
2591                         result = *value;
2592                         Jump(&exit);
2593                     }
2594                     Bind(&isHole);
2595                     {
2596                         Jump(&loopExit);
2597                     }
2598                 }
2599                 Bind(&notLessThanLength);
2600                 {
2601                     Jump(&loopExit);
2602                 }
2603             }
2604             Bind(&isDictionaryElement);
2605             {
2606                 GateRef entryA = FindElementFromNumberDictionary(glue, elements, index);
2607                 Label notNegtiveOne(env);
2608                 Label negtiveOne(env);
2609                 Branch(Int32NotEqual(entryA, Int32(-1)), &notNegtiveOne, &negtiveOne);
2610                 Bind(&notNegtiveOne);
2611                 {
2612                     GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, entryA);
2613                     GateRef value = GetValueFromDictionary<NumberDictionary>(elements, entryA);
2614                     Label isAccessor(env);
2615                     Label notAccessor(env);
2616                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2617                     Bind(&isAccessor);
2618                     {
2619                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2620                         Jump(&exit);
2621                     }
2622                     Bind(&notAccessor);
2623                     {
2624                         result = value;
2625                         Jump(&exit);
2626                     }
2627                 }
2628                 Bind(&negtiveOne);
2629                 Jump(&loopExit);
2630             }
2631             Bind(&loopExit);
2632             {
2633                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2634                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2635             }
2636         }
2637         Bind(&loopEnd);
2638         LoopEnd(&loopHead);
2639         Bind(&afterLoop);
2640         {
2641             result = Undefined();
2642             Jump(&exit);
2643         }
2644     }
2645     Bind(&exit);
2646     auto ret = *result;
2647     env->SubCfgExit();
2648     return ret;
2649 }
2650 
GetPropertyByValue(GateRef glue,GateRef receiver,GateRef keyValue,ProfileOperation callback)2651 GateRef StubBuilder::GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue, ProfileOperation callback)
2652 {
2653     auto env = GetEnvironment();
2654     Label entry(env);
2655     env->SubCfgEntry(&entry);
2656     DEFVARIABLE(key, VariableType::JS_ANY(), keyValue);
2657     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2658     DEFVARIABLE(isInternal, VariableType::BOOL(), True());
2659     Label isNumberOrStringSymbol(env);
2660     Label notNumber(env);
2661     Label isStringOrSymbol(env);
2662     Label notStringOrSymbol(env);
2663     Label exit(env);
2664 
2665     Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, &notNumber);
2666     Bind(&notNumber);
2667     {
2668         Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, &notStringOrSymbol);
2669         Bind(&notStringOrSymbol);
2670         {
2671             result = Hole();
2672             Jump(&exit);
2673         }
2674     }
2675     Bind(&isNumberOrStringSymbol);
2676     {
2677         GateRef index64 = TryToElementsIndex(glue, *key);
2678         Label validIndex(env);
2679         Label notValidIndex(env);
2680         Label greaterThanInt32Max(env);
2681         Label notGreaterThanInt32Max(env);
2682         Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
2683         Bind(&greaterThanInt32Max);
2684         {
2685             Jump(&exit);
2686         }
2687         Bind(&notGreaterThanInt32Max);
2688         GateRef index = TruncInt64ToInt32(index64);
2689         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
2690         Bind(&validIndex);
2691         {
2692             result = GetPropertyByIndex(glue, receiver, index, callback);
2693             Jump(&exit);
2694         }
2695         Bind(&notValidIndex);
2696         {
2697             Label notNumber1(env);
2698             Label getByName(env);
2699             Branch(TaggedIsNumber(*key), &exit, &notNumber1);
2700             Bind(&notNumber1);
2701             {
2702                 Label isString(env);
2703                 Label notString(env);
2704                 Label isInternalString(env);
2705                 Label notIntenalString(env);
2706                 Branch(TaggedIsString(*key), &isString, &notString);
2707                 Bind(&isString);
2708                 {
2709                     Branch(IsInternalString(*key), &isInternalString, &notIntenalString);
2710                     Bind(&isInternalString);
2711                     Jump(&getByName);
2712                     Bind(&notIntenalString);
2713                     {
2714                         Label notFind(env);
2715                         Label find(env);
2716                         // if key can't find in stringtabele, key is not propertyname for a object
2717                         GateRef res = CallNGCRuntime(glue, RTSTUB_ID(TryGetInternString), { glue, *key });
2718                         Branch(TaggedIsHole(res), &notFind, &find);
2719                         Bind(&notFind);
2720                         {
2721                             isInternal = False();
2722                             Jump(&getByName);
2723                         }
2724                         Bind(&find);
2725                         {
2726                             key = res;
2727                             Jump(&getByName);
2728                         }
2729                     }
2730                 }
2731                 Bind(&notString);
2732                 {
2733                     Jump(&getByName);
2734                 }
2735             }
2736             Bind(&getByName);
2737             {
2738                 result = GetPropertyByName(glue, receiver, *key, callback, *isInternal, true);
2739                 Jump(&exit);
2740             }
2741         }
2742     }
2743     Bind(&exit);
2744     auto ret = *result;
2745     env->SubCfgExit();
2746     return ret;
2747 }
2748 
GetPropertyByName(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback,GateRef isInternal,bool canUseIsInternal)2749 GateRef StubBuilder::GetPropertyByName(GateRef glue, GateRef receiver, GateRef key,
2750                                        ProfileOperation callback, GateRef isInternal, bool canUseIsInternal)
2751 {
2752     auto env = GetEnvironment();
2753     Label entry(env);
2754     env->SubCfgEntry(&entry);
2755     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
2756     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
2757     Label exit(env);
2758     Label loopHead(env);
2759     Label loopEnd(env);
2760     Label loopExit(env);
2761     Label afterLoop(env);
2762     Label findProperty(env);
2763     Jump(&loopHead);
2764     LoopBegin(&loopHead);
2765     {
2766         GateRef hclass = LoadHClass(*holder);
2767         GateRef jsType = GetObjectType(hclass);
2768         Label isSIndexObj(env);
2769         Label notSIndexObj(env);
2770         Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
2771         Bind(&isSIndexObj);
2772         {
2773             // TypeArray
2774             Label isFastTypeArray(env);
2775             Label notFastTypeArray(env);
2776             Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
2777             Bind(&isFastTypeArray);
2778             {
2779                 result = GetTypeArrayPropertyByName(glue, receiver, *holder, key, jsType);
2780                 Label isNull(env);
2781                 Label notNull(env);
2782                 Branch(TaggedIsNull(*result), &isNull, &notNull);
2783                 Bind(&isNull);
2784                 {
2785                     result = Hole();
2786                     Jump(&exit);
2787                 }
2788                 Bind(&notNull);
2789                 Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
2790             }
2791             Bind(&notFastTypeArray);
2792             {
2793                 result = Hole();
2794                 Jump(&exit);
2795             }
2796         }
2797         Bind(&notSIndexObj);
2798         {
2799             if (canUseIsInternal) {
2800                 Branch(isInternal, &findProperty, &loopExit);
2801             } else {
2802                 Jump(&findProperty);
2803             }
2804             Label isDicMode(env);
2805             Label notDicMode(env);
2806             Bind(&findProperty);
2807             Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
2808             Bind(&notDicMode);
2809             {
2810                 GateRef layOutInfo = GetLayoutFromHClass(hclass);
2811                 GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
2812                 // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
2813                 GateRef entryA = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
2814                 Label hasEntry(env);
2815                 Label noEntry(env);
2816                 // if branch condition : entry != -1
2817                 Branch(Int32NotEqual(entryA, Int32(-1)), &hasEntry, &noEntry);
2818                 Bind(&hasEntry);
2819                 {
2820                     // PropertyAttributes attr(layoutInfo->GetAttr(entry))
2821                     GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entryA);
2822                     GateRef attr = GetInt32OfTInt(propAttr);
2823                     GateRef value = JSObjectGetProperty(*holder, hclass, attr);
2824                     Label isAccessor(env);
2825                     Label notAccessor(env);
2826                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
2827                     Bind(&isAccessor);
2828                     {
2829                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2830                         Jump(&exit);
2831                     }
2832                     Bind(&notAccessor);
2833                     {
2834                         Label notHole(env);
2835                         Branch(TaggedIsHole(value), &noEntry, &notHole);
2836                         Bind(&notHole);
2837                         {
2838                             result = value;
2839                             Jump(&exit);
2840                         }
2841                     }
2842                 }
2843                 Bind(&noEntry);
2844                 {
2845                     Jump(&loopExit);
2846                 }
2847             }
2848             Bind(&isDicMode);
2849             {
2850                 GateRef array = GetPropertiesArray(*holder);
2851                 // int entry = dict->FindEntry(key)
2852                 GateRef entryB = FindEntryFromNameDictionary(glue, array, key);
2853                 Label notNegtiveOne(env);
2854                 Label negtiveOne(env);
2855                 // if branch condition : entry != -1
2856                 Branch(Int32NotEqual(entryB, Int32(-1)), &notNegtiveOne, &negtiveOne);
2857                 Bind(&notNegtiveOne);
2858                 {
2859                     // auto value = dict->GetValue(entry)
2860                     GateRef attr = GetAttributesFromDictionary<NameDictionary>(array, entryB);
2861                     // auto attr = dict->GetAttributes(entry)
2862                     GateRef value = GetValueFromDictionary<NameDictionary>(array, entryB);
2863                     Label isAccessor1(env);
2864                     Label notAccessor1(env);
2865                     Branch(IsAccessor(attr), &isAccessor1, &notAccessor1);
2866                     Bind(&isAccessor1);
2867                     {
2868                         result = CallGetterHelper(glue, receiver, *holder, value, callback);
2869                         Jump(&exit);
2870                     }
2871                     Bind(&notAccessor1);
2872                     {
2873                         result = value;
2874                         Jump(&exit);
2875                     }
2876                 }
2877                 Bind(&negtiveOne);
2878                 Jump(&loopExit);
2879             }
2880             Bind(&loopExit);
2881             {
2882                 holder = GetPrototypeFromHClass(LoadHClass(*holder));
2883                 Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
2884             }
2885         }
2886         Bind(&loopEnd);
2887         LoopEnd(&loopHead);
2888         Bind(&afterLoop);
2889         {
2890             result = Undefined();
2891             Jump(&exit);
2892         }
2893     }
2894     Bind(&exit);
2895     auto ret = *result;
2896     env->SubCfgExit();
2897     return ret;
2898 }
2899 
CopyAllHClass(GateRef glue,GateRef dstHClass,GateRef srcHClass)2900 void StubBuilder::CopyAllHClass(GateRef glue, GateRef dstHClass, GateRef srcHClass)
2901 {
2902     auto env = GetEnvironment();
2903     Label entry(env);
2904     Label isTS(env);
2905     Label isNotTS(env);
2906     env->SubCfgEntry(&entry);
2907     auto proto = GetPrototypeFromHClass(srcHClass);
2908     SetPrototypeToHClass(VariableType::JS_POINTER(), glue, dstHClass, proto);
2909     SetBitFieldToHClass(glue, dstHClass, GetBitFieldFromHClass(srcHClass));
2910     SetIsAllTaggedProp(glue, dstHClass, GetIsAllTaggedPropFromHClass(srcHClass));
2911     SetNumberOfPropsToHClass(glue, dstHClass, GetNumberOfPropsFromHClass(srcHClass));
2912     SetTransitionsToHClass(VariableType::INT64(), glue, dstHClass, Undefined());
2913     SetParentToHClass(VariableType::INT64(), glue, dstHClass, Undefined());
2914     SetProtoChangeDetailsToHClass(VariableType::INT64(), glue, dstHClass, Null());
2915     SetEnumCacheToHClass(VariableType::INT64(), glue, dstHClass, Null());
2916     SetLayoutToHClass(VariableType::JS_POINTER(),
2917                       glue,
2918                       dstHClass,
2919                       GetLayoutFromHClass(srcHClass),
2920                       MemoryOrder::Create(MemoryOrder::MEMORY_ORDER_RELEASE));
2921     Branch(IsTSHClass(srcHClass), &isTS, &isNotTS);
2922     Bind(&isTS);
2923     {
2924         SetIsTS(glue, dstHClass, False());
2925         Jump(&isNotTS);
2926     }
2927     Bind(&isNotTS);
2928     env->SubCfgExit();
2929     return;
2930 }
2931 
TransitionForRepChange(GateRef glue,GateRef receiver,GateRef key,GateRef attr)2932 void StubBuilder::TransitionForRepChange(GateRef glue, GateRef receiver, GateRef key, GateRef attr)
2933 {
2934     auto env = GetEnvironment();
2935     Label subEntry(env);
2936     env->SubCfgEntry(&subEntry);
2937     GateRef hclass = LoadHClass(receiver);
2938     GateRef type = GetObjectType(hclass);
2939     GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass),
2940                             Int32(JSTaggedValue::TaggedTypeSize()));
2941     GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass);
2942     GateRef newJshclass = CallRuntime(glue, RTSTUB_ID(NewEcmaHClass),
2943         { IntToTaggedInt(size), IntToTaggedInt(type),
2944           IntToTaggedInt(inlineProps) });
2945     CopyAllHClass(glue, newJshclass, hclass);
2946     CallRuntime(glue, RTSTUB_ID(CopyAndUpdateObjLayout),
2947                 { hclass, newJshclass, key, IntToTaggedInt(attr) });
2948 #if ECMASCRIPT_ENABLE_IC
2949     NotifyHClassChanged(glue, hclass, newJshclass);
2950 #endif
2951     StoreHClass(glue, receiver, newJshclass);
2952     // Because we currently only supports Fast ElementsKind
2953     CallRuntime(glue, RTSTUB_ID(TryRestoreElementsKind), { receiver, newJshclass });
2954     env->SubCfgExit();
2955 }
2956 
TransitToElementsKind(GateRef glue,GateRef receiver,GateRef value,GateRef kind)2957 void StubBuilder::TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind)
2958 {
2959     auto env = GetEnvironment();
2960     Label subEntry(env);
2961     env->SubCfgEntry(&subEntry);
2962     Label exit(env);
2963 
2964     GateRef hclass = LoadHClass(receiver);
2965     GateRef elementsKind = GetElementsKindFromHClass(hclass);
2966 
2967     Label isNoneDefault(env);
2968     Branch(Int32Equal(elementsKind, Int32(static_cast<int32_t>(ElementsKind::GENERIC))), &exit, &isNoneDefault);
2969     Bind(&isNoneDefault);
2970     {
2971         GateRef newKind = TaggedToElementKind(value);
2972         newKind = Int32Or(newKind, kind);
2973         newKind = Int32Or(newKind, elementsKind);
2974         Label change(env);
2975         Branch(Int32Equal(elementsKind, newKind), &exit, &change);
2976         Bind(&change);
2977         {
2978             CallRuntime(glue, RTSTUB_ID(UpdateHClassForElementsKind), { receiver, newKind });
2979             CallRuntime(glue, RTSTUB_ID(MigrateArrayWithKind),
2980                         { receiver, IntToTaggedInt(elementsKind), IntToTaggedInt(newKind) });
2981             Jump(&exit);
2982         }
2983     }
2984 
2985     Bind(&exit);
2986     env->SubCfgExit();
2987 }
2988 
AddElementInternal(GateRef glue,GateRef receiver,GateRef index,GateRef value,GateRef attr)2989 GateRef StubBuilder::AddElementInternal(GateRef glue, GateRef receiver, GateRef index, GateRef value, GateRef attr)
2990 {
2991     auto env = GetEnvironment();
2992     Label subEntry(env);
2993     env->SubCfgEntry(&subEntry);
2994     Label exit(env);
2995     DEFVARIABLE(kind, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::NONE)));
2996     DEFVARIABLE(result, VariableType::BOOL(), False());
2997     Label isArray(env);
2998     Label notArray(env);
2999     Branch(IsJsArray(receiver), &isArray, &notArray);
3000     Bind(&isArray);
3001     {
3002         GateRef oldLen = GetArrayLength(receiver);
3003         Label indexGreaterOrEq(env);
3004         Branch(Int32GreaterThanOrEqual(index, oldLen), &indexGreaterOrEq, &notArray);
3005         Bind(&indexGreaterOrEq);
3006         {
3007             Label isArrLenWritable(env);
3008             Label notArrLenWritable(env);
3009             Branch(IsArrayLengthWritable(glue, receiver), &isArrLenWritable, &notArrLenWritable);
3010             Bind(&isArrLenWritable);
3011             {
3012                 SetArrayLength(glue, receiver, Int32Add(index, Int32(1)));
3013                 Label indexGreater(env);
3014                 Branch(Int32GreaterThan(index, oldLen), &indexGreater, &notArray);
3015                 Bind(&indexGreater);
3016                 kind = Int32(static_cast<int32_t>(ElementsKind::HOLE));
3017                 Jump(&notArray);
3018             }
3019             Bind(&notArrLenWritable);
3020             result = False();
3021             Jump(&exit);
3022         }
3023     }
3024     Bind(&notArray);
3025     {
3026         NotifyStableArrayElementsGuardians(glue, receiver);
3027         GateRef hclass = LoadHClass(receiver);
3028         GateRef elements = GetElementsArray(receiver);
3029         Label isDicMode(env);
3030         Label notDicMode(env);
3031         Branch(IsDictionaryElement(hclass), &isDicMode, &notDicMode);
3032         Bind(&isDicMode);
3033         {
3034             GateRef res = CallRuntime(glue, RTSTUB_ID(NumberDictionaryPut),
3035                 { receiver, elements, IntToTaggedInt(index), value, IntToTaggedInt(attr), TaggedFalse() });
3036             SetElementsArray(VariableType::JS_POINTER(), glue, receiver, res);
3037             result = True();
3038             Jump(&exit);
3039         }
3040         Bind(&notDicMode);
3041         {
3042             GateRef capacity = GetLengthOfTaggedArray(elements);
3043             GateRef notDefault = BoolNot(IsDefaultAttribute(attr));
3044             Label indexGreaterLen(env);
3045             Label notGreaterLen(env);
3046             Branch(BoolOr(Int32GreaterThanOrEqual(index, capacity), notDefault), &indexGreaterLen, &notGreaterLen);
3047             Bind(&indexGreaterLen);
3048             {
3049                 Label isTransToDict(env);
3050                 Label notTransToDict(env);
3051                 Branch(BoolOr(ShouldTransToDict(capacity, index), notDefault), &isTransToDict, &notTransToDict);
3052                 Bind(&isTransToDict);
3053                 {
3054                     GateRef res = CallRuntime(glue, RTSTUB_ID(NumberDictionaryPut),
3055                         { receiver, elements, IntToTaggedInt(index), value, IntToTaggedInt(attr), TaggedTrue() });
3056                     SetElementsArray(VariableType::JS_POINTER(), glue, receiver, res);
3057                     result = True();
3058                     Jump(&exit);
3059                 }
3060                 Bind(&notTransToDict);
3061                 {
3062                     GrowElementsCapacity(glue, receiver, Int32Add(index, Int32(1)));
3063                     SetValueWithElementsKind(glue, receiver, value, index, Boolean(true), *kind);
3064                     result = True();
3065                     Jump(&exit);
3066                 }
3067             }
3068             Bind(&notGreaterLen);
3069             {
3070                 SetValueWithElementsKind(glue, receiver, value, index, Boolean(true), *kind);
3071                 result = True();
3072                 Jump(&exit);
3073             }
3074         }
3075     }
3076     Bind(&exit);
3077     auto ret = *result;
3078     env->SubCfgExit();
3079     return ret;
3080 }
3081 
GrowElementsCapacity(GateRef glue,GateRef receiver,GateRef capacity)3082 GateRef StubBuilder::GrowElementsCapacity(GateRef glue, GateRef receiver, GateRef capacity)
3083 {
3084     auto env = GetEnvironment();
3085     Label subEntry(env);
3086     env->SubCfgEntry(&subEntry);
3087     DEFVARIABLE(newElements, VariableType::JS_ANY(), Hole());
3088     NewObjectStubBuilder newBuilder(this);
3089     GateRef newCapacity = ComputeElementCapacity(capacity);
3090     GateRef elements = GetElementsArray(receiver);
3091     newElements = newBuilder.CopyArray(glue, elements, capacity, newCapacity);
3092     SetElementsArray(VariableType::JS_POINTER(), glue, receiver, *newElements);
3093     auto ret = *newElements;
3094     env->SubCfgExit();
3095     return ret;
3096 }
3097 
ShouldTransToDict(GateRef capacity,GateRef index)3098 GateRef StubBuilder::ShouldTransToDict(GateRef capacity, GateRef index)
3099 {
3100     auto env = GetEnvironment();
3101     Label subEntry(env);
3102     env->SubCfgEntry(&subEntry);
3103     Label exit(env);
3104     DEFVARIABLE(result, VariableType::BOOL(), True());
3105     Label isGreaterThanCapcity(env);
3106     Label notGreaterThanCapcity(env);
3107     Branch(Int32GreaterThanOrEqual(index, capacity), &isGreaterThanCapcity, &notGreaterThanCapcity);
3108     Bind(&isGreaterThanCapcity);
3109     {
3110         Label isLessThanMax(env);
3111         Label notLessThanMax(env);
3112         Branch(Int32LessThanOrEqual(Int32Sub(index, capacity),
3113                                     Int32(JSObject::MAX_GAP)), &isLessThanMax, &notLessThanMax);
3114         Bind(&isLessThanMax);
3115         {
3116             Label isLessThanInt32Max(env);
3117             Label notLessThanInt32Max(env);
3118             Branch(Int32LessThan(index, Int32(INT32_MAX)), &isLessThanInt32Max, &notLessThanInt32Max);
3119             Bind(&isLessThanInt32Max);
3120             {
3121                 Label isLessThanMin(env);
3122                 Label notLessThanMin(env);
3123                 Branch(Int32LessThan(capacity, Int32(JSObject::MIN_GAP)), &isLessThanMin, &notLessThanMin);
3124                 Bind(&isLessThanMin);
3125                 {
3126                     result = False();
3127                     Jump(&exit);
3128                 }
3129                 Bind(&notLessThanMin);
3130                 {
3131                     result = Int32GreaterThan(index, Int32Mul(capacity, Int32(JSObject::FAST_ELEMENTS_FACTOR)));
3132                     Jump(&exit);
3133                 }
3134             }
3135             Bind(&notLessThanInt32Max);
3136             {
3137                 result = True();
3138                 Jump(&exit);
3139             }
3140         }
3141         Bind(&notLessThanMax);
3142         {
3143             result = True();
3144             Jump(&exit);
3145         }
3146     }
3147     Bind(&notGreaterThanCapcity);
3148     {
3149         result = False();
3150         Jump(&exit);
3151     }
3152     Bind(&exit);
3153     auto ret = *result;
3154     env->SubCfgExit();
3155     return ret;
3156 }
3157 
NotifyStableArrayElementsGuardians(GateRef glue,GateRef receiver)3158 void StubBuilder::NotifyStableArrayElementsGuardians(GateRef glue, GateRef receiver)
3159 {
3160     auto env = GetEnvironment();
3161     Label subEntry(env);
3162     env->SubCfgEntry(&subEntry);
3163     Label exit(env);
3164     GateRef guardiansOffset =
3165                 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
3166     GateRef guardians = Load(VariableType::BOOL(), glue, guardiansOffset);
3167     Label isGuardians(env);
3168     Branch(Equal(guardians, True()), &isGuardians, &exit);
3169     Bind(&isGuardians);
3170     {
3171         GateRef hclass = LoadHClass(receiver);
3172         Label isProtoType(env);
3173         Branch(BoolOr(IsProtoTypeHClass(hclass), IsJsArray(receiver)), &isProtoType, &exit);
3174         Bind(&isProtoType);
3175         {
3176             Label isEnvProtoType(env);
3177             GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3178             GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3179             GateRef objectFunctionPrototype = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
3180                                                                 GlobalEnv::OBJECT_FUNCTION_PROTOTYPE_INDEX);
3181             GateRef arrayPrototype = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
3182                                                        GlobalEnv::ARRAY_PROTOTYPE_INDEX);
3183             Branch(BoolOr(Equal(objectFunctionPrototype, receiver), Equal(arrayPrototype, receiver)),
3184                 &isEnvProtoType, &exit);
3185             Bind(&isEnvProtoType);
3186             Store(VariableType::BOOL(), glue, glue, guardiansOffset, False());
3187             Jump(&exit);
3188         }
3189     }
3190     Bind(&exit);
3191     env->SubCfgExit();
3192     return;
3193 }
3194 
IsArrayLengthWritable(GateRef glue,GateRef receiver)3195 GateRef StubBuilder::IsArrayLengthWritable(GateRef glue, GateRef receiver)
3196 {
3197     auto env = GetEnvironment();
3198     Label subEntry(env);
3199     env->SubCfgEntry(&subEntry);
3200     Label exit(env);
3201     GateRef hclass = LoadHClass(receiver);
3202     Label isDicMode(env);
3203     Label notDicMode(env);
3204     DEFVARIABLE(result, VariableType::BOOL(), False());
3205     Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
3206     Bind(&isDicMode);
3207     {
3208         GateRef array = GetPropertiesArray(receiver);
3209         GateRef lengthString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
3210                                                       ConstantIndex::LENGTH_STRING_INDEX);
3211         GateRef entry = FindEntryFromNameDictionary(glue, array, lengthString);
3212         Label notNegtiveOne(env);
3213         Label isNegtiveOne(env);
3214         Branch(Int32NotEqual(entry, Int32(-1)), &notNegtiveOne, &isNegtiveOne);
3215         Bind(&notNegtiveOne);
3216         {
3217             GateRef attr = GetAttributesFromDictionary<NameDictionary>(array, entry);
3218             result = IsWritable(attr);
3219             Jump(&exit);
3220         }
3221         Bind(&isNegtiveOne);
3222         {
3223             GateRef attr1 = Int32(PropertyAttributes::GetDefaultAttributes());
3224             result = IsWritable(attr1);
3225             Jump(&exit);
3226         }
3227     }
3228     Bind(&notDicMode);
3229     {
3230         GateRef layoutInfo = GetLayoutFromHClass(hclass);
3231         GateRef propAttr = GetPropAttrFromLayoutInfo(layoutInfo, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
3232         GateRef attr = GetInt32OfTInt(propAttr);
3233         result = IsWritable(attr);
3234         Jump(&exit);
3235     }
3236     Bind(&exit);
3237     auto ret = *result;
3238     env->SubCfgExit();
3239     return ret;
3240 }
3241 
FindTransitions(GateRef glue,GateRef receiver,GateRef hclass,GateRef key,GateRef metaData)3242 GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, GateRef key, GateRef metaData)
3243 {
3244     auto env = GetEnvironment();
3245     Label entry(env);
3246     env->SubCfgEntry(&entry);
3247     Label exit(env);
3248     GateRef transitionOffset = IntPtr(JSHClass::TRANSTIONS_OFFSET);
3249     GateRef transition = Load(VariableType::JS_POINTER(), hclass, transitionOffset);
3250     DEFVARIABLE(result, VariableType::JS_ANY(), transition);
3251 
3252     Label notUndefined(env);
3253     Branch(Equal(transition, Undefined()), &exit, &notUndefined);
3254     Bind(&notUndefined);
3255     {
3256         Label isWeak(env);
3257         Label notWeak(env);
3258         Branch(TaggedIsWeak(transition), &isWeak, &notWeak);
3259         Bind(&isWeak);
3260         {
3261             GateRef transitionHClass = LoadObjectFromWeakRef(transition);
3262             GateRef propNums = GetNumberOfPropsFromHClass(transitionHClass);
3263             GateRef last = Int32Sub(propNums, Int32(1));
3264             GateRef layoutInfo = GetLayoutFromHClass(transitionHClass);
3265             GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last);
3266             GateRef cachedAttr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(layoutInfo, last));
3267             GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr);
3268             Label keyMatch(env);
3269             Label isMatch(env);
3270             Label notMatch(env);
3271             Branch(Equal(cachedKey, key), &keyMatch, &notMatch);
3272             Bind(&keyMatch);
3273             {
3274                 Branch(Int32Equal(metaData, cachedMetaData), &isMatch, &notMatch);
3275                 Bind(&isMatch);
3276                 {
3277                     GateRef oldHClass = LoadHClass(receiver);
3278                     GateRef prototype = GetPrototypeFromHClass(oldHClass);
3279                     StorePrototype(glue, transitionHClass, prototype);
3280 #if ECMASCRIPT_ENABLE_IC
3281                     NotifyHClassChanged(glue, hclass, transitionHClass);
3282 #endif
3283                     StoreHClass(glue, receiver, transitionHClass);
3284                     // Because we currently only supports Fast ElementsKind
3285                     CallRuntime(glue, RTSTUB_ID(TryRestoreElementsKind), { receiver, transitionHClass });
3286                     Jump(&exit);
3287                 }
3288             }
3289             Bind(&notMatch);
3290             {
3291                 result = Undefined();
3292                 Jump(&exit);
3293             }
3294         }
3295         Bind(&notWeak);
3296         {
3297             // need to find from dictionary
3298             GateRef entryA = FindEntryFromTransitionDictionary(glue, transition, key, metaData);
3299             Label isFound(env);
3300             Label notFound(env);
3301             Branch(Int32NotEqual(entryA, Int32(-1)), &isFound, &notFound);
3302             Bind(&isFound);
3303             auto value = GetValueFromDictionary<TransitionsDictionary>(transition, entryA);
3304             Label valueUndefined(env);
3305             Label valueNotUndefined(env);
3306             Branch(Int64NotEqual(value, Undefined()), &valueNotUndefined,
3307                 &valueUndefined);
3308             Bind(&valueNotUndefined);
3309             {
3310                 GateRef newHClass = LoadObjectFromWeakRef(value);
3311                 result = newHClass;
3312                 GateRef oldHClass = LoadHClass(receiver);
3313                 GateRef prototype = GetPrototypeFromHClass(oldHClass);
3314                 StorePrototype(glue, newHClass, prototype);
3315 #if ECMASCRIPT_ENABLE_IC
3316                 NotifyHClassChanged(glue, hclass, newHClass);
3317 #endif
3318                 StoreHClass(glue, receiver, newHClass);
3319                 // Because we currently only supports Fast ElementsKind
3320                 CallRuntime(glue, RTSTUB_ID(TryRestoreElementsKind), { receiver, newHClass });
3321                 Jump(&exit);
3322                 Bind(&notFound);
3323                 result = Undefined();
3324                 Jump(&exit);
3325             }
3326             Bind(&valueUndefined);
3327             {
3328                 result = Undefined();
3329                 Jump(&exit);
3330             }
3331         }
3332     }
3333     Bind(&exit);
3334     auto ret = *result;
3335     env->SubCfgExit();
3336     return ret;
3337 }
3338 
SetPropertyByIndex(GateRef glue,GateRef receiver,GateRef index,GateRef value,bool useOwn,ProfileOperation callback)3339 GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn,
3340     ProfileOperation callback)
3341 {
3342     auto env = GetEnvironment();
3343     Label entry(env);
3344     env->SubCfgEntry(&entry);
3345     DEFVARIABLE(returnValue, VariableType::JS_ANY(), Hole());
3346     DEFVARIABLE(holder, VariableType::JS_ANY(), receiver);
3347     Label exit(env);
3348     Label ifEnd(env);
3349     Label loopHead(env);
3350     Label loopEnd(env);
3351     Label loopExit(env);
3352     Label afterLoop(env);
3353     Label isJsCOWArray(env);
3354     Label isNotJsCOWArray(env);
3355     Label setElementsArray(env);
3356     if (!useOwn) {
3357         Jump(&loopHead);
3358         LoopBegin(&loopHead);
3359     }
3360     GateRef hclass = LoadHClass(*holder);
3361     GateRef jsType = GetObjectType(hclass);
3362     Label isSpecialIndex(env);
3363     Label notSpecialIndex(env);
3364     Branch(IsSpecialIndexedObj(jsType), &isSpecialIndex, &notSpecialIndex);
3365     Bind(&isSpecialIndex);
3366     {
3367         // TypeArray
3368         Label isFastTypeArray(env);
3369         Label notFastTypeArray(env);
3370         Label checkIsOnPrototypeChain(env);
3371         Label notTypedArrayProto(env);
3372         Branch(Int32Equal(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY))), &exit, &notTypedArrayProto);
3373         Bind(&notTypedArrayProto);
3374         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
3375         Bind(&isFastTypeArray);
3376         {
3377             Branch(Equal(*holder, receiver), &checkIsOnPrototypeChain, &exit);
3378             Bind(&checkIsOnPrototypeChain);
3379             {
3380                 returnValue = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
3381                     { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType)});
3382                 Jump(&exit);
3383             }
3384         }
3385         Bind(&notFastTypeArray);
3386         returnValue = Hole();
3387         Jump(&exit);
3388     }
3389     Bind(&notSpecialIndex);
3390     {
3391         GateRef elements = GetElementsArray(*holder);
3392         Label isDictionaryElement(env);
3393         Label notDictionaryElement(env);
3394         Branch(IsDictionaryElement(hclass), &isDictionaryElement, &notDictionaryElement);
3395         Bind(&notDictionaryElement);
3396         {
3397             Label isReceiver(env);
3398             if (useOwn) {
3399                 Branch(Equal(*holder, receiver), &isReceiver, &ifEnd);
3400             } else {
3401                 Branch(Equal(*holder, receiver), &isReceiver, &afterLoop);
3402             }
3403             Bind(&isReceiver);
3404             {
3405                 GateRef length = GetLengthOfTaggedArray(elements);
3406                 Label inRange(env);
3407                 if (useOwn) {
3408                     Branch(Int64LessThan(index, length), &inRange, &ifEnd);
3409                 } else {
3410                     Branch(Int64LessThan(index, length), &inRange, &loopExit);
3411                 }
3412                 Bind(&inRange);
3413                 {
3414                     GateRef value1 = GetTaggedValueWithElementsKind(*holder, index);
3415                     Label notHole(env);
3416                     if (useOwn) {
3417                         Branch(Int64NotEqual(value1, Hole()), &notHole, &ifEnd);
3418                     } else {
3419                         Branch(Int64NotEqual(value1, Hole()), &notHole, &loopExit);
3420                     }
3421                     Bind(&notHole);
3422                     {
3423                         Branch(IsJsCOWArray(*holder), &isJsCOWArray, &isNotJsCOWArray);
3424                         Bind(&isJsCOWArray);
3425                         {
3426                             CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {*holder});
3427                             SetValueWithElementsKind(glue, *holder, value, index, Boolean(true),
3428                                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
3429                             returnValue = Undefined();
3430                             Jump(&exit);
3431                         }
3432                         Bind(&isNotJsCOWArray);
3433                         {
3434                             Jump(&setElementsArray);
3435                         }
3436                         Bind(&setElementsArray);
3437                         {
3438                             SetValueWithElementsKind(glue, *holder, value, index, Boolean(true),
3439                                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
3440                             returnValue = Undefined();
3441                             Jump(&exit);
3442                         }
3443                     }
3444                 }
3445             }
3446         }
3447         Bind(&isDictionaryElement);
3448         {
3449             GateRef entryA = FindElementFromNumberDictionary(glue, elements, index);
3450             Label negtiveOne(env);
3451             Label notNegtiveOne(env);
3452             Branch(Int32NotEqual(entryA, Int32(-1)), &notNegtiveOne, &negtiveOne);
3453             Bind(&notNegtiveOne);
3454             {
3455                 GateRef attr = GetAttributesFromDictionary<NumberDictionary>(elements, entryA);
3456                 Label isWritandConfig(env);
3457                 Label notWritandConfig(env);
3458                 Branch(BoolAnd(IsWritable(attr), IsConfigable(attr)), &isWritandConfig, &notWritandConfig);
3459                 Bind(&isWritandConfig);
3460                 {
3461                     Label isAccessor(env);
3462                     Label notAccessor(env);
3463                     Branch(IsAccessor(attr), &isAccessor, &notAccessor);
3464                     Bind(&isAccessor);
3465                     {
3466                         GateRef accessor = GetValueFromDictionary<NumberDictionary>(elements, entryA);
3467                         Label shouldCall(env);
3468                         Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &notAccessor);
3469                         Bind(&shouldCall);
3470                         {
3471                             returnValue = CallSetterHelper(glue, receiver, accessor, value, callback);
3472                             Jump(&exit);
3473                         }
3474                     }
3475                     Bind(&notAccessor);
3476                     {
3477                         Label holdEqualsRecv(env);
3478                         if (useOwn) {
3479                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &ifEnd);
3480                         } else {
3481                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &afterLoop);
3482                         }
3483                         Bind(&holdEqualsRecv);
3484                         {
3485                             UpdateValueInDict<NumberDictionary>(glue, elements, entryA, value);
3486                             returnValue = Undefined();
3487                             Jump(&exit);
3488                         }
3489                     }
3490                 }
3491                 Bind(&notWritandConfig);
3492                 {
3493                     returnValue = Hole();
3494                     Jump(&exit);
3495                 }
3496             }
3497             Bind(&negtiveOne);
3498             returnValue = Hole();
3499             Jump(&exit);
3500         }
3501     }
3502     if (useOwn) {
3503         Bind(&ifEnd);
3504     } else {
3505         Bind(&loopExit);
3506         {
3507             holder = GetPrototypeFromHClass(LoadHClass(*holder));
3508             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
3509         }
3510         Bind(&loopEnd);
3511         LoopEnd(&loopHead);
3512         Bind(&afterLoop);
3513     }
3514     Label isExtensible(env);
3515     Label notExtensible(env);
3516     Branch(IsExtensible(receiver), &isExtensible, &notExtensible);
3517     Bind(&isExtensible);
3518     {
3519         Label success(env);
3520         Label failed(env);
3521         Branch(AddElementInternal(glue, receiver, index, value,
3522                                   Int32(PropertyAttributes::GetDefaultAttributes())), &success, &failed);
3523         Bind(&success);
3524         {
3525             returnValue = Undefined();
3526             Jump(&exit);
3527         }
3528         Bind(&failed);
3529         {
3530             returnValue = Exception();
3531             Jump(&exit);
3532         }
3533     }
3534     Bind(&notExtensible);
3535     {
3536         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
3537         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3538         returnValue = Exception();
3539         Jump(&exit);
3540     }
3541     Bind(&exit);
3542     auto ret = *returnValue;
3543     env->SubCfgExit();
3544     return ret;
3545 }
3546 
SetPropertyByName(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn,GateRef isInternal,ProfileOperation callback,bool canUseIsInternal)3547 GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value,
3548     bool useOwn, GateRef isInternal, ProfileOperation callback, bool canUseIsInternal)
3549 {
3550     auto env = GetEnvironment();
3551     Label entryPass(env);
3552     env->SubCfgEntry(&entryPass);
3553     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3554     DEFVARIABLE(holder, VariableType::JS_POINTER(), receiver);
3555     DEFVARIABLE(receiverHoleEntry, VariableType::INT32(), Int32(-1));
3556     Label exit(env);
3557     Label ifEnd(env);
3558     Label loopHead(env);
3559     Label loopEnd(env);
3560     Label loopExit(env);
3561     Label afterLoop(env);
3562     Label findProperty(env);
3563     if (!useOwn) {
3564         // a do-while loop
3565         Jump(&loopHead);
3566         LoopBegin(&loopHead);
3567     }
3568     // auto *hclass = holder.GetTaggedObject()->GetClass()
3569     // JSType jsType = hclass->GetObjectType()
3570     GateRef hclass = LoadHClass(*holder);
3571     GateRef jsType = GetObjectType(hclass);
3572     Label isSIndexObj(env);
3573     Label notSIndexObj(env);
3574     // if branch condition : IsSpecialIndexedObj(jsType)
3575     Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, &notSIndexObj);
3576     Bind(&isSIndexObj);
3577     {
3578         Label isFastTypeArray(env);
3579         Label notFastTypeArray(env);
3580         Branch(IsFastTypeArray(jsType), &isFastTypeArray, &notFastTypeArray);
3581         Bind(&isFastTypeArray);
3582         {
3583             result = SetTypeArrayPropertyByName(glue, receiver, *holder, key, value, jsType);
3584             Label isNull(env);
3585             Label notNull(env);
3586             Branch(TaggedIsNull(*result), &isNull, &notNull);
3587             Bind(&isNull);
3588             {
3589                 result = Hole();
3590                 Jump(&exit);
3591             }
3592             Bind(&notNull);
3593             Branch(TaggedIsHole(*result), &notSIndexObj, &exit);
3594         }
3595         Bind(&notFastTypeArray);
3596 
3597         Label isSpecialContainer(env);
3598         Label notSpecialContainer(env);
3599         // Add SpecialContainer
3600         Branch(IsSpecialContainer(jsType), &isSpecialContainer, &notSpecialContainer);
3601         Bind(&isSpecialContainer);
3602         {
3603             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotSetPropertyOnContainer));
3604             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3605             result = Exception();
3606             Jump(&exit);
3607         }
3608         Bind(&notSpecialContainer);
3609         {
3610             result = Hole();
3611             Jump(&exit);
3612         }
3613     }
3614     Bind(&notSIndexObj);
3615     {
3616         if (canUseIsInternal) {
3617             if (useOwn) {
3618                 Branch(isInternal, &findProperty, &ifEnd);
3619             } else {
3620                 Branch(isInternal, &findProperty, &loopExit);
3621             }
3622         } else {
3623             Jump(&findProperty);
3624         }
3625         Label isDicMode(env);
3626         Label notDicMode(env);
3627         Bind(&findProperty);
3628         // if branch condition : LIKELY(!hclass->IsDictionaryMode())
3629         Branch(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMode);
3630         Bind(&notDicMode);
3631         {
3632             // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject())
3633             GateRef layOutInfo = GetLayoutFromHClass(hclass);
3634             // int propsNumber = hclass->NumberOfPropsFromHClass()
3635             GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
3636             // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
3637             GateRef entry = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum);
3638             Label hasEntry(env);
3639             // if branch condition : entry != -1
3640             if (useOwn) {
3641                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &ifEnd);
3642             } else {
3643                 Branch(Int32NotEqual(entry, Int32(-1)), &hasEntry, &loopExit);
3644             }
3645             Bind(&hasEntry);
3646             {
3647                 // PropertyAttributes attr(layoutInfo->GetAttr(entry))
3648                 GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry);
3649                 GateRef attr = GetInt32OfTInt(propAttr);
3650                 Label isAccessor(env);
3651                 Label notAccessor(env);
3652                 Branch(IsAccessor(attr), &isAccessor, &notAccessor);
3653                 Bind(&isAccessor);
3654                 {
3655                     // auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr)
3656                     GateRef accessor = JSObjectGetProperty(*holder, hclass, attr);
3657                     Label shouldCall(env);
3658                     // ShouldCallSetter(receiver, *holder, accessor, attr)
3659                     Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &notAccessor);
3660                     Bind(&shouldCall);
3661                     {
3662                         result = CallSetterHelper(glue, receiver, accessor, value, callback);
3663                         Jump(&exit);
3664                     }
3665                 }
3666                 Bind(&notAccessor);
3667                 {
3668                     Label writable(env);
3669                     Label notWritable(env);
3670                     Branch(IsWritable(attr), &writable, &notWritable);
3671                     Bind(&notWritable);
3672                     {
3673                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
3674                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3675                         result = Exception();
3676                         Jump(&exit);
3677                     }
3678                     Bind(&writable);
3679                     {
3680                         Label isTS(env);
3681                         Label notTS(env);
3682                         Branch(IsTSHClass(hclass), &isTS, &notTS);
3683                         Bind(&isTS);
3684                         {
3685                             GateRef attrVal = JSObjectGetProperty(*holder, hclass, attr);
3686                             Label attrValIsHole(env);
3687                             Branch(TaggedIsHole(attrVal), &attrValIsHole, &notTS);
3688                             Bind(&attrValIsHole);
3689                             {
3690                                 Label storeReceiverHoleEntry(env);
3691                                 Label noNeedStore(env);
3692                                 GateRef checkReceiverHoleEntry = Int32Equal(*receiverHoleEntry, Int32(-1));
3693                                 GateRef checkHolderEqualsRecv = Equal(*holder, receiver);
3694                                 Branch(BoolAnd(checkReceiverHoleEntry, checkHolderEqualsRecv),
3695                                     &storeReceiverHoleEntry, &noNeedStore);
3696                                 Bind(&storeReceiverHoleEntry);
3697                                 {
3698                                     receiverHoleEntry = entry;
3699                                     Jump(&noNeedStore);
3700                                 }
3701                                 Bind(&noNeedStore);
3702                                 if (useOwn) {
3703                                     Jump(&ifEnd);
3704                                 } else {
3705                                     Jump(&loopExit);
3706                                 }
3707                             }
3708                         }
3709                         Bind(&notTS);
3710                         Label holdEqualsRecv(env);
3711                         if (useOwn) {
3712                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &ifEnd);
3713                         } else {
3714                             Branch(Equal(*holder, receiver), &holdEqualsRecv, &afterLoop);
3715                         }
3716                         Bind(&holdEqualsRecv);
3717                         {
3718                             // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value)
3719                             // return JSTaggedValue::Undefined()
3720                             Label executeSetProp(env);
3721                             CheckUpdateSharedType(false, &result, glue, jsType, attr, value, &executeSetProp, &exit);
3722                             Bind(&executeSetProp);
3723                             JSObjectSetProperty(glue, *holder, hclass, attr, key, value);
3724                             ProfilerStubBuilder(env).UpdatePropAttrWithValue(
3725                                 glue, jsType, layOutInfo, attr, entry, value, callback);
3726                             result = Undefined();
3727                             Jump(&exit);
3728                         }
3729                     }
3730                 }
3731             }
3732         }
3733         Bind(&isDicMode);
3734         {
3735             GateRef array = GetPropertiesArray(*holder);
3736             // int entry = dict->FindEntry(key)
3737             GateRef entry1 = FindEntryFromNameDictionary(glue, array, key);
3738             Label notNegtiveOne(env);
3739             // if branch condition : entry != -1
3740             if (useOwn) {
3741                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &ifEnd);
3742             } else {
3743                 Branch(Int32NotEqual(entry1, Int32(-1)), &notNegtiveOne, &loopExit);
3744             }
3745             Bind(&notNegtiveOne);
3746             {
3747                 // auto attr = dict->GetAttributes(entry)
3748                 GateRef attr1 = GetAttributesFromDictionary<NameDictionary>(array, entry1);
3749                 Label isAccessor1(env);
3750                 Label notAccessor1(env);
3751                 // if branch condition : UNLIKELY(attr.IsAccessor())
3752                 Branch(IsAccessor(attr1), &isAccessor1, &notAccessor1);
3753                 Bind(&isAccessor1);
3754                 {
3755                     // auto accessor = dict->GetValue(entry)
3756                     GateRef accessor1 = GetValueFromDictionary<NameDictionary>(array, entry1);
3757                     Label shouldCall1(env);
3758                     Branch(ShouldCallSetter(receiver, *holder, accessor1, attr1), &shouldCall1, &notAccessor1);
3759                     Bind(&shouldCall1);
3760                     {
3761                         result = CallSetterHelper(glue, receiver, accessor1, value, callback);
3762                         Jump(&exit);
3763                     }
3764                 }
3765                 Bind(&notAccessor1);
3766                 {
3767                     Label writable1(env);
3768                     Label notWritable1(env);
3769                     Branch(IsWritable(attr1), &writable1, &notWritable1);
3770                     Bind(&notWritable1);
3771                     {
3772                         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetReadOnlyProperty));
3773                         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3774                         result = Exception();
3775                         Jump(&exit);
3776                     }
3777                     Bind(&writable1);
3778                     {
3779                         Label holdEqualsRecv1(env);
3780                         if (useOwn) {
3781                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &ifEnd);
3782                         } else {
3783                             Branch(Equal(*holder, receiver), &holdEqualsRecv1, &afterLoop);
3784                         }
3785                         Bind(&holdEqualsRecv1);
3786                         {
3787                             // dict->UpdateValue(thread, entry, value)
3788                             // return JSTaggedValue::Undefined()
3789                             Label executeSetProp(env);
3790                             CheckUpdateSharedType(true, &result, glue, jsType, attr1, value, &executeSetProp, &exit);
3791                             Bind(&executeSetProp);
3792                             UpdateValueInDict<NameDictionary>(glue, array, entry1, value);
3793                             result = Undefined();
3794                             Jump(&exit);
3795                         }
3796                     }
3797                 }
3798             }
3799         }
3800     }
3801     if (useOwn) {
3802         Bind(&ifEnd);
3803     } else {
3804         Bind(&loopExit);
3805         {
3806             // holder = hclass->GetPrototype()
3807             holder = GetPrototypeFromHClass(LoadHClass(*holder));
3808             // loop condition for a do-while loop
3809             Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop);
3810         }
3811         Bind(&loopEnd);
3812         LoopEnd(&loopHead);
3813         Bind(&afterLoop);
3814     }
3815     Label holeEntryNotNegtiveOne(env);
3816     Label holeEntryIfEnd(env);
3817     Branch(Int32NotEqual(*receiverHoleEntry, Int32(-1)), &holeEntryNotNegtiveOne, &holeEntryIfEnd);
3818     Bind(&holeEntryNotNegtiveOne);
3819     {
3820         GateRef receiverHClass = LoadHClass(receiver);
3821         GateRef receiverLayoutInfo = GetLayoutFromHClass(receiverHClass);
3822         GateRef holePropAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry);
3823         GateRef holeAttr = GetInt32OfTInt(holePropAttr);
3824         JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, key, value);
3825         ProfilerStubBuilder(env).UpdatePropAttrWithValue(
3826             glue, jsType, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback);
3827         result = Undefined();
3828         Jump(&exit);
3829     }
3830     Bind(&holeEntryIfEnd);
3831 
3832     Label extensible(env);
3833     Label inextensible(env);
3834     Branch(IsExtensible(receiver), &extensible, &inextensible);
3835     Bind(&inextensible);
3836     {
3837         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible));
3838         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
3839         result = Exception();
3840         Jump(&exit);
3841     }
3842     Bind(&extensible);
3843     {
3844         result = AddPropertyByName(glue, receiver, key, value,
3845             Int32(PropertyAttributes::GetDefaultAttributes()), callback);
3846         Jump(&exit);
3847     }
3848     Bind(&exit);
3849     auto ret = *result;
3850     env->SubCfgExit();
3851     return ret;
3852 }
3853 
SetPropertyByValue(GateRef glue,GateRef receiver,GateRef key,GateRef value,bool useOwn,ProfileOperation callback)3854 GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn,
3855     ProfileOperation callback)
3856 {
3857     auto env = GetEnvironment();
3858     Label subEntry1(env);
3859     env->SubCfgEntry(&subEntry1);
3860     DEFVARIABLE(varKey, VariableType::JS_ANY(), key);
3861     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3862     DEFVARIABLE(isInternal, VariableType::BOOL(), True());
3863     Label isNumberOrStringSymbol(env);
3864     Label notNumber(env);
3865     Label isStringOrSymbol(env);
3866     Label notStringOrSymbol(env);
3867     Label exit(env);
3868     Branch(TaggedIsNumber(*varKey), &isNumberOrStringSymbol, &notNumber);
3869     Bind(&notNumber);
3870     {
3871         Branch(TaggedIsStringOrSymbol(*varKey), &isNumberOrStringSymbol, &notStringOrSymbol);
3872         Bind(&notStringOrSymbol);
3873         {
3874             result = Hole();
3875             Jump(&exit);
3876         }
3877     }
3878     Bind(&isNumberOrStringSymbol);
3879     {
3880         GateRef index64 = TryToElementsIndex(glue, *varKey);
3881         Label validIndex(env);
3882         Label notValidIndex(env);
3883         Label greaterThanInt32Max(env);
3884         Label notGreaterThanInt32Max(env);
3885         Branch(Int64GreaterThanOrEqual(index64, Int64(INT32_MAX)), &greaterThanInt32Max, &notGreaterThanInt32Max);
3886         Bind(&greaterThanInt32Max);
3887         {
3888             Jump(&exit);
3889         }
3890         Bind(&notGreaterThanInt32Max);
3891         GateRef index = TruncInt64ToInt32(index64);
3892         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
3893         Bind(&validIndex);
3894         {
3895             result = SetPropertyByIndex(glue, receiver, index, value, useOwn);
3896             Jump(&exit);
3897         }
3898         Bind(&notValidIndex);
3899         {
3900             Label isNumber1(env);
3901             Label notNumber1(env);
3902             Label setByName(env);
3903             Branch(TaggedIsNumber(*varKey), &isNumber1, &notNumber1);
3904             Bind(&isNumber1);
3905             {
3906                 result = Hole();
3907                 Jump(&exit);
3908             }
3909             Label isString(env);
3910             Label notString(env);
3911             Bind(&notNumber1);
3912             {
3913                 Label notIntenalString(env);
3914                 Branch(TaggedIsString(*varKey), &isString, &notString);
3915                 Bind(&isString);
3916                 {
3917                     Branch(IsInternalString(*varKey), &setByName, &notIntenalString);
3918                     Bind(&notIntenalString);
3919                     {
3920                         Label notFind(env);
3921                         Label find(env);
3922                         GateRef res = CallNGCRuntime(glue, RTSTUB_ID(TryGetInternString), { glue, *varKey });
3923                         Branch(TaggedIsHole(res), &notFind, &find);
3924                         Bind(&notFind);
3925                         {
3926                             varKey = CallRuntime(glue, RTSTUB_ID(InsertStringToTable), { *varKey });
3927                             isInternal = False();
3928                             Jump(&setByName);
3929                         }
3930                         Bind(&find);
3931                         {
3932                             varKey = res;
3933                             Jump(&setByName);
3934                         }
3935                     }
3936                 }
3937             }
3938             Bind(&notString);
3939             CheckDetectorName(glue, *varKey, &setByName, &exit);
3940             Bind(&setByName);
3941             {
3942                 result = SetPropertyByName(glue, receiver, *varKey, value, useOwn,  *isInternal, callback, true);
3943                 Jump(&exit);
3944             }
3945         }
3946     }
3947     Bind(&exit);
3948     auto ret = *result;
3949     env->SubCfgExit();
3950     return ret;
3951 }
3952 
NotifyHClassChanged(GateRef glue,GateRef oldHClass,GateRef newHClass)3953 void StubBuilder::NotifyHClassChanged(GateRef glue, GateRef oldHClass, GateRef newHClass)
3954 {
3955     auto env = GetEnvironment();
3956     Label entry(env);
3957     env->SubCfgEntry(&entry);
3958     Label exit(env);
3959     Label isProtoType(env);
3960     Branch(IsProtoTypeHClass(oldHClass), &isProtoType, &exit);
3961     Bind(&isProtoType);
3962     {
3963         Label notEqualHClass(env);
3964         Branch(Equal(oldHClass, newHClass), &exit, &notEqualHClass);
3965         Bind(&notEqualHClass);
3966         {
3967             SetIsProtoTypeToHClass(glue, newHClass, True());
3968             CallRuntime(glue, RTSTUB_ID(NoticeThroughChainAndRefreshUser), { oldHClass, newHClass });
3969             Jump(&exit);
3970         }
3971     }
3972     Bind(&exit);
3973     env->SubCfgExit();
3974     return;
3975 }
3976 
GetContainerProperty(GateRef glue,GateRef receiver,GateRef index,GateRef jsType)3977 GateRef StubBuilder::GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType)
3978 {
3979     auto env = GetEnvironment();
3980     Label entry(env);
3981     env->SubCfgEntry(&entry);
3982     Label exit(env);
3983     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
3984 
3985     Label isDefaultLabel(env);
3986     Label noDefaultLabel(env);
3987     Branch(IsSpecialContainer(jsType), &noDefaultLabel, &isDefaultLabel);
3988     Bind(&noDefaultLabel);
3989     {
3990         result = JSAPIContainerGet(glue, receiver, index);
3991         Jump(&exit);
3992     }
3993     Bind(&isDefaultLabel);
3994     {
3995         Jump(&exit);
3996     }
3997     Bind(&exit);
3998 
3999     auto ret = *result;
4000     env->SubCfgExit();
4001     return ret;
4002 }
4003 
FastTypeOf(GateRef glue,GateRef obj)4004 GateRef StubBuilder::FastTypeOf(GateRef glue, GateRef obj)
4005 {
4006     auto env = GetEnvironment();
4007     Label entry(env);
4008     env->SubCfgEntry(&entry);
4009     Label exit(env);
4010 
4011     GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
4012         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
4013     GateRef undefinedIndex = GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX);
4014     GateRef gConstUndefinedStr = Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
4015     DEFVARIABLE(result, VariableType::JS_POINTER(), gConstUndefinedStr);
4016     Label objIsTrue(env);
4017     Label objNotTrue(env);
4018     Label defaultLabel(env);
4019     GateRef gConstBooleanStr = Load(VariableType::JS_POINTER(), gConstAddr,
4020         GetGlobalConstantOffset(ConstantIndex::BOOLEAN_STRING_INDEX));
4021     Branch(TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
4022     Bind(&objIsTrue);
4023     {
4024         result = gConstBooleanStr;
4025         Jump(&exit);
4026     }
4027     Bind(&objNotTrue);
4028     {
4029         Label objIsFalse(env);
4030         Label objNotFalse(env);
4031         Branch(TaggedIsFalse(obj), &objIsFalse, &objNotFalse);
4032         Bind(&objIsFalse);
4033         {
4034             result = gConstBooleanStr;
4035             Jump(&exit);
4036         }
4037         Bind(&objNotFalse);
4038         {
4039             Label objIsNull(env);
4040             Label objNotNull(env);
4041             Branch(TaggedIsNull(obj), &objIsNull, &objNotNull);
4042             Bind(&objIsNull);
4043             {
4044                 result = Load(VariableType::JS_POINTER(), gConstAddr,
4045                     GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX));
4046                 Jump(&exit);
4047             }
4048             Bind(&objNotNull);
4049             {
4050                 Label objIsUndefined(env);
4051                 Label objNotUndefined(env);
4052                 Branch(TaggedIsUndefined(obj), &objIsUndefined, &objNotUndefined);
4053                 Bind(&objIsUndefined);
4054                 {
4055                     result = Load(VariableType::JS_POINTER(), gConstAddr,
4056                         GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX));
4057                     Jump(&exit);
4058                 }
4059                 Bind(&objNotUndefined);
4060                 Jump(&defaultLabel);
4061             }
4062         }
4063     }
4064     Bind(&defaultLabel);
4065     {
4066         Label objIsHeapObject(env);
4067         Label objNotHeapObject(env);
4068         Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject);
4069         Bind(&objIsHeapObject);
4070         {
4071             Label objIsString(env);
4072             Label objNotString(env);
4073             Branch(IsString(obj), &objIsString, &objNotString);
4074             Bind(&objIsString);
4075             {
4076                 result = Load(VariableType::JS_POINTER(), gConstAddr,
4077                     GetGlobalConstantOffset(ConstantIndex::STRING_STRING_INDEX));
4078                 Jump(&exit);
4079             }
4080             Bind(&objNotString);
4081             {
4082                 Label objIsSymbol(env);
4083                 Label objNotSymbol(env);
4084                 Branch(IsSymbol(obj), &objIsSymbol, &objNotSymbol);
4085                 Bind(&objIsSymbol);
4086                 {
4087                     result = Load(VariableType::JS_POINTER(), gConstAddr,
4088                         GetGlobalConstantOffset(ConstantIndex::SYMBOL_STRING_INDEX));
4089                     Jump(&exit);
4090                 }
4091                 Bind(&objNotSymbol);
4092                 {
4093                     Label objIsCallable(env);
4094                     Label objNotCallable(env);
4095                     Branch(IsCallable(obj), &objIsCallable, &objNotCallable);
4096                     Bind(&objIsCallable);
4097                     {
4098                         result = Load(VariableType::JS_POINTER(), gConstAddr,
4099                             GetGlobalConstantOffset(ConstantIndex::FUNCTION_STRING_INDEX));
4100                         Jump(&exit);
4101                     }
4102                     Bind(&objNotCallable);
4103                     {
4104                         Label objIsBigInt(env);
4105                         Label objNotBigInt(env);
4106                         Branch(TaggedObjectIsBigInt(obj), &objIsBigInt, &objNotBigInt);
4107                         Bind(&objIsBigInt);
4108                         {
4109                             result = Load(VariableType::JS_POINTER(), gConstAddr,
4110                                 GetGlobalConstantOffset(ConstantIndex::BIGINT_STRING_INDEX));
4111                             Jump(&exit);
4112                         }
4113                         Bind(&objNotBigInt);
4114                         {
4115                             result = Load(VariableType::JS_POINTER(), gConstAddr,
4116                                 GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX));
4117                             Jump(&exit);
4118                         }
4119                     }
4120                 }
4121             }
4122         }
4123         Bind(&objNotHeapObject);
4124         {
4125             Label objIsNum(env);
4126             Label objNotNum(env);
4127             Branch(TaggedIsNumber(obj), &objIsNum, &objNotNum);
4128             Bind(&objIsNum);
4129             {
4130                 result = Load(VariableType::JS_POINTER(), gConstAddr,
4131                     GetGlobalConstantOffset(ConstantIndex::NUMBER_STRING_INDEX));
4132                 Jump(&exit);
4133             }
4134             Bind(&objNotNum);
4135             Jump(&exit);
4136         }
4137     }
4138     Bind(&exit);
4139     auto ret = *result;
4140     env->SubCfgExit();
4141     return ret;
4142 }
4143 
InstanceOf(GateRef glue,GateRef object,GateRef target,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)4144 GateRef StubBuilder::InstanceOf(
4145     GateRef glue, GateRef object, GateRef target, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
4146 {
4147     auto env = GetEnvironment();
4148     Label entry(env);
4149     env->SubCfgEntry(&entry);
4150     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4151     Label exit(env);
4152 
4153     // 1.If Type(target) is not Object, throw a TypeError exception.
4154     Label targetIsHeapObject(env);
4155     Label targetIsEcmaObject(env);
4156     Label targetNotEcmaObject(env);
4157     Branch(TaggedIsHeapObject(target), &targetIsHeapObject, &targetNotEcmaObject);
4158     Bind(&targetIsHeapObject);
4159     Branch(TaggedObjectIsEcmaObject(target), &targetIsEcmaObject, &targetNotEcmaObject);
4160     Bind(&targetNotEcmaObject);
4161     {
4162         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
4163         // stability testing log 20240127
4164         CallRuntime(glue, RTSTUB_ID(DumpObject), { target, IntToTaggedInt(taggedId) });
4165         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
4166         result = Exception();
4167         Jump(&exit);
4168     }
4169     Bind(&targetIsEcmaObject);
4170     {
4171         // 2.Let instOfHandler be GetMethod(target, @@hasInstance).
4172         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
4173         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
4174         GateRef hasInstanceSymbol = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
4175                                                       GlobalEnv::HASINSTANCE_SYMBOL_INDEX);
4176         GateRef instof = GetMethod(glue, target, hasInstanceSymbol, profileTypeInfo, slotId);
4177 
4178         // 3.ReturnIfAbrupt(instOfHandler).
4179         Label isPendingException(env);
4180         Label noPendingException(env);
4181         Branch(HasPendingException(glue), &isPendingException, &noPendingException);
4182         Bind(&isPendingException);
4183         {
4184             result = Exception();
4185             Jump(&exit);
4186         }
4187         Bind(&noPendingException);
4188 
4189         // 4.If instOfHandler is not undefined, then
4190         Label instOfNotUndefined(env);
4191         Label instOfIsUndefined(env);
4192         Label fastPath(env);
4193         Label targetNotCallable(env);
4194         Branch(TaggedIsUndefined(instof), &instOfIsUndefined, &instOfNotUndefined);
4195         Bind(&instOfNotUndefined);
4196         {
4197             TryFastHasInstance(glue, instof, target, object, &fastPath, &exit, &result, callback);
4198         }
4199         Bind(&instOfIsUndefined);
4200         {
4201             // 5.If IsCallable(target) is false, throw a TypeError exception.
4202             Branch(IsCallable(target), &fastPath, &targetNotCallable);
4203             Bind(&targetNotCallable);
4204             {
4205                 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
4206                 // stability testing log 20240127
4207                 CallRuntime(glue, RTSTUB_ID(DumpObject), { target, IntToTaggedInt(taggedId) });
4208                 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
4209                 result = Exception();
4210                 Jump(&exit);
4211             }
4212         }
4213         Bind(&fastPath);
4214         {
4215             // 6.Return ? OrdinaryHasInstance(target, object).
4216             result = OrdinaryHasInstance(glue, target, object);
4217             Jump(&exit);
4218         }
4219     }
4220     Bind(&exit);
4221     auto ret = *result;
4222     env->SubCfgExit();
4223     return ret;
4224 }
4225 
TryFastHasInstance(GateRef glue,GateRef instof,GateRef target,GateRef object,Label * fastPath,Label * exit,Variable * result,ProfileOperation callback)4226 void StubBuilder::TryFastHasInstance(GateRef glue, GateRef instof, GateRef target, GateRef object, Label *fastPath,
4227                                      Label *exit, Variable *result, ProfileOperation callback)
4228 {
4229     auto env = GetEnvironment();
4230 
4231     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
4232     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
4233     GateRef function = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::HASINSTANCE_FUNCTION_INDEX);
4234 
4235     Label slowPath(env);
4236     Label tryFastPath(env);
4237     GateRef isEqual = IntPtrEqual(instof, function);
4238     Branch(isEqual, &tryFastPath, &slowPath);
4239     Bind(&tryFastPath);
4240     Jump(fastPath);
4241     Bind(&slowPath);
4242     {
4243         GateRef retValue = JSCallDispatch(glue, instof, Int32(1), 0, Circuit::NullGate(),
4244                                           JSCallMode::CALL_SETTER, { target, object }, callback);
4245         result->WriteVariable(FastToBoolean(retValue));
4246         Jump(exit);
4247     }
4248 }
4249 
GetMethod(GateRef glue,GateRef obj,GateRef key,GateRef profileTypeInfo,GateRef slotId)4250 GateRef StubBuilder::GetMethod(GateRef glue, GateRef obj, GateRef key, GateRef profileTypeInfo, GateRef slotId)
4251 {
4252     auto env = GetEnvironment();
4253     Label entry(env);
4254     env->SubCfgEntry(&entry);
4255     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4256     Label exit(env);
4257 
4258     StringIdInfo info;
4259     AccessObjectStubBuilder builder(this);
4260     GateRef value = builder.LoadObjByName(glue, obj, key, info, profileTypeInfo, slotId, ProfileOperation());
4261 
4262     Label isPendingException(env);
4263     Label noPendingException(env);
4264     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
4265     Bind(&isPendingException);
4266     {
4267         result = Exception();
4268         Jump(&exit);
4269     }
4270     Bind(&noPendingException);
4271     Label valueIsUndefinedOrNull(env);
4272     Label valueNotUndefinedOrNull(env);
4273     Branch(TaggedIsUndefinedOrNull(value), &valueIsUndefinedOrNull, &valueNotUndefinedOrNull);
4274     Bind(&valueIsUndefinedOrNull);
4275     {
4276         result = Undefined();
4277         Jump(&exit);
4278     }
4279     Bind(&valueNotUndefinedOrNull);
4280     {
4281         Label valueIsCallable(env);
4282         Label valueNotCallable(env);
4283         Label valueIsHeapObject(env);
4284         Branch(TaggedIsHeapObject(value), &valueIsHeapObject, &valueNotCallable);
4285         Bind(&valueIsHeapObject);
4286         Branch(IsCallable(value), &valueIsCallable, &valueNotCallable);
4287         Bind(&valueNotCallable);
4288         {
4289             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(NonCallable));
4290             CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
4291             result = Exception();
4292             Jump(&exit);
4293         }
4294         Bind(&valueIsCallable);
4295         {
4296             result = value;
4297             Jump(&exit);
4298         }
4299     }
4300     Bind(&exit);
4301     auto ret = *result;
4302     env->SubCfgExit();
4303     return ret;
4304 }
4305 
FastGetPropertyByName(GateRef glue,GateRef obj,GateRef key,ProfileOperation callback)4306 GateRef StubBuilder::FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback)
4307 {
4308     auto env = GetEnvironment();
4309     Label entry(env);
4310     env->SubCfgEntry(&entry);
4311     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4312     Label exit(env);
4313     Label checkResult(env);
4314     Label fastpath(env);
4315     Label slowpath(env);
4316 
4317     Branch(TaggedIsHeapObject(obj), &fastpath, &slowpath);
4318     Bind(&fastpath);
4319     {
4320         result = GetPropertyByName(glue, obj, key, callback, True());
4321         Branch(TaggedIsHole(*result), &slowpath, &exit);
4322     }
4323     Bind(&slowpath);
4324     {
4325         result = CallRuntime(glue, RTSTUB_ID(LoadICByName), { Undefined(), obj, key, IntToTaggedInt(Int32(0)) });
4326         Jump(&exit);
4327     }
4328     Bind(&exit);
4329     auto ret = *result;
4330     env->SubCfgExit();
4331     return ret;
4332 }
4333 
FastGetPropertyByIndex(GateRef glue,GateRef obj,GateRef index,ProfileOperation callback)4334 GateRef StubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback)
4335 {
4336     auto env = GetEnvironment();
4337     Label entry(env);
4338     env->SubCfgEntry(&entry);
4339     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4340     Label exit(env);
4341     Label fastPath(env);
4342     Label slowPath(env);
4343 
4344     Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath);
4345     Bind(&fastPath);
4346     {
4347         result = GetPropertyByIndex(glue, obj, index, callback);
4348         Label notHole(env);
4349         Branch(TaggedIsHole(*result), &slowPath, &exit);
4350     }
4351     Bind(&slowPath);
4352     {
4353         result = CallRuntime(glue, RTSTUB_ID(LdObjByIndex),
4354             { obj, IntToTaggedInt(index), TaggedFalse(), Undefined() });
4355         Jump(&exit);
4356     }
4357     Bind(&exit);
4358     auto ret = *result;
4359     env->SubCfgExit();
4360     return ret;
4361 }
4362 
FastSetPropertyByName(GateRef glue,GateRef obj,GateRef key,GateRef value,ProfileOperation callback)4363 void StubBuilder::FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key, GateRef value,
4364     ProfileOperation callback)
4365 {
4366     auto env = GetEnvironment();
4367     Label entry(env);
4368     env->SubCfgEntry(&entry);
4369     DEFVARIABLE(keyVar, VariableType::JS_ANY(), key);
4370     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4371     DEFVARIABLE(isInternal, VariableType::BOOL(), True());
4372     Label exit(env);
4373     Label fastPath(env);
4374     Label slowPath(env);
4375     Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath);
4376     Bind(&fastPath);
4377     {
4378         Label isString(env);
4379         Label getByName(env);
4380         Label isInternalString(env);
4381         Label notIntenalString(env);
4382         Branch(TaggedIsString(*keyVar), &isString, &getByName);
4383         Bind(&isString);
4384         {
4385             Branch(IsInternalString(*keyVar), &isInternalString, &notIntenalString);
4386             Bind(&isInternalString);
4387             Jump(&getByName);
4388             Bind(&notIntenalString);
4389             {
4390                 Label notFind(env);
4391                 Label find(env);
4392                 GateRef res = CallNGCRuntime(glue, RTSTUB_ID(TryGetInternString), { glue, *keyVar });
4393                 Branch(TaggedIsHole(res), &notFind, &find);
4394                 Bind(&notFind);
4395                 {
4396                     keyVar = CallRuntime(glue, RTSTUB_ID(InsertStringToTable), { key });
4397                     isInternal = False();
4398                     Jump(&getByName);
4399                 }
4400                 Bind(&find);
4401                 {
4402                     keyVar = res;
4403                     Jump(&getByName);
4404                 }
4405             }
4406         }
4407         Bind(&getByName);
4408 
4409         result = SetPropertyByName(glue, obj, *keyVar, value, false, *isInternal, callback, true);
4410         Label notHole(env);
4411         Branch(TaggedIsHole(*result), &slowPath, &exit);
4412     }
4413     Bind(&slowPath);
4414     {
4415         result = CallRuntime(glue, RTSTUB_ID(StoreICByValue), { obj, *keyVar, value, IntToTaggedInt(Int32(0)) });
4416         Jump(&exit);
4417     }
4418     Bind(&exit);
4419     env->SubCfgExit();
4420 }
4421 
FastSetPropertyByIndex(GateRef glue,GateRef obj,GateRef index,GateRef value)4422 void StubBuilder::FastSetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, GateRef value)
4423 {
4424     auto env = GetEnvironment();
4425     Label entry(env);
4426     env->SubCfgEntry(&entry);
4427     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4428     Label exit(env);
4429     Label fastPath(env);
4430     Label slowPath(env);
4431 
4432     Branch(TaggedIsHeapObject(obj), &fastPath, &slowPath);
4433     Bind(&fastPath);
4434     {
4435         result = SetPropertyByIndex(glue, obj, index, value, false);
4436         Label notHole(env);
4437         Branch(TaggedIsHole(*result), &slowPath, &exit);
4438     }
4439     Bind(&slowPath);
4440     {
4441         result = CallRuntime(glue, RTSTUB_ID(StObjByIndex),
4442             { obj, IntToTaggedInt(index), value });
4443         Jump(&exit);
4444     }
4445     Bind(&exit);
4446     env->SubCfgExit();
4447 }
4448 
GetCtorPrototype(GateRef ctor)4449 GateRef StubBuilder::GetCtorPrototype(GateRef ctor)
4450 {
4451     auto env = GetEnvironment();
4452     Label entry(env);
4453     env->SubCfgEntry(&entry);
4454     DEFVARIABLE(constructorPrototype, VariableType::JS_ANY(), Undefined());
4455     Label exit(env);
4456     Label isHClass(env);
4457     Label isPrototype(env);
4458     Label isHeapObject(env);
4459     Label notHeapObject(env);
4460 
4461     GateRef ctorProtoOrHC = Load(VariableType::JS_POINTER(), ctor, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
4462     Branch(TaggedIsHeapObject(ctorProtoOrHC), &isHeapObject, &notHeapObject);
4463     Bind(&notHeapObject);
4464     {
4465         // If go slow path, return hole.
4466         constructorPrototype = Hole();
4467         Jump(&exit);
4468     }
4469     Bind(&isHeapObject);
4470     Branch(IsJSHClass(ctorProtoOrHC), &isHClass, &isPrototype);
4471     Bind(&isHClass);
4472     {
4473         constructorPrototype = Load(VariableType::JS_POINTER(), ctorProtoOrHC, IntPtr(JSHClass::PROTOTYPE_OFFSET));
4474         Jump(&exit);
4475     }
4476     Bind(&isPrototype);
4477     {
4478         constructorPrototype = ctorProtoOrHC;
4479         Jump(&exit);
4480     }
4481 
4482     Bind(&exit);
4483     auto ret = *constructorPrototype;
4484     env->SubCfgExit();
4485     return ret;
4486 }
4487 
OrdinaryHasInstance(GateRef glue,GateRef target,GateRef obj)4488 GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj)
4489 {
4490     auto env = GetEnvironment();
4491     Label entry(env);
4492     env->SubCfgEntry(&entry);
4493     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4494     Label exit(env);
4495     DEFVARIABLE(object, VariableType::JS_ANY(), obj);
4496 
4497     // 1. If IsCallable(C) is false, return false.
4498     Label targetIsCallable(env);
4499     Label targetNotCallable(env);
4500     Branch(IsCallable(target), &targetIsCallable, &targetNotCallable);
4501     Bind(&targetNotCallable);
4502     {
4503         result = TaggedFalse();
4504         Jump(&exit);
4505     }
4506     Bind(&targetIsCallable);
4507     {
4508         // 2. If C has a [[BoundTargetFunction]] internal slot, then
4509         //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
4510         //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
4511         Label targetIsBoundFunction(env);
4512         Label targetNotBoundFunction(env);
4513         Branch(IsBoundFunction(target), &targetIsBoundFunction, &targetNotBoundFunction);
4514         Bind(&targetIsBoundFunction);
4515         {
4516             GateRef boundTarget = Load(VariableType::JS_ANY(), target, IntPtr(JSBoundFunction::BOUND_TARGET_OFFSET));
4517             result = CallRuntime(glue, RTSTUB_ID(InstanceOf), { obj, boundTarget });
4518             Jump(&exit);
4519         }
4520         Bind(&targetNotBoundFunction);
4521         {
4522             // 3. If Type(O) is not Object, return false
4523             Label objIsHeapObject(env);
4524             Label objIsEcmaObject(env);
4525             Label objNotEcmaObject(env);
4526             Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotEcmaObject);
4527             Bind(&objIsHeapObject);
4528             Branch(TaggedObjectIsEcmaObject(obj), &objIsEcmaObject, &objNotEcmaObject);
4529             Bind(&objNotEcmaObject);
4530             {
4531                 result = TaggedFalse();
4532                 Jump(&exit);
4533             }
4534             Bind(&objIsEcmaObject);
4535             {
4536                 // 4. Let P be Get(C, "prototype").
4537                 Label getCtorProtoSlowPath(env);
4538                 Label ctorIsJSFunction(env);
4539                 Label gotCtorPrototype(env);
4540                 DEFVARIABLE(constructorPrototype, VariableType::JS_ANY(), Undefined());
4541                 Branch(IsJSFunction(target), &ctorIsJSFunction, &getCtorProtoSlowPath);
4542                 Bind(&ctorIsJSFunction);
4543                 {
4544                     Label getCtorProtoFastPath(env);
4545                     GateRef ctorProtoOrHC = Load(VariableType::JS_POINTER(), target,
4546                                                  IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
4547 
4548                     Branch(TaggedIsHole(ctorProtoOrHC), &getCtorProtoSlowPath, &getCtorProtoFastPath);
4549                     Bind(&getCtorProtoFastPath);
4550                     {
4551                         constructorPrototype = GetCtorPrototype(target);
4552                         Branch(TaggedIsHole(*constructorPrototype), &getCtorProtoSlowPath, &gotCtorPrototype);
4553                     }
4554                 }
4555                 Bind(&getCtorProtoSlowPath);
4556                 {
4557                     auto prototypeString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
4558                                                                   ConstantIndex::PROTOTYPE_STRING_INDEX);
4559                     constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation());
4560                     Jump(&gotCtorPrototype);
4561                 }
4562                 Bind(&gotCtorPrototype);
4563 
4564                 // 5. ReturnIfAbrupt(P).
4565                 // no throw exception, so needn't return
4566                 Label isPendingException(env);
4567                 Label noPendingException(env);
4568                 Branch(HasPendingException(glue), &isPendingException, &noPendingException);
4569                 Bind(&isPendingException);
4570                 {
4571                     result = Exception();
4572                     Jump(&exit);
4573                 }
4574                 Bind(&noPendingException);
4575 
4576                 // 6. If Type(P) is not Object, throw a TypeError exception.
4577                 Label constructorPrototypeIsHeapObject(env);
4578                 Label constructorPrototypeIsEcmaObject(env);
4579                 Label constructorPrototypeNotEcmaObject(env);
4580                 Branch(TaggedIsHeapObject(*constructorPrototype), &constructorPrototypeIsHeapObject,
4581                     &constructorPrototypeNotEcmaObject);
4582                 Bind(&constructorPrototypeIsHeapObject);
4583                 Branch(TaggedObjectIsEcmaObject(*constructorPrototype), &constructorPrototypeIsEcmaObject,
4584                     &constructorPrototypeNotEcmaObject);
4585                 Bind(&constructorPrototypeNotEcmaObject);
4586                 {
4587                     GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InstanceOfErrorTargetNotCallable));
4588                     CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
4589                     result = Exception();
4590                     Jump(&exit);
4591                 }
4592                 Bind(&constructorPrototypeIsEcmaObject);
4593                 {
4594                     // 7. Repeat
4595                     //    a.Let O be O.[[GetPrototypeOf]]().
4596                     //    b.ReturnIfAbrupt(O).
4597                     //    c.If O is null, return false.
4598                     //    d.If SameValue(P, O) is true, return true.
4599                     Label loopHead(env);
4600                     Label loopEnd(env);
4601                     Label afterLoop(env);
4602                     Label strictEqual1(env);
4603                     Label notStrictEqual1(env);
4604                     Label shouldReturn(env);
4605                     Label shouldContinue(env);
4606 
4607                     Branch(TaggedIsNull(*object), &afterLoop, &loopHead);
4608                     LoopBegin(&loopHead);
4609                     {
4610                         GateRef isEqual = SameValue(glue, *object, *constructorPrototype);
4611 
4612                         Branch(isEqual, &strictEqual1, &notStrictEqual1);
4613                         Bind(&strictEqual1);
4614                         {
4615                             result = TaggedTrue();
4616                             Jump(&exit);
4617                         }
4618                         Bind(&notStrictEqual1);
4619                         {
4620                             object = GetPrototype(glue, *object);
4621 
4622                             Branch(HasPendingException(glue), &shouldReturn, &shouldContinue);
4623                             Bind(&shouldReturn);
4624                             {
4625                                 result = Exception();
4626                                 Jump(&exit);
4627                             }
4628                         }
4629                         Bind(&shouldContinue);
4630                         Branch(TaggedIsNull(*object), &afterLoop, &loopEnd);
4631                     }
4632                     Bind(&loopEnd);
4633                     LoopEnd(&loopHead);
4634                     Bind(&afterLoop);
4635                     {
4636                         result = TaggedFalse();
4637                         Jump(&exit);
4638                     }
4639                 }
4640             }
4641         }
4642     }
4643     Bind(&exit);
4644     auto ret = *result;
4645     env->SubCfgExit();
4646     return ret;
4647 }
4648 
GetPrototype(GateRef glue,GateRef object)4649 GateRef StubBuilder::GetPrototype(GateRef glue, GateRef object)
4650 {
4651     auto env = GetEnvironment();
4652     Label entry(env);
4653     env->SubCfgEntry(&entry);
4654     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
4655     Label exit(env);
4656     Label objectIsHeapObject(env);
4657     Label objectIsEcmaObject(env);
4658     Label objectNotEcmaObject(env);
4659 
4660     Branch(TaggedIsHeapObject(object), &objectIsHeapObject, &objectNotEcmaObject);
4661     Bind(&objectIsHeapObject);
4662     Branch(TaggedObjectIsEcmaObject(object), &objectIsEcmaObject, &objectNotEcmaObject);
4663     Bind(&objectNotEcmaObject);
4664     {
4665         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotGetNotEcmaObject));
4666         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
4667         CallRuntime(glue, RTSTUB_ID(Dump), { object });
4668         result = Exception();
4669         Jump(&exit);
4670     }
4671     Bind(&objectIsEcmaObject);
4672     {
4673         Label objectIsJsProxy(env);
4674         Label objectNotIsJsProxy(env);
4675         Branch(IsJsProxy(object), &objectIsJsProxy, &objectNotIsJsProxy);
4676         Bind(&objectIsJsProxy);
4677         {
4678             result = CallRuntime(glue, RTSTUB_ID(CallGetPrototype), { object });
4679             Jump(&exit);
4680         }
4681         Bind(&objectNotIsJsProxy);
4682         {
4683             result = GetPrototypeFromHClass(LoadHClass(object));
4684             Jump(&exit);
4685         }
4686     }
4687     Bind(&exit);
4688     auto ret = *result;
4689     env->SubCfgExit();
4690     return ret;
4691 }
4692 
SameValue(GateRef glue,GateRef left,GateRef right)4693 GateRef StubBuilder::SameValue(GateRef glue, GateRef left, GateRef right)
4694 {
4695     auto env = GetEnvironment();
4696     Label entry(env);
4697     env->SubCfgEntry(&entry);
4698     DEFVARIABLE(result, VariableType::BOOL(), False());
4699     Label exit(env);
4700     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
4701     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
4702     Label strictEqual(env);
4703     Label stringEqualCheck(env);
4704     Label stringCompare(env);
4705     Label bigIntEqualCheck(env);
4706     Label numberEqualCheck1(env);
4707 
4708     Branch(Equal(left, right), &strictEqual, &numberEqualCheck1);
4709     Bind(&strictEqual);
4710     {
4711         result = True();
4712         Jump(&exit);
4713     }
4714     Bind(&numberEqualCheck1);
4715     {
4716         Label leftIsNumber(env);
4717         Label leftIsNotNumber(env);
4718         Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
4719         Bind(&leftIsNumber);
4720         {
4721             Label rightIsNumber(env);
4722             Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4723             Bind(&rightIsNumber);
4724             {
4725                 Label numberEqualCheck2(env);
4726                 Label leftIsInt(env);
4727                 Label leftNotInt(env);
4728                 Label getRight(env);
4729                 Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
4730                 Bind(&leftIsInt);
4731                 {
4732                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4733                     Jump(&getRight);
4734                 }
4735                 Bind(&leftNotInt);
4736                 {
4737                     doubleLeft = GetDoubleOfTDouble(left);
4738                     Jump(&getRight);
4739                 }
4740                 Bind(&getRight);
4741                 {
4742                     Label rightIsInt(env);
4743                     Label rightNotInt(env);
4744                     Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
4745                     Bind(&rightIsInt);
4746                     {
4747                         doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4748                         Jump(&numberEqualCheck2);
4749                     }
4750                     Bind(&rightNotInt);
4751                     {
4752                         doubleRight = GetDoubleOfTDouble(right);
4753                         Jump(&numberEqualCheck2);
4754                     }
4755                 }
4756                 Bind(&numberEqualCheck2);
4757                 {
4758                     Label boolAndCheck(env);
4759                     Label signbitCheck(env);
4760                     Branch(DoubleEqual(*doubleLeft, *doubleRight), &signbitCheck, &boolAndCheck);
4761                     Bind(&signbitCheck);
4762                     {
4763                         GateRef leftEncoding = CastDoubleToInt64(*doubleLeft);
4764                         GateRef RightEncoding = CastDoubleToInt64(*doubleRight);
4765                         Label leftIsMinusZero(env);
4766                         Label leftNotMinusZero(env);
4767                         Branch(Int64Equal(leftEncoding, Int64(base::MINUS_ZERO_BITS)),
4768                             &leftIsMinusZero, &leftNotMinusZero);
4769                         Bind(&leftIsMinusZero);
4770                         {
4771                             Label rightIsMinusZero(env);
4772                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &rightIsMinusZero, &exit);
4773                             Bind(&rightIsMinusZero);
4774                             {
4775                                 result = True();
4776                                 Jump(&exit);
4777                             }
4778                         }
4779                         Bind(&leftNotMinusZero);
4780                         {
4781                             Label rightNotMinusZero(env);
4782                             Branch(Int64Equal(RightEncoding, Int64(base::MINUS_ZERO_BITS)), &exit, &rightNotMinusZero);
4783                             Bind(&rightNotMinusZero);
4784                             {
4785                                 result = True();
4786                                 Jump(&exit);
4787                             }
4788                         }
4789                     }
4790                     Bind(&boolAndCheck);
4791                     {
4792                         result = BoolAnd(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight));
4793                         Jump(&exit);
4794                     }
4795                 }
4796             }
4797         }
4798         Bind(&leftIsNotNumber);
4799         Branch(TaggedIsNumber(right), &exit, &stringEqualCheck);
4800         Bind(&stringEqualCheck);
4801         Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
4802         Bind(&stringCompare);
4803         {
4804             result = FastStringEqual(glue, left, right);
4805             Jump(&exit);
4806         }
4807         Bind(&bigIntEqualCheck);
4808         {
4809             Label leftIsBigInt(env);
4810             Label leftIsNotBigInt(env);
4811             Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
4812             Bind(&leftIsBigInt);
4813             {
4814                 Label rightIsBigInt(env);
4815                 Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
4816                 Bind(&rightIsBigInt);
4817                 result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
4818                 Jump(&exit);
4819             }
4820         }
4821     }
4822     Bind(&exit);
4823     auto ret = *result;
4824     env->SubCfgExit();
4825     return ret;
4826 }
4827 
SameValueZero(GateRef glue,GateRef left,GateRef right)4828 GateRef StubBuilder::SameValueZero(GateRef glue, GateRef left, GateRef right)
4829 {
4830     auto env = GetEnvironment();
4831     Label entry(env);
4832     env->SubCfgEntry(&entry);
4833     DEFVARIABLE(result, VariableType::BOOL(), False());
4834     Label exit(env);
4835     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
4836     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
4837     Label strictEqual(env);
4838     Label stringEqualCheck(env);
4839     Label stringCompare(env);
4840     Label bigIntEqualCheck(env);
4841     Label numberEqualCheck1(env);
4842 
4843     Branch(Equal(left, right), &strictEqual, &numberEqualCheck1);
4844     Bind(&strictEqual);
4845     {
4846         result = True();
4847         Jump(&exit);
4848     }
4849     Bind(&numberEqualCheck1);
4850     {
4851         Label leftIsNumber(env);
4852         Label leftIsNotNumber(env);
4853         Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
4854         Bind(&leftIsNumber);
4855         {
4856             Label rightIsNumber(env);
4857             Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
4858             Bind(&rightIsNumber);
4859             {
4860                 Label numberEqualCheck2(env);
4861                 Label leftIsInt(env);
4862                 Label leftNotInt(env);
4863                 Label getRight(env);
4864                 Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
4865                 Bind(&leftIsInt);
4866                 {
4867                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
4868                     Jump(&getRight);
4869                 }
4870                 Bind(&leftNotInt);
4871                 {
4872                     doubleLeft = GetDoubleOfTDouble(left);
4873                     Jump(&getRight);
4874                 }
4875                 Bind(&getRight);
4876                 {
4877                     Label rightIsInt(env);
4878                     Label rightNotInt(env);
4879                     Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
4880                     Bind(&rightIsInt);
4881                     {
4882                         doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
4883                         Jump(&numberEqualCheck2);
4884                     }
4885                     Bind(&rightNotInt);
4886                     {
4887                         doubleRight = GetDoubleOfTDouble(right);
4888                         Jump(&numberEqualCheck2);
4889                     }
4890                 }
4891                 Bind(&numberEqualCheck2);
4892                 {
4893                     Label nanCheck(env);
4894                     Label doubleEqual(env);
4895                     Branch(DoubleEqual(*doubleLeft, *doubleRight), &doubleEqual, &nanCheck);
4896                     Bind(&doubleEqual);
4897                     {
4898                         result = True();
4899                         Jump(&exit);
4900                     }
4901                     Bind(&nanCheck);
4902                     {
4903                         result = BoolAnd(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight));
4904                         Jump(&exit);
4905                     }
4906                 }
4907             }
4908         }
4909         Bind(&leftIsNotNumber);
4910         Branch(TaggedIsNumber(right), &exit, &stringEqualCheck);
4911         Bind(&stringEqualCheck);
4912         Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
4913         Bind(&stringCompare);
4914         {
4915             result = FastStringEqual(glue, left, right);
4916             Jump(&exit);
4917         }
4918         Bind(&bigIntEqualCheck);
4919         {
4920             Label leftIsBigInt(env);
4921             Label leftIsNotBigInt(env);
4922             Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
4923             Bind(&leftIsBigInt);
4924             {
4925                 Label rightIsBigInt(env);
4926                 Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
4927                 Bind(&rightIsBigInt);
4928                 result = CallNGCRuntime(glue, RTSTUB_ID(BigIntSameValueZero), { left, right });
4929                 Jump(&exit);
4930             }
4931         }
4932     }
4933     Bind(&exit);
4934     auto ret = *result;
4935     env->SubCfgExit();
4936     return ret;
4937 }
4938 
FastStringEqual(GateRef glue,GateRef left,GateRef right)4939 GateRef StubBuilder::FastStringEqual(GateRef glue, GateRef left, GateRef right)
4940 {
4941     auto env = GetEnvironment();
4942     Label entry(env);
4943     env->SubCfgEntry(&entry);
4944     DEFVARIABLE(result, VariableType::BOOL(), False());
4945     Label exit(env);
4946     Label hashcodeCompare(env);
4947     Label contentsCompare(env);
4948     Label lenEqualOneCheck(env);
4949     Label lenIsOne(env);
4950     Branch(Int32Equal(GetLengthFromString(left), GetLengthFromString(right)), &lenEqualOneCheck, &exit);
4951     Bind(&lenEqualOneCheck);
4952     Branch(Int32Equal(GetLengthFromString(left), Int32(1)), &lenIsOne, &hashcodeCompare);
4953     Bind(&lenIsOne);
4954     {
4955         Label leftFlattenFastPath(env);
4956         FlatStringStubBuilder leftFlat(this);
4957         leftFlat.FlattenString(glue, left, &leftFlattenFastPath);
4958         Bind(&leftFlattenFastPath);
4959         {
4960             Label rightFlattenFastPath(env);
4961             FlatStringStubBuilder rightFlat(this);
4962             rightFlat.FlattenString(glue, right, &rightFlattenFastPath);
4963             Bind(&rightFlattenFastPath);
4964             {
4965                 BuiltinsStringStubBuilder stringBuilder(this);
4966                 StringInfoGateRef leftStrInfoGate(&leftFlat);
4967                 StringInfoGateRef rightStrInfoGate(&rightFlat);
4968                 GateRef leftStrToInt = stringBuilder.StringAt(leftStrInfoGate, Int32(0));
4969                 GateRef rightStrToInt = stringBuilder.StringAt(rightStrInfoGate, Int32(0));
4970                 result = Equal(leftStrToInt, rightStrToInt);
4971                 Jump(&exit);
4972             }
4973         }
4974     }
4975 
4976     Bind(&hashcodeCompare);
4977     Label leftNotNeg(env);
4978     GateRef leftHash = TryGetHashcodeFromString(left);
4979     GateRef rightHash = TryGetHashcodeFromString(right);
4980     Branch(Int64Equal(leftHash, Int64(-1)), &contentsCompare, &leftNotNeg);
4981     Bind(&leftNotNeg);
4982     {
4983         Label rightNotNeg(env);
4984         Branch(Int64Equal(rightHash, Int64(-1)), &contentsCompare, &rightNotNeg);
4985         Bind(&rightNotNeg);
4986         Branch(Int64Equal(leftHash, rightHash), &contentsCompare, &exit);
4987     }
4988 
4989     Bind(&contentsCompare);
4990     {
4991         GateRef stringEqual = CallRuntime(glue, RTSTUB_ID(StringEqual), { left, right });
4992         result = Equal(stringEqual, TaggedTrue());
4993         Jump(&exit);
4994     }
4995 
4996     Bind(&exit);
4997     auto ret = *result;
4998     env->SubCfgExit();
4999     return ret;
5000 }
5001 
FastStrictEqual(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5002 GateRef StubBuilder::FastStrictEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5003 {
5004     auto env = GetEnvironment();
5005     Label entry(env);
5006     env->SubCfgEntry(&entry);
5007     DEFVARIABLE(result, VariableType::BOOL(), False());
5008     Label strictEqual(env);
5009     Label leftIsNumber(env);
5010     Label leftIsNotNumber(env);
5011     Label sameVariableCheck(env);
5012     Label stringEqualCheck(env);
5013     Label stringCompare(env);
5014     Label bigIntEqualCheck(env);
5015     Label exit(env);
5016     Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
5017     Bind(&leftIsNumber);
5018     {
5019         Label rightIsNumber(env);
5020         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
5021         Bind(&rightIsNumber);
5022         {
5023             DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
5024             DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
5025             DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::IntType()));
5026             Label leftIsInt(env);
5027             Label leftNotInt(env);
5028             Label getRight(env);
5029             Label numberEqualCheck(env);
5030 
5031             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
5032             Bind(&leftIsInt);
5033             {
5034                 doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
5035                 Jump(&getRight);
5036             }
5037             Bind(&leftNotInt);
5038             {
5039                 curType = Int32(PGOSampleType::DoubleType());
5040                 doubleLeft = GetDoubleOfTDouble(left);
5041                 Jump(&getRight);
5042             }
5043             Bind(&getRight);
5044             {
5045                 Label rightIsInt(env);
5046                 Label rightNotInt(env);
5047                 Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
5048                 Bind(&rightIsInt);
5049                 {
5050                     GateRef type = Int32(PGOSampleType::IntType());
5051                     COMBINE_TYPE_CALL_BACK(curType, type);
5052                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
5053                     Jump(&numberEqualCheck);
5054                 }
5055                 Bind(&rightNotInt);
5056                 {
5057                     GateRef type = Int32(PGOSampleType::DoubleType());
5058                     COMBINE_TYPE_CALL_BACK(curType, type);
5059                     doubleRight = GetDoubleOfTDouble(right);
5060                     Jump(&numberEqualCheck);
5061                 }
5062             }
5063             Bind(&numberEqualCheck);
5064             {
5065                 Label doubleEqualCheck(env);
5066                 Branch(BoolOr(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight)), &exit, &doubleEqualCheck);
5067                 Bind(&doubleEqualCheck);
5068                 {
5069                     result = DoubleEqual(*doubleLeft, *doubleRight);
5070                     Jump(&exit);
5071                 }
5072             }
5073         }
5074     }
5075     Bind(&leftIsNotNumber);
5076     Branch(TaggedIsNumber(right), &exit, &sameVariableCheck);
5077     Bind(&sameVariableCheck);
5078     Branch(Equal(left, right), &strictEqual, &stringEqualCheck);
5079     Bind(&stringEqualCheck);
5080     Branch(BothAreString(left, right), &stringCompare, &bigIntEqualCheck);
5081     Bind(&stringCompare);
5082     {
5083         callback.ProfileOpType(Int32(PGOSampleType::StringType()));
5084         result = FastStringEqual(glue, left, right);
5085         Jump(&exit);
5086     }
5087     Bind(&bigIntEqualCheck);
5088     {
5089         Label leftIsBigInt(env);
5090         Label leftIsNotBigInt(env);
5091         Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
5092         Bind(&leftIsBigInt);
5093         {
5094             Label rightIsBigInt(env);
5095             Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
5096             Bind(&rightIsBigInt);
5097             callback.ProfileOpType(Int32(PGOSampleType::BigIntType()));
5098             result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
5099             Jump(&exit);
5100         }
5101     }
5102     Bind(&strictEqual);
5103     {
5104         callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
5105         result = True();
5106         Jump(&exit);
5107     }
5108     Bind(&exit);
5109     auto ret = *result;
5110     env->SubCfgExit();
5111     return ret;
5112 }
5113 
FastEqual(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5114 GateRef StubBuilder::FastEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5115 {
5116     auto env = GetEnvironment();
5117     Label entry(env);
5118     env->SubCfgEntry(&entry);
5119     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5120     Label leftEqualRight(env);
5121     Label leftNotEqualRight(env);
5122     Label exit(env);
5123     Branch(Equal(left, right), &leftEqualRight, &leftNotEqualRight);
5124     Bind(&leftEqualRight);
5125     {
5126         Label leftIsDouble(env);
5127         Label leftNotDoubleOrLeftNotNan(env);
5128         Branch(TaggedIsDouble(left), &leftIsDouble, &leftNotDoubleOrLeftNotNan);
5129         Bind(&leftIsDouble);
5130         {
5131             callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
5132             GateRef doubleLeft = GetDoubleOfTDouble(left);
5133             Label leftIsNan(env);
5134             Label leftIsNotNan(env);
5135             Branch(DoubleIsNAN(doubleLeft), &leftIsNan, &leftIsNotNan);
5136             Bind(&leftIsNan);
5137             {
5138                 result = TaggedFalse();
5139                 Jump(&exit);
5140             }
5141             Bind(&leftIsNotNan);
5142             {
5143                 result = TaggedTrue();
5144                 Jump(&exit);
5145             }
5146         }
5147         Bind(&leftNotDoubleOrLeftNotNan);
5148         {
5149             // Collect the type of left value
5150             result = TaggedTrue();
5151             if (callback.IsEmpty()) {
5152                 Jump(&exit);
5153             } else {
5154                 Label leftIsInt(env);
5155                 Label leftIsNotInt(env);
5156                 Branch(TaggedIsInt(left), &leftIsInt, &leftIsNotInt);
5157                 Bind(&leftIsInt);
5158                 {
5159                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
5160                     Jump(&exit);
5161                 }
5162                 Bind(&leftIsNotInt);
5163                 {
5164                     Label leftIsString(env);
5165                     Label leftIsNotString(env);
5166                     Branch(TaggedIsString(left), &leftIsString, &leftIsNotString);
5167                     Bind(&leftIsString);
5168                     {
5169                         callback.ProfileOpType(Int32(PGOSampleType::StringType()));
5170                         Jump(&exit);
5171                     }
5172                     Bind(&leftIsNotString);
5173                     {
5174                         callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
5175                         Jump(&exit);
5176                     }
5177                 }
5178             }
5179         }
5180     }
5181     Bind(&leftNotEqualRight);
5182     {
5183         Label leftIsNumber(env);
5184         Label leftNotNumberOrLeftNotIntOrRightNotInt(env);
5185         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrLeftNotIntOrRightNotInt);
5186         Bind(&leftIsNumber);
5187         {
5188             Label leftIsInt(env);
5189             Branch(TaggedIsInt(left), &leftIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
5190             Bind(&leftIsInt);
5191             {
5192                 Label rightIsInt(env);
5193                 Branch(TaggedIsInt(right), &rightIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
5194                 Bind(&rightIsInt);
5195                 {
5196                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
5197                     result = TaggedFalse();
5198                     Jump(&exit);
5199                 }
5200             }
5201         }
5202         Bind(&leftNotNumberOrLeftNotIntOrRightNotInt);
5203         {
5204             DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
5205             Label rightIsUndefinedOrNull(env);
5206             Label rightIsNotUndefinedOrNull(env);
5207             Branch(TaggedIsUndefinedOrNull(right), &rightIsUndefinedOrNull, &rightIsNotUndefinedOrNull);
5208             Bind(&rightIsUndefinedOrNull);
5209             {
5210                 curType = Int32(PGOSampleType::UndefineOrNullType());
5211                 Label leftIsHeapObject(env);
5212                 Label leftNotHeapObject(env);
5213                 Branch(TaggedIsHeapObject(left), &leftIsHeapObject, &leftNotHeapObject);
5214                 Bind(&leftIsHeapObject);
5215                 {
5216                     GateRef type = Int32(PGOSampleType::HeapObjectType());
5217                     COMBINE_TYPE_CALL_BACK(curType, type);
5218                     result = TaggedFalse();
5219                     Jump(&exit);
5220                 }
5221                 Bind(&leftNotHeapObject);
5222                 {
5223                     Label leftIsUndefinedOrNull(env);
5224                     Label leftIsNotUndefinedOrNull(env);
5225                     // if left is undefined or null, then result is true, otherwise result is false
5226                     Branch(TaggedIsUndefinedOrNull(left), &leftIsUndefinedOrNull, &leftIsNotUndefinedOrNull);
5227                     Bind(&leftIsUndefinedOrNull);
5228                     {
5229                         callback.ProfileOpType(*curType);
5230                         result = TaggedTrue();
5231                         Jump(&exit);
5232                     }
5233                     Bind(&leftIsNotUndefinedOrNull);
5234                     {
5235                         callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
5236                         result = TaggedFalse();
5237                         Jump(&exit);
5238                     }
5239                 }
5240             }
5241             Bind(&rightIsNotUndefinedOrNull);
5242             {
5243                 Label leftIsUndefinedOrNull(env);
5244                 Label leftIsNotUndefinedOrNull(env);
5245                 Branch(TaggedIsUndefinedOrNull(right), &leftIsUndefinedOrNull, &leftIsNotUndefinedOrNull);
5246                 // If left is undefined or null, result will always be false
5247                 // because we can ensure that right is not null here.
5248                 Bind(&leftIsUndefinedOrNull);
5249                 {
5250                     callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
5251                     result = TaggedFalse();
5252                     Jump(&exit);
5253                 }
5254                 Bind(&leftIsNotUndefinedOrNull);
5255                 {
5256                     Label leftIsBool(env);
5257                     Label leftNotBoolOrRightNotSpecial(env);
5258                     Branch(TaggedIsBoolean(left), &leftIsBool, &leftNotBoolOrRightNotSpecial);
5259                     Bind(&leftIsBool);
5260                     {
5261                         curType = Int32(PGOSampleType::BooleanType());
5262                         Label rightIsSpecial(env);
5263                         Branch(TaggedIsSpecial(right), &rightIsSpecial, &leftNotBoolOrRightNotSpecial);
5264                         Bind(&rightIsSpecial);
5265                         {
5266                             GateRef type = Int32(PGOSampleType::SpecialType());
5267                             COMBINE_TYPE_CALL_BACK(curType, type);
5268                             result = TaggedFalse();
5269                             Jump(&exit);
5270                         }
5271                     }
5272                     Bind(&leftNotBoolOrRightNotSpecial);
5273                     {
5274                         Label bothString(env);
5275                         Label eitherNotString(env);
5276                         Branch(BothAreString(left, right), &bothString, &eitherNotString);
5277                         Bind(&bothString);
5278                         {
5279                             callback.ProfileOpType(Int32(PGOSampleType::StringType()));
5280                             Label stringEqual(env);
5281                             Label stringNotEqual(env);
5282                             Branch(FastStringEqual(glue, left, right), &stringEqual, &stringNotEqual);
5283                             Bind(&stringEqual);
5284                             result = TaggedTrue();
5285                             Jump(&exit);
5286                             Bind(&stringNotEqual);
5287                             result = TaggedFalse();
5288                             Jump(&exit);
5289                         }
5290                         Bind(&eitherNotString);
5291                         callback.ProfileOpType(Int32(PGOSampleType::AnyType()));
5292                         Jump(&exit);
5293                     }
5294                 }
5295             }
5296         }
5297     }
5298     Bind(&exit);
5299     auto ret = *result;
5300     env->SubCfgExit();
5301     return ret;
5302 }
5303 
FastToBoolean(GateRef value,bool flag)5304 GateRef StubBuilder::FastToBoolean(GateRef value, bool flag)
5305 {
5306     auto env = GetEnvironment();
5307     Label entry(env);
5308     env->SubCfgEntry(&entry);
5309     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5310     Label exit(env);
5311 
5312     Label isSpecial(env);
5313     Label notSpecial(env);
5314     Label isNumber(env);
5315     Label isInt(env);
5316     Label isDouble(env);
5317     Label notNumber(env);
5318     Label notNan(env);
5319     Label isString(env);
5320     Label notString(env);
5321     Label isBigint(env);
5322     Label lengthIsOne(env);
5323     Label returnTrue(env);
5324     Label returnFalse(env);
5325 
5326     Branch(TaggedIsSpecial(value), &isSpecial, &notSpecial);
5327     Bind(&isSpecial);
5328     {
5329         Branch(TaggedIsTrue(value), &returnTrue, &returnFalse);
5330     }
5331     Bind(&notSpecial);
5332     {
5333         Branch(TaggedIsNumber(value), &isNumber, &notNumber);
5334         Bind(&notNumber);
5335         {
5336             Branch(IsString(value), &isString, &notString);
5337             Bind(&isString);
5338             {
5339                 auto len = GetLengthFromString(value);
5340                 Branch(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue);
5341             }
5342             Bind(&notString);
5343             Branch(TaggedObjectIsBigInt(value), &isBigint, &returnTrue);
5344             Bind(&isBigint);
5345             {
5346                 auto len = Load(VariableType::INT32(), value, IntPtr(BigInt::LENGTH_OFFSET));
5347                 Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &returnTrue);
5348                 Bind(&lengthIsOne);
5349                 {
5350                     auto data = PtrAdd(value, IntPtr(BigInt::DATA_OFFSET));
5351                     auto data0 = Load(VariableType::INT32(), data, Int32(0));
5352                     Branch(Int32Equal(data0, Int32(0)), &returnFalse, &returnTrue);
5353                 }
5354             }
5355         }
5356         Bind(&isNumber);
5357         {
5358             Branch(TaggedIsInt(value), &isInt, &isDouble);
5359             Bind(&isInt);
5360             {
5361                 auto intValue = GetInt32OfTInt(value);
5362                 Branch(Int32Equal(intValue, Int32(0)), &returnFalse, &returnTrue);
5363             }
5364             Bind(&isDouble);
5365             {
5366                 auto doubleValue = GetDoubleOfTDouble(value);
5367                 Branch(DoubleIsNAN(doubleValue), &returnFalse, &notNan);
5368                 Bind(&notNan);
5369                 Branch(DoubleEqual(doubleValue, Double(0.0)), &returnFalse, &returnTrue);
5370             }
5371         }
5372     }
5373     if (flag == 1) {
5374         Bind(&returnTrue);
5375         {
5376             result = TaggedTrue();
5377             Jump(&exit);
5378         }
5379         Bind(&returnFalse);
5380         {
5381             result = TaggedFalse();
5382             Jump(&exit);
5383         }
5384     } else {
5385         Bind(&returnFalse);
5386         {
5387             result = TaggedTrue();
5388             Jump(&exit);
5389         }
5390         Bind(&returnTrue);
5391         {
5392             result = TaggedFalse();
5393             Jump(&exit);
5394         }
5395     }
5396 
5397     Bind(&exit);
5398     auto ret = *result;
5399     env->SubCfgExit();
5400     return ret;
5401 }
5402 
FastDiv(GateRef left,GateRef right,ProfileOperation callback)5403 GateRef StubBuilder::FastDiv(GateRef left, GateRef right, ProfileOperation callback)
5404 {
5405     auto env = GetEnvironment();
5406     Label entry(env);
5407     env->SubCfgEntry(&entry);
5408     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5409     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
5410     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
5411     DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
5412     Label leftIsNumber(env);
5413     Label leftNotNumberOrRightNotNumber(env);
5414     Label leftIsNumberAndRightIsNumber(env);
5415     Label leftIsDoubleAndRightIsDouble(env);
5416     Label exit(env);
5417     Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
5418     Bind(&leftIsNumber);
5419     {
5420         Label rightIsNumber(env);
5421         Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
5422         Bind(&rightIsNumber);
5423         {
5424             Label leftIsInt(env);
5425             Label leftNotInt(env);
5426             Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
5427             Bind(&leftIsInt);
5428             {
5429                 Label rightIsInt(env);
5430                 Label bailout(env);
5431                 Branch(TaggedIsInt(right), &rightIsInt, &bailout);
5432                 Bind(&rightIsInt);
5433                 {
5434                     result = FastIntDiv(left, right, &bailout, callback);
5435                     Jump(&exit);
5436                 }
5437                 Bind(&bailout);
5438                 {
5439                     curType = Int32(PGOSampleType::IntOverFlowType());
5440                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
5441                     Jump(&leftIsNumberAndRightIsNumber);
5442                 }
5443             }
5444             Bind(&leftNotInt);
5445             {
5446                 curType = Int32(PGOSampleType::DoubleType());
5447                 doubleLeft = GetDoubleOfTDouble(left);
5448                 Jump(&leftIsNumberAndRightIsNumber);
5449             }
5450         }
5451     }
5452     Bind(&leftNotNumberOrRightNotNumber);
5453     {
5454         Jump(&exit);
5455     }
5456     Bind(&leftIsNumberAndRightIsNumber);
5457     {
5458         Label rightIsInt(env);
5459         Label rightNotInt(env);
5460         Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
5461         Bind(&rightIsInt);
5462         {
5463             GateRef type = Int32(PGOSampleType::IntType());
5464             COMBINE_TYPE_CALL_BACK(curType, type);
5465             doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
5466             Jump(&leftIsDoubleAndRightIsDouble);
5467         }
5468         Bind(&rightNotInt);
5469         {
5470             GateRef type = Int32(PGOSampleType::DoubleType());
5471             COMBINE_TYPE_CALL_BACK(curType, type);
5472             doubleRight = GetDoubleOfTDouble(right);
5473             Jump(&leftIsDoubleAndRightIsDouble);
5474         }
5475     }
5476     Bind(&leftIsDoubleAndRightIsDouble);
5477     {
5478         Label rightIsZero(env);
5479         Label rightNotZero(env);
5480         Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZero, &rightNotZero);
5481         Bind(&rightIsZero);
5482         {
5483             Label leftIsZero(env);
5484             Label leftNotZero(env);
5485             Label leftIsZeroOrNan(env);
5486             Label leftNotZeroAndNotNan(env);
5487             Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZero, &leftNotZero);
5488             Bind(&leftIsZero);
5489             {
5490                 Jump(&leftIsZeroOrNan);
5491             }
5492             Bind(&leftNotZero);
5493             {
5494                 Label leftIsNan(env);
5495                 Branch(DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan);
5496                 Bind(&leftIsNan);
5497                 {
5498                     Jump(&leftIsZeroOrNan);
5499                 }
5500             }
5501             Bind(&leftIsZeroOrNan);
5502             {
5503                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
5504                 Jump(&exit);
5505             }
5506             Bind(&leftNotZeroAndNotNan);
5507             {
5508                 GateRef intLeftTmp = CastDoubleToInt64(*doubleLeft);
5509                 GateRef intRightTmp = CastDoubleToInt64(*doubleRight);
5510                 GateRef flagBit = Int64And(Int64Xor(intLeftTmp, intRightTmp), Int64(base::DOUBLE_SIGN_MASK));
5511                 GateRef tmpResult = Int64Xor(flagBit, CastDoubleToInt64(Double(base::POSITIVE_INFINITY)));
5512                 result = DoubleToTaggedDoublePtr(CastInt64ToFloat64(tmpResult));
5513                 Jump(&exit);
5514             }
5515         }
5516         Bind(&rightNotZero);
5517         {
5518             result = DoubleToTaggedDoublePtr(DoubleDiv(*doubleLeft, *doubleRight));
5519             Jump(&exit);
5520         }
5521     }
5522     Bind(&exit);
5523     auto ret = *result;
5524     env->SubCfgExit();
5525     return ret;
5526 }
5527 
5528 template<OpCode Op>
FastBinaryOp(GateRef glue,GateRef left,GateRef right,const BinaryOperation & intOp,const BinaryOperation & floatOp,ProfileOperation callback)5529 GateRef StubBuilder::FastBinaryOp(GateRef glue, GateRef left, GateRef right,
5530                                   const BinaryOperation& intOp,
5531                                   const BinaryOperation& floatOp,
5532                                   ProfileOperation callback)
5533 {
5534     auto env = GetEnvironment();
5535     Label entry(env);
5536     env->SubCfgEntry(&entry);
5537     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5538     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
5539     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
5540 
5541     Label exit(env);
5542     Label doFloatOp(env);
5543     Label doIntOp(env);
5544     Label leftIsNumber(env);
5545     Label rightIsNumber(env);
5546     Label leftIsIntRightIsDouble(env);
5547     Label rightIsInt(env);
5548     Label rightIsDouble(env);
5549     Label checkString(env);
5550     if (Op == OpCode::ADD) {
5551         Branch(TaggedIsNumber(left), &leftIsNumber, &checkString);
5552     } else {
5553         Branch(TaggedIsNumber(left), &leftIsNumber, &exit);
5554     }
5555     Bind(&leftIsNumber);
5556     {
5557         Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
5558         Bind(&rightIsNumber);
5559         {
5560             Label leftIsInt(env);
5561             Label leftIsDouble(env);
5562             Branch(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
5563             Bind(&leftIsInt);
5564             {
5565                 Branch(TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
5566                 Bind(&leftIsIntRightIsDouble);
5567                 {
5568                     callback.ProfileOpType(Int32(PGOSampleType::NumberType()));
5569                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
5570                     doubleRight = GetDoubleOfTDouble(right);
5571                     Jump(&doFloatOp);
5572                 }
5573             }
5574             Bind(&leftIsDouble);
5575             {
5576                 Branch(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
5577                 Bind(&rightIsInt);
5578                 {
5579                     callback.ProfileOpType(Int32(PGOSampleType::NumberType()));
5580                     doubleLeft = GetDoubleOfTDouble(left);
5581                     doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
5582                     Jump(&doFloatOp);
5583                 }
5584                 Bind(&rightIsDouble);
5585                 {
5586                     callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
5587                     doubleLeft = GetDoubleOfTDouble(left);
5588                     doubleRight = GetDoubleOfTDouble(right);
5589                     Jump(&doFloatOp);
5590                 }
5591             }
5592         }
5593     }
5594     if (Op == OpCode::ADD) {
5595         Bind(&checkString);
5596         {
5597             Label stringAdd(env);
5598             Label hasPendingException(env);
5599             GateRef bothString = BoolAnd(TaggedIsString(left), TaggedIsString(right));
5600             Branch(bothString, &stringAdd, &exit);
5601             Bind(&stringAdd);
5602             {
5603                 callback.ProfileOpType(Int32(PGOSampleType::StringType()));
5604                 BuiltinsStringStubBuilder builtinsStringStubBuilder(this);
5605                 result = builtinsStringStubBuilder.StringConcat(glue, left, right);
5606                 Branch(HasPendingException(glue), &hasPendingException, &exit);
5607                 Bind(&hasPendingException);
5608                 result = Exception();
5609                 Jump(&exit);
5610             }
5611         }
5612     }
5613     Bind(&doIntOp);
5614     {
5615         result = intOp(env, left, right);
5616         Jump(&exit);
5617     }
5618     Bind(&doFloatOp);
5619     {
5620         result = floatOp(env, *doubleLeft, *doubleRight);
5621         Jump(&exit);
5622     }
5623     Bind(&exit);
5624     auto ret = *result;
5625     env->SubCfgExit();
5626     return ret;
5627 }
5628 
5629 template<OpCode Op>
FastAddSubAndMul(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5630 GateRef StubBuilder::FastAddSubAndMul(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5631 {
5632     auto intOperation = [=](Environment *env, GateRef left, GateRef right) {
5633         Label entry(env);
5634         env->SubCfgEntry(&entry);
5635         DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5636         Label exit(env);
5637         Label overflow(env);
5638         Label notOverflow(env);
5639         auto res = BinaryOpWithOverflow<Op, MachineType::I32>(GetInt32OfTInt(left), GetInt32OfTInt(right));
5640         GateRef condition = env->GetBuilder()->ExtractValue(MachineType::I1, res, Int32(1));
5641         Branch(condition, &overflow, &notOverflow);
5642         Bind(&overflow);
5643         {
5644             auto doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
5645             auto doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
5646             auto ret = BinaryOp<Op, MachineType::F64>(doubleLeft, doubleRight);
5647             result = DoubleToTaggedDoublePtr(ret);
5648             callback.ProfileOpType(Int32(PGOSampleType::IntOverFlowType()));
5649             Jump(&exit);
5650         }
5651         Bind(&notOverflow);
5652         {
5653             res = env->GetBuilder()->ExtractValue(MachineType::I32, res, Int32(0));
5654             if (Op == OpCode::MUL) {
5655                 Label resultIsZero(env);
5656                 Label returnNegativeZero(env);
5657                 Label returnResult(env);
5658                 Branch(Int32Equal(res, Int32(0)), &resultIsZero, &returnResult);
5659                 Bind(&resultIsZero);
5660                 GateRef leftNegative = Int32LessThan(GetInt32OfTInt(left), Int32(0));
5661                 GateRef rightNegative = Int32LessThan(GetInt32OfTInt(right), Int32(0));
5662                 Branch(BoolOr(leftNegative, rightNegative), &returnNegativeZero, &returnResult);
5663                 Bind(&returnNegativeZero);
5664                 result = DoubleToTaggedDoublePtr(Double(-0.0));
5665                 callback.ProfileOpType(Int32(PGOSampleType::DoubleType()));
5666                 Jump(&exit);
5667                 Bind(&returnResult);
5668                 result = IntToTaggedPtr(res);
5669                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
5670                 Jump(&exit);
5671             } else {
5672                 result = IntToTaggedPtr(res);
5673                 callback.ProfileOpType(Int32(PGOSampleType::IntType()));
5674                 Jump(&exit);
5675             }
5676         }
5677         Bind(&exit);
5678         auto ret = *result;
5679         env->SubCfgExit();
5680         return ret;
5681     };
5682     auto floatOperation = [=]([[maybe_unused]] Environment *env, GateRef left, GateRef right) {
5683         auto res = BinaryOp<Op, MachineType::F64>(left, right);
5684         return DoubleToTaggedDoublePtr(res);
5685     };
5686     return FastBinaryOp<Op>(glue, left, right, intOperation, floatOperation, callback);
5687 }
5688 
FastIntDiv(GateRef left,GateRef right,Label * bailout,ProfileOperation callback)5689 GateRef StubBuilder::FastIntDiv(GateRef left, GateRef right, Label *bailout, ProfileOperation callback)
5690 {
5691     auto env = GetEnvironment();
5692     Label entry(env);
5693     env->SubCfgEntry(&entry);
5694     DEFVARIABLE(intResult, VariableType::INT32(), Int32(0));
5695 
5696     GateRef intLeft = GetInt32OfTInt(left);
5697     GateRef intRight = GetInt32OfTInt(right);
5698     Label exit(env);
5699     Label rightIsNotZero(env);
5700     Label leftIsIntMin(env);
5701     Label leftAndRightIsNotBoundary(env);
5702     Branch(Int32Equal(intRight, Int32(0)), bailout, &rightIsNotZero);
5703     Bind(&rightIsNotZero);
5704     Branch(Int32Equal(intLeft, Int32(INT_MIN)), &leftIsIntMin, &leftAndRightIsNotBoundary);
5705     Bind(&leftIsIntMin);
5706     Branch(Int32Equal(intRight, Int32(-1)), bailout, &leftAndRightIsNotBoundary);
5707     Bind(&leftAndRightIsNotBoundary);
5708     {
5709         Label leftIsZero(env);
5710         Label leftIsNotZero(env);
5711         Branch(Int32Equal(intLeft, Int32(0)), &leftIsZero, &leftIsNotZero);
5712         Bind(&leftIsZero);
5713         {
5714             Branch(Int32LessThan(intRight, Int32(0)), bailout, &leftIsNotZero);
5715         }
5716         Bind(&leftIsNotZero);
5717         {
5718             intResult = Int32Div(intLeft, intRight);
5719             GateRef truncated = Int32Mul(*intResult, intRight);
5720             Branch(Equal(intLeft, truncated), &exit, bailout);
5721         }
5722     }
5723     Bind(&exit);
5724     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
5725     auto ret = IntToTaggedPtr(*intResult);
5726     env->SubCfgExit();
5727     return ret;
5728 }
5729 
FastAdd(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5730 GateRef StubBuilder::FastAdd(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5731 {
5732     return FastAddSubAndMul<OpCode::ADD>(glue, left, right, callback);
5733 }
5734 
FastSub(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5735 GateRef StubBuilder::FastSub(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5736 {
5737     return FastAddSubAndMul<OpCode::SUB>(glue, left, right, callback);
5738 }
5739 
FastMul(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5740 GateRef StubBuilder::FastMul(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5741 {
5742     return FastAddSubAndMul<OpCode::MUL>(glue, left, right, callback);
5743 }
5744 
FastMod(GateRef glue,GateRef left,GateRef right,ProfileOperation callback)5745 GateRef StubBuilder::FastMod(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
5746 {
5747     auto env = GetEnvironment();
5748     Label entry(env);
5749     env->SubCfgEntry(&entry);
5750     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5751     DEFVARIABLE(intLeft, VariableType::INT32(), Int32(0));
5752     DEFVARIABLE(intRight, VariableType::INT32(), Int32(0));
5753     DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
5754     DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
5755     Label leftIsInt(env);
5756     Label leftNotIntOrRightNotInt(env);
5757     Label exit(env);
5758     Branch(TaggedIsInt(left), &leftIsInt, &leftNotIntOrRightNotInt);
5759     Bind(&leftIsInt);
5760     {
5761         Label rightIsInt(env);
5762         Branch(TaggedIsInt(right), &rightIsInt, &leftNotIntOrRightNotInt);
5763         Bind(&rightIsInt);
5764         {
5765             intLeft = GetInt32OfTInt(left);
5766             intRight = GetInt32OfTInt(right);
5767             Label leftGreaterZero(env);
5768             Branch(Int32GreaterThanOrEqual(*intLeft, Int32(0)), &leftGreaterZero, &leftNotIntOrRightNotInt);
5769             Bind(&leftGreaterZero);
5770             {
5771                 Label rightGreaterZero(env);
5772                 Branch(Int32GreaterThan(*intRight, Int32(0)), &rightGreaterZero, &leftNotIntOrRightNotInt);
5773                 Bind(&rightGreaterZero);
5774                 {
5775                     callback.ProfileOpType(Int32(PGOSampleType::IntType()));
5776                     result = IntToTaggedPtr(Int32Mod(*intLeft, *intRight));
5777                     Jump(&exit);
5778                 }
5779             }
5780         }
5781     }
5782     Bind(&leftNotIntOrRightNotInt);
5783     {
5784         Label leftIsNumber(env);
5785         Label leftNotNumberOrRightNotNumber(env);
5786         Label leftIsNumberAndRightIsNumber(env);
5787         Label leftIsDoubleAndRightIsDouble(env);
5788         DEFVARIABLE(curType, VariableType::INT32(), Int32(PGOSampleType::None()));
5789         // less than 0 result should be double
5790         curType = Int32(PGOSampleType::DoubleType());
5791         Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
5792         Bind(&leftIsNumber);
5793         {
5794             Label rightIsNumber(env);
5795             Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
5796             Bind(&rightIsNumber);
5797             {
5798                 Label leftIsInt1(env);
5799                 Label leftNotInt1(env);
5800                 Branch(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
5801                 Bind(&leftIsInt1);
5802                 {
5803                     GateRef type = Int32(PGOSampleType::IntType());
5804                     COMBINE_TYPE_CALL_BACK(curType, type);
5805                     doubleLeft = ChangeInt32ToFloat64(GetInt32OfTInt(left));
5806                     Jump(&leftIsNumberAndRightIsNumber);
5807                 }
5808                 Bind(&leftNotInt1);
5809                 {
5810                     GateRef type = Int32(PGOSampleType::DoubleType());
5811                     COMBINE_TYPE_CALL_BACK(curType, type);
5812                     doubleLeft = GetDoubleOfTDouble(left);
5813                     Jump(&leftIsNumberAndRightIsNumber);
5814                 }
5815             }
5816         }
5817         Bind(&leftNotNumberOrRightNotNumber);
5818         {
5819             Jump(&exit);
5820         }
5821         Bind(&leftIsNumberAndRightIsNumber);
5822         {
5823             Label rightIsInt1(env);
5824             Label rightNotInt1(env);
5825             Branch(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
5826             Bind(&rightIsInt1);
5827             {
5828                 GateRef type = Int32(PGOSampleType::IntType());
5829                 COMBINE_TYPE_CALL_BACK(curType, type);
5830                 doubleRight = ChangeInt32ToFloat64(GetInt32OfTInt(right));
5831                 Jump(&leftIsDoubleAndRightIsDouble);
5832             }
5833             Bind(&rightNotInt1);
5834             {
5835                 GateRef type = Int32(PGOSampleType::DoubleType());
5836                 COMBINE_TYPE_CALL_BACK(curType, type);
5837                 doubleRight = GetDoubleOfTDouble(right);
5838                 Jump(&leftIsDoubleAndRightIsDouble);
5839             }
5840         }
5841         Bind(&leftIsDoubleAndRightIsDouble);
5842         {
5843             Label rightNotZero(env);
5844             Label rightIsZeroOrNanOrLeftIsNanOrInf(env);
5845             Label rightNotZeroAndNanAndLeftNotNanAndInf(env);
5846             Branch(DoubleEqual(*doubleRight, Double(0.0)), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotZero);
5847             Bind(&rightNotZero);
5848             {
5849                 Label rightNotNan(env);
5850                 Branch(DoubleIsNAN(*doubleRight), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotNan);
5851                 Bind(&rightNotNan);
5852                 {
5853                     Label leftNotNan(env);
5854                     Branch(DoubleIsNAN(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &leftNotNan);
5855                     Bind(&leftNotNan);
5856                     {
5857                         Branch(DoubleIsINF(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf,
5858                             &rightNotZeroAndNanAndLeftNotNanAndInf);
5859                     }
5860                 }
5861             }
5862             Bind(&rightIsZeroOrNanOrLeftIsNanOrInf);
5863             {
5864                 result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
5865                 Jump(&exit);
5866             }
5867             Bind(&rightNotZeroAndNanAndLeftNotNanAndInf);
5868             {
5869                 Label leftNotZero(env);
5870                 Label leftIsZeroOrRightIsInf(env);
5871                 Branch(DoubleEqual(*doubleLeft, Double(0.0)), &leftIsZeroOrRightIsInf, &leftNotZero);
5872                 Bind(&leftNotZero);
5873                 {
5874                     Label rightNotInf(env);
5875                     Branch(DoubleIsINF(*doubleRight), &leftIsZeroOrRightIsInf, &rightNotInf);
5876                     Bind(&rightNotInf);
5877                     {
5878                         result = DoubleToTaggedDoublePtr(CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
5879                             { *doubleLeft, *doubleRight }));
5880                         Jump(&exit);
5881                     }
5882                 }
5883                 Bind(&leftIsZeroOrRightIsInf);
5884                 {
5885                     result = DoubleToTaggedDoublePtr(*doubleLeft);
5886                     Jump(&exit);
5887                 }
5888             }
5889         }
5890     }
5891     Bind(&exit);
5892     auto ret = *result;
5893     env->SubCfgExit();
5894     return ret;
5895 }
5896 
GetGlobalOwnProperty(GateRef glue,GateRef receiver,GateRef key,ProfileOperation callback)5897 GateRef StubBuilder::GetGlobalOwnProperty(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
5898 {
5899     auto env = GetEnvironment();
5900     Label entryLabel(env);
5901     env->SubCfgEntry(&entryLabel);
5902     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5903     GateRef properties = GetPropertiesFromJSObject(receiver);
5904     GateRef entry = FindEntryFromNameDictionary(glue, properties, key);
5905     Label notNegtiveOne(env);
5906     Label exit(env);
5907     Branch(Int32NotEqual(entry, Int32(-1)), &notNegtiveOne, &exit);
5908     Bind(&notNegtiveOne);
5909     {
5910         result = GetValueFromGlobalDictionary(properties, entry);
5911         Label callGetter(env);
5912         Branch(TaggedIsAccessor(*result), &callGetter, &exit);
5913         Bind(&callGetter);
5914         {
5915             result = CallGetterHelper(glue, receiver, receiver, *result, callback);
5916             Jump(&exit);
5917         }
5918     }
5919     Bind(&exit);
5920     auto ret = *result;
5921     env->SubCfgExit();
5922     return ret;
5923 }
5924 
GetConstPoolFromFunction(GateRef jsFunc)5925 GateRef StubBuilder::GetConstPoolFromFunction(GateRef jsFunc)
5926 {
5927     return env_->GetBuilder()->GetConstPoolFromFunction(jsFunc);
5928 }
5929 
GetStringFromConstPool(GateRef glue,GateRef constpool,GateRef index)5930 GateRef StubBuilder::GetStringFromConstPool(GateRef glue, GateRef constpool, GateRef index)
5931 {
5932     GateRef module = Circuit::NullGate();
5933     GateRef hirGate = Circuit::NullGate();
5934     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::STRING);
5935 }
5936 
GetMethodFromConstPool(GateRef glue,GateRef constpool,GateRef module,GateRef index)5937 GateRef StubBuilder::GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef module, GateRef index)
5938 {
5939     GateRef hirGate = Circuit::NullGate();
5940     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::METHOD);
5941 }
5942 
GetArrayLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)5943 GateRef StubBuilder::GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
5944 {
5945     GateRef hirGate = Circuit::NullGate();
5946     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index,
5947                                                       ConstPoolType::ARRAY_LITERAL);
5948 }
5949 
GetObjectLiteralFromConstPool(GateRef glue,GateRef constpool,GateRef index,GateRef module)5950 GateRef StubBuilder::GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module)
5951 {
5952     GateRef hirGate = Circuit::NullGate();
5953     return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index,
5954                                                       ConstPoolType::OBJECT_LITERAL);
5955 }
5956 
JSAPIContainerGet(GateRef glue,GateRef receiver,GateRef index)5957 GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef index)
5958 {
5959     auto env = GetEnvironment();
5960     Label entry(env);
5961     env->SubCfgEntry(&entry);
5962     Label exit(env);
5963     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
5964 
5965     GateRef lengthOffset = IntPtr(panda::ecmascript::JSAPIArrayList::LENGTH_OFFSET);
5966     GateRef length = GetInt32OfTInt(Load(VariableType::INT64(), receiver, lengthOffset));
5967     Label isVailedIndex(env);
5968     Label notValidIndex(env);
5969     Branch(BoolAnd(Int32GreaterThanOrEqual(index, Int32(0)),
5970         Int32UnsignedLessThan(index, length)), &isVailedIndex, &notValidIndex);
5971     Bind(&isVailedIndex);
5972     {
5973         GateRef elements = GetElementsArray(receiver);
5974         result = GetValueFromTaggedArray(elements, index);
5975         Jump(&exit);
5976     }
5977     Bind(&notValidIndex);
5978     {
5979         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(GetPropertyOutOfBounds));
5980         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
5981         result = Exception();
5982         Jump(&exit);
5983     }
5984 
5985     Bind(&exit);
5986     auto ret = *result;
5987     env->SubCfgExit();
5988     return ret;
5989 }
5990 
GetEnumCacheKind(GateRef glue,GateRef enumCache)5991 GateRef StubBuilder::GetEnumCacheKind(GateRef glue, GateRef enumCache)
5992 {
5993     return env_->GetBuilder()->GetEnumCacheKind(glue, enumCache);
5994 }
5995 
IsEnumCacheValid(GateRef receiver,GateRef cachedHclass,GateRef kind)5996 GateRef StubBuilder::IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind)
5997 {
5998     return env_->GetBuilder()->IsEnumCacheValid(receiver, cachedHclass, kind);
5999 }
6000 
NeedCheckProperty(GateRef receiver)6001 GateRef StubBuilder::NeedCheckProperty(GateRef receiver)
6002 {
6003     return env_->GetBuilder()->NeedCheckProperty(receiver);
6004 }
6005 
NextInternal(GateRef glue,GateRef iter)6006 GateRef StubBuilder::NextInternal(GateRef glue, GateRef iter)
6007 {
6008     auto env = GetEnvironment();
6009     Label entry(env);
6010     env->SubCfgEntry(&entry);
6011     Label exit(env);
6012     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
6013 
6014     Label notFinish(env);
6015     Label notEnumCacheValid(env);
6016     Label fastGetKey(env);
6017     Label slowpath(env);
6018 
6019     GateRef index = GetIndexFromForInIterator(iter);
6020     GateRef length = GetLengthFromForInIterator(iter);
6021     Branch(Int32GreaterThanOrEqual(index, length), &exit, &notFinish);
6022     Bind(&notFinish);
6023     GateRef keys = GetKeysFromForInIterator(iter);
6024     GateRef receiver = GetObjectFromForInIterator(iter);
6025     GateRef cachedHclass = GetCachedHclassFromForInIterator(iter);
6026     GateRef kind = GetEnumCacheKind(glue, keys);
6027     Branch(IsEnumCacheValid(receiver, cachedHclass, kind), &fastGetKey, &notEnumCacheValid);
6028     Bind(&notEnumCacheValid);
6029     Branch(NeedCheckProperty(receiver), &slowpath, &fastGetKey);
6030     Bind(&fastGetKey);
6031     {
6032         result = GetValueFromTaggedArray(keys, index);
6033         IncreaseInteratorIndex(glue, iter, index);
6034         Jump(&exit);
6035     }
6036     Bind(&slowpath);
6037     {
6038         result = CallRuntime(glue, RTSTUB_ID(GetNextPropNameSlowpath), { iter });
6039         Jump(&exit);
6040     }
6041     Bind(&exit);
6042     auto ret = *result;
6043     env->SubCfgExit();
6044     return ret;
6045 }
6046 
GetFunctionPrototype(GateRef glue,size_t index)6047 GateRef StubBuilder::GetFunctionPrototype(GateRef glue, size_t index)
6048 {
6049     auto env = GetEnvironment();
6050     Label entry(env);
6051     env->SubCfgEntry(&entry);
6052     Label exit(env);
6053     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
6054 
6055     Label isHeapObject(env);
6056     Label isJSHclass(env);
6057 
6058     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env_->Is32Bit()));
6059     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
6060     GateRef func = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, index);
6061     GateRef protoOrHclass = Load(VariableType::JS_ANY(), func, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
6062     result = protoOrHclass;
6063     Branch(TaggedIsHeapObject(protoOrHclass), &isHeapObject, &exit);
6064     Bind(&isHeapObject);
6065     Branch(IsJSHClass(protoOrHclass), &isJSHclass, &exit);
6066     Bind(&isJSHclass);
6067     {
6068         result = GetPrototypeFromHClass(protoOrHclass);
6069         Jump(&exit);
6070     }
6071     Bind(&exit);
6072     auto ret = *result;
6073     env->SubCfgExit();
6074     return ret;
6075 }
6076 
ToObject(GateRef glue,GateRef obj)6077 GateRef StubBuilder::ToObject(GateRef glue, GateRef obj)
6078 {
6079     auto env = GetEnvironment();
6080     Label entry(env);
6081     env->SubCfgEntry(&entry);
6082     Label exit(env);
6083     DEFVARIABLE(result, VariableType::JS_ANY(), obj);
6084     DEFVARIABLE(taggedId, VariableType::INT32(), Int32(0));
6085     Label isNumber(env);
6086     Label notNumber(env);
6087     Label isBoolean(env);
6088     Label notBoolean(env);
6089     Label isString(env);
6090     Label notString(env);
6091     Label isECMAObject(env);
6092     Label notIsECMAObject(env);
6093     Label isSymbol(env);
6094     Label notSymbol(env);
6095     Label isUndefined(env);
6096     Label notIsUndefined(env);
6097     Label isNull(env);
6098     Label notIsNull(env);
6099     Label isHole(env);
6100     Label notIsHole(env);
6101     Label isBigInt(env);
6102     Label notIsBigInt(env);
6103     Label throwError(env);
6104     Branch(IsEcmaObject(obj), &isECMAObject, &notIsECMAObject);
6105     Bind(&isECMAObject);
6106     {
6107         result = obj;
6108         Jump(&exit);
6109     }
6110     Bind(&notIsECMAObject);
6111     Branch(TaggedIsNumber(obj), &isNumber, &notNumber);
6112     Bind(&isNumber);
6113     {
6114         result = NewJSPrimitiveRef(glue, GlobalEnv::NUMBER_FUNCTION_INDEX, obj);
6115         Jump(&exit);
6116     }
6117     Bind(&notNumber);
6118     Branch(TaggedIsBoolean(obj), &isBoolean, &notBoolean);
6119     Bind(&isBoolean);
6120     {
6121         result = NewJSPrimitiveRef(glue, GlobalEnv::BOOLEAN_FUNCTION_INDEX, obj);
6122         Jump(&exit);
6123     }
6124     Bind(&notBoolean);
6125     Branch(TaggedIsString(obj), &isString, &notString);
6126     Bind(&isString);
6127     {
6128         result = NewJSPrimitiveRef(glue, GlobalEnv::STRING_FUNCTION_INDEX, obj);
6129         Jump(&exit);
6130     }
6131     Bind(&notString);
6132     Branch(TaggedIsSymbol(obj), &isSymbol, &notSymbol);
6133     Bind(&isSymbol);
6134     {
6135         result = NewJSPrimitiveRef(glue, GlobalEnv::SYMBOL_FUNCTION_INDEX, obj);
6136         Jump(&exit);
6137     }
6138     Bind(&notSymbol);
6139     Branch(TaggedIsUndefined(obj), &isUndefined, &notIsUndefined);
6140     Bind(&isUndefined);
6141     {
6142         taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotUndefinedObject));
6143         Jump(&throwError);
6144     }
6145     Bind(&notIsUndefined);
6146     Branch(TaggedIsHole(obj), &isHole, &notIsHole);
6147     Bind(&isHole);
6148     {
6149         taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotHoleObject));
6150         Jump(&throwError);
6151     }
6152     Bind(&notIsHole);
6153     Branch(TaggedIsNull(obj), &isNull, &notIsNull);
6154     Bind(&isNull);
6155     {
6156         taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotNullObject));
6157         Jump(&throwError);
6158     }
6159     Bind(&notIsNull);
6160     Branch(TaggedIsBigInt(obj), &isBigInt, &notIsBigInt);
6161     Bind(&isBigInt);
6162     {
6163         result = NewJSPrimitiveRef(glue, GlobalEnv::BIGINT_FUNCTION_INDEX, obj);
6164         Jump(&exit);
6165     }
6166     Bind(&notIsBigInt);
6167     {
6168         taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotNullObject));
6169         Jump(&throwError);
6170     }
6171     Bind(&throwError);
6172     {
6173         CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(*taggedId) });
6174         result = Exception();
6175         Jump(&exit);
6176     }
6177     Bind(&exit);
6178     auto ret = *result;
6179     env->SubCfgExit();
6180     return ret;
6181 }
6182 
NewJSPrimitiveRef(GateRef glue,size_t index,GateRef obj)6183 GateRef StubBuilder::NewJSPrimitiveRef(GateRef glue, size_t index, GateRef obj)
6184 {
6185     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env_->Is32Bit()));
6186     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
6187     GateRef func = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, index);
6188     GateRef protoOrHclass = Load(VariableType::JS_ANY(), func, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
6189     NewObjectStubBuilder newBuilder(env_);
6190     GateRef newObj  = newBuilder.NewJSObject(glue, protoOrHclass);
6191     GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET);
6192     Store(VariableType::JS_ANY(), glue, newObj, valueOffset, obj);
6193     return newObj;
6194 }
6195 
DeletePropertyOrThrow(GateRef glue,GateRef obj,GateRef value)6196 GateRef StubBuilder::DeletePropertyOrThrow(GateRef glue, GateRef obj, GateRef value)
6197 {
6198     auto env = GetEnvironment();
6199     Label entry(env);
6200     env->SubCfgEntry(&entry);
6201     Label exit(env);
6202     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
6203     DEFVARIABLE(key, VariableType::JS_ANY(), value);
6204     Label toObject(env);
6205     Label isNotExceptiont(env);
6206     Label objectIsEcmaObject(env);
6207     Label objectIsHeapObject(env);
6208     GateRef object = ToObject(glue, obj);
6209     Branch(TaggedIsException(object), &exit, &isNotExceptiont);
6210     Bind(&isNotExceptiont);
6211     {
6212         Label deleteProper(env);
6213         Label notStringOrSymbol(env);
6214         Label notPrimitive(env);
6215         Branch(TaggedIsStringOrSymbol(value), &deleteProper, &notStringOrSymbol);
6216         Bind(&notStringOrSymbol);
6217         {
6218             Branch(TaggedIsNumber(value), &deleteProper, &notPrimitive);
6219             Bind(&notPrimitive);
6220             {
6221                 key = CallRuntime(glue, RTSTUB_ID(ToPropertyKey), {value});
6222                 Branch(TaggedIsException(*key), &exit, &deleteProper);
6223             }
6224         }
6225         Bind(&deleteProper);
6226         {
6227             result = DeleteProperty(glue, object, *key);
6228             Jump(&exit);
6229         }
6230     }
6231     Bind(&exit);
6232     auto ret = *result;
6233     env->SubCfgExit();
6234     return ret;
6235 }
6236 
DeleteProperty(GateRef glue,GateRef obj,GateRef value)6237 GateRef StubBuilder::DeleteProperty(GateRef glue, GateRef obj, GateRef value)
6238 {
6239     auto env = GetEnvironment();
6240     Label entry(env);
6241     env->SubCfgEntry(&entry);
6242     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
6243     Label exit(env);
6244     Label notRegularJSObject(env);
6245     Label regularJSObjDeletePrototype(env);
6246     Branch(TaggedIsRegularObject(obj), &regularJSObjDeletePrototype, &notRegularJSObject);
6247     Bind(&regularJSObjDeletePrototype);
6248     {
6249         result = CallRuntime(glue, RTSTUB_ID(RegularJSObjDeletePrototype), { obj, value});
6250         Jump(&exit);
6251     }
6252     Bind(&notRegularJSObject);
6253     {
6254         result = CallRuntime(glue, RTSTUB_ID(CallJSObjDeletePrototype), { obj, value});
6255         Jump(&exit);
6256     }
6257 
6258     Bind(&exit);
6259     auto ret = *result;
6260     env->SubCfgExit();
6261     return ret;
6262 }
6263 
ToPrototypeOrObj(GateRef glue,GateRef obj)6264 GateRef StubBuilder::ToPrototypeOrObj(GateRef glue, GateRef obj)
6265 {
6266     auto env = GetEnvironment();
6267     Label entry(env);
6268     env->SubCfgEntry(&entry);
6269     Label exit(env);
6270     DEFVARIABLE(result, VariableType::JS_ANY(), obj);
6271 
6272     Label isNumber(env);
6273     Label notNumber(env);
6274     Label isBoolean(env);
6275     Label notBoolean(env);
6276     Label isString(env);
6277     Label notString(env);
6278     Label isSymbol(env);
6279     Label notSymbol(env);
6280     Label isBigInt(env);
6281     Branch(TaggedIsNumber(obj), &isNumber, &notNumber);
6282     Bind(&isNumber);
6283     {
6284         result = GetFunctionPrototype(glue, GlobalEnv::NUMBER_FUNCTION_INDEX);
6285         Jump(&exit);
6286     }
6287     Bind(&notNumber);
6288     Branch(TaggedIsBoolean(obj), &isBoolean, &notBoolean);
6289     Bind(&isBoolean);
6290     {
6291         result = GetFunctionPrototype(glue, GlobalEnv::BOOLEAN_FUNCTION_INDEX);
6292         Jump(&exit);
6293     }
6294     Bind(&notBoolean);
6295     Branch(TaggedIsString(obj), &isString, &notString);
6296     Bind(&isString);
6297     {
6298         result = GetFunctionPrototype(glue, GlobalEnv::STRING_FUNCTION_INDEX);
6299         Jump(&exit);
6300     }
6301     Bind(&notString);
6302     Branch(TaggedIsSymbol(obj), &isSymbol, &notSymbol);
6303     Bind(&isSymbol);
6304     {
6305         result = GetFunctionPrototype(glue, GlobalEnv::SYMBOL_FUNCTION_INDEX);
6306         Jump(&exit);
6307     }
6308     Bind(&notSymbol);
6309     Branch(TaggedIsBigInt(obj), &isBigInt, &exit);
6310     Bind(&isBigInt);
6311     {
6312         result = GetFunctionPrototype(glue, GlobalEnv::BIGINT_FUNCTION_INDEX);
6313         Jump(&exit);
6314     }
6315     Bind(&exit);
6316     auto ret = *result;
6317     env->SubCfgExit();
6318     return ret;
6319 }
6320 
IsSpecialKeysObject(GateRef obj)6321 GateRef StubBuilder::IsSpecialKeysObject(GateRef obj)
6322 {
6323     return BoolOr(BoolOr(IsTypedArray(obj), IsModuleNamespace(obj)), ObjIsSpecialContainer(obj));
6324 }
6325 
IsSlowKeysObject(GateRef obj)6326 GateRef StubBuilder::IsSlowKeysObject(GateRef obj)
6327 {
6328     auto env = GetEnvironment();
6329     Label entry(env);
6330     env->SubCfgEntry(&entry);
6331     Label exit(env);
6332     DEFVARIABLE(result, VariableType::BOOL(), False());
6333 
6334     Label isHeapObject(env);
6335     Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
6336     Bind(&isHeapObject);
6337     {
6338         result = BoolOr(BoolOr(IsJSGlobalObject(obj), IsJsProxy(obj)), IsSpecialKeysObject(obj));
6339         Jump(&exit);
6340     }
6341     Bind(&exit);
6342     auto ret = *result;
6343     env->SubCfgExit();
6344     return ret;
6345 }
6346 
GetNumberOfElements(GateRef obj)6347 GateRef StubBuilder::GetNumberOfElements(GateRef obj)
6348 {
6349     auto env = GetEnvironment();
6350     Label entry(env);
6351     env->SubCfgEntry(&entry);
6352     Label exit(env);
6353     DEFVARIABLE(numOfElements, VariableType::INT32(), Int32(0));
6354     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
6355 
6356     Label isJSPrimitiveRef(env);
6357     Label isPrimitiveString(env);
6358     Label notPrimitiveString(env);
6359     Label isDictMode(env);
6360     Label notDictMode(env);
6361 
6362     Branch(IsJSPrimitiveRef(obj), &isJSPrimitiveRef, &notPrimitiveString);
6363     Bind(&isJSPrimitiveRef);
6364     GateRef value = Load(VariableType::JS_ANY(), obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
6365     Branch(TaggedIsString(value), &isPrimitiveString, &notPrimitiveString);
6366     Bind(&isPrimitiveString);
6367     {
6368         numOfElements = GetLengthFromString(value);
6369         Jump(&notPrimitiveString);
6370     }
6371     Bind(&notPrimitiveString);
6372     GateRef elements = GetElementsArray(obj);
6373     Branch(IsDictionaryMode(elements), &isDictMode, &notDictMode);
6374     Bind(&notDictMode);
6375     {
6376         Label loopHead(env);
6377         Label loopEnd(env);
6378         Label iLessLength(env);
6379         Label notHole(env);
6380         GateRef elementsLen = GetLengthOfTaggedArray(elements);
6381         Jump(&loopHead);
6382         LoopBegin(&loopHead);
6383         {
6384             Branch(Int32UnsignedLessThan(*i, elementsLen), &iLessLength, &exit);
6385             Bind(&iLessLength);
6386             {
6387                 GateRef element = GetValueFromTaggedArray(elements, *i);
6388                 Branch(TaggedIsHole(element), &loopEnd, &notHole);
6389                 Bind(&notHole);
6390                 numOfElements = Int32Add(*numOfElements, Int32(1));
6391                 Jump(&loopEnd);
6392             }
6393             Bind(&loopEnd);
6394             i = Int32Add(*i, Int32(1));
6395             LoopEnd(&loopHead);
6396         }
6397     }
6398     Bind(&isDictMode);
6399     {
6400         GateRef entryCount = TaggedGetInt(
6401             GetValueFromTaggedArray(elements, Int32(TaggedHashTable<NumberDictionary>::NUMBER_OF_ENTRIES_INDEX)));
6402         numOfElements = Int32Add(*numOfElements, entryCount);
6403         Jump(&exit);
6404     }
6405     Bind(&exit);
6406     auto ret = *numOfElements;
6407     env->SubCfgExit();
6408     return ret;
6409 }
6410 
IsSimpleEnumCacheValid(GateRef obj)6411 GateRef StubBuilder::IsSimpleEnumCacheValid(GateRef obj)
6412 {
6413     auto env = GetEnvironment();
6414     Label entry(env);
6415     env->SubCfgEntry(&entry);
6416     Label exit(env);
6417     DEFVARIABLE(result, VariableType::BOOL(), False());
6418     DEFVARIABLE(current, VariableType::JS_ANY(), Undefined());
6419 
6420     Label receiverHasNoElements(env);
6421 
6422     GateRef numOfElements = GetNumberOfElements(obj);
6423     Branch(Int32GreaterThan(numOfElements, Int32(0)), &exit, &receiverHasNoElements);
6424     Bind(&receiverHasNoElements);
6425     {
6426         Label loopHead(env);
6427         Label loopEnd(env);
6428         Label afterLoop(env);
6429         Label currentHasNoElements(env);
6430         Label enumCacheIsUndefined(env);
6431         current = GetPrototypeFromHClass(LoadHClass(obj));
6432         Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop);
6433         LoopBegin(&loopHead);
6434         {
6435             GateRef numOfCurrentElements = GetNumberOfElements(*current);
6436             Branch(Int32GreaterThan(numOfCurrentElements, Int32(0)), &exit, &currentHasNoElements);
6437             Bind(&currentHasNoElements);
6438             GateRef hclass = LoadHClass(*current);
6439             GateRef protoEnumCache = GetEnumCacheFromHClass(hclass);
6440             Branch(TaggedIsUndefined(protoEnumCache), &enumCacheIsUndefined, &exit);
6441             Bind(&enumCacheIsUndefined);
6442             current = GetPrototypeFromHClass(hclass);
6443             Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop);
6444         }
6445         Bind(&loopEnd);
6446         LoopEnd(&loopHead);
6447         Bind(&afterLoop);
6448         {
6449             result = True();
6450             Jump(&exit);
6451         }
6452     }
6453     Bind(&exit);
6454     auto ret = *result;
6455     env->SubCfgExit();
6456     return ret;
6457 }
6458 
IsEnumCacheWithProtoChainInfoValid(GateRef obj)6459 GateRef StubBuilder::IsEnumCacheWithProtoChainInfoValid(GateRef obj)
6460 {
6461     auto env = GetEnvironment();
6462     Label entry(env);
6463     env->SubCfgEntry(&entry);
6464     Label exit(env);
6465     DEFVARIABLE(result, VariableType::BOOL(), False());
6466     DEFVARIABLE(current, VariableType::JS_ANY(), Undefined());
6467 
6468     Label receiverHasNoElements(env);
6469     Label prototypeIsEcmaObj(env);
6470     Label isProtoChangeMarker(env);
6471     Label protoNotChanged(env);
6472 
6473     GateRef numOfElements = GetNumberOfElements(obj);
6474     Branch(Int32GreaterThan(numOfElements, Int32(0)), &exit, &receiverHasNoElements);
6475     Bind(&receiverHasNoElements);
6476     GateRef prototype = GetPrototypeFromHClass(LoadHClass(obj));
6477     Branch(IsEcmaObject(prototype), &prototypeIsEcmaObj, &exit);
6478     Bind(&prototypeIsEcmaObj);
6479     GateRef protoChangeMarker = GetProtoChangeMarkerFromHClass(LoadHClass(prototype));
6480     Branch(TaggedIsProtoChangeMarker(protoChangeMarker), &isProtoChangeMarker, &exit);
6481     Bind(&isProtoChangeMarker);
6482     Branch(GetHasChanged(protoChangeMarker), &exit, &protoNotChanged);
6483     Bind(&protoNotChanged);
6484     {
6485         Label loopHead(env);
6486         Label loopEnd(env);
6487         Label afterLoop(env);
6488         Label currentHasNoElements(env);
6489         current = prototype;
6490         Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop);
6491         LoopBegin(&loopHead);
6492         {
6493             GateRef numOfCurrentElements = GetNumberOfElements(*current);
6494             Branch(Int32GreaterThan(numOfCurrentElements, Int32(0)), &exit, &currentHasNoElements);
6495             Bind(&currentHasNoElements);
6496             current = GetPrototypeFromHClass(LoadHClass(*current));
6497             Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop);
6498         }
6499         Bind(&loopEnd);
6500         LoopEnd(&loopHead);
6501         Bind(&afterLoop);
6502         {
6503             result = True();
6504             Jump(&exit);
6505         }
6506     }
6507     Bind(&exit);
6508     auto ret = *result;
6509     env->SubCfgExit();
6510     return ret;
6511 }
6512 
TryGetEnumCache(GateRef glue,GateRef obj)6513 GateRef StubBuilder::TryGetEnumCache(GateRef glue, GateRef obj)
6514 {
6515     auto env = GetEnvironment();
6516     Label entry(env);
6517     env->SubCfgEntry(&entry);
6518     Label exit(env);
6519     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
6520 
6521     Label notSlowKeys(env);
6522     Label notDictionaryMode(env);
6523     Label checkSimpleEnumCache(env);
6524     Label notSimpleEnumCache(env);
6525     Label checkEnumCacheWithProtoChainInfo(env);
6526     Label enumCacheValid(env);
6527 
6528     Branch(IsSlowKeysObject(obj), &exit, &notSlowKeys);
6529     Bind(&notSlowKeys);
6530     GateRef hclass = LoadHClass(obj);
6531     Branch(IsDictionaryModeByHClass(hclass), &exit, &notDictionaryMode);
6532     Bind(&notDictionaryMode);
6533     GateRef enumCache = GetEnumCacheFromHClass(hclass);
6534     GateRef kind = GetEnumCacheKind(glue, enumCache);
6535     Branch(Int32Equal(kind, Int32(static_cast<int32_t>(EnumCacheKind::SIMPLE))),
6536            &checkSimpleEnumCache, &notSimpleEnumCache);
6537     Bind(&checkSimpleEnumCache);
6538     {
6539         Branch(IsSimpleEnumCacheValid(obj), &enumCacheValid, &exit);
6540     }
6541     Bind(&notSimpleEnumCache);
6542     Branch(Int32Equal(kind, Int32(static_cast<int32_t>(EnumCacheKind::PROTOCHAIN))),
6543            &checkEnumCacheWithProtoChainInfo, &exit);
6544     Bind(&checkEnumCacheWithProtoChainInfo);
6545     {
6546         Branch(IsEnumCacheWithProtoChainInfoValid(obj), &enumCacheValid, &exit);
6547     }
6548     Bind(&enumCacheValid);
6549     {
6550         result = enumCache;
6551         Jump(&exit);
6552     }
6553     Bind(&exit);
6554     auto ret = *result;
6555     env->SubCfgExit();
6556     return ret;
6557 }
6558 
DoubleToInt(GateRef glue,GateRef x,size_t typeBits)6559 GateRef StubBuilder::DoubleToInt(GateRef glue, GateRef x, size_t typeBits)
6560 {
6561     auto env = GetEnvironment();
6562     Label entry(env);
6563     env->SubCfgEntry(&entry);
6564     Label exit(env);
6565     Label overflow(env);
6566 
6567     GateRef xInt = ChangeFloat64ToInt32(x);
6568     DEFVARIABLE(result, VariableType::INT32(), xInt);
6569 
6570     if (env->IsAmd64()) {
6571         // 0x80000000: amd64 overflow return value
6572         Branch(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit);
6573     } else {
6574         GateRef xInt64 = CastDoubleToInt64(x);
6575         // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
6576         GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
6577         exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
6578         exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
6579         GateRef bits = Int32(typeBits - 1);
6580         // exp < 32 - 1
6581         Branch(Int32LessThan(exp, bits), &exit, &overflow);
6582     }
6583     Bind(&overflow);
6584     {
6585         result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), { x, IntPtr(typeBits) });
6586         Jump(&exit);
6587     }
6588     Bind(&exit);
6589     auto ret = *result;
6590     env->SubCfgExit();
6591     return ret;
6592 }
6593 
ReturnExceptionIfAbruptCompletion(GateRef glue)6594 void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue)
6595 {
6596     auto env = GetEnvironment();
6597     Label entry(env);
6598     env->SubCfgEntry(&entry);
6599     Label exit(env);
6600     Label hasPendingException(env);
6601     GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env->IsArch32Bit()));
6602     GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset);
6603     Branch(TaggedIsNotHole(exception), &hasPendingException, &exit);
6604     Bind(&hasPendingException);
6605     Return(Exception());
6606     Bind(&exit);
6607     env->SubCfgExit();
6608     return;
6609 }
6610 
GetHashcodeFromString(GateRef glue,GateRef value)6611 GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
6612 {
6613     return env_->GetBuilder()->GetHashcodeFromString(glue, value);
6614 }
6615 
ConstructorCheck(GateRef glue,GateRef ctor,GateRef outPut,GateRef thisObj)6616 GateRef StubBuilder::ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut, GateRef thisObj)
6617 {
6618     auto env = GetEnvironment();
6619     Label entryPass(env);
6620     Label exit(env);
6621     env->SubCfgEntry(&entryPass);
6622     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
6623     Label isHeapObject(env);
6624     Label isEcmaObj(env);
6625     Label notEcmaObj(env);
6626     Branch(TaggedIsHeapObject(outPut), &isHeapObject, &notEcmaObj);
6627     Bind(&isHeapObject);
6628     Branch(TaggedObjectIsEcmaObject(outPut), &isEcmaObj, &notEcmaObj);
6629     Bind(&isEcmaObj);
6630     {
6631         result = outPut;
6632         Jump(&exit);
6633     }
6634     Bind(&notEcmaObj);
6635     {
6636         Label ctorIsBase(env);
6637         Label ctorNotBase(env);
6638         Branch(IsBase(ctor), &ctorIsBase, &ctorNotBase);
6639         Bind(&ctorIsBase);
6640         {
6641             result = thisObj;
6642             Jump(&exit);
6643         }
6644         Bind(&ctorNotBase);
6645         {
6646             Label throwExeption(env);
6647             Label returnObj(env);
6648             Branch(TaggedIsUndefined(outPut), &returnObj, &throwExeption);
6649             Bind(&returnObj);
6650             result = thisObj;
6651             Jump(&exit);
6652             Bind(&throwExeption);
6653             {
6654                 CallRuntime(glue, RTSTUB_ID(ThrowNonConstructorException), {});
6655                 Jump(&exit);
6656             }
6657         }
6658     }
6659     Bind(&exit);
6660     auto ret = *result;
6661     env->SubCfgExit();
6662     return ret;
6663 }
6664 
GetIterator(GateRef glue,GateRef obj,ProfileOperation callback)6665 GateRef StubBuilder::GetIterator(GateRef glue, GateRef obj, ProfileOperation callback)
6666 {
6667     auto env = GetEnvironment();
6668     Label entryPass(env);
6669     Label exit(env);
6670     env->SubCfgEntry(&entryPass);
6671     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
6672 
6673     Label isPendingException(env);
6674     Label noPendingException(env);
6675     Label isHeapObject(env);
6676     Label objIsCallable(env);
6677 
6678     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
6679     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
6680     GateRef iteratorKey = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ITERATOR_SYMBOL_INDEX);
6681     result = FastGetPropertyByName(glue, obj, iteratorKey, ProfileOperation());
6682     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
6683     Bind(&isPendingException);
6684     {
6685         result = Exception();
6686         Jump(&exit);
6687     }
6688     Bind(&noPendingException);
6689     callback.ProfileGetIterator(*result);
6690     Branch(TaggedIsHeapObject(*result), &isHeapObject, &exit);
6691     Bind(&isHeapObject);
6692     Branch(IsCallable(*result), &objIsCallable, &exit);
6693     Bind(&objIsCallable);
6694     {
6695         result = JSCallDispatch(glue, *result, Int32(0), 0, Circuit::NullGate(),
6696                                 JSCallMode::CALL_GETTER, { obj }, ProfileOperation());
6697         Jump(&exit);
6698     }
6699 
6700     Bind(&exit);
6701     auto ret = *result;
6702     env->SubCfgExit();
6703     return ret;
6704 }
6705 
IsCallModeSupportPGO(JSCallMode mode)6706 bool StubBuilder::IsCallModeSupportPGO(JSCallMode mode)
6707 {
6708     switch (mode) {
6709         case JSCallMode::CALL_ARG0:
6710         case JSCallMode::CALL_ARG1:
6711         case JSCallMode::CALL_ARG2:
6712         case JSCallMode::CALL_ARG3:
6713         case JSCallMode::CALL_WITH_ARGV:
6714         case JSCallMode::CALL_THIS_ARG0:
6715         case JSCallMode::CALL_THIS_ARG1:
6716         case JSCallMode::CALL_THIS_ARG2:
6717         case JSCallMode::CALL_THIS_ARG3:
6718         case JSCallMode::CALL_THIS_WITH_ARGV:
6719         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
6720         case JSCallMode::SUPER_CALL_WITH_ARGV:
6721         case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
6722             return true;
6723         case JSCallMode::DEPRECATED_CALL_ARG0:
6724         case JSCallMode::DEPRECATED_CALL_ARG1:
6725         case JSCallMode::DEPRECATED_CALL_ARG2:
6726         case JSCallMode::DEPRECATED_CALL_ARG3:
6727         case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
6728         case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
6729         case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
6730         case JSCallMode::CALL_ENTRY:
6731         case JSCallMode::CALL_FROM_AOT:
6732         case JSCallMode::CALL_GENERATOR:
6733         case JSCallMode::CALL_GETTER:
6734         case JSCallMode::CALL_SETTER:
6735         case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
6736         case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
6737             return false;
6738         default:
6739             LOG_ECMA(FATAL) << "this branch is unreachable";
6740             UNREACHABLE();
6741     }
6742 }
6743 
JSCallDispatch(GateRef glue,GateRef func,GateRef actualNumArgs,GateRef jumpSize,GateRef hotnessCounter,JSCallMode mode,std::initializer_list<GateRef> args,ProfileOperation callback)6744 GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize,
6745                                     GateRef hotnessCounter, JSCallMode mode, std::initializer_list<GateRef> args,
6746                                     ProfileOperation callback)
6747 {
6748     auto env = GetEnvironment();
6749     Label entryPass(env);
6750     Label exit(env);
6751     env->SubCfgEntry(&entryPass);
6752     DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
6753     // 1. call initialize
6754     Label funcIsHeapObject(env);
6755     Label funcIsCallable(env);
6756     Label funcNotCallable(env);
6757     // save pc
6758     SavePcIfNeeded(glue);
6759     GateRef bitfield = 0;
6760 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
6761     CallNGCRuntime(glue, RTSTUB_ID(StartCallTimer), { glue, func, False()});
6762 #endif
6763     Branch(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable);
6764     Bind(&funcIsHeapObject);
6765     GateRef hclass = LoadHClass(func);
6766     bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
6767     Branch(IsCallableFromBitField(bitfield), &funcIsCallable, &funcNotCallable);
6768     Bind(&funcNotCallable);
6769     {
6770         CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {});
6771         Jump(&exit);
6772     }
6773     Bind(&funcIsCallable);
6774     GateRef method = GetMethodFromJSFunction(func);
6775     GateRef callField = GetCallFieldFromMethod(method);
6776     GateRef isNativeMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsNativeBit::START_BIT);
6777 
6778     // 2. call dispatch
6779     Label methodIsNative(env);
6780     Label methodNotNative(env);
6781     Branch(Int64NotEqual(Int64And(callField, isNativeMask), Int64(0)), &methodIsNative, &methodNotNative);
6782     auto data = std::begin(args);
6783     Label notFastBuiltinsArg0(env);
6784     Label notFastBuiltinsArg1(env);
6785     Label notFastBuiltinsArg2(env);
6786     Label notFastBuiltinsArg3(env);
6787     Label notFastBuiltins(env);
6788     // 3. call native
6789     Bind(&methodIsNative);
6790     {
6791         if (IsCallModeSupportPGO(mode)) {
6792             callback.ProfileNativeCall(func);
6793         }
6794         GateRef nativeCode = Load(VariableType::NATIVE_POINTER(), method,
6795             IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
6796         GateRef newTarget = Undefined();
6797         GateRef thisValue = Undefined();
6798         GateRef numArgs = Int32Add(actualNumArgs, Int32(NUM_MANDATORY_JSFUNC_ARGS));
6799         switch (mode) {
6800             case JSCallMode::CALL_THIS_ARG0: {
6801                 thisValue = data[0];
6802                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
6803                     method, &notFastBuiltinsArg0, &exit, &result, args, mode);
6804                 Bind(&notFastBuiltinsArg0);
6805                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6806                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
6807                 break;
6808             }
6809             case JSCallMode::CALL_ARG0:
6810             case JSCallMode::DEPRECATED_CALL_ARG0:
6811                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6812                     { nativeCode, glue, numArgs, func, newTarget, thisValue });
6813                 break;
6814             case JSCallMode::CALL_THIS_ARG1: {
6815                 thisValue = data[1];
6816                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
6817                     method, &notFastBuiltinsArg1, &exit, &result, args, mode);
6818                 Bind(&notFastBuiltinsArg1);
6819                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6820                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
6821                 break;
6822             }
6823             case JSCallMode::CALL_ARG1:
6824             case JSCallMode::DEPRECATED_CALL_ARG1:
6825                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6826                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0]});
6827                 break;
6828             case JSCallMode::CALL_THIS_ARG2: {
6829                 thisValue = data[2];
6830                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
6831                     method, &notFastBuiltinsArg2, &exit, &result, args, mode);
6832                 Bind(&notFastBuiltinsArg2);
6833                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6834                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
6835                 break;
6836             }
6837             case JSCallMode::CALL_ARG2:
6838             case JSCallMode::DEPRECATED_CALL_ARG2:
6839                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6840                     { nativeCode, glue, numArgs, func, newTarget, thisValue, data[0], data[1] });
6841                 break;
6842             case JSCallMode::CALL_THIS_ARG3: {
6843                 thisValue = data[3];
6844                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
6845                     method, &notFastBuiltinsArg3, &exit, &result, args, mode);
6846                 Bind(&notFastBuiltinsArg3);
6847                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6848                     { nativeCode, glue, numArgs, func,
6849                         newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
6850                 break;
6851             }
6852             case JSCallMode::CALL_ARG3:
6853             case JSCallMode::DEPRECATED_CALL_ARG3:
6854                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6855                     { nativeCode, glue, numArgs, func,
6856                       newTarget, thisValue, data[0], data[1], data[2] }); // 2: args2
6857                 break;
6858             case JSCallMode::CALL_THIS_WITH_ARGV:
6859             case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
6860             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV: {
6861                 thisValue = data[2]; // 2: this input
6862                 [[fallthrough]];
6863             }
6864             case JSCallMode::CALL_WITH_ARGV:
6865             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
6866                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatchNative),
6867                     { glue, nativeCode, func, thisValue, data[0], data[1] });
6868                 break;
6869             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
6870             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV: {
6871                 CallFastPath(glue, nativeCode, func, thisValue, actualNumArgs, callField,
6872                     method, &notFastBuiltins, &exit, &result, args, mode);
6873                 Bind(&notFastBuiltins);
6874                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatchNative),
6875                     { glue, nativeCode, func, data[2], data[0], data[1] });
6876                 break;
6877             }
6878             case JSCallMode::CALL_GETTER:
6879                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6880                     { nativeCode, glue, numArgs, func, newTarget, data[0] });
6881                 break;
6882             case JSCallMode::CALL_SETTER:
6883                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6884                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1] });
6885                 break;
6886             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
6887                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
6888                     { nativeCode, glue, numArgs, func, newTarget, data[0], data[1], data[2], data[3] });
6889                 break;
6890             case JSCallMode::SUPER_CALL_WITH_ARGV:
6891                 result = CallRuntime(glue, RTSTUB_ID(SuperCall), { data[0], data[1], IntToTaggedInt(data[2]) });
6892                 break;
6893             case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
6894                 result = CallRuntime(glue, RTSTUB_ID(SuperCallSpread), {data[0], data[1]});
6895                 break;
6896             default:
6897                 LOG_ECMA(FATAL) << "this branch is unreachable";
6898                 UNREACHABLE();
6899         }
6900         Jump(&exit);
6901     }
6902     // 4. call nonNative
6903     Bind(&methodNotNative);
6904 
6905     if (IsCallModeSupportPGO(mode)) {
6906         callback.ProfileCall(func);
6907     }
6908     Label funcIsClassConstructor(env);
6909     Label funcNotClassConstructor(env);
6910     Label methodNotAot(env);
6911     if (!AssemblerModule::IsCallNew(mode)) {
6912         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &funcNotClassConstructor);
6913         Bind(&funcIsClassConstructor);
6914         {
6915             CallRuntime(glue, RTSTUB_ID(ThrowCallConstructorException), {});
6916             Jump(&exit);
6917         }
6918         Bind(&funcNotClassConstructor);
6919     } else {
6920         Branch(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &methodNotAot);
6921         Bind(&funcIsClassConstructor);
6922     }
6923     GateRef sp = 0;
6924     if (env->IsAsmInterp()) {
6925         sp = Argument(static_cast<size_t>(InterpreterHandlerInputs::SP));
6926     }
6927     Label methodisAot(env);
6928     Label methodIsFastCall(env);
6929     Label methodNotFastCall(env);
6930     Label fastCall(env);
6931     Label fastCallBridge(env);
6932     Label slowCall(env);
6933     Label slowCallBridge(env);
6934     {
6935         GateRef newTarget = Undefined();
6936         GateRef thisValue = Undefined();
6937         GateRef realNumArgs = Int64Add(ZExtInt32ToInt64(actualNumArgs), Int64(NUM_MANDATORY_JSFUNC_ARGS));
6938         Branch(JudgeAotAndFastCallWithMethod(method, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL),
6939             &methodIsFastCall, &methodNotFastCall);
6940         Bind(&methodIsFastCall);
6941         {
6942             GateRef expectedNum = Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
6943                 Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
6944             GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
6945             Branch(Int64LessThanOrEqual(expectedArgc, realNumArgs), &fastCall, &fastCallBridge);
6946             Bind(&fastCall);
6947             {
6948                 GateRef code = GetAotCodeAddr(method);
6949                 switch (mode) {
6950                     case JSCallMode::CALL_THIS_ARG0:
6951                         thisValue = data[0];
6952                         [[fallthrough]];
6953                     case JSCallMode::CALL_ARG0:
6954                     case JSCallMode::DEPRECATED_CALL_ARG0:
6955                         result = FastCallOptimized(glue, code, { glue, func, thisValue});
6956                         Jump(&exit);
6957                         break;
6958                     case JSCallMode::CALL_THIS_ARG1:
6959                         thisValue = data[1];
6960                         [[fallthrough]];
6961                     case JSCallMode::CALL_ARG1:
6962                     case JSCallMode::DEPRECATED_CALL_ARG1:
6963                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0] });
6964                         Jump(&exit);
6965                         break;
6966                     case JSCallMode::CALL_THIS_ARG2:
6967                         thisValue = data[2];
6968                         [[fallthrough]];
6969                     case JSCallMode::CALL_ARG2:
6970                     case JSCallMode::DEPRECATED_CALL_ARG2:
6971                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0], data[1] });
6972                         Jump(&exit);
6973                         break;
6974                     case JSCallMode::CALL_THIS_ARG3:
6975                         thisValue = data[3];
6976                         [[fallthrough]];
6977                     case JSCallMode::CALL_ARG3:
6978                     case JSCallMode::DEPRECATED_CALL_ARG3:
6979                         result = FastCallOptimized(glue, code, { glue, func, thisValue, data[0], data[1], data[2] });
6980                         Jump(&exit);
6981                         break;
6982                     case JSCallMode::CALL_THIS_WITH_ARGV:
6983                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
6984                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
6985                         thisValue = data[2]; // 2: this input
6986                         [[fallthrough]];
6987                     case JSCallMode::CALL_WITH_ARGV:
6988                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
6989                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgV),
6990                             { glue, func, thisValue, ZExtInt32ToInt64(actualNumArgs), data[1] });
6991                         Jump(&exit);
6992                         break;
6993                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
6994                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
6995                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgV),
6996                             { glue, func, data[2], ZExtInt32ToInt64(actualNumArgs), data[1]});
6997                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
6998                         Jump(&exit);
6999                         break;
7000                     case JSCallMode::CALL_GETTER:
7001                         result = FastCallOptimized(glue, code, { glue, func, data[0] });
7002                         Jump(&exit);
7003                         break;
7004                     case JSCallMode::CALL_SETTER:
7005                         result = FastCallOptimized(glue, code, { glue, func, data[0], data[1] });
7006                         Jump(&exit);
7007                         break;
7008                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
7009                         result = FastCallOptimized(glue, code, { glue, func, data[0], data[1], data[2], data[3] });
7010                         Jump(&exit);
7011                         break;
7012                     case JSCallMode::SUPER_CALL_WITH_ARGV:
7013                         result = CallRuntime(glue, RTSTUB_ID(SuperCall), { data[0], data[1], IntToTaggedInt(data[2]) });
7014                         Jump(&exit);
7015                         break;
7016                     case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
7017                         result = CallRuntime(glue, RTSTUB_ID(SuperCallSpread), {data[0], data[1]});
7018                         Jump(&exit);
7019                         break;
7020                     default:
7021                         LOG_ECMA(FATAL) << "this branch is unreachable";
7022                         UNREACHABLE();
7023                 }
7024             }
7025             Bind(&fastCallBridge);
7026             {
7027                 switch (mode) {
7028                     case JSCallMode::CALL_THIS_ARG0:
7029                         thisValue = data[0];
7030                         [[fallthrough]];
7031                     case JSCallMode::CALL_ARG0:
7032                     case JSCallMode::DEPRECATED_CALL_ARG0:
7033                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7034                             { glue, realNumArgs, func, newTarget, thisValue});
7035                         Jump(&exit);
7036                         break;
7037                     case JSCallMode::CALL_THIS_ARG1:
7038                         thisValue = data[1];
7039                         [[fallthrough]];
7040                     case JSCallMode::CALL_ARG1:
7041                     case JSCallMode::DEPRECATED_CALL_ARG1:
7042                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7043                             { glue, realNumArgs, func, newTarget, thisValue, data[0] });
7044                         Jump(&exit);
7045                         break;
7046                     case JSCallMode::CALL_THIS_ARG2:
7047                         thisValue = data[2];
7048                         [[fallthrough]];
7049                     case JSCallMode::CALL_ARG2:
7050                     case JSCallMode::DEPRECATED_CALL_ARG2:
7051                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7052                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
7053                         Jump(&exit);
7054                         break;
7055                     case JSCallMode::CALL_THIS_ARG3:
7056                         thisValue = data[3];
7057                         [[fallthrough]];
7058                     case JSCallMode::CALL_ARG3:
7059                     case JSCallMode::DEPRECATED_CALL_ARG3:
7060                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7061                             { glue, realNumArgs, func, newTarget, thisValue,
7062                             data[0], data[1], data[2] }); // 2: args2
7063                         Jump(&exit);
7064                         break;
7065                     case JSCallMode::CALL_THIS_WITH_ARGV:
7066                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
7067                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
7068                         thisValue = data[2]; // 2: this input
7069                         [[fallthrough]];
7070                     case JSCallMode::CALL_WITH_ARGV:
7071                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
7072                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgVAndPushUndefined),
7073                             { glue, func, thisValue, ZExtInt32ToInt64(actualNumArgs), data[1], expectedNum });
7074                         Jump(&exit);
7075                         break;
7076                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
7077                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
7078                         result = CallNGCRuntime(glue, RTSTUB_ID(JSFastCallWithArgVAndPushUndefined),
7079                             { glue, func, data[2], ZExtInt32ToInt64(actualNumArgs), data[1], expectedNum });
7080                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
7081                         Jump(&exit);
7082                         break;
7083                     case JSCallMode::CALL_GETTER:
7084                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7085                             { glue, realNumArgs, func, newTarget, data[0]});
7086                         Jump(&exit);
7087                         break;
7088                     case JSCallMode::CALL_SETTER:
7089                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7090                             { glue, realNumArgs, func, newTarget, data[0], data[1]});
7091                         Jump(&exit);
7092                         break;
7093                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
7094                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedFastCallAndPushUndefined),
7095                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
7096                         Jump(&exit);
7097                         break;
7098                     case JSCallMode::SUPER_CALL_WITH_ARGV:
7099                         result = CallRuntime(glue, RTSTUB_ID(SuperCall), { data[0], data[1], IntToTaggedInt(data[2]) });
7100                         Jump(&exit);
7101                         break;
7102                     case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
7103                         result = CallRuntime(glue, RTSTUB_ID(SuperCallSpread), {data[0], data[1]});
7104                         Jump(&exit);
7105                         break;
7106                     default:
7107                         LOG_ECMA(FATAL) << "this branch is unreachable";
7108                         UNREACHABLE();
7109                 }
7110             }
7111         }
7112 
7113         Bind(&methodNotFastCall);
7114         Branch(JudgeAotAndFastCallWithMethod(method, CircuitBuilder::JudgeMethodType::HAS_AOT),
7115             &methodisAot, &methodNotAot);
7116         Bind(&methodisAot);
7117         {
7118             GateRef expectedNum = Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
7119                 Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
7120             GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
7121             Branch(Int64LessThanOrEqual(expectedArgc, realNumArgs), &slowCall, &slowCallBridge);
7122             Bind(&slowCall);
7123             {
7124                 GateRef code = GetAotCodeAddr(method);
7125                 switch (mode) {
7126                     case JSCallMode::CALL_THIS_ARG0:
7127                         thisValue = data[0];
7128                         [[fallthrough]];
7129                     case JSCallMode::CALL_ARG0:
7130                     case JSCallMode::DEPRECATED_CALL_ARG0:
7131                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue });
7132                         Jump(&exit);
7133                         break;
7134                     case JSCallMode::CALL_THIS_ARG1:
7135                         thisValue = data[1];
7136                         [[fallthrough]];
7137                     case JSCallMode::CALL_ARG1:
7138                     case JSCallMode::DEPRECATED_CALL_ARG1:
7139                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue, data[0] });
7140                         Jump(&exit);
7141                         break;
7142                     case JSCallMode::CALL_THIS_ARG2:
7143                         thisValue = data[2];
7144                         [[fallthrough]];
7145                     case JSCallMode::CALL_ARG2:
7146                     case JSCallMode::DEPRECATED_CALL_ARG2:
7147                         result = CallOptimized(glue, code,
7148                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
7149                         Jump(&exit);
7150                         break;
7151                     case JSCallMode::CALL_THIS_ARG3:
7152                         thisValue = data[3];
7153                         [[fallthrough]];
7154                     case JSCallMode::CALL_ARG3:
7155                     case JSCallMode::DEPRECATED_CALL_ARG3:
7156                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, thisValue,
7157                             data[0], data[1], data[2] });
7158                         Jump(&exit);
7159                         break;
7160                     case JSCallMode::CALL_THIS_WITH_ARGV:
7161                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
7162                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
7163                         thisValue = data[2]; // 2: this input
7164                         [[fallthrough]];
7165                     case JSCallMode::CALL_WITH_ARGV:
7166                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
7167                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
7168                             { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
7169                         Jump(&exit);
7170                         break;
7171                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
7172                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
7173                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgV),
7174                             { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
7175                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
7176                         Jump(&exit);
7177                         break;
7178                     case JSCallMode::CALL_GETTER:
7179                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, data[0] });
7180                         Jump(&exit);
7181                         break;
7182                     case JSCallMode::CALL_SETTER:
7183                         result = CallOptimized(glue, code, { glue, realNumArgs, func, newTarget, data[0], data[1] });
7184                         Jump(&exit);
7185                         break;
7186                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
7187                         result = CallOptimized(glue, code,
7188                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
7189                         Jump(&exit);
7190                         break;
7191                     case JSCallMode::SUPER_CALL_WITH_ARGV:
7192                         result = CallRuntime(glue, RTSTUB_ID(SuperCall), { data[0], data[1], IntToTaggedInt(data[2]) });
7193                         Jump(&exit);
7194                         break;
7195                     case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
7196                         result = CallRuntime(glue, RTSTUB_ID(SuperCallSpread), {data[0], data[1]});
7197                         Jump(&exit);
7198                         break;
7199                     default:
7200                         LOG_ECMA(FATAL) << "this branch is unreachable";
7201                         UNREACHABLE();
7202                 }
7203             }
7204             Bind(&slowCallBridge);
7205             {
7206                 switch (mode) {
7207                     case JSCallMode::CALL_THIS_ARG0:
7208                         thisValue = data[0];
7209                         [[fallthrough]];
7210                     case JSCallMode::CALL_ARG0:
7211                     case JSCallMode::DEPRECATED_CALL_ARG0:
7212                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7213                             { glue, realNumArgs, func, newTarget, thisValue});
7214                         Jump(&exit);
7215                         break;
7216                     case JSCallMode::CALL_THIS_ARG1:
7217                         thisValue = data[1];
7218                         [[fallthrough]];
7219                     case JSCallMode::CALL_ARG1:
7220                     case JSCallMode::DEPRECATED_CALL_ARG1:
7221                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7222                             { glue, realNumArgs, func, newTarget, thisValue, data[0] });
7223                         Jump(&exit);
7224                         break;
7225                     case JSCallMode::CALL_THIS_ARG2:
7226                         thisValue = data[2];
7227                         [[fallthrough]];
7228                     case JSCallMode::CALL_ARG2:
7229                     case JSCallMode::DEPRECATED_CALL_ARG2:
7230                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7231                             { glue, realNumArgs, func, newTarget, thisValue, data[0], data[1] });
7232                         Jump(&exit);
7233                         break;
7234                     case JSCallMode::CALL_THIS_ARG3:
7235                         thisValue = data[3];
7236                         [[fallthrough]];
7237                     case JSCallMode::CALL_ARG3:
7238                     case JSCallMode::DEPRECATED_CALL_ARG3:
7239                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7240                             { glue, realNumArgs, func, newTarget, thisValue,
7241                             data[0], data[1], data[2] }); // 2: args2
7242                         Jump(&exit);
7243                         break;
7244                     case JSCallMode::CALL_THIS_WITH_ARGV:
7245                     case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
7246                     case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
7247                         thisValue = data[2]; // 2: this input
7248                         [[fallthrough]];
7249                     case JSCallMode::CALL_WITH_ARGV:
7250                     case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
7251                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgVAndPushUndefined),
7252                             { glue, ZExtInt32ToInt64(actualNumArgs), func, newTarget, thisValue, data[1] });
7253                         Jump(&exit);
7254                         break;
7255                     case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
7256                     case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
7257                         result = CallNGCRuntime(glue, RTSTUB_ID(JSCallWithArgVAndPushUndefined),
7258                             { glue, ZExtInt32ToInt64(actualNumArgs), func, func, data[2], data[1]});
7259                         result = ConstructorCheck(glue, func, *result, data[2]);  // 2: the second index
7260                         Jump(&exit);
7261                         break;
7262                     case JSCallMode::CALL_GETTER:
7263                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7264                             { glue, realNumArgs, func, newTarget, data[0]});
7265                         Jump(&exit);
7266                         break;
7267                     case JSCallMode::CALL_SETTER:
7268                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7269                             { glue, realNumArgs, func, newTarget, data[0], data[1]});
7270                         Jump(&exit);
7271                         break;
7272                     case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
7273                         result = CallNGCRuntime(glue, RTSTUB_ID(OptimizedCallAndPushUndefined),
7274                             { glue, realNumArgs, func, newTarget, data[0], data[1], data[2], data[3] });
7275                         Jump(&exit);
7276                         break;
7277                     case JSCallMode::SUPER_CALL_WITH_ARGV:
7278                         result = CallRuntime(glue, RTSTUB_ID(SuperCall), { data[0], data[1], IntToTaggedInt(data[2]) });
7279                         Jump(&exit);
7280                         break;
7281                     case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
7282                         result = CallRuntime(glue, RTSTUB_ID(SuperCallSpread), {data[0], data[1]});
7283                         Jump(&exit);
7284                         break;
7285                     default:
7286                         LOG_ECMA(FATAL) << "this branch is unreachable";
7287                         UNREACHABLE();
7288                 }
7289             }
7290         }
7291 
7292         Bind(&methodNotAot);
7293         if (jumpSize != 0) {
7294             SaveJumpSizeIfNeeded(glue, jumpSize);
7295         }
7296         SaveHotnessCounterIfNeeded(glue, sp, hotnessCounter, mode);
7297         switch (mode) {
7298             case JSCallMode::CALL_THIS_ARG0:
7299                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg0AndDispatch),
7300                     { glue, sp, func, method, callField, data[0] });
7301                 Return();
7302                 break;
7303             case JSCallMode::CALL_ARG0:
7304             case JSCallMode::DEPRECATED_CALL_ARG0:
7305                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg0AndDispatch),
7306                     { glue, sp, func, method, callField });
7307                 Return();
7308                 break;
7309             case JSCallMode::CALL_THIS_ARG1:
7310                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArg1AndDispatch),
7311                     { glue, sp, func, method, callField, data[0], data[1] });
7312                 Return();
7313                 break;
7314             case JSCallMode::CALL_ARG1:
7315             case JSCallMode::DEPRECATED_CALL_ARG1:
7316                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArg1AndDispatch),
7317                     { glue, sp, func, method, callField, data[0] });
7318                 Return();
7319                 break;
7320             case JSCallMode::CALL_THIS_ARG2:
7321                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs2AndDispatch),
7322                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
7323                 Return();
7324                 break;
7325             case JSCallMode::CALL_ARG2:
7326             case JSCallMode::DEPRECATED_CALL_ARG2:
7327                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs2AndDispatch),
7328                     { glue, sp, func, method, callField, data[0], data[1] });
7329                 Return();
7330                 break;
7331             case JSCallMode::CALL_THIS_ARG3:
7332                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisArgs3AndDispatch),
7333                     { glue, sp, func, method, callField, data[0], data[1], data[2], data[3] });
7334                 Return();
7335                 break;
7336             case JSCallMode::CALL_ARG3:
7337             case JSCallMode::DEPRECATED_CALL_ARG3:
7338                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgs3AndDispatch),
7339                     { glue, sp, func, method, callField, data[0], data[1], data[2] }); // 2: args2
7340                 Return();
7341                 break;
7342             case JSCallMode::CALL_WITH_ARGV:
7343             case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
7344                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallRangeAndDispatch),
7345                     { glue, sp, func, method, callField, data[0], data[1] });
7346                 Return();
7347                 break;
7348             case JSCallMode::CALL_THIS_WITH_ARGV:
7349             case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
7350                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallThisRangeAndDispatch),
7351                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
7352                 Return();
7353                 break;
7354             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
7355             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
7356                 result = CallNGCRuntime(glue, RTSTUB_ID(PushCallNewAndDispatch),
7357                     { glue, sp, func, method, callField, data[0], data[1], data[2] });
7358                 Return();
7359                 break;
7360             case JSCallMode::CALL_GETTER:
7361                 result = CallNGCRuntime(glue, RTSTUB_ID(CallGetter),
7362                     { glue, func, method, callField, data[0] });
7363                 Jump(&exit);
7364                 break;
7365             case JSCallMode::CALL_SETTER:
7366                 result = CallNGCRuntime(glue, RTSTUB_ID(CallSetter),
7367                     { glue, func, method, callField, data[1], data[0] });
7368                 Jump(&exit);
7369                 break;
7370             case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
7371                 result = CallNGCRuntime(glue, RTSTUB_ID(CallContainersArgs3),
7372                     { glue, func, method, callField, data[1], data[2], data[3], data[0] });
7373                 Jump(&exit);
7374                 break;
7375             case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
7376                 result = CallNGCRuntime(glue, RTSTUB_ID(CallReturnWithArgv),
7377                     { glue, func, method, callField, data[0], data[1], data[2] });
7378                 Jump(&exit);
7379                 break;
7380             case JSCallMode::SUPER_CALL_WITH_ARGV:
7381             case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
7382                 result = CallNGCRuntime(glue, RTSTUB_ID(PushSuperCallAndDispatch),
7383                     { glue, sp, func, method, callField, data[2], data[3], data[4], data[5] });
7384                 Return();
7385                 break;
7386             default:
7387                 LOG_ECMA(FATAL) << "this branch is unreachable";
7388                 UNREACHABLE();
7389         }
7390     }
7391     Bind(&exit);
7392     auto ret = *result;
7393     env->SubCfgExit();
7394     return ret;
7395 }
7396 
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)7397 void StubBuilder::CallFastPath(GateRef glue, GateRef nativeCode, GateRef func, GateRef thisValue,
7398     GateRef actualNumArgs, GateRef callField, GateRef method, Label* notFastBuiltins, Label* exit, Variable* result,
7399     std::initializer_list<GateRef> args, JSCallMode mode)
7400 {
7401     auto env = GetEnvironment();
7402     auto data = std::begin(args);
7403     Label isFastBuiltins(env);
7404     GateRef numArgs = ZExtInt32ToPtr(actualNumArgs);
7405     GateRef isFastBuiltinsMask = Int64(static_cast<uint64_t>(1) << MethodLiteral::IsFastBuiltinBit::START_BIT);
7406     Branch(Int64NotEqual(Int64And(callField, isFastBuiltinsMask), Int64(0)), &isFastBuiltins, notFastBuiltins);
7407     Bind(&isFastBuiltins);
7408     {
7409         GateRef builtinId = GetBuiltinId(method);
7410         GateRef ret;
7411         switch (mode) {
7412             case JSCallMode::CALL_THIS_ARG0:
7413                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue, numArgs,
7414                     Undefined(), Undefined(), Undefined()});
7415                 break;
7416             case JSCallMode::CALL_THIS_ARG1:
7417                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(),
7418                                                           thisValue, numArgs, data[0], Undefined(), Undefined() });
7419                 break;
7420             case JSCallMode::CALL_THIS_ARG2:
7421                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
7422                                                           numArgs, data[0], data[1], Undefined() });
7423                 break;
7424             case JSCallMode::CALL_THIS_ARG3:
7425                 ret = DispatchBuiltins(glue, builtinId, { glue, nativeCode, func, Undefined(), thisValue,
7426                                                           numArgs, data[0], data[1], data[2] });
7427                 break;
7428             case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
7429             case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
7430                 ret = DispatchBuiltinsWithArgv(glue, builtinId, { glue, nativeCode, func, func, thisValue,
7431                                                                   numArgs, data[1] });
7432                 break;
7433             default:
7434                 LOG_ECMA(FATAL) << "this branch is unreachable";
7435                 UNREACHABLE();
7436         }
7437         result->WriteVariable(ret);
7438         Jump(exit);
7439     }
7440     Bind(notFastBuiltins);
7441 }
7442 
TryStringOrSymbolToElementIndex(GateRef glue,GateRef key)7443 GateRef StubBuilder::TryStringOrSymbolToElementIndex(GateRef glue, GateRef key)
7444 {
7445     auto env = GetEnvironment();
7446     Label entry(env);
7447     env->SubCfgEntry(&entry);
7448     Label exit(env);
7449     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
7450 
7451     Label keyNotSymbol(env);
7452     Branch(IsSymbol(key), &exit, &keyNotSymbol);
7453     Bind(&keyNotSymbol);
7454 
7455     Label greatThanZero(env);
7456     Label inRange(env);
7457     Label flattenFastPath(env);
7458     auto len = GetLengthFromString(key);
7459     Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
7460     Bind(&greatThanZero);
7461     Branch(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange);
7462     Bind(&inRange);
7463     {
7464         Label isUtf8(env);
7465         DEFVARIABLE(c, VariableType::INT32(), Int32(0));
7466         Branch(IsUtf16String(key), &exit, &isUtf8);
7467         Bind(&isUtf8);
7468         FlatStringStubBuilder thisFlat(this);
7469         thisFlat.FlattenString(glue, key, &flattenFastPath);
7470         Bind(&flattenFastPath);
7471         StringInfoGateRef stringInfoGate(&thisFlat);
7472         GateRef data = GetNormalStringData(stringInfoGate);
7473         c = ZExtInt8ToInt32(Load(VariableType::INT8(), data));
7474         Label isDigitZero(env);
7475         Label notDigitZero(env);
7476         Branch(Int32Equal(*c, Int32('0')), &isDigitZero, &notDigitZero);
7477         Bind(&isDigitZero);
7478         {
7479             Label lengthIsOne(env);
7480             Branch(Int32Equal(len, Int32(1)), &lengthIsOne, &exit);
7481             Bind(&lengthIsOne);
7482             {
7483                 result = Int32(0);
7484                 Jump(&exit);
7485             }
7486         }
7487         Bind(&notDigitZero);
7488         {
7489             Label isDigit(env);
7490             Label notIsDigit(env);
7491             DEFVARIABLE(i, VariableType::INT32(), Int32(1));
7492             DEFVARIABLE(n, VariableType::INT64(), Int64Sub(SExtInt32ToInt64(*c), Int64('0')));
7493 
7494             Branch(IsDigit(*c), &isDigit, &notIsDigit);
7495             Label loopHead(env);
7496             Label loopEnd(env);
7497             Label afterLoop(env);
7498             Bind(&isDigit);
7499             Branch(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop);
7500             LoopBegin(&loopHead);
7501             {
7502                 c = ZExtInt8ToInt32(Load(VariableType::INT8(), data, ZExtInt32ToPtr(*i)));
7503                 Label isDigit2(env);
7504                 Label notDigit2(env);
7505                 Branch(IsDigit(*c), &isDigit2, &notDigit2);
7506                 Bind(&isDigit2);
7507                 {
7508                     // 10 means the base of digit is 10.
7509                     n = Int64Add(Int64Mul(*n, Int64(10)),
7510                                  Int64Sub(SExtInt32ToInt64(*c), Int64('0')));
7511                     i = Int32Add(*i, Int32(1));
7512                     Branch(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop);
7513                 }
7514                 Bind(&notDigit2);
7515                 {
7516                     Label hasPoint(env);
7517                     Branch(Int32Equal(*c, Int32('.')), &hasPoint, &exit);
7518                     Bind(&hasPoint);
7519                     {
7520                         result = Int32(-2); // -2:return -2 means should goto slow path
7521                         Jump(&exit);
7522                     }
7523                 }
7524             }
7525             Bind(&loopEnd);
7526             LoopEnd(&loopHead);
7527             Bind(&afterLoop);
7528             {
7529                 Label lessThanMaxIndex(env);
7530                 Branch(Int64LessThan(*n, Int64(JSObject::MAX_ELEMENT_INDEX)),
7531                        &lessThanMaxIndex, &exit);
7532                 Bind(&lessThanMaxIndex);
7533                 {
7534                     result = TruncInt64ToInt32(*n);
7535                     Jump(&exit);
7536                 }
7537             }
7538             Bind(&notIsDigit);
7539             {
7540                 Label isNegative(env);
7541                 Branch(Int32Equal(*c, Int32('-')), &isNegative, &exit);
7542                 Bind(&isNegative);
7543                 {
7544                     result = Int32(-2); // -2:return -2 means should goto slow path
7545                     Jump(&exit);
7546                 }
7547             }
7548         }
7549     }
7550     Bind(&exit);
7551     auto ret = *result;
7552     env->SubCfgExit();
7553     return ret;
7554 }
7555 
GetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef jsType)7556 GateRef StubBuilder::GetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder,
7557                                                 GateRef key, GateRef jsType)
7558 {
7559     auto env = GetEnvironment();
7560     Label entry(env);
7561     env->SubCfgEntry(&entry);
7562     Label exit(env);
7563     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
7564 
7565     Label notOnProtoChain(env);
7566     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
7567     Bind(&notOnProtoChain);
7568 
7569     auto negativeZero = GetGlobalConstantValue(
7570         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
7571     Label isNegativeZero(env);
7572     Label notNegativeZero(env);
7573     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
7574     Bind(&isNegativeZero);
7575     {
7576         result = Undefined();
7577         Jump(&exit);
7578     }
7579     Bind(&notNegativeZero);
7580     {
7581         GateRef index = TryStringOrSymbolToElementIndex(glue, key);
7582         Label validIndex(env);
7583         Label notValidIndex(env);
7584         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
7585         Bind(&validIndex);
7586         {
7587             TypedArrayStubBuilder typedArrayStubBuilder(this);
7588             result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, holder, index, jsType);
7589             Jump(&exit);
7590         }
7591         Bind(&notValidIndex);
7592         {
7593             Label returnNull(env);
7594             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
7595             Bind(&returnNull);
7596             {
7597                 result = Null();
7598                 Jump(&exit);
7599             }
7600         }
7601     }
7602 
7603     Bind(&exit);
7604     auto ret = *result;
7605     env->SubCfgExit();
7606     return ret;
7607 }
7608 
SetTypeArrayPropertyByName(GateRef glue,GateRef receiver,GateRef holder,GateRef key,GateRef value,GateRef jsType)7609 GateRef StubBuilder::SetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder, GateRef key,
7610                                                 GateRef value, GateRef jsType)
7611 {
7612     auto env = GetEnvironment();
7613     Label entry(env);
7614     env->SubCfgEntry(&entry);
7615     Label exit(env);
7616     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
7617     Label notOnProtoChain(env);
7618     Branch(Int64NotEqual(receiver, holder), &exit, &notOnProtoChain);
7619     Bind(&notOnProtoChain);
7620 
7621     auto negativeZero = GetGlobalConstantValue(
7622         VariableType::JS_POINTER(), glue, ConstantIndex::NEGATIVE_ZERO_STRING_INDEX);
7623     Label isNegativeZero(env);
7624     Label notNegativeZero(env);
7625     Branch(Equal(negativeZero, key), &isNegativeZero, &notNegativeZero);
7626     Bind(&isNegativeZero);
7627     {
7628         Label isObj(env);
7629         Label notObj(env);
7630         Branch(IsEcmaObject(value), &isObj, &notObj);
7631         Bind(&isObj);
7632         {
7633             result = Null();
7634             Jump(&exit);
7635         }
7636         Bind(&notObj);
7637         result = Undefined();
7638         Jump(&exit);
7639     }
7640     Bind(&notNegativeZero);
7641     {
7642         GateRef index = TryStringOrSymbolToElementIndex(glue, key);
7643         Label validIndex(env);
7644         Label notValidIndex(env);
7645         Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
7646         Bind(&validIndex);
7647         {
7648             result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
7649                 { receiver, IntToTaggedInt(index), value, IntToTaggedInt(jsType) });
7650             Jump(&exit);
7651         }
7652         Bind(&notValidIndex);
7653         {
7654             Label returnNull(env);
7655             Branch(Int32Equal(index, Int32(-2)), &returnNull, &exit); // -2:equal -2 means should goto slow path
7656             Bind(&returnNull);
7657             {
7658                 result = Null();
7659                 Jump(&exit);
7660             }
7661         }
7662     }
7663 
7664     Bind(&exit);
7665     auto ret = *result;
7666     env->SubCfgExit();
7667     return ret;
7668 }
7669 
Assert(int messageId,int line,GateRef glue,GateRef condition,Label * nextLabel)7670 void StubBuilder::Assert(int messageId, int line, GateRef glue, GateRef condition, Label *nextLabel)
7671 {
7672     auto env = GetEnvironment();
7673     Label ok(env);
7674     Label notOk(env);
7675     Branch(condition, &ok, &notOk);
7676     Bind(&ok);
7677     {
7678         Jump(nextLabel);
7679     }
7680     Bind(&notOk);
7681     {
7682         FatalPrint(glue, { Int32(messageId), Int32(line) });
7683         Jump(nextLabel);
7684     }
7685 }
7686 
GetNormalStringData(const StringInfoGateRef & stringInfoGate)7687 GateRef StubBuilder::GetNormalStringData(const StringInfoGateRef &stringInfoGate)
7688 {
7689     auto env = GetEnvironment();
7690     Label entry(env);
7691     env->SubCfgEntry(&entry);
7692     Label exit(env);
7693     Label isConstantString(env);
7694     Label isLineString(env);
7695     Label isUtf8(env);
7696     Label isUtf16(env);
7697     DEFVARIABLE(result, VariableType::NATIVE_POINTER(), Undefined());
7698     Branch(IsConstantString(stringInfoGate.GetString()), &isConstantString, &isLineString);
7699     Bind(&isConstantString);
7700     {
7701         GateRef address = PtrAdd(stringInfoGate.GetString(), IntPtr(ConstantString::CONSTANT_DATA_OFFSET));
7702         result = PtrAdd(Load(VariableType::NATIVE_POINTER(), address, IntPtr(0)),
7703             ZExtInt32ToPtr(stringInfoGate.GetStartIndex()));
7704         Jump(&exit);
7705     }
7706     Bind(&isLineString);
7707     {
7708         GateRef data = ChangeTaggedPointerToInt64(
7709             PtrAdd(stringInfoGate.GetString(), IntPtr(LineEcmaString::DATA_OFFSET)));
7710         Branch(IsUtf8String(stringInfoGate.GetString()), &isUtf8, &isUtf16);
7711         Bind(&isUtf8);
7712         {
7713             result = PtrAdd(data, ZExtInt32ToPtr(stringInfoGate.GetStartIndex()));
7714             Jump(&exit);
7715         }
7716         Bind(&isUtf16);
7717         {
7718             GateRef offset = PtrMul(ZExtInt32ToPtr(stringInfoGate.GetStartIndex()), IntPtr(sizeof(uint16_t)));
7719             result = PtrAdd(data, offset);
7720             Jump(&exit);
7721         }
7722     }
7723     Bind(&exit);
7724     auto ret = *result;
7725     env->SubCfgExit();
7726     return ret;
7727 }
7728 
ToNumber(GateRef glue,GateRef tagged)7729 GateRef StubBuilder::ToNumber(GateRef glue, GateRef tagged)
7730 {
7731     auto env = GetEnvironment();
7732     Label entry(env);
7733     env->SubCfgEntry(&entry);
7734     Label exit(env);
7735     Label isNumber(env);
7736     Label notNumber(env);
7737     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
7738     Branch(TaggedIsNumber(tagged), &isNumber, &notNumber);
7739     Bind(&isNumber);
7740     {
7741         result = tagged;
7742         Jump(&exit);
7743     }
7744     Bind(&notNumber);
7745     {
7746         result = CallRuntime(glue, RTSTUB_ID(ToNumber), { tagged });
7747         Jump(&exit);
7748     }
7749     Bind(&exit);
7750     auto ret = *result;
7751     env->SubCfgExit();
7752     return ret;
7753 }
7754 
ToLength(GateRef glue,GateRef target)7755 GateRef StubBuilder::ToLength(GateRef glue, GateRef target)
7756 {
7757     auto env = GetEnvironment();
7758     Label subentry(env);
7759     env->SubCfgEntry(&subentry);
7760     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
7761     Label exit(env);
7762 
7763     GateRef number = ToNumber(glue, target);
7764     Label isPendingException(env);
7765     Label noPendingException(env);
7766     Branch(HasPendingException(glue), &isPendingException, &noPendingException);
7767     Bind(&isPendingException);
7768     {
7769         Jump(&exit);
7770     }
7771     Bind(&noPendingException);
7772     {
7773         GateRef num = GetDoubleOfTNumber(number);
7774         Label targetLessThanZero(env);
7775         Label targetGreaterThanZero(env);
7776         Label targetLessThanSafeNumber(env);
7777         Label targetGreaterThanSafeNumber(env);
7778         Branch(DoubleLessThan(num, Double(0.0)), &targetLessThanZero, &targetGreaterThanZero);
7779         Bind(&targetLessThanZero);
7780         {
7781             res = DoubleToTaggedDoublePtr(Double(0.0));
7782             Jump(&exit);
7783         }
7784         Bind(&targetGreaterThanZero);
7785         Branch(DoubleGreaterThan(num, Double(SAFE_NUMBER)), &targetGreaterThanSafeNumber, &targetLessThanSafeNumber);
7786         Bind(&targetGreaterThanSafeNumber);
7787         {
7788             res = DoubleToTaggedDoublePtr(Double(SAFE_NUMBER));
7789             Jump(&exit);
7790         }
7791         Bind(&targetLessThanSafeNumber);
7792         {
7793             res = number;
7794             Jump(&exit);
7795         }
7796     }
7797     Bind(&exit);
7798     auto ret = *res;
7799     env->SubCfgExit();
7800     return ret;
7801 }
7802 
TaggedGetNumber(GateRef x)7803 GateRef StubBuilder::TaggedGetNumber(GateRef x)
7804 {
7805     auto env = GetEnvironment();
7806     Label subentry(env);
7807     Label exit(env);
7808     env->SubCfgEntry(&subentry);
7809 
7810     Label targetIsInt(env);
7811     Label targetIsDouble(env);
7812     DEFVALUE(number, env_, VariableType::FLOAT64(), Double(0));
7813     Branch(TaggedIsInt(x), &targetIsInt, &targetIsDouble);
7814     Bind(&targetIsInt);
7815     {
7816         number = ChangeInt32ToFloat64(TaggedGetInt(x));
7817         Jump(&exit);
7818     }
7819     Bind(&targetIsDouble);
7820     {
7821         number = GetDoubleOfTDouble(x);
7822         Jump(&exit);
7823     }
7824     Bind(&exit);
7825     GateRef ret = *number;
7826     env->SubCfgExit();
7827     return ret;
7828 }
7829 
NumberGetInt(GateRef glue,GateRef x)7830 GateRef StubBuilder::NumberGetInt(GateRef glue, GateRef x)
7831 {
7832     auto env = GetEnvironment();
7833     Label subentry(env);
7834     Label exit(env);
7835     env->SubCfgEntry(&subentry);
7836 
7837     Label targetIsInt(env);
7838     Label targetIsDouble(env);
7839     DEFVALUE(number, env_, VariableType::INT32(), Int32(0));
7840     Branch(TaggedIsInt(x), &targetIsInt, &targetIsDouble);
7841     Bind(&targetIsInt);
7842     {
7843         number = TaggedGetInt(x);
7844         Jump(&exit);
7845     }
7846     Bind(&targetIsDouble);
7847     {
7848         number = DoubleToInt(glue, GetDoubleOfTDouble(x));
7849         Jump(&exit);
7850     }
7851     Bind(&exit);
7852     GateRef ret = *number;
7853     env->SubCfgExit();
7854     return ret;
7855 }
7856 
HasStableElements(GateRef glue,GateRef obj)7857 GateRef StubBuilder::HasStableElements(GateRef glue, GateRef obj)
7858 {
7859     auto env = GetEnvironment();
7860     Label subentry(env);
7861     env->SubCfgEntry(&subentry);
7862     DEFVARIABLE(result, VariableType::BOOL(), False());
7863     Label exit(env);
7864     Label targetIsHeapObject(env);
7865     Label targetIsStableElements(env);
7866 
7867     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
7868     Bind(&targetIsHeapObject);
7869     {
7870         GateRef jsHclass = LoadHClass(obj);
7871         Branch(IsStableElements(jsHclass), &targetIsStableElements, &exit);
7872         Bind(&targetIsStableElements);
7873         {
7874             GateRef guardiansOffset =
7875                 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
7876             result = Load(VariableType::BOOL(), glue, guardiansOffset);
7877             Jump(&exit);
7878         }
7879     }
7880     Bind(&exit);
7881     auto res = *result;
7882     env->SubCfgExit();
7883     return res;
7884 }
7885 
IsStableJSArguments(GateRef glue,GateRef obj)7886 GateRef StubBuilder::IsStableJSArguments(GateRef glue, GateRef obj)
7887 {
7888     auto env = GetEnvironment();
7889     Label subentry(env);
7890     env->SubCfgEntry(&subentry);
7891     DEFVARIABLE(result, VariableType::BOOL(), False());
7892     Label exit(env);
7893     Label targetIsHeapObject(env);
7894     Label targetIsStableArguments(env);
7895 
7896     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
7897     Bind(&targetIsHeapObject);
7898     {
7899         GateRef jsHclass = LoadHClass(obj);
7900         Branch(IsStableArguments(jsHclass), &targetIsStableArguments, &exit);
7901         Bind(&targetIsStableArguments);
7902         {
7903             GateRef guardiansOffset =
7904                 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
7905             result = Load(VariableType::BOOL(), glue, guardiansOffset);
7906             Jump(&exit);
7907         }
7908     }
7909     Bind(&exit);
7910     auto res = *result;
7911     env->SubCfgExit();
7912     return res;
7913 }
7914 
IsStableJSArray(GateRef glue,GateRef obj)7915 GateRef StubBuilder::IsStableJSArray(GateRef glue, GateRef obj)
7916 {
7917     auto env = GetEnvironment();
7918     Label subentry(env);
7919     env->SubCfgEntry(&subentry);
7920     DEFVARIABLE(result, VariableType::BOOL(), False());
7921     Label exit(env);
7922     Label targetIsHeapObject(env);
7923     Label targetIsStableArray(env);
7924 
7925     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
7926     Bind(&targetIsHeapObject);
7927     {
7928         GateRef jsHclass = LoadHClass(obj);
7929         Branch(IsStableArray(jsHclass), &targetIsStableArray, &exit);
7930         Bind(&targetIsStableArray);
7931         {
7932             GateRef guardiansOffset =
7933                 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(env->Is32Bit()));
7934             GateRef guardians = Load(VariableType::BOOL(), glue, guardiansOffset);
7935             result.WriteVariable(guardians);
7936             Jump(&exit);
7937         }
7938     }
7939     Bind(&exit);
7940     auto res = *result;
7941     env->SubCfgExit();
7942     return res;
7943 }
7944 
UpdateProfileTypeInfo(GateRef glue,GateRef jsFunc)7945 GateRef StubBuilder::UpdateProfileTypeInfo(GateRef glue, GateRef jsFunc)
7946 {
7947     auto env = GetEnvironment();
7948     Label entry(env);
7949     env->SubCfgEntry(&entry);
7950     Label needUpdate(env);
7951     Label exit(env);
7952     DEFVARIABLE(profileTypeInfo, VariableType::JS_POINTER(), GetProfileTypeInfo(jsFunc));
7953     Branch(TaggedIsUndefined(*profileTypeInfo), &needUpdate, &exit);
7954     Bind(&needUpdate);
7955     {
7956         profileTypeInfo = CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounter), { jsFunc });
7957         Jump(&exit);
7958     }
7959     Bind(&exit);
7960     auto ret = *profileTypeInfo;
7961     env->SubCfgExit();
7962     return ret;
7963 }
7964 
GetFuncKind(GateRef method)7965 GateRef StubBuilder::GetFuncKind(GateRef method)
7966 {
7967     GateRef extraLiteralInfoOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET);
7968     GateRef bitfield = Load(VariableType::INT32(), method, extraLiteralInfoOffset);
7969 
7970     GateRef kind = Int32And(Int32LSR(bitfield, Int32(Method::FunctionKindBits::START_BIT)),
7971                             Int32((1LU << Method::FunctionKindBits::SIZE) - 1));
7972     return kind;
7973 }
7974 
GetCallSpreadArgs(GateRef glue,GateRef array,ProfileOperation callBack)7975 GateRef StubBuilder::GetCallSpreadArgs(GateRef glue, GateRef array, ProfileOperation callBack)
7976 {
7977     auto env = GetEnvironment();
7978     Label subEntry(env);
7979     env->SubCfgEntry(&subEntry);
7980     DEFVARIABLE(result, VariableType::JS_POINTER(), NullPtr());
7981     Label fastPath(env);
7982     Label noCopyPath(env);
7983     Label exit(env);
7984 
7985     GateRef itor = GetIterator(glue, array, callBack);
7986     GateRef iterHClass = LoadHClass(itor);
7987     GateRef isJSArrayIter = Int32Equal(GetObjectType(iterHClass),
7988                                        Int32(static_cast<int32_t>(JSType::JS_ARRAY_ITERATOR)));
7989     GateRef needCopy = BoolAnd(IsStableJSArray(glue, array), isJSArrayIter);
7990     Branch(needCopy, &fastPath, &noCopyPath);
7991     Bind(&fastPath);
7992     {
7993         // copy operation is omitted
7994         result = GetElementsArray(array);
7995         Jump(&exit);
7996     }
7997     Bind(&noCopyPath);
7998     {
7999         result = CallRuntime(glue, RTSTUB_ID(GetCallSpreadArgs), { array });
8000         Jump(&exit);
8001     }
8002     Bind(&exit);
8003     auto ret = *result;
8004     env->SubCfgExit();
8005     return ret;
8006 }
8007 
CalArrayRelativePos(GateRef index,GateRef arrayLen)8008 GateRef StubBuilder::CalArrayRelativePos(GateRef index, GateRef arrayLen)
8009 {
8010     auto env = GetEnvironment();
8011     Label entryPass(env);
8012     env->SubCfgEntry(&entryPass);
8013     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
8014 
8015     Label indexLessZero(env);
8016     Label indexNotLessZero(env);
8017     Label exit(env);
8018     Branch(Int32LessThan(index, Int32(0)), &indexLessZero, &indexNotLessZero);
8019     Bind(&indexLessZero);
8020     {
8021         GateRef tempBeginIndex = Int32Add(arrayLen, index);
8022         Label beginIndexLargeZero(env);
8023         Branch(Int32GreaterThan(tempBeginIndex, Int32(0)), &beginIndexLargeZero, &exit);
8024         Bind(&beginIndexLargeZero);
8025         {
8026             result = tempBeginIndex;
8027             Jump(&exit);
8028         }
8029     }
8030     Bind(&indexNotLessZero);
8031     {
8032         Label lessLen(env);
8033         Label largeLen(env);
8034         Branch(Int32LessThan(index, arrayLen), &lessLen, &largeLen);
8035         Bind(&lessLen);
8036         {
8037             result = index;
8038             Jump(&exit);
8039         }
8040         Bind(&largeLen);
8041         {
8042             result = arrayLen;
8043             Jump(&exit);
8044         }
8045     }
8046 
8047     Bind(&exit);
8048     auto ret = *result;
8049     env->SubCfgExit();
8050     return ret;
8051 }
8052 
AppendSkipHole(GateRef glue,GateRef first,GateRef second,GateRef copyLength)8053 GateRef StubBuilder::AppendSkipHole(GateRef glue, GateRef first, GateRef second, GateRef copyLength)
8054 {
8055     auto env = GetEnvironment();
8056     Label subEntry(env);
8057     env->SubCfgEntry(&subEntry);
8058     Label exit(env);
8059     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
8060     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
8061     DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
8062 
8063     GateRef firstLength = GetLengthOfTaggedArray(first);
8064     GateRef secondLength = GetLengthOfTaggedArray(second);
8065     NewObjectStubBuilder newBuilder(this);
8066     GateRef array = newBuilder.NewTaggedArray(glue, copyLength);
8067     Label loopHead(env);
8068     Label loopEnd(env);
8069     Label afterLoop(env);
8070     Label storeValue(env);
8071     Label notHole(env);
8072     Jump(&loopHead);
8073     LoopBegin(&loopHead);
8074     {
8075         Branch(Int32UnsignedLessThan(*index, firstLength), &storeValue, &afterLoop);
8076         Bind(&storeValue);
8077         {
8078             GateRef value = GetValueFromTaggedArray(first, *index);
8079             Branch(TaggedIsHole(value), &afterLoop, &notHole);
8080             Bind(&notHole);
8081             SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, value);
8082             index = Int32Add(*index, Int32(1));
8083             Jump(&loopEnd);
8084         }
8085     }
8086     Bind(&loopEnd);
8087     LoopEnd(&loopHead);
8088     Bind(&afterLoop);
8089     {
8090         Label loopHead1(env);
8091         Label loopEnd1(env);
8092         Label storeValue1(env);
8093         Label notHole1(env);
8094         Jump(&loopHead1);
8095         LoopBegin(&loopHead1);
8096         {
8097             Branch(Int32UnsignedLessThan(*i, secondLength), &storeValue1, &exit);
8098             Bind(&storeValue1);
8099             {
8100                 GateRef value1 = GetValueFromTaggedArray(second, *i);
8101                 Branch(TaggedIsHole(value1), &exit, &notHole1);
8102                 Bind(&notHole1);
8103                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, value1);
8104                 i = Int32Add(*i, Int32(1));
8105                 index = Int32Add(*index, Int32(1));
8106                 Jump(&loopEnd1);
8107             }
8108         }
8109         Bind(&loopEnd1);
8110         LoopEnd(&loopHead1);
8111     }
8112     Bind(&exit);
8113     res = array;
8114     auto ret = *res;
8115     env->SubCfgExit();
8116     return ret;
8117 }
8118 
IntToEcmaString(GateRef glue,GateRef number)8119 GateRef StubBuilder::IntToEcmaString(GateRef glue, GateRef number)
8120 {
8121     auto env = GetEnvironment();
8122     Label subEntry(env);
8123     env->SubCfgEntry(&subEntry);
8124     Label exit(env);
8125     DEFVARIABLE(n, VariableType::INT32(), number);
8126     DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
8127 
8128     GateRef isPositive = Int32GreaterThanOrEqual(number, Int32(0));
8129     GateRef isSingle = Int32LessThan(number, Int32(10));
8130     Label process(env);
8131     Label callRuntime(env);
8132     Label afterNew(env);
8133     Branch(BoolAnd(isPositive, isSingle), &process, &callRuntime);
8134     Bind(&process);
8135     {
8136         NewObjectStubBuilder newBuilder(this);
8137         newBuilder.SetParameters(glue, 0);
8138         newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), true);
8139         Bind(&afterNew);
8140         n = Int32Add(Int32('0'), *n);
8141         GateRef dst = ChangeTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
8142         Store(VariableType::INT8(), glue, dst, IntPtr(0), TruncInt32ToInt8(*n));
8143         Jump(&exit);
8144     }
8145     Bind(&callRuntime);
8146     {
8147         result = CallRuntime(glue, RTSTUB_ID(IntToString), { IntToTaggedInt(*n) });
8148         Jump(&exit);
8149     }
8150     Bind(&exit);
8151     auto ret = *result;
8152     env->SubCfgExit();
8153     return ret;
8154 }
8155 
GetTaggedValueWithElementsKind(GateRef receiver,GateRef index)8156 GateRef StubBuilder::GetTaggedValueWithElementsKind(GateRef receiver, GateRef index)
8157 {
8158     auto env = GetEnvironment();
8159     Label entryPass(env);
8160     env->SubCfgEntry(&entryPass);
8161     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
8162     Label exit(env);
8163 
8164     GateRef hclass = LoadHClass(receiver);
8165     DEFVARIABLE(elementsKind, VariableType::INT32(), GetElementsKindFromHClass(hclass));
8166     Label isMutantTaggedArray(env);
8167     Label isNotMutantTaggedArray(env);
8168     GateRef elements = GetElementsArray(receiver);
8169     Branch(IsMutantTaggedArray(elements), &isMutantTaggedArray, &isNotMutantTaggedArray);
8170     Bind(&isNotMutantTaggedArray);
8171     {
8172         elementsKind = Int32(static_cast<int32_t>(ElementsKind::GENERIC));
8173         Jump(&isMutantTaggedArray);
8174     }
8175     Bind(&isMutantTaggedArray);
8176     GateRef rawValue = GetValueFromMutantTaggedArray(elements, index);
8177     Label isSpecialHole(env);
8178     Label isNotSpecialHole(env);
8179     Branch(Int64Equal(rawValue, SpecialHole()), &isSpecialHole, &isNotSpecialHole);
8180     Bind(&isSpecialHole);
8181     {
8182         Jump(&exit);
8183     }
8184     Bind(&isNotSpecialHole);
8185     {
8186         Label isInt(env);
8187         Label isNotInt(env);
8188         GateRef elementsKindIntLowerBound = Int32GreaterThanOrEqual(*elementsKind,
8189                                                                     Int32(static_cast<int32_t>(ElementsKind::INT)));
8190         GateRef elementsKindIntUpperBound = Int32LessThanOrEqual(*elementsKind,
8191                                                                  Int32(static_cast<int32_t>(ElementsKind::HOLE_INT)));
8192         GateRef checkIntKind = BoolAnd(elementsKindIntLowerBound, elementsKindIntUpperBound);
8193         Branch(checkIntKind, &isInt, &isNotInt);
8194         Bind(&isInt);
8195         {
8196             result = Int64ToTaggedIntPtr(rawValue);
8197             Jump(&exit);
8198         }
8199         Bind(&isNotInt);
8200         {
8201             Label isNumber(env);
8202             Label isNotNumber(env);
8203             GateRef elementsKindNumberLB = Int32GreaterThanOrEqual(*elementsKind,
8204                                                                    Int32(static_cast<int32_t>(ElementsKind::NUMBER)));
8205             GateRef elementsKindNumberUB = Int32LessThanOrEqual(*elementsKind,
8206                                                                 Int32(static_cast<int32_t>(ElementsKind::HOLE_NUMBER)));
8207             GateRef checkNumberKind = BoolAnd(elementsKindNumberLB, elementsKindNumberUB);
8208             Branch(checkNumberKind, &isNumber, &isNotNumber);
8209             Bind(&isNumber);
8210             {
8211                 GateRef numberValue = CastInt64ToFloat64(rawValue);
8212                 result = DoubleToTaggedDoublePtr(numberValue);
8213                 Jump(&exit);
8214             }
8215             Bind(&isNotNumber);
8216             {
8217                 result = Int64ToTaggedPtr(rawValue);
8218                 Jump(&exit);
8219             }
8220         }
8221     }
8222     Bind(&exit);
8223     auto ret = *result;
8224     env->SubCfgExit();
8225     return ret;
8226 }
8227 
SetValueWithElementsKind(GateRef glue,GateRef receiver,GateRef rawValue,GateRef index,GateRef needTransition,GateRef extraKind)8228 GateRef StubBuilder::SetValueWithElementsKind(GateRef glue, GateRef receiver, GateRef rawValue,
8229                                               GateRef index, GateRef needTransition, GateRef extraKind)
8230 {
8231     auto env = GetEnvironment();
8232     Label entryPass(env);
8233     env->SubCfgEntry(&entryPass);
8234     DEFVARIABLE(result, VariableType::INT64(), SpecialHole());
8235     Label exit(env);
8236 
8237     Label transitElementsKind(env);
8238     Label finishTransition(env);
8239     Branch(needTransition, &transitElementsKind, &finishTransition);
8240     Bind(&transitElementsKind);
8241     {
8242         TransitToElementsKind(glue, receiver, rawValue, extraKind);
8243         Jump(&finishTransition);
8244     }
8245     Bind(&finishTransition);
8246     GateRef hclass = LoadHClass(receiver);
8247     DEFVARIABLE(elementsKind, VariableType::INT32(), GetElementsKindFromHClass(hclass));
8248     Label setValue(env);
8249     Label isMutantTaggedArray(env);
8250     Label isNotMutantTaggedArray(env);
8251     GateRef elements = GetElementsArray(receiver);
8252     Branch(IsMutantTaggedArray(elements), &isMutantTaggedArray, &isNotMutantTaggedArray);
8253     Bind(&isNotMutantTaggedArray);
8254     {
8255         elementsKind = Int32(static_cast<int32_t>(ElementsKind::GENERIC));
8256         Jump(&isMutantTaggedArray);
8257     }
8258     Bind(&isMutantTaggedArray);
8259     Label isHole(env);
8260     Label isNotHole(env);
8261     GateRef valueIsHole = TaggedIsHole(rawValue);
8262     GateRef elementsKindInNumbersLB = Int32GreaterThanOrEqual(*elementsKind,
8263                                                               Int32(static_cast<int32_t>(ElementsKind::HOLE)));
8264     GateRef elementsKindInNumbersUB = Int32LessThan(*elementsKind, Int32(static_cast<int32_t>(ElementsKind::STRING)));
8265     GateRef checkInNumersKind = BoolAnd(BoolAnd(valueIsHole, elementsKindInNumbersLB), elementsKindInNumbersUB);
8266     Branch(checkInNumersKind, &isHole, &isNotHole);
8267     Bind(&isHole);
8268     {
8269         Jump(&setValue);
8270     }
8271     Bind(&isNotHole);
8272     {
8273         Label isInt(env);
8274         Label isNotInt(env);
8275         GateRef elementsKindIntLB = Int32GreaterThanOrEqual(*elementsKind,
8276                                                             Int32(static_cast<int32_t>(ElementsKind::INT)));
8277         GateRef elementsKindIntUB = Int32LessThanOrEqual(*elementsKind,
8278                                                          Int32(static_cast<int32_t>(ElementsKind::HOLE_INT)));
8279         GateRef checkIntKind = BoolAnd(elementsKindIntLB, elementsKindIntUB);
8280         Branch(checkIntKind, &isInt, &isNotInt);
8281         Bind(&isInt);
8282         {
8283             result = GetInt64OfTInt(rawValue);
8284             Jump(&setValue);
8285         }
8286         Bind(&isNotInt);
8287         {
8288             Label isNumber(env);
8289             Label isNotNumber(env);
8290             GateRef elementsKindNumberLB = Int32GreaterThanOrEqual(*elementsKind,
8291                                                                    Int32(static_cast<int32_t>(ElementsKind::NUMBER)));
8292             GateRef elementsKindNumberUB = Int32LessThanOrEqual(*elementsKind,
8293                                                                 Int32(static_cast<int32_t>(ElementsKind::HOLE_NUMBER)));
8294             GateRef checkNumberKind = BoolAnd(elementsKindNumberLB, elementsKindNumberUB);
8295             Branch(checkNumberKind, &isNumber, &isNotNumber);
8296             Bind(&isNumber);
8297             {
8298                 Label isNumberInt(env);
8299                 Label isNotNumberInt(env);
8300                 Branch(TaggedIsInt(rawValue), &isNumberInt, &isNotNumberInt);
8301                 Bind(&isNumberInt);
8302                 {
8303                     result = CastDoubleToInt64(GetDoubleOfTInt(rawValue));
8304                     Jump(&setValue);
8305                 }
8306                 Bind(&isNotNumberInt);
8307                 {
8308                     result = CastDoubleToInt64(GetDoubleOfTDouble(rawValue));
8309                     Jump(&setValue);
8310                 }
8311             }
8312             Bind(&isNotNumber);
8313             {
8314                 result = ChangeTaggedPointerToInt64(rawValue);
8315                 Jump(&setValue);
8316             }
8317         }
8318     }
8319     Bind(&setValue);
8320     Label storeToNormalArray(env);
8321     Label storeToMutantArray(env);
8322     Branch(TaggedIsHeapObject(rawValue), &storeToNormalArray, &storeToMutantArray);
8323     Bind(&storeToNormalArray);
8324     {
8325         SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, *result);
8326         Jump(&exit);
8327     }
8328     Bind(&storeToMutantArray);
8329     {
8330         SetValueToTaggedArray(VariableType::INT64(), glue, elements, index, *result);
8331         Jump(&exit);
8332     }
8333     Bind(&exit);
8334     auto ret = *result;
8335     env->SubCfgExit();
8336     return ret;
8337 }
8338 }  // namespace panda::ecmascript::kungfu
8339