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