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