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