• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/type_lowering.h"
17 #include "ecmascript/compiler/builtins_lowering.h"
18 #include "ecmascript/compiler/new_object_stub_builder.h"
19 #include "ecmascript/deoptimizer/deoptimizer.h"
20 #include "ecmascript/js_arraybuffer.h"
21 #include "ecmascript/js_native_pointer.h"
22 
23 namespace panda::ecmascript::kungfu {
RunTypeLowering()24 void TypeLowering::RunTypeLowering()
25 {
26     std::vector<GateRef> gateList;
27     circuit_->GetAllGates(gateList);
28     for (const auto &gate : gateList) {
29         LowerType(gate);
30     }
31 
32     if (IsLogEnabled()) {
33         LOG_COMPILER(INFO) << "";
34         LOG_COMPILER(INFO) << "\033[34m" << "=================="
35                            << " after type lowering "
36                            << "[" << GetMethodName() << "] "
37                            << "==================" << "\033[0m";
38         circuit_->PrintAllGatesWithBytecode();
39         LOG_COMPILER(INFO) << "\033[34m" << "=========================== End =========================" << "\033[0m";
40     }
41 }
42 
LowerType(GateRef gate)43 void TypeLowering::LowerType(GateRef gate)
44 {
45     GateRef glue = acc_.GetGlueFromArgList();
46     auto op = OpCode(acc_.GetOpCode(gate));
47     switch (op) {
48         case OpCode::PRIMITIVE_TYPE_CHECK:
49             LowerPrimitiveTypeCheck(gate);
50             break;
51         case OpCode::ARRAY_CHECK:
52             LowerArrayCheck(gate, glue);
53             break;
54         case OpCode::STABLE_ARRAY_CHECK:
55             LowerStableArrayCheck(gate, glue);
56             break;
57         case OpCode::TYPED_ARRAY_CHECK:
58             LowerTypedArrayCheck(gate, glue);
59             break;
60         case OpCode::OBJECT_TYPE_CHECK:
61             LowerObjectTypeCheck(gate);
62             break;
63         case OpCode::INDEX_CHECK:
64             LowerIndexCheck(gate);
65             break;
66         case OpCode::INT32_OVERFLOW_CHECK:
67             LowerOverflowCheck(gate);
68             break;
69         case OpCode::TYPED_CALL_CHECK:
70             LowerCallTargetCheck(gate);
71             break;
72         case OpCode::TYPED_BINARY_OP:
73             LowerTypedBinaryOp(gate);
74             break;
75         case OpCode::TYPE_CONVERT:
76             LowerTypeConvert(gate);
77             break;
78         case OpCode::TYPED_UNARY_OP:
79             LowerTypedUnaryOp(gate);
80             break;
81         case OpCode::LOAD_PROPERTY:
82             LowerLoadProperty(gate, glue);
83             break;
84         case OpCode::STORE_PROPERTY:
85             LowerStoreProperty(gate, glue);
86             break;
87         case OpCode::LOAD_ARRAY_LENGTH:
88             LowerLoadArrayLength(gate);
89             break;
90         case OpCode::LOAD_ELEMENT:
91             LowerLoadElement(gate);
92             break;
93         case OpCode::STORE_ELEMENT:
94             LowerStoreElement(gate, glue);
95             break;
96         case OpCode::HEAP_ALLOC:
97             LowerHeapAllocate(gate, glue);
98             break;
99         case OpCode::TYPED_CALL:
100             LowerTypedCallBuitin(gate);
101             break;
102         case OpCode::TYPED_NEW_ALLOCATE_THIS:
103             LowerTypedNewAllocateThis(gate, glue);
104             break;
105         case OpCode::TYPED_SUPER_ALLOCATE_THIS:
106             LowerTypedSuperAllocateThis(gate, glue);
107             break;
108         case OpCode::GET_SUPER_CONSTRUCTOR:
109             LowerGetSuperConstructor(gate);
110             break;
111         default:
112             break;
113     }
114 }
115 
LowerPrimitiveTypeCheck(GateRef gate)116 void TypeLowering::LowerPrimitiveTypeCheck(GateRef gate)
117 {
118     Environment env(gate, circuit_, &builder_);
119     auto type = acc_.GetParamGateType(gate);
120     if (type.IsIntType()) {
121         LowerIntCheck(gate);
122     } else if (type.IsDoubleType()) {
123         LowerDoubleCheck(gate);
124     } else if (type.IsNumberType()) {
125         LowerNumberCheck(gate);
126     } else if (type.IsBooleanType()) {
127         LowerBooleanCheck(gate);
128     } else {
129         UNREACHABLE();
130     }
131 }
132 
LowerIntCheck(GateRef gate)133 void TypeLowering::LowerIntCheck(GateRef gate)
134 {
135     GateRef frameState = GetFrameState(gate);
136 
137     GateRef value = acc_.GetValueIn(gate, 0);
138     GateRef typeCheck = builder_.TaggedIsInt(value);
139     builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTINT);
140 
141     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
142 }
143 
LowerDoubleCheck(GateRef gate)144 void TypeLowering::LowerDoubleCheck(GateRef gate)
145 {
146     GateRef frameState = GetFrameState(gate);
147 
148     GateRef value = acc_.GetValueIn(gate, 0);
149     GateRef typeCheck = builder_.TaggedIsDouble(value);
150     builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTDOUBLE);
151 
152     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
153 }
154 
LowerNumberCheck(GateRef gate)155 void TypeLowering::LowerNumberCheck(GateRef gate)
156 {
157     GateRef frameState = GetFrameState(gate);
158 
159     GateRef value = acc_.GetValueIn(gate, 0);
160     GateRef typeCheck = builder_.TaggedIsNumber(value);
161     builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTNUMBER);
162 
163     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
164 }
165 
LowerBooleanCheck(GateRef gate)166 void TypeLowering::LowerBooleanCheck(GateRef gate)
167 {
168     GateRef frameState = GetFrameState(gate);
169 
170     GateRef value = acc_.GetValueIn(gate, 0);
171     GateRef typeCheck = builder_.TaggedIsBoolean(value);
172     builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTBOOL);
173 
174     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
175 }
176 
LowerArrayCheck(GateRef gate,GateRef glue)177 void TypeLowering::LowerArrayCheck(GateRef gate, GateRef glue)
178 {
179     Environment env(gate, circuit_, &builder_);
180     GateRef frameState = GetFrameState(gate);
181 
182     GateRef glueGlobalEnvOffset = builder_.IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(false));
183     GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
184     GateRef receiver = acc_.GetValueIn(gate, 0);
185     GateRef receiverHClass = builder_.LoadHClass(receiver);
186     GateRef arrayFunction =
187         builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
188     GateRef protoOrHclass =
189         builder_.Load(VariableType::JS_ANY(), arrayFunction,
190                       builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
191     GateRef hcalssCheck = builder_.Equal(receiverHClass, protoOrHclass);
192     builder_.DeoptCheck(hcalssCheck, frameState, DeoptType::NOTARRAY);
193 
194     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
195 }
196 
LowerStableArrayCheck(GateRef gate,GateRef glue)197 void TypeLowering::LowerStableArrayCheck(GateRef gate, GateRef glue)
198 {
199     Environment env(gate, circuit_, &builder_);
200     GateRef frameState = GetFrameState(gate);
201 
202     GateRef glueGlobalEnvOffset = builder_.IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(false));
203     GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
204     GateRef receiver = acc_.GetValueIn(gate, 0);
205     GateRef receiverHClass = builder_.LoadHClass(receiver);
206     GateRef arrayFunction =
207         builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
208     GateRef protoOrHclass =
209         builder_.Load(VariableType::JS_ANY(), arrayFunction,
210                       builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
211     GateRef hcalssCheck = builder_.Equal(receiverHClass, protoOrHclass);
212     GateRef guardiansOffset = builder_.IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(false));
213     GateRef guardians = builder_.Load(VariableType(MachineType::I64, GateType::BooleanType()), glue, guardiansOffset);
214     GateRef guardiansCheck = builder_.Equal(guardians, builder_.TaggedTrue());
215     GateRef check = builder_.BoolAnd(hcalssCheck, guardiansCheck);
216     builder_.DeoptCheck(check, frameState, DeoptType::NOTSARRAY);
217 
218     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
219 }
220 
LowerTypedArrayCheck(GateRef gate,GateRef glue)221 void TypeLowering::LowerTypedArrayCheck(GateRef gate, GateRef glue)
222 {
223     Environment env(gate, circuit_, &builder_);
224     auto type = acc_.GetParamGateType(gate);
225     if (tsManager_->IsFloat32ArrayType(type)) {
226         LowerFloat32ArrayCheck(gate, glue);
227     } else {
228         LOG_ECMA(FATAL) << "this branch is unreachable";
229         UNREACHABLE();
230     }
231 }
232 
LowerFloat32ArrayCheck(GateRef gate,GateRef glue)233 void TypeLowering::LowerFloat32ArrayCheck(GateRef gate, GateRef glue)
234 {
235     GateRef frameState = GetFrameState(gate);
236 
237     GateRef glueGlobalEnvOffset = builder_.IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(false));
238     GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
239     GateRef receiver = acc_.GetValueIn(gate, 0);
240     GateRef receiverHClass = builder_.LoadHClass(receiver);
241     GateRef float32ArrayFunction =
242         builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::FLOAT32_ARRAY_FUNCTION_INDEX);
243     GateRef protoOrHclass =
244         builder_.Load(VariableType::JS_ANY(), float32ArrayFunction,
245                       builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
246     GateRef check = builder_.Equal(receiverHClass, protoOrHclass);
247     builder_.DeoptCheck(check, frameState, DeoptType::NOTF32ARRAY);
248 
249     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
250 }
251 
LowerObjectTypeCheck(GateRef gate)252 void TypeLowering::LowerObjectTypeCheck(GateRef gate)
253 {
254     Environment env(gate, circuit_, &builder_);
255     auto type = acc_.GetParamGateType(gate);
256     if (tsManager_->IsClassInstanceTypeKind(type)) {
257         LowerClassInstanceCheck(gate);
258     } else {
259         UNREACHABLE();
260     }
261 }
262 
LowerClassInstanceCheck(GateRef gate)263 void TypeLowering::LowerClassInstanceCheck(GateRef gate)
264 {
265     GateRef frameState = GetFrameState(gate);
266 
267     ArgumentAccessor argAcc(circuit_);
268     GateRef jsFunc = argAcc.GetCommonArgGate(CommonArgIdx::FUNC);
269     auto receiver = acc_.GetValueIn(gate, 0);
270     auto receiverHClass = builder_.LoadHClass(receiver);
271     auto hclassOffset = acc_.GetValueIn(gate, 1);
272     GateRef hclass = GetObjectFromConstPool(jsFunc, hclassOffset);
273     GateRef check = builder_.Equal(receiverHClass, hclass);
274     builder_.DeoptCheck(check, frameState, DeoptType::WRONGHCLASS);
275 
276     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
277 }
278 
LowerIndexCheck(GateRef gate)279 void TypeLowering::LowerIndexCheck(GateRef gate)
280 {
281     Environment env(gate, circuit_, &builder_);
282     auto type = acc_.GetParamGateType(gate);
283     if (tsManager_->IsArrayTypeKind(type)) {
284         LowerArrayIndexCheck(gate);
285     } else if (tsManager_->IsFloat32ArrayType(type)) {
286         LowerFloat32ArrayIndexCheck(gate);
287     } else {
288         LOG_ECMA(FATAL) << "this branch is unreachable";
289         UNREACHABLE();
290     }
291 }
292 
LowerArrayIndexCheck(GateRef gate)293 void TypeLowering::LowerArrayIndexCheck(GateRef gate)
294 {
295     GateRef frameState = GetFrameState(gate);
296 
297     GateRef receiver = acc_.GetValueIn(gate, 0);
298     GateRef hclassIndex = builder_.GetInt32OfTInt(acc_.GetValueIn(gate, 1));
299     GateRef length =
300             builder_.Load(VariableType::INT32(), receiver, builder_.IntPtr(JSArray::LENGTH_OFFSET));
301     GateRef lengthCheck = builder_.Int32UnsignedLessThan(hclassIndex, length);
302     GateRef nonNegativeCheck = builder_.Int32LessThanOrEqual(builder_.Int32(0), hclassIndex);
303     GateRef check = builder_.BoolAnd(lengthCheck, nonNegativeCheck);
304     builder_.DeoptCheck(check, frameState, DeoptType::NOTARRAYIDX);
305 
306     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
307 }
308 
LowerFloat32ArrayIndexCheck(GateRef gate)309 void TypeLowering::LowerFloat32ArrayIndexCheck(GateRef gate)
310 {
311     GateRef frameState = GetFrameState(gate);
312 
313     GateRef receiver = acc_.GetValueIn(gate, 0);
314     GateRef index = builder_.GetInt32OfTInt(acc_.GetValueIn(gate, 1));
315     GateRef length =
316             builder_.Load(VariableType::INT32(), receiver, builder_.IntPtr(JSTypedArray::ARRAY_LENGTH_OFFSET));
317     GateRef nonNegativeCheck = builder_.Int32LessThanOrEqual(builder_.Int32(0), index);
318     GateRef lengthCheck = builder_.Int32UnsignedLessThan(index, length);
319     GateRef check = builder_.BoolAnd(nonNegativeCheck, lengthCheck);
320     builder_.DeoptCheck(check, frameState, DeoptType::NOTF32ARRAYIDX);
321 
322     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
323 }
324 
LowerOverflowCheck(GateRef gate)325 void TypeLowering::LowerOverflowCheck(GateRef gate)
326 {
327     Environment env(gate, circuit_, &builder_);
328     TypedUnaryAccessor accessor(acc_.TryGetValue(gate));
329     auto op = accessor.GetTypedUnOp();
330     switch (op) {
331         case TypedUnOp::TYPED_INC: {
332             LowerTypedIncOverflowCheck(gate);
333             break;
334         }
335         case TypedUnOp::TYPED_DEC: {
336             LowerTypedDecOverflowCheck(gate);
337             break;
338         }
339         case TypedUnOp::TYPED_NEG: {
340             LowerTypedNegOverflowCheck(gate);
341             break;
342         }
343         default: {
344             LOG_COMPILER(FATAL) << "this branch is unreachable";
345             UNREACHABLE();
346             break;
347         }
348     }
349 }
350 
LowerTypedIncOverflowCheck(GateRef gate)351 void TypeLowering::LowerTypedIncOverflowCheck(GateRef gate)
352 {
353     GateRef frameState = GetFrameState(gate);
354 
355     GateRef value = acc_.GetValueIn(gate, 0);
356     GateRef intVal = builder_.GetInt64OfTInt(value);
357     GateRef max = builder_.Int64(INT32_MAX);
358     GateRef rangeCheck = builder_.Int64NotEqual(intVal, max);
359     builder_.DeoptCheck(rangeCheck, frameState, DeoptType::NOTINCOV);
360 
361     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
362 }
363 
LowerTypedDecOverflowCheck(GateRef gate)364 void TypeLowering::LowerTypedDecOverflowCheck(GateRef gate)
365 {
366     GateRef frameState = GetFrameState(gate);
367 
368     GateRef value = acc_.GetValueIn(gate, 0);
369     GateRef intVal = builder_.GetInt64OfTInt(value);
370     GateRef min = builder_.Int64(INT32_MIN);
371     GateRef rangeCheck = builder_.Int64NotEqual(intVal, min);
372     builder_.DeoptCheck(rangeCheck, frameState, DeoptType::NOTDECOV);
373 
374     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
375 }
376 
LowerTypedNegOverflowCheck(GateRef gate)377 void TypeLowering::LowerTypedNegOverflowCheck(GateRef gate)
378 {
379     GateRef frameState = GetFrameState(gate);
380 
381     GateRef value = acc_.GetValueIn(gate, 0);
382     GateRef intVal = builder_.GetInt64OfTInt(value);
383     GateRef min = builder_.Int64(INT32_MIN);
384     GateRef zero = builder_.Int64(0);
385     GateRef notMin = builder_.Int64NotEqual(intVal, min);
386     GateRef notZero = builder_.Int64NotEqual(intVal, zero);
387     GateRef rangeCheck = builder_.BoolAnd(notMin, notZero);
388     builder_.DeoptCheck(rangeCheck, frameState, DeoptType::NOTNEGOV);
389 
390     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
391 }
392 
LowerCallRuntime(GateRef glue,int index,const std::vector<GateRef> & args,bool useLabel)393 GateRef TypeLowering::LowerCallRuntime(GateRef glue, int index, const std::vector<GateRef> &args, bool useLabel)
394 {
395     if (useLabel) {
396         GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args);
397         return result;
398     } else {
399         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
400         GateRef target = builder_.IntPtr(index);
401         GateRef result = builder_.Call(cs, glue, target, dependEntry_, args);
402         return result;
403     }
404 }
405 
LowerTypeConvert(GateRef gate)406 void TypeLowering::LowerTypeConvert(GateRef gate)
407 {
408     Environment env(gate, circuit_, &builder_);
409     GateAccessor acc(circuit_);
410     auto leftType = acc_.GetLeftType(gate);
411     auto rightType = acc_.GetRightType(gate);
412     if (rightType.IsNumberType()) {
413         GateRef value = acc_.GetValueIn(gate, 0);
414         if (leftType.IsDigitablePrimitiveType()) {
415             LowerPrimitiveToNumber(gate, value, leftType);
416         }
417         return;
418     }
419 }
420 
LowerPrimitiveToNumber(GateRef dst,GateRef src,GateType srcType)421 void TypeLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType srcType)
422 {
423     Label exit(&builder_);
424     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
425     if (srcType.IsBooleanType()) {
426         Label isTrue(&builder_);
427         Label isFalse(&builder_);
428         builder_.Branch(builder_.TaggedIsTrue(src), &isTrue, &isFalse);
429         builder_.Bind(&isTrue);
430         result = IntToTaggedIntPtr(builder_.Int32(1));
431         builder_.Jump(&exit);
432         builder_.Bind(&isFalse);
433         result = IntToTaggedIntPtr(builder_.Int32(0));
434         builder_.Jump(&exit);
435     } else if (srcType.IsUndefinedType()) {
436         result = DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
437     } else if (srcType.IsBigIntType() || srcType.IsNumberType()) {
438         result = src;
439         builder_.Jump(&exit);
440     } else if (srcType.IsNullType()) {
441         result = IntToTaggedIntPtr(builder_.Int32(0));
442         builder_.Jump(&exit);
443     } else {
444         LOG_ECMA(FATAL) << "this branch is unreachable";
445         UNREACHABLE();
446     }
447     builder_.Bind(&exit);
448     acc_.ReplaceGate(dst, builder_.GetState(), builder_.GetDepend(), *result);
449 }
450 
GetConstPool(GateRef jsFunc)451 GateRef TypeLowering::GetConstPool(GateRef jsFunc)
452 {
453     GateRef method = builder_.GetMethodFromFunction(jsFunc);
454     return builder_.Load(VariableType::JS_ANY(), method, builder_.IntPtr(Method::CONSTANT_POOL_OFFSET));
455 }
456 
GetObjectFromConstPool(GateRef jsFunc,GateRef index)457 GateRef TypeLowering::GetObjectFromConstPool(GateRef jsFunc, GateRef index)
458 {
459     GateRef constPool = GetConstPool(jsFunc);
460     return builder_.GetValueFromTaggedArray(constPool, index);
461 }
462 
LowerLoadProperty(GateRef gate,GateRef glue)463 void TypeLowering::LowerLoadProperty(GateRef gate, [[maybe_unused]] GateRef glue)
464 {
465     Environment env(gate, circuit_, &builder_);
466     Label hole(&builder_);
467     Label exit(&builder_);
468     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
469     GateRef receiver = acc_.GetValueIn(gate, 0);
470     GateRef offset = acc_.GetValueIn(gate, 1);
471     result = builder_.Load(VariableType::JS_ANY(), receiver, offset);
472     // simplify the process, need to query the vtable to complete the whole process later
473     builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_HOLE), &hole, &exit);
474     builder_.Bind(&hole);
475     {
476         result = builder_.UndefineConstant();
477         builder_.Jump(&exit);
478     }
479     builder_.Bind(&exit);
480     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
481 }
482 
LowerStoreProperty(GateRef gate,GateRef glue)483 void TypeLowering::LowerStoreProperty(GateRef gate, GateRef glue)
484 {
485     Environment env(gate, circuit_, &builder_);
486     GateRef receiver = acc_.GetValueIn(gate, 0);
487     GateRef offset = acc_.GetValueIn(gate, 1);
488     GateRef value = acc_.GetValueIn(gate, 2);
489     builder_.Store(VariableType::JS_ANY(), glue, receiver, offset, value);
490     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
491 }
492 
LowerLoadArrayLength(GateRef gate)493 void TypeLowering::LowerLoadArrayLength(GateRef gate)
494 {
495     Environment env(gate, circuit_, &builder_);
496     GateRef array = acc_.GetValueIn(gate, 0);
497     GateRef offset = builder_.IntPtr(JSArray::LENGTH_OFFSET);
498     GateRef result = builder_.Load(VariableType::JS_ANY(), array, offset);
499     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
500 }
501 
LowerLoadElement(GateRef gate)502 void TypeLowering::LowerLoadElement(GateRef gate)
503 {
504     Environment env(gate, circuit_, &builder_);
505     auto op = acc_.GetTypedLoadOp(gate);
506     switch (op) {
507         case TypedLoadOp::ARRAY_LOAD_ELEMENT:
508             LowerArrayLoadElement(gate);
509             break;
510         case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
511             LowerFloat32ArrayLoadElement(gate);
512             break;
513         default:
514             UNREACHABLE();
515     }
516 }
517 
518 // for JSArray
LowerArrayLoadElement(GateRef gate)519 void TypeLowering::LowerArrayLoadElement(GateRef gate)
520 {
521     Environment env(gate, circuit_, &builder_);
522     GateRef receiver = acc_.GetValueIn(gate, 0);
523     GateRef element =
524         builder_.Load(VariableType::JS_POINTER(), receiver, builder_.IntPtr(JSObject::ELEMENTS_OFFSET));
525     GateRef index = acc_.GetValueIn(gate, 1);
526     index = builder_.GetInt32OfTInt(index);
527     GateRef res = builder_.GetValueFromTaggedArray(element, index);
528     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), res);
529     Label isHole(&builder_);
530     Label exit(&builder_);
531     builder_.Branch(builder_.TaggedIsHole(res), &isHole, &exit);
532     builder_.Bind(&isHole);
533     {
534         result = builder_.UndefineConstant();
535         builder_.Jump(&exit);
536     }
537     builder_.Bind(&exit);
538     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
539 }
540 
541 // for Float32Array
LowerFloat32ArrayLoadElement(GateRef gate)542 void TypeLowering::LowerFloat32ArrayLoadElement(GateRef gate)
543 {
544     Environment env(gate, circuit_, &builder_);
545     Label isArrayBuffer(&builder_);
546     Label isByteArray(&builder_);
547     Label exit(&builder_);
548     DEFVAlUE(res, (&builder_), VariableType::FLOAT32(), builder_.Double(0));
549     GateRef receiver = acc_.GetValueIn(gate, 0);
550     GateRef arrbuffer =
551         builder_.Load(VariableType::JS_POINTER(), receiver, builder_.IntPtr(JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET));
552     GateRef index = acc_.GetValueIn(gate, 1);
553     index = builder_.GetInt32OfTInt(index);
554     GateRef elementSize = builder_.Int32(4);  // 4: float32 occupy 4 bytes
555     GateRef offset = builder_.PtrMul(index, elementSize);
556     GateRef byteOffset =
557         builder_.Load(VariableType::INT32(), receiver, builder_.IntPtr(JSTypedArray::BYTE_OFFSET_OFFSET));
558     // viewed arraybuffer could be JSArrayBuffer or ByteArray
559     GateRef isOnHeap = builder_.Load(VariableType::BOOL(), receiver, builder_.IntPtr(JSTypedArray::ON_HEAP_OFFSET));
560     builder_.Branch(isOnHeap, &isByteArray, &isArrayBuffer);
561     builder_.Bind(&isByteArray);
562     {
563         GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
564         res = builder_.Load(VariableType::FLOAT32(), data, builder_.PtrAdd(offset, byteOffset));
565         builder_.Jump(&exit);
566     }
567     builder_.Bind(&isArrayBuffer);
568     {
569         GateRef data = builder_.Load(VariableType::JS_POINTER(), arrbuffer,
570                                      builder_.IntPtr(JSArrayBuffer::DATA_OFFSET));
571         GateRef block = builder_.Load(VariableType::JS_ANY(), data, builder_.IntPtr(JSNativePointer::POINTER_OFFSET));
572         res = builder_.Load(VariableType::FLOAT32(), block, builder_.PtrAdd(offset, byteOffset));
573         builder_.Jump(&exit);
574     }
575 
576     builder_.Bind(&exit);
577     GateRef result = builder_.Float32ToTaggedDoublePtr(*res);
578     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
579 }
580 
LowerStoreElement(GateRef gate,GateRef glue)581 void TypeLowering::LowerStoreElement(GateRef gate, GateRef glue)
582 {
583     Environment env(gate, circuit_, &builder_);
584     auto op = acc_.GetTypedStoreOp(gate);
585     switch (op) {
586         case TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT:
587             LowerFloat32ArrayStoreElement(gate, glue);
588             break;
589         default:
590             UNREACHABLE();
591     }
592 }
593 
594 // for Float32Array
LowerFloat32ArrayStoreElement(GateRef gate,GateRef glue)595 void TypeLowering::LowerFloat32ArrayStoreElement(GateRef gate, GateRef glue)
596 {
597     Environment env(gate, circuit_, &builder_);
598     Label isArrayBuffer(&builder_);
599     Label isByteArray(&builder_);
600     Label afterGetValue(&builder_);
601     Label exit(&builder_);
602     GateRef receiver = acc_.GetValueIn(gate, 0);
603     GateRef index = acc_.GetValueIn(gate, 1);
604     GateRef elementSize = builder_.Int32(4);  // 4: float32 occupy 4 bytes
605     GateRef offset = builder_.PtrMul(index, elementSize);
606     GateRef byteOffset =
607         builder_.Load(VariableType::INT32(), receiver, builder_.IntPtr(JSTypedArray::BYTE_OFFSET_OFFSET));
608 
609     GateRef value = acc_.GetValueIn(gate, 2);
610     GateType valueType = acc_.GetGateType(value);
611     DEFVAlUE(storeValue, (&builder_), VariableType::FLOAT32(), builder_.Double(0));
612     if (valueType.IsIntType()) {
613         storeValue = builder_.TaggedIntPtrToFloat32(value);
614     } else if (valueType.IsDoubleType()) {
615         storeValue = builder_.TaggedDoublePtrToFloat32(value);
616     } else {
617         Label valueIsInt(&builder_);
618         Label valueIsDouble(&builder_);
619         builder_.Branch(builder_.TaggedIsInt(value), &valueIsInt, &valueIsDouble);
620         builder_.Bind(&valueIsInt);
621         {
622             storeValue = builder_.TaggedIntPtrToFloat32(value);
623             builder_.Jump(&afterGetValue);
624         }
625         builder_.Bind(&valueIsDouble);
626         {
627             storeValue = builder_.TaggedDoublePtrToFloat32(value);
628             builder_.Jump(&afterGetValue);
629         }
630         builder_.Bind(&afterGetValue);
631     }
632     GateRef arrbuffer =
633         builder_.Load(VariableType::JS_POINTER(), receiver, builder_.IntPtr(JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET));
634     // viewed arraybuffer could be JSArrayBuffer or ByteArray
635     GateRef isOnHeap = builder_.Load(VariableType::BOOL(), receiver, builder_.IntPtr(JSTypedArray::ON_HEAP_OFFSET));
636     builder_.Branch(isOnHeap, &isByteArray, &isArrayBuffer);
637     builder_.Bind(&isByteArray);
638     {
639         GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
640         builder_.Store(VariableType::VOID(), glue, data, builder_.PtrAdd(offset, byteOffset), *storeValue);
641         builder_.Jump(&exit);
642     }
643     builder_.Bind(&isArrayBuffer);
644     {
645         GateRef data = builder_.Load(VariableType::JS_POINTER(), arrbuffer,
646                                      builder_.IntPtr(JSArrayBuffer::DATA_OFFSET));
647         GateRef block = builder_.Load(VariableType::JS_ANY(), data, builder_.IntPtr(JSNativePointer::POINTER_OFFSET));
648         builder_.Store(VariableType::VOID(), glue, block, builder_.PtrAdd(offset, byteOffset), *storeValue);
649         builder_.Jump(&exit);
650     }
651     builder_.Bind(&exit);
652     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
653 }
654 
LowerHeapAllocate(GateRef gate,GateRef glue)655 void TypeLowering::LowerHeapAllocate(GateRef gate, GateRef glue)
656 {
657     Environment env(gate, circuit_, &builder_);
658     auto bit = acc_.TryGetValue(gate);
659     switch (bit) {
660         case RegionSpaceFlag::IN_YOUNG_SPACE:
661             LowerHeapAllocateInYoung(gate, glue);
662             break;
663         default:
664             UNREACHABLE();
665     }
666 }
667 
LowerHeapAllocateInYoung(GateRef gate,GateRef glue)668 void TypeLowering::LowerHeapAllocateInYoung(GateRef gate, GateRef glue)
669 {
670     Label success(&builder_);
671     Label callRuntime(&builder_);
672     Label exit(&builder_);
673     auto initialHClass = acc_.GetValueIn(gate, 0);
674     auto size = builder_.GetObjectSizeFromHClass(initialHClass);
675     auto topOffset = JSThread::GlueData::GetNewSpaceAllocationTopAddressOffset(false);
676     auto endOffset = JSThread::GlueData::GetNewSpaceAllocationEndAddressOffset(false);
677     auto topAddress = builder_.Load(VariableType::NATIVE_POINTER(), glue, builder_.IntPtr(topOffset));
678     auto endAddress = builder_.Load(VariableType::NATIVE_POINTER(), glue, builder_.IntPtr(endOffset));
679     auto top = builder_.Load(VariableType::JS_POINTER(), topAddress, builder_.IntPtr(0));
680     auto end = builder_.Load(VariableType::JS_POINTER(), endAddress, builder_.IntPtr(0));
681     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
682     auto newTop = builder_.PtrAdd(top, size);
683     builder_.Branch(builder_.IntPtrGreaterThan(newTop, end), &callRuntime, &success);
684     builder_.Bind(&success);
685     {
686         builder_.Store(VariableType::NATIVE_POINTER(), glue, topAddress, builder_.IntPtr(0), newTop);
687         result = top;
688         builder_.Jump(&exit);
689     }
690     builder_.Bind(&callRuntime);
691     {
692         result = LowerCallRuntime(glue, RTSTUB_ID(AllocateInYoung),  {builder_.ToTaggedInt(size)}, true);
693         builder_.Jump(&exit);
694     }
695     builder_.Bind(&exit);
696 
697     // initialization
698     Label afterInitialize(&builder_);
699     InitializeWithSpeicalValue(&afterInitialize, *result, glue, builder_.HoleConstant(),
700                                builder_.Int32(JSObject::SIZE), builder_.TruncInt64ToInt32(size));
701     builder_.Bind(&afterInitialize);
702     builder_.Store(VariableType::JS_POINTER(), glue, *result, builder_.IntPtr(0), initialHClass);
703     GateRef hashOffset = builder_.IntPtr(ECMAObject::HASH_OFFSET);
704     builder_.Store(VariableType::INT64(), glue, *result, hashOffset, builder_.Int64(JSTaggedValue(0).GetRawData()));
705 
706     GateRef emptyArray = builder_.GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
707                                                          ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
708     GateRef propertiesOffset = builder_.IntPtr(JSObject::PROPERTIES_OFFSET);
709     builder_.Store(VariableType::JS_POINTER(), glue, *result, propertiesOffset, emptyArray);
710     GateRef elementsOffset = builder_.IntPtr(JSObject::ELEMENTS_OFFSET);
711     builder_.Store(VariableType::JS_POINTER(), glue, *result, elementsOffset, emptyArray);
712 
713     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
714 }
715 
InitializeWithSpeicalValue(Label * exit,GateRef object,GateRef glue,GateRef value,GateRef start,GateRef end)716 void TypeLowering::InitializeWithSpeicalValue(Label *exit, GateRef object, GateRef glue,
717                                               GateRef value, GateRef start, GateRef end)
718 {
719     Label begin(&builder_);
720     Label storeValue(&builder_);
721     Label endLoop(&builder_);
722 
723     DEFVAlUE(startOffset, (&builder_), VariableType::INT32(), start);
724     builder_.Jump(&begin);
725     builder_.LoopBegin(&begin);
726     {
727         builder_.Branch(builder_.Int32UnsignedLessThan(*startOffset, end), &storeValue, exit);
728         builder_.Bind(&storeValue);
729         {
730             builder_.Store(VariableType::INT64(), glue, object, builder_.ZExtInt32ToPtr(*startOffset), value);
731             startOffset = builder_.Int32Add(*startOffset, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
732             builder_.Jump(&endLoop);
733         }
734         builder_.Bind(&endLoop);
735         builder_.LoopEnd(&begin);
736     }
737 }
738 
LowerTypedBinaryOp(GateRef gate)739 void TypeLowering::LowerTypedBinaryOp(GateRef gate)
740 {
741     Environment env(gate, circuit_, &builder_);
742     TypedBinOp op = acc_.GetTypedBinaryOp(gate);
743     switch (op) {
744         case TypedBinOp::TYPED_ADD: {
745             LowerTypedAdd(gate);
746             break;
747         }
748         case TypedBinOp::TYPED_SUB: {
749             LowerTypedSub(gate);
750             break;
751         }
752         case TypedBinOp::TYPED_MUL: {
753             LowerTypedMul(gate);
754             break;
755         }
756         case TypedBinOp::TYPED_MOD: {
757             LowerTypedMod(gate);
758             break;
759         }
760         case TypedBinOp::TYPED_LESS: {
761             LowerTypedLess(gate);
762             break;
763         }
764         case TypedBinOp::TYPED_LESSEQ: {
765             LowerTypedLessEq(gate);
766             break;
767         }
768         case TypedBinOp::TYPED_GREATER: {
769             LowerTypedGreater(gate);
770             break;
771         }
772         case TypedBinOp::TYPED_GREATEREQ: {
773             LowerTypedGreaterEq(gate);
774             break;
775         }
776         case TypedBinOp::TYPED_DIV: {
777             LowerTypedDiv(gate);
778             break;
779         }
780         case TypedBinOp::TYPED_EQ: {
781             LowerTypedEq(gate);
782             break;
783         }
784         case TypedBinOp::TYPED_NOTEQ: {
785             LowerTypedNotEq(gate);
786             break;
787         }
788         case TypedBinOp::TYPED_SHL: {
789             LowerTypedShl(gate);
790             break;
791         }
792         case TypedBinOp::TYPED_SHR: {
793             LowerTypedShr(gate);
794             break;
795         }
796         case TypedBinOp::TYPED_ASHR: {
797             LowerTypedAshr(gate);
798             break;
799         }
800         case TypedBinOp::TYPED_AND: {
801             LowerTypedAnd(gate);
802             break;
803         }
804         case TypedBinOp::TYPED_OR: {
805             LowerTypedOr(gate);
806             break;
807         }
808         case TypedBinOp::TYPED_XOR: {
809             LowerTypedXor(gate);
810             break;
811         }
812         default:
813             LOG_COMPILER(FATAL) << "unkown TypedBinOp: " << static_cast<int>(op);
814             break;
815     }
816 }
817 
LowerTypedUnaryOp(GateRef gate)818 void TypeLowering::LowerTypedUnaryOp(GateRef gate)
819 {
820     Environment env(gate, circuit_, &builder_);
821     TypedUnaryAccessor accessor(acc_.TryGetValue(gate));
822     GateType valueType = accessor.GetTypeValue();
823     auto op = accessor.GetTypedUnOp();
824     switch (op) {
825         case TypedUnOp::TYPED_TONUMBER:
826             break;
827         case TypedUnOp::TYPED_NEG:
828             LowerTypedNeg(gate, valueType);
829             break;
830         case TypedUnOp::TYPED_NOT:
831             LowerTypedNot(gate, valueType);
832             break;
833         case TypedUnOp::TYPED_INC:
834             LowerTypedInc(gate, valueType);
835             break;
836         case TypedUnOp::TYPED_DEC:
837             LowerTypedDec(gate, valueType);
838             break;
839         case TypedUnOp::TYPED_TOBOOL:
840             LowerTypedToBool(gate, valueType);
841             break;
842         default:
843             LOG_COMPILER(FATAL) << "unkown TypedUnOp: " << static_cast<int>(op);
844             break;
845     }
846 }
847 
LowerTypedAdd(GateRef gate)848 void TypeLowering::LowerTypedAdd(GateRef gate)
849 {
850     auto leftType = acc_.GetLeftType(gate);
851     auto rightType = acc_.GetRightType(gate);
852     if (leftType.IsNumberType() && rightType.IsNumberType()) {
853         LowerNumberAdd(gate);
854     } else {
855         UNREACHABLE();
856     }
857 }
858 
LowerTypedSub(GateRef gate)859 void TypeLowering::LowerTypedSub(GateRef gate)
860 {
861     auto leftType = acc_.GetLeftType(gate);
862     auto rightType = acc_.GetRightType(gate);
863     if (leftType.IsNumberType() && rightType.IsNumberType()) {
864         LowerNumberSub(gate);
865     } else {
866         UNREACHABLE();
867     }
868 }
869 
LowerTypedMul(GateRef gate)870 void TypeLowering::LowerTypedMul(GateRef gate)
871 {
872     auto leftType = acc_.GetLeftType(gate);
873     auto rightType = acc_.GetRightType(gate);
874     if (leftType.IsNumberType() && rightType.IsNumberType()) {
875         LowerNumberMul(gate);
876     } else {
877         UNREACHABLE();
878     }
879 }
880 
LowerTypedMod(GateRef gate)881 void TypeLowering::LowerTypedMod(GateRef gate)
882 {
883     auto leftType = acc_.GetLeftType(gate);
884     auto rightType = acc_.GetRightType(gate);
885     if (leftType.IsNumberType() && rightType.IsNumberType()) {
886         LowerNumberMod(gate);
887     } else {
888         UNREACHABLE();
889     }
890 }
891 
LowerTypedLess(GateRef gate)892 void TypeLowering::LowerTypedLess(GateRef gate)
893 {
894     auto leftType = acc_.GetLeftType(gate);
895     auto rightType = acc_.GetRightType(gate);
896     if (leftType.IsNumberType() && rightType.IsNumberType()) {
897         LowerNumberLess(gate);
898     } else {
899         UNREACHABLE();
900     }
901 }
902 
LowerTypedLessEq(GateRef gate)903 void TypeLowering::LowerTypedLessEq(GateRef gate)
904 {
905     auto leftType = acc_.GetLeftType(gate);
906     auto rightType = acc_.GetRightType(gate);
907     if (leftType.IsNumberType() && rightType.IsNumberType()) {
908         LowerNumberLessEq(gate);
909     } else {
910         UNREACHABLE();
911     }
912 }
913 
LowerTypedGreater(GateRef gate)914 void TypeLowering::LowerTypedGreater(GateRef gate)
915 {
916     auto leftType = acc_.GetLeftType(gate);
917     auto rightType = acc_.GetRightType(gate);
918     if (leftType.IsNumberType() && rightType.IsNumberType()) {
919         LowerNumberGreater(gate);
920     } else {
921         UNREACHABLE();
922     }
923 }
924 
LowerTypedGreaterEq(GateRef gate)925 void TypeLowering::LowerTypedGreaterEq(GateRef gate)
926 {
927     auto leftType = acc_.GetLeftType(gate);
928     auto rightType = acc_.GetRightType(gate);
929     if (leftType.IsNumberType() && rightType.IsNumberType()) {
930         LowerNumberGreaterEq(gate);
931     } else {
932         UNREACHABLE();
933     }
934 }
935 
LowerTypedDiv(GateRef gate)936 void TypeLowering::LowerTypedDiv(GateRef gate)
937 {
938     auto leftType = acc_.GetLeftType(gate);
939     auto rightType = acc_.GetRightType(gate);
940     if (leftType.IsNumberType() && rightType.IsNumberType()) {
941         LowerNumberDiv(gate);
942     } else {
943         UNREACHABLE();
944     }
945 }
946 
LowerTypedEq(GateRef gate)947 void TypeLowering::LowerTypedEq(GateRef gate)
948 {
949     auto leftType = acc_.GetLeftType(gate);
950     auto rightType = acc_.GetRightType(gate);
951     if (leftType.IsNumberType() && rightType.IsNumberType()) {
952         LowerNumberEq(gate);
953     } else {
954         UNREACHABLE();
955     }
956     return;
957 }
958 
LowerTypedNotEq(GateRef gate)959 void TypeLowering::LowerTypedNotEq(GateRef gate)
960 {
961     auto leftType = acc_.GetLeftType(gate);
962     auto rightType = acc_.GetRightType(gate);
963     if (leftType.IsNumberType() && rightType.IsNumberType()) {
964         LowerNumberNotEq(gate);
965     } else {
966         UNREACHABLE();
967     }
968 }
969 
LowerTypedShl(GateRef gate)970 void TypeLowering::LowerTypedShl(GateRef gate)
971 {
972     auto leftType = acc_.GetLeftType(gate);
973     auto rightType = acc_.GetRightType(gate);
974     if (leftType.IsNumberType() && rightType.IsNumberType()) {
975         LowerNumberShl(gate);
976     } else {
977         UNREACHABLE();
978     }
979 }
980 
LowerTypedShr(GateRef gate)981 void TypeLowering::LowerTypedShr(GateRef gate)
982 {
983     auto leftType = acc_.GetLeftType(gate);
984     auto rightType = acc_.GetRightType(gate);
985     if (leftType.IsNumberType() && rightType.IsNumberType()) {
986         LowerNumberShr(gate);
987     } else {
988         UNREACHABLE();
989     }
990 }
991 
LowerTypedAshr(GateRef gate)992 void TypeLowering::LowerTypedAshr(GateRef gate)
993 {
994     auto leftType = acc_.GetLeftType(gate);
995     auto rightType = acc_.GetRightType(gate);
996     if (leftType.IsNumberType() && rightType.IsNumberType()) {
997         LowerNumberAshr(gate);
998     } else {
999         UNREACHABLE();
1000     }
1001 }
1002 
LowerTypedAnd(GateRef gate)1003 void TypeLowering::LowerTypedAnd(GateRef gate)
1004 {
1005     auto leftType = acc_.GetLeftType(gate);
1006     auto rightType = acc_.GetRightType(gate);
1007     if (leftType.IsNumberType() && rightType.IsNumberType()) {
1008         LowerNumberAnd(gate);
1009     } else {
1010         UNREACHABLE();
1011     }
1012 }
1013 
LowerTypedOr(GateRef gate)1014 void TypeLowering::LowerTypedOr(GateRef gate)
1015 {
1016     auto leftType = acc_.GetLeftType(gate);
1017     auto rightType = acc_.GetRightType(gate);
1018     if (leftType.IsNumberType() && rightType.IsNumberType()) {
1019         LowerNumberOr(gate);
1020     } else {
1021         UNREACHABLE();
1022     }
1023     return;
1024 }
1025 
LowerTypedXor(GateRef gate)1026 void TypeLowering::LowerTypedXor(GateRef gate)
1027 {
1028     auto leftType = acc_.GetLeftType(gate);
1029     auto rightType = acc_.GetRightType(gate);
1030     if (leftType.IsNumberType() && rightType.IsNumberType()) {
1031         LowerNumberXor(gate);
1032     } else {
1033         UNREACHABLE();
1034     }
1035 }
1036 
LowerTypedInc(GateRef gate,GateType value)1037 void TypeLowering::LowerTypedInc(GateRef gate, GateType value)
1038 {
1039     if (value.IsNumberType()) {
1040         LowerNumberInc(gate, value);
1041     } else {
1042         UNREACHABLE();
1043     }
1044 }
1045 
LowerTypedDec(GateRef gate,GateType value)1046 void TypeLowering::LowerTypedDec(GateRef gate, GateType value)
1047 {
1048     if (value.IsNumberType()) {
1049         LowerNumberDec(gate, value);
1050     } else {
1051         UNREACHABLE();
1052     }
1053 }
1054 
LowerTypedNeg(GateRef gate,GateType value)1055 void TypeLowering::LowerTypedNeg(GateRef gate, GateType value)
1056 {
1057     if (value.IsNumberType()) {
1058         LowerNumberNeg(gate, value);
1059     } else {
1060         UNREACHABLE();
1061     }
1062     return;
1063 }
1064 
LowerTypedToBool(GateRef gate,GateType value)1065 void TypeLowering::LowerTypedToBool(GateRef gate, GateType value)
1066 {
1067     if (value.IsNumberType()) {
1068         LowerNumberToBool(gate, value);
1069     } else if (value.IsBooleanType()) {
1070         LowerBooleanToBool(gate);
1071     } else {
1072         UNREACHABLE();
1073     }
1074 }
1075 
LowerTypedNot(GateRef gate,GateType value)1076 void TypeLowering::LowerTypedNot(GateRef gate, GateType value)
1077 {
1078     if (value.IsNumberType()) {
1079         LowerNumberNot(gate, value);
1080     } else {
1081         UNREACHABLE();
1082     }
1083 }
1084 
LowerNumberAdd(GateRef gate)1085 void TypeLowering::LowerNumberAdd(GateRef gate)
1086 {
1087     GateRef left = acc_.GetValueIn(gate, 0);
1088     GateRef right = acc_.GetValueIn(gate, 1);
1089     GateType leftType = acc_.GetLeftType(gate);
1090     GateType rightType = acc_.GetRightType(gate);
1091     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1092     result = CalculateNumbers<OpCode::ADD>(left, right, leftType, rightType);
1093     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1094 }
1095 
LowerNumberSub(GateRef gate)1096 void TypeLowering::LowerNumberSub(GateRef gate)
1097 {
1098     GateRef left = acc_.GetValueIn(gate, 0);
1099     GateRef right = acc_.GetValueIn(gate, 1);
1100     GateType leftType = acc_.GetLeftType(gate);
1101     GateType rightType = acc_.GetRightType(gate);
1102     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1103     result = CalculateNumbers<OpCode::SUB>(left, right, leftType, rightType);
1104     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1105 }
1106 
LowerNumberMul(GateRef gate)1107 void TypeLowering::LowerNumberMul(GateRef gate)
1108 {
1109     GateRef left = acc_.GetValueIn(gate, 0);
1110     GateRef right = acc_.GetValueIn(gate, 1);
1111     GateType leftType = acc_.GetLeftType(gate);
1112     GateType rightType = acc_.GetRightType(gate);
1113     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1114     result = CalculateNumbers<OpCode::MUL>(left, right, leftType, rightType);
1115     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1116 }
1117 
LowerNumberMod(GateRef gate)1118 void TypeLowering::LowerNumberMod(GateRef gate)
1119 {
1120     GateRef left = acc_.GetValueIn(gate, 0);
1121     GateRef right = acc_.GetValueIn(gate, 1);
1122     GateType leftType = acc_.GetLeftType(gate);
1123     GateType rightType = acc_.GetRightType(gate);
1124     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1125     result = ModNumbers(left, right, leftType, rightType);
1126     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1127 }
1128 
LowerNumberLess(GateRef gate)1129 void TypeLowering::LowerNumberLess(GateRef gate)
1130 {
1131     GateRef left = acc_.GetValueIn(gate, 0);
1132     GateRef right = acc_.GetValueIn(gate, 1);
1133     GateType leftType = acc_.GetLeftType(gate);
1134     GateType rightType = acc_.GetRightType(gate);
1135     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1136     result = CompareNumbers<TypedBinOp::TYPED_LESS>(left, right, leftType, rightType);
1137     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1138 }
1139 
LowerNumberLessEq(GateRef gate)1140 void TypeLowering::LowerNumberLessEq(GateRef gate)
1141 {
1142     GateRef left = acc_.GetValueIn(gate, 0);
1143     GateRef right = acc_.GetValueIn(gate, 1);
1144     GateType leftType = acc_.GetLeftType(gate);
1145     GateType rightType = acc_.GetRightType(gate);
1146     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1147     result = CompareNumbers<TypedBinOp::TYPED_LESSEQ>(left, right, leftType, rightType);
1148     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1149 }
1150 
LowerNumberGreater(GateRef gate)1151 void TypeLowering::LowerNumberGreater(GateRef gate)
1152 {
1153     GateRef left = acc_.GetValueIn(gate, 0);
1154     GateRef right = acc_.GetValueIn(gate, 1);
1155     GateType leftType = acc_.GetLeftType(gate);
1156     GateType rightType = acc_.GetRightType(gate);
1157     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1158     result = CompareNumbers<TypedBinOp::TYPED_LESS>(right, left, rightType, leftType);
1159     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1160 }
1161 
LowerNumberGreaterEq(GateRef gate)1162 void TypeLowering::LowerNumberGreaterEq(GateRef gate)
1163 {
1164     GateRef left = acc_.GetValueIn(gate, 0);
1165     GateRef right = acc_.GetValueIn(gate, 1);
1166     GateType leftType = acc_.GetLeftType(gate);
1167     GateType rightType = acc_.GetRightType(gate);
1168     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1169     result = CompareNumbers<TypedBinOp::TYPED_LESSEQ>(right, left, rightType, leftType);
1170     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1171 }
1172 
LowerNumberDiv(GateRef gate)1173 void TypeLowering::LowerNumberDiv(GateRef gate)
1174 {
1175     GateRef left = acc_.GetValueIn(gate, 0);
1176     GateRef right = acc_.GetValueIn(gate, 1);
1177     GateType leftType = acc_.GetLeftType(gate);
1178     GateType rightType = acc_.GetRightType(gate);
1179     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1180     result = DivNumbers(left, right, leftType, rightType);
1181     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1182 }
1183 
LowerNumberEq(GateRef gate)1184 void TypeLowering::LowerNumberEq(GateRef gate)
1185 {
1186     GateRef left = acc_.GetValueIn(gate, 0);
1187     GateRef right = acc_.GetValueIn(gate, 1);
1188     GateType leftType = acc_.GetLeftType(gate);
1189     GateType rightType = acc_.GetRightType(gate);
1190     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1191     result = CompareNumbers<TypedBinOp::TYPED_EQ>(left, right, leftType, rightType);
1192     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1193 }
1194 
LowerNumberNotEq(GateRef gate)1195 void TypeLowering::LowerNumberNotEq(GateRef gate)
1196 {
1197     GateRef left = acc_.GetValueIn(gate, 0);
1198     GateRef right = acc_.GetValueIn(gate, 1);
1199     GateType leftType = acc_.GetLeftType(gate);
1200     GateType rightType = acc_.GetRightType(gate);
1201     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1202     result = CompareNumbers<TypedBinOp::TYPED_NOTEQ>(left, right, leftType, rightType);
1203     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1204 }
1205 
LowerNumberShl(GateRef gate)1206 void TypeLowering::LowerNumberShl(GateRef gate)
1207 {
1208     GateRef left = acc_.GetValueIn(gate, 0);
1209     GateRef right = acc_.GetValueIn(gate, 1);
1210     GateType leftType = acc_.GetLeftType(gate);
1211     GateType rightType = acc_.GetRightType(gate);
1212     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1213     result = ShiftNumber<OpCode::LSL>(left, right, leftType, rightType);
1214     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1215 }
1216 
LowerNumberShr(GateRef gate)1217 void TypeLowering::LowerNumberShr(GateRef gate)
1218 {
1219     GateRef left = acc_.GetValueIn(gate, 0);
1220     GateRef right = acc_.GetValueIn(gate, 1);
1221     GateType leftType = acc_.GetLeftType(gate);
1222     GateType rightType = acc_.GetRightType(gate);
1223     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1224     result = ShiftNumber<OpCode::LSR>(left, right, leftType, rightType);
1225     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1226 }
1227 
LowerNumberAshr(GateRef gate)1228 void TypeLowering::LowerNumberAshr(GateRef gate)
1229 {
1230     GateRef left = acc_.GetValueIn(gate, 0);
1231     GateRef right = acc_.GetValueIn(gate, 1);
1232     GateType leftType = acc_.GetLeftType(gate);
1233     GateType rightType = acc_.GetRightType(gate);
1234     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1235     result = ShiftNumber<OpCode::ASR>(left, right, leftType, rightType);
1236     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1237 }
1238 
LowerNumberAnd(GateRef gate)1239 void TypeLowering::LowerNumberAnd(GateRef gate)
1240 {
1241     GateRef left = acc_.GetValueIn(gate, 0);
1242     GateRef right = acc_.GetValueIn(gate, 1);
1243     GateType leftType = acc_.GetLeftType(gate);
1244     GateType rightType = acc_.GetRightType(gate);
1245     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1246     result = LogicalNumbers<OpCode::AND>(left, right, leftType, rightType);
1247     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1248 }
1249 
LowerNumberOr(GateRef gate)1250 void TypeLowering::LowerNumberOr(GateRef gate)
1251 {
1252     GateRef left = acc_.GetValueIn(gate, 0);
1253     GateRef right = acc_.GetValueIn(gate, 1);
1254     GateType leftType = acc_.GetLeftType(gate);
1255     GateType rightType = acc_.GetRightType(gate);
1256     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1257     result = LogicalNumbers<OpCode::OR>(left, right, leftType, rightType);
1258     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1259 }
1260 
LowerNumberXor(GateRef gate)1261 void TypeLowering::LowerNumberXor(GateRef gate)
1262 {
1263     GateRef left = acc_.GetValueIn(gate, 0);
1264     GateRef right = acc_.GetValueIn(gate, 1);
1265     GateType leftType = acc_.GetLeftType(gate);
1266     GateType rightType = acc_.GetRightType(gate);
1267     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1268     result = LogicalNumbers<OpCode::XOR>(left, right, leftType, rightType);
1269     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1270 }
1271 
LowerNumberInc(GateRef gate,GateType valueType)1272 void TypeLowering::LowerNumberInc(GateRef gate, GateType valueType)
1273 {
1274     GateRef value = acc_.GetValueIn(gate, 0);
1275     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1276     result = MonocularNumber<TypedUnOp::TYPED_INC>(value, valueType);
1277     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1278 }
1279 
LowerNumberDec(GateRef gate,GateType valueType)1280 void TypeLowering::LowerNumberDec(GateRef gate, GateType valueType)
1281 {
1282     GateRef value = acc_.GetValueIn(gate, 0);
1283     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1284     result = MonocularNumber<TypedUnOp::TYPED_DEC>(value, valueType);
1285     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1286 }
1287 
LowerNumberNeg(GateRef gate,GateType valueType)1288 void TypeLowering::LowerNumberNeg(GateRef gate, GateType valueType)
1289 {
1290     GateRef value = acc_.GetValueIn(gate, 0);
1291     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1292     if (valueType.IsIntType()) {
1293         // value is int
1294         GateRef intVal = builder_.GetInt64OfTInt(value);
1295         GateRef res = BinaryOp<OpCode::SUB, MachineType::I64>(builder_.Int64(0), intVal);
1296         result = builder_.ToTaggedIntPtr(res);
1297     } else if (valueType.IsDoubleType()) {
1298         // value is double
1299         GateRef doubleVal = builder_.GetDoubleOfTDouble(value);
1300         GateRef res = BinaryOp<OpCode::SUB, MachineType::F64>(builder_.Double(0), doubleVal);
1301         result = DoubleToTaggedDoublePtr(res);
1302     } else {
1303         // value is number and need typecheck in runtime
1304         Label valueIsInt(&builder_);
1305         Label valueIsDouble(&builder_);
1306         Label exit(&builder_);
1307         builder_.Branch(builder_.TaggedIsInt(value), &valueIsInt, &valueIsDouble);
1308         builder_.Bind(&valueIsInt);
1309         {
1310             GateRef intVal = builder_.GetInt64OfTInt(value);
1311             Label overflow(&builder_);
1312             Label notOverflow(&builder_);
1313             GateRef min = builder_.Int64(INT32_MIN);
1314             builder_.Branch(builder_.Int64Equal(intVal, min), &overflow, &notOverflow);
1315             builder_.Bind(&overflow);
1316             {
1317                 GateRef res = builder_.Double(static_cast<double>(JSTaggedValue::TAG_INT32_INC_MAX));
1318                 result = builder_.DoubleToTaggedDoublePtr(res);
1319                 builder_.Jump(&exit);
1320             }
1321             builder_.Bind(&notOverflow);
1322             {
1323                 GateRef res = BinaryOp<OpCode::SUB, MachineType::I64>(builder_.Int64(0), intVal);
1324                 result = builder_.ToTaggedIntPtr(res);
1325                 builder_.Jump(&exit);
1326             }
1327         }
1328         builder_.Bind(&valueIsDouble);
1329         {
1330             GateRef doubleVal = builder_.GetDoubleOfTDouble(value);
1331             GateRef res = BinaryOp<OpCode::SUB, MachineType::F64>(builder_.Double(0), doubleVal);
1332             result = DoubleToTaggedDoublePtr(res);
1333             builder_.Jump(&exit);
1334         }
1335         builder_.Bind(&exit);
1336     }
1337     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1338 }
1339 
LowerNumberToBool(GateRef gate,GateType valueType)1340 void TypeLowering::LowerNumberToBool(GateRef gate, GateType valueType)
1341 {
1342     GateRef value = acc_.GetValueIn(gate, 0);
1343     DEFVAlUE(result, (&builder_), VariableType::BOOL(), builder_.HoleConstant());
1344     if (valueType.IsIntType()) {
1345         // value is int
1346         GateRef intVal = builder_.GetInt64OfTInt(value);
1347         result = builder_.BoolNot(builder_.Equal(intVal, builder_.Int64(0)));
1348     } else if (valueType.IsDoubleType()) {
1349         // value is double
1350         GateRef doubleVal = builder_.GetDoubleOfTDouble(value);
1351         GateRef doubleNotZero = builder_.BoolNot(builder_.Equal(doubleVal, builder_.Double(0)));
1352         GateRef doubleNotNAN = builder_.BoolNot(builder_.DoubleIsNAN(doubleVal));
1353         result = builder_.BoolAnd(doubleNotZero, doubleNotNAN);
1354     } else {
1355         // value is number and need typecheck in runtime
1356         Label valueIsInt(&builder_);
1357         Label valueIsDouble(&builder_);
1358         Label exit(&builder_);
1359         builder_.Branch(builder_.TaggedIsInt(value), &valueIsInt, &valueIsDouble);
1360         builder_.Bind(&valueIsInt);
1361         {
1362             GateRef intVal = builder_.GetInt64OfTInt(value);
1363             result = builder_.BoolNot(builder_.Equal(intVal, builder_.Int64(0)));
1364             builder_.Jump(&exit);
1365         }
1366         builder_.Bind(&valueIsDouble);
1367         {
1368             GateRef doubleVal = builder_.GetDoubleOfTDouble(value);
1369             GateRef doubleNotZero = builder_.BoolNot(builder_.Equal(doubleVal, builder_.Double(0)));
1370             GateRef doubleNotNAN = builder_.BoolNot(builder_.DoubleIsNAN(doubleVal));
1371             result = builder_.BoolAnd(doubleNotZero, doubleNotNAN);
1372             builder_.Jump(&exit);
1373         }
1374         builder_.Bind(&exit);
1375     }
1376     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1377 }
1378 
LowerBooleanToBool(GateRef gate)1379 void TypeLowering::LowerBooleanToBool(GateRef gate)
1380 {
1381     GateRef value = acc_.GetValueIn(gate, 0);
1382     GateRef result = builder_.TaggedIsTrue(value);
1383     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1384 }
1385 
LowerNumberNot(GateRef gate,GateType valueType)1386 void TypeLowering::LowerNumberNot(GateRef gate, GateType valueType)
1387 {
1388     GateRef value = acc_.GetValueIn(gate, 0);
1389     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1390     result = MonocularNumber<TypedUnOp::TYPED_NOT>(value, valueType);
1391     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1392 }
1393 
1394 template<OpCode Op>
CalculateNumbers(GateRef left,GateRef right,GateType leftType,GateType rightType)1395 GateRef TypeLowering::CalculateNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType)
1396 {
1397     auto env = builder_.GetCurrentEnvironment();
1398     Label entry(&builder_);
1399     env->SubCfgEntry(&entry);
1400     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1401     DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
1402     DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
1403 
1404     Label exit(&builder_);
1405     Label doFloatOp(&builder_);
1406     Label doIntOp(&builder_);
1407     Label leftIsIntRightIsDouble(&builder_);
1408     Label rightIsInt(&builder_);
1409     Label rightIsDouble(&builder_);
1410     Label leftIsInt(&builder_);
1411     Label leftIsDouble(&builder_);
1412     bool intOptAccessed = false;
1413 
1414     auto LowerIntOpInt = [&]() -> void {
1415         builder_.Jump(&doIntOp);
1416         intOptAccessed = true;
1417     };
1418     auto LowerDoubleOpInt = [&]() -> void {
1419         doubleLeft = builder_.GetDoubleOfTDouble(left);
1420         doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
1421         builder_.Jump(&doFloatOp);
1422     };
1423     auto LowerIntOpDouble = [&]() -> void {
1424         doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
1425         doubleRight = builder_.GetDoubleOfTDouble(right);
1426         builder_.Jump(&doFloatOp);
1427     };
1428     auto LowerDoubleOpDouble = [&]() -> void {
1429         doubleLeft = builder_.GetDoubleOfTDouble(left);
1430         doubleRight = builder_.GetDoubleOfTDouble(right);
1431         builder_.Jump(&doFloatOp);
1432     };
1433     auto LowerRightWhenLeftIsInt = [&]() -> void {
1434         if (rightType.IsIntType()) {
1435             LowerIntOpInt();
1436         } else if (rightType.IsDoubleType()) {
1437             LowerIntOpDouble();
1438         } else {
1439             builder_.Branch(builder_.TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
1440             intOptAccessed = true;
1441             builder_.Bind(&leftIsIntRightIsDouble);
1442             LowerIntOpDouble();
1443         }
1444     };
1445     auto LowerRightWhenLeftIsDouble = [&]() -> void {
1446         if (rightType.IsIntType()) {
1447             LowerDoubleOpInt();
1448         } else if (rightType.IsDoubleType()) {
1449             LowerDoubleOpDouble();
1450         } else {
1451             builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1452             builder_.Bind(&rightIsInt);
1453             LowerDoubleOpInt();
1454             builder_.Bind(&rightIsDouble);
1455             LowerDoubleOpDouble();
1456         }
1457     };
1458 
1459     if (leftType.IsIntType()) {
1460         // left is int
1461         LowerRightWhenLeftIsInt();
1462     } else if (leftType.IsDoubleType()) {
1463         // left is double
1464         LowerRightWhenLeftIsDouble();
1465     } else {
1466         // left is number and need typecheck in runtime
1467         builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftIsDouble);
1468         builder_.Bind(&leftIsInt);
1469         LowerRightWhenLeftIsInt();
1470         builder_.Bind(&leftIsDouble);
1471         LowerRightWhenLeftIsDouble();
1472     }
1473     if (intOptAccessed) {
1474         builder_.Bind(&doIntOp);
1475         {
1476             Label overflow(&builder_);
1477             Label notOverflow(&builder_);
1478             Label notOverflowOrUnderflow(&builder_);
1479             // handle left is int and right is int
1480             GateRef res = BinaryOp<Op, MachineType::I64>(builder_.GetInt64OfTInt(left),
1481                                                          builder_.GetInt64OfTInt(right));
1482             GateRef max = builder_.Int64(INT32_MAX);
1483             GateRef min = builder_.Int64(INT32_MIN);
1484             builder_.Branch(builder_.Int64GreaterThan(res, max), &overflow, &notOverflow);
1485             builder_.Bind(&notOverflow);
1486             {
1487                 builder_.Branch(builder_.Int64LessThan(res, min), &overflow, &notOverflowOrUnderflow);
1488             }
1489             builder_.Bind(&overflow);
1490             {
1491                 doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
1492                 doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
1493                 builder_.Jump(&doFloatOp);
1494             }
1495             builder_.Bind(&notOverflowOrUnderflow);
1496             {
1497                 result = builder_.ToTaggedIntPtr(res);
1498                 builder_.Jump(&exit);
1499             }
1500         }
1501     }
1502     builder_.Bind(&doFloatOp);
1503     {
1504         // Other situations
1505         auto res = BinaryOp<Op, MachineType::F64>(*doubleLeft, *doubleRight);
1506         result = DoubleToTaggedDoublePtr(res);
1507         builder_.Jump(&exit);
1508     }
1509     builder_.Bind(&exit);
1510     auto ret = *result;
1511     env->SubCfgExit();
1512     return ret;
1513 }
1514 
1515 template<OpCode Op>
ShiftNumber(GateRef left,GateRef right,GateType leftType,GateType rightType)1516 GateRef TypeLowering::ShiftNumber(GateRef left, GateRef right,
1517                                   GateType leftType, GateType rightType)
1518 {
1519     auto env = builder_.GetCurrentEnvironment();
1520     Label entry(&builder_);
1521     env->SubCfgEntry(&entry);
1522     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1523     DEFVAlUE(intLeft, (&builder_), VariableType::INT32(), builder_.Int32(0));
1524     DEFVAlUE(intRight, (&builder_), VariableType::INT32(), builder_.Int32(0));
1525 
1526     Label exit(&builder_);
1527     Label doIntOp(&builder_);
1528     Label leftIsIntRightIsInt(&builder_);
1529     Label leftIsIntRightIsDouble(&builder_);
1530     Label rightIsInt(&builder_);
1531     Label rightIsDouble(&builder_);
1532     Label leftIsInt(&builder_);
1533     Label leftIsDouble(&builder_);
1534     Label overflow(&builder_);
1535     Label notOverflow(&builder_);
1536 
1537     auto LowerIntOpInt = [&]() -> void {
1538         intLeft = builder_.GetInt32OfTInt(left);
1539         intRight = builder_.GetInt32OfTInt(right);
1540         builder_.Jump(&doIntOp);
1541     };
1542     auto LowerDoubleOpInt = [&]() -> void {
1543         intLeft = TruncDoubleToInt(builder_.GetDoubleOfTDouble(left));
1544         intRight = builder_.GetInt32OfTInt(right);
1545         builder_.Jump(&doIntOp);
1546     };
1547     auto LowerIntOpDouble = [&]() -> void {
1548         intLeft = builder_.GetInt32OfTInt(left);
1549         intRight = TruncDoubleToInt(builder_.GetDoubleOfTDouble(right));
1550         builder_.Jump(&doIntOp);
1551     };
1552     auto LowerDoubleOpDouble = [&]() -> void {
1553         intLeft = TruncDoubleToInt(builder_.GetDoubleOfTDouble(left));
1554         intRight = TruncDoubleToInt(builder_.GetDoubleOfTDouble(right));
1555         builder_.Jump(&doIntOp);
1556     };
1557     auto LowerRightWhenLeftIsInt = [&]() -> void {
1558         if (rightType.IsIntType()) {
1559             LowerIntOpInt();
1560         } else if (rightType.IsDoubleType()) {
1561             LowerIntOpDouble();
1562         } else {
1563             builder_.Branch(builder_.TaggedIsInt(right), &leftIsIntRightIsInt, &leftIsIntRightIsDouble);
1564             builder_.Bind(&leftIsIntRightIsInt);
1565             LowerIntOpInt();
1566             builder_.Bind(&leftIsIntRightIsDouble);
1567             LowerIntOpDouble();
1568         }
1569     };
1570     auto LowerRightWhenLeftIsDouble = [&]() -> void {
1571         if (rightType.IsIntType()) {
1572             LowerDoubleOpInt();
1573         } else if (rightType.IsDoubleType()) {
1574             LowerDoubleOpDouble();
1575         } else {
1576             builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1577             builder_.Bind(&rightIsInt);
1578             LowerDoubleOpInt();
1579             builder_.Bind(&rightIsDouble);
1580             LowerDoubleOpDouble();
1581         }
1582     };
1583 
1584     if (leftType.IsIntType()) {
1585         // left is int
1586         LowerRightWhenLeftIsInt();
1587     } else if (leftType.IsDoubleType()) {
1588         // left is double
1589         LowerRightWhenLeftIsDouble();
1590     } else {
1591         // left is number and need typecheck in runtime
1592         builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftIsDouble);
1593         builder_.Bind(&leftIsInt);
1594         LowerRightWhenLeftIsInt();
1595         builder_.Bind(&leftIsDouble);
1596         LowerRightWhenLeftIsDouble();
1597     }
1598     builder_.Bind(&doIntOp);
1599     {
1600         GateRef res = Circuit::NullGate();
1601         GateRef shift = builder_.Int32And(*intRight, builder_.Int32(0x1f));
1602         switch (Op) {
1603             case OpCode::LSL: {
1604                 res = builder_.Int32LSL(*intLeft, shift);
1605                 result = IntToTaggedIntPtr(res);
1606                 builder_.Jump(&exit);
1607                 break;
1608             }
1609             case OpCode::LSR: {
1610                 res = builder_.Int32LSR(*intLeft, shift);
1611                 auto condition = builder_.Int32UnsignedGreaterThan(res, builder_.Int32(INT32_MAX));
1612                 builder_.Branch(condition, &overflow, &notOverflow);
1613                 builder_.Bind(&overflow);
1614                 {
1615                     result = builder_.DoubleToTaggedDoublePtr(builder_.ChangeUInt32ToFloat64(res));
1616                     builder_.Jump(&exit);
1617                 }
1618                 builder_.Bind(&notOverflow);
1619                 {
1620                     result = IntToTaggedIntPtr(res);
1621                     builder_.Jump(&exit);
1622                 }
1623                 break;
1624             }
1625             case OpCode::ASR: {
1626                 res = builder_.Int32ASR(*intLeft, shift);
1627                 result = IntToTaggedIntPtr(res);
1628                 builder_.Jump(&exit);
1629                 break;
1630             }
1631             default:
1632                 UNREACHABLE();
1633                 break;
1634         }
1635     }
1636     builder_.Bind(&exit);
1637     auto ret = *result;
1638     env->SubCfgExit();
1639     return ret;
1640 }
1641 
1642 template<OpCode Op>
LogicalNumbers(GateRef left,GateRef right,GateType leftType,GateType rightType)1643 GateRef TypeLowering::LogicalNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType)
1644 {
1645     auto env = builder_.GetCurrentEnvironment();
1646     Label entry(&builder_);
1647     env->SubCfgEntry(&entry);
1648     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1649     DEFVAlUE(intLeft, (&builder_), VariableType::INT32(), builder_.Int32(0));
1650     DEFVAlUE(intRight, (&builder_), VariableType::INT32(), builder_.Int32(0));
1651 
1652     Label exit(&builder_);
1653     Label doIntOp(&builder_);
1654     Label leftIsIntRightIsInt(&builder_);
1655     Label leftIsIntRightIsDouble(&builder_);
1656     Label rightIsInt(&builder_);
1657     Label rightIsDouble(&builder_);
1658     Label leftIsInt(&builder_);
1659     Label leftIsDouble(&builder_);
1660 
1661     auto LowerIntOpInt = [&]() -> void {
1662         intLeft = builder_.GetInt32OfTInt(left);
1663         intRight = builder_.GetInt32OfTInt(right);
1664         builder_.Jump(&doIntOp);
1665     };
1666     auto LowerDoubleOpInt = [&]() -> void {
1667         intLeft = TruncDoubleToInt(builder_.GetDoubleOfTDouble(left));
1668         intRight = builder_.GetInt32OfTInt(right);
1669         builder_.Jump(&doIntOp);
1670     };
1671     auto LowerIntOpDouble = [&]() -> void {
1672         intLeft = builder_.GetInt32OfTInt(left);
1673         intRight = TruncDoubleToInt(builder_.GetDoubleOfTDouble(right));
1674         builder_.Jump(&doIntOp);
1675     };
1676     auto LowerDoubleOpDouble = [&]() -> void {
1677         intLeft = TruncDoubleToInt(builder_.GetDoubleOfTDouble(left));
1678         intRight = TruncDoubleToInt(builder_.GetDoubleOfTDouble(right));
1679         builder_.Jump(&doIntOp);
1680     };
1681     auto LowerRightWhenLeftIsInt = [&]() -> void {
1682         if (rightType.IsIntType()) {
1683             LowerIntOpInt();
1684         } else if (rightType.IsDoubleType()) {
1685             LowerIntOpDouble();
1686         } else {
1687             builder_.Branch(builder_.TaggedIsInt(right), &leftIsIntRightIsInt, &leftIsIntRightIsDouble);
1688             builder_.Bind(&leftIsIntRightIsInt);
1689             LowerIntOpInt();
1690             builder_.Bind(&leftIsIntRightIsDouble);
1691             LowerIntOpDouble();
1692         }
1693     };
1694     auto LowerRightWhenLeftIsDouble = [&]() -> void {
1695         if (rightType.IsIntType()) {
1696             LowerDoubleOpInt();
1697         } else if (rightType.IsDoubleType()) {
1698             LowerDoubleOpDouble();
1699         } else {
1700             builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1701             builder_.Bind(&rightIsInt);
1702             LowerDoubleOpInt();
1703             builder_.Bind(&rightIsDouble);
1704             LowerDoubleOpDouble();
1705         }
1706     };
1707 
1708     if (leftType.IsIntType()) {
1709         // left is int
1710         LowerRightWhenLeftIsInt();
1711     } else if (leftType.IsDoubleType()) {
1712         // left is double
1713         LowerRightWhenLeftIsDouble();
1714     } else {
1715         // left is number and need typecheck in runtime
1716         builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftIsDouble);
1717         builder_.Bind(&leftIsInt);
1718         LowerRightWhenLeftIsInt();
1719         builder_.Bind(&leftIsDouble);
1720         LowerRightWhenLeftIsDouble();
1721     }
1722     builder_.Bind(&doIntOp);
1723     {
1724         GateRef res = Circuit::NullGate();
1725         switch (Op) {
1726             case OpCode::AND: {
1727                 res = builder_.Int32And(*intLeft, *intRight);
1728                 break;
1729             }
1730             case OpCode::OR: {
1731                 res = builder_.Int32Or(*intLeft, *intRight);
1732                 break;
1733             }
1734             case OpCode::XOR: {
1735                 res = builder_.Int32Xor(*intLeft, *intRight);
1736                 break;
1737             }
1738             default:
1739                 UNREACHABLE();
1740                 break;
1741         }
1742         result = IntToTaggedIntPtr(res);
1743         builder_.Jump(&exit);
1744     }
1745     builder_.Bind(&exit);
1746     auto ret = *result;
1747     env->SubCfgExit();
1748     return ret;
1749 }
1750 
1751 template<TypedBinOp Op>
CompareNumbers(GateRef left,GateRef right,GateType leftType,GateType rightType)1752 GateRef TypeLowering::CompareNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType)
1753 {
1754     auto env = builder_.GetCurrentEnvironment();
1755     Label entry(&builder_);
1756     env->SubCfgEntry(&entry);
1757     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1758     DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
1759     DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
1760 
1761     Label exit(&builder_);
1762     Label doFloatOp(&builder_);
1763     Label doIntOp(&builder_);
1764     Label leftIsIntRightIsDouble(&builder_);
1765     Label rightIsInt(&builder_);
1766     Label rightIsDouble(&builder_);
1767     Label leftIsInt(&builder_);
1768     Label leftIsDouble(&builder_);
1769     bool intOptAccessed = false;
1770     bool floatOptAccessed = false;
1771 
1772     auto LowerIntOpInt = [&]() -> void {
1773         builder_.Jump(&doIntOp);
1774         intOptAccessed = true;
1775     };
1776     auto LowerDoubleOpInt = [&]() -> void {
1777         doubleLeft = builder_.GetDoubleOfTDouble(left);
1778         doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
1779         builder_.Jump(&doFloatOp);
1780         floatOptAccessed = true;
1781     };
1782     auto LowerIntOpDouble = [&]() -> void {
1783         doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
1784         doubleRight = builder_.GetDoubleOfTDouble(right);
1785         builder_.Jump(&doFloatOp);
1786         floatOptAccessed = true;
1787     };
1788     auto LowerDoubleOpDouble = [&]() -> void {
1789         doubleLeft = builder_.GetDoubleOfTDouble(left);
1790         doubleRight = builder_.GetDoubleOfTDouble(right);
1791         builder_.Jump(&doFloatOp);
1792         floatOptAccessed = true;
1793     };
1794     auto LowerRightWhenLeftIsInt = [&]() -> void {
1795         if (rightType.IsIntType()) {
1796             LowerIntOpInt();
1797         } else if (rightType.IsDoubleType()) {
1798             LowerIntOpDouble();
1799         } else {
1800             builder_.Branch(builder_.TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
1801             intOptAccessed = true;
1802             builder_.Bind(&leftIsIntRightIsDouble);
1803             LowerIntOpDouble();
1804         }
1805     };
1806     auto LowerRightWhenLeftIsDouble = [&]() -> void {
1807         if (rightType.IsIntType()) {
1808             LowerDoubleOpInt();
1809         } else if (rightType.IsDoubleType()) {
1810             LowerDoubleOpDouble();
1811         } else {
1812             builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1813             builder_.Bind(&rightIsInt);
1814             LowerDoubleOpInt();
1815             builder_.Bind(&rightIsDouble);
1816             LowerDoubleOpDouble();
1817         }
1818     };
1819 
1820     if (leftType.IsIntType()) {
1821         // left is int
1822         LowerRightWhenLeftIsInt();
1823     } else if (leftType.IsDoubleType()) {
1824         // left is double
1825         LowerRightWhenLeftIsDouble();
1826     } else {
1827         // left is number and need typecheck in runtime
1828         builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftIsDouble);
1829         builder_.Bind(&leftIsInt);
1830         LowerRightWhenLeftIsInt();
1831         builder_.Bind(&leftIsDouble);
1832         LowerRightWhenLeftIsDouble();
1833     }
1834     if (intOptAccessed) {
1835         builder_.Bind(&doIntOp);
1836         {
1837             GateRef intLeft = builder_.GetInt32OfTInt(left);
1838             GateRef intRight = builder_.GetInt32OfTInt(right);
1839             auto cmp = builder_.ZExtInt1ToInt64(CompareInt<Op>(intLeft, intRight));
1840             auto res = builder_.Int64Or(cmp, builder_.Int64(JSTaggedValue::TAG_BOOLEAN_MASK));
1841             result = builder_.Int64ToTaggedPtr(res);
1842             builder_.Jump(&exit);
1843         }
1844     }
1845     if (floatOptAccessed) {
1846         builder_.Bind(&doFloatOp);
1847         {
1848             // Other situations
1849             auto cmp = builder_.ZExtInt1ToInt64(CompareDouble<Op>(*doubleLeft, *doubleRight));
1850             auto res = builder_.Int64Or(cmp, builder_.Int64(JSTaggedValue::TAG_BOOLEAN_MASK));
1851             result = builder_.Int64ToTaggedPtr(res);
1852             builder_.Jump(&exit);
1853         }
1854     }
1855     builder_.Bind(&exit);
1856     auto ret = *result;
1857     env->SubCfgExit();
1858     return ret;
1859 }
1860 
1861 template<TypedBinOp Op>
CompareInt(GateRef left,GateRef right)1862 GateRef TypeLowering::CompareInt(GateRef left, GateRef right)
1863 {
1864     GateRef condition = Circuit::NullGate();
1865     switch (Op) {
1866         case TypedBinOp::TYPED_LESS:
1867             condition = builder_.Int32LessThan(left, right);
1868             break;
1869         case TypedBinOp::TYPED_LESSEQ:
1870             condition = builder_.Int32LessThanOrEqual(left, right);
1871             break;
1872         case TypedBinOp::TYPED_GREATER:
1873             condition = builder_.Int32GreaterThan(left, right);
1874             break;
1875         case TypedBinOp::TYPED_GREATEREQ:
1876             condition = builder_.Int32GreaterThanOrEqual(left, right);
1877             break;
1878         case TypedBinOp::TYPED_EQ:
1879             condition = builder_.Int32Equal(left, right);
1880             break;
1881         case TypedBinOp::TYPED_NOTEQ:
1882             condition = builder_.Int32NotEqual(left, right);
1883             break;
1884         default:
1885             break;
1886     }
1887     return condition;
1888 }
1889 
1890 template<TypedBinOp Op>
CompareDouble(GateRef left,GateRef right)1891 GateRef TypeLowering::CompareDouble(GateRef left, GateRef right)
1892 {
1893     GateRef condition = Circuit::NullGate();
1894     switch (Op) {
1895         case TypedBinOp::TYPED_LESS:
1896             condition = builder_.DoubleLessThan(left, right);
1897             break;
1898         case TypedBinOp::TYPED_LESSEQ:
1899             condition = builder_.DoubleLessThanOrEqual(left, right);
1900             break;
1901         case TypedBinOp::TYPED_GREATER:
1902             condition = builder_.DoubleGreaterThan(left, right);
1903             break;
1904         case TypedBinOp::TYPED_GREATEREQ:
1905             condition = builder_.DoubleGreaterThanOrEqual(left, right);
1906             break;
1907         case TypedBinOp::TYPED_EQ:
1908             condition = builder_.DoubleEqual(left, right);
1909             break;
1910         case TypedBinOp::TYPED_NOTEQ:
1911             condition = builder_.DoubleNotEqual(left, right);
1912             break;
1913         default:
1914             break;
1915     }
1916     return condition;
1917 }
1918 
1919 template<TypedUnOp Op>
MonocularNumber(GateRef value,GateType valueType)1920 GateRef TypeLowering::MonocularNumber(GateRef value, GateType valueType)
1921 {
1922     auto env = builder_.GetCurrentEnvironment();
1923     Label entry(&builder_);
1924     env->SubCfgEntry(&entry);
1925     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1926     DEFVAlUE(doubleVal, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
1927 
1928     Label exit(&builder_);
1929     Label doFloatOp(&builder_);
1930     Label doIntOp(&builder_);
1931     Label valueIsInt(&builder_);
1932     Label valueIsDouble(&builder_);
1933     bool intOptAccessed = false;
1934     bool floatOptAccessed = false;
1935 
1936     auto LowerIntOp = [&]() -> void {
1937         builder_.Jump(&doIntOp);
1938         intOptAccessed = true;
1939     };
1940     auto LowerDoubleOp = [&]() -> void {
1941         doubleVal = builder_.GetDoubleOfTDouble(value);
1942         builder_.Jump(&doFloatOp);
1943         floatOptAccessed = true;
1944     };
1945 
1946     if (valueType.IsIntType()) {
1947         // value is int
1948         // no need to consider if value will overflow or underflow,
1949         // since guard has already checked that.
1950         GateRef intVal = builder_.GetInt64OfTInt(value);
1951         GateRef res = Circuit::NullGate();
1952         switch (Op) {
1953             case TypedUnOp::TYPED_INC: {
1954                 res = builder_.Int64Add(intVal, builder_.Int64(1));
1955                 result = builder_.ToTaggedIntPtr(res);
1956                 builder_.Jump(&exit);
1957                 break;
1958             }
1959             case TypedUnOp::TYPED_DEC: {
1960                 res = builder_.Int64Sub(intVal, builder_.Int64(1));
1961                 result = builder_.ToTaggedIntPtr(res);
1962                 builder_.Jump(&exit);
1963                 break;
1964             }
1965             case TypedUnOp::TYPED_NOT: {
1966                 res = builder_.Int64Not(intVal);
1967                 result = builder_.ToTaggedIntPtr(res);
1968                 builder_.Jump(&exit);
1969                 break;
1970             }
1971             default:
1972                 break;
1973         }
1974     } else if (valueType.IsDoubleType()) {
1975         // value is double
1976         LowerDoubleOp();
1977     } else {
1978         // value is number and need typecheck in runtime
1979         builder_.Branch(builder_.TaggedIsInt(value), &valueIsInt, &valueIsDouble);
1980         builder_.Bind(&valueIsInt);
1981         LowerIntOp();
1982         builder_.Bind(&valueIsDouble);
1983         LowerDoubleOp();
1984     }
1985     if (intOptAccessed) {
1986         builder_.Bind(&doIntOp);
1987         {
1988             GateRef intVal = builder_.GetInt64OfTInt(value);
1989             GateRef res = Circuit::NullGate();
1990             switch (Op) {
1991                 case TypedUnOp::TYPED_INC: {
1992                     Label overflow(&builder_);
1993                     Label notOverflow(&builder_);
1994                     GateRef max = builder_.Int64(INT32_MAX);
1995                     builder_.Branch(builder_.Int64Equal(intVal, max), &overflow, &notOverflow);
1996                     builder_.Bind(&overflow);
1997                     {
1998                         res = builder_.Double(JSTaggedValue::TAG_INT32_INC_MAX);
1999                         result = DoubleToTaggedDoublePtr(res);
2000                         builder_.Jump(&exit);
2001                     }
2002                     builder_.Bind(&notOverflow);
2003                     {
2004                         res = builder_.Int64Add(intVal, builder_.Int64(1));
2005                         result = builder_.ToTaggedIntPtr(res);
2006                         builder_.Jump(&exit);
2007                     }
2008                     break;
2009                 }
2010                 case TypedUnOp::TYPED_DEC: {
2011                     Label underflow(&builder_);
2012                     Label notUnderflow(&builder_);
2013                     GateRef min = builder_.Int64(INT32_MIN);
2014                     builder_.Branch(builder_.Int64Equal(intVal, min), &underflow, &notUnderflow);
2015                     builder_.Bind(&underflow);
2016                     {
2017                         res = builder_.Double(static_cast<double>(JSTaggedValue::TAG_INT32_DEC_MIN));
2018                         result = DoubleToTaggedDoublePtr(res);
2019                         builder_.Jump(&exit);
2020                     }
2021                     builder_.Bind(&notUnderflow);
2022                     {
2023                         res = builder_.Int64Sub(intVal, builder_.Int64(1));
2024                         result = builder_.ToTaggedIntPtr(res);
2025                         builder_.Jump(&exit);
2026                     }
2027                     break;
2028                 }
2029                 case TypedUnOp::TYPED_NOT: {
2030                     res = builder_.Int64Not(intVal);
2031                     result = builder_.ToTaggedIntPtr(res);
2032                     builder_.Jump(&exit);
2033                     break;
2034                 }
2035                 default:
2036                     break;
2037             }
2038         }
2039     }
2040     if (floatOptAccessed) {
2041         builder_.Bind(&doFloatOp);
2042         {
2043             auto res = Circuit::NullGate();
2044             switch (Op) {
2045                 case TypedUnOp::TYPED_INC: {
2046                     res = builder_.DoubleAdd(*doubleVal, builder_.Double(1.0));
2047                     result = DoubleToTaggedDoublePtr(res);
2048                     break;
2049                 }
2050                 case TypedUnOp::TYPED_DEC: {
2051                     res = builder_.DoubleSub(*doubleVal, builder_.Double(1.0));
2052                     result = DoubleToTaggedDoublePtr(res);
2053                     break;
2054                 }
2055                 case TypedUnOp::TYPED_NOT: {
2056                     res = builder_.TruncFloatToInt64(*doubleVal);
2057                     result = builder_.ToTaggedIntPtr(builder_.Int64Not(res));
2058                     break;
2059                 }
2060                 default:
2061                     break;
2062             }
2063             builder_.Jump(&exit);
2064         }
2065     }
2066     builder_.Bind(&exit);
2067     auto ret = *result;
2068     env->SubCfgExit();
2069     return ret;
2070 }
2071 
2072 template<OpCode Op, MachineType Type>
BinaryOp(GateRef x,GateRef y)2073 GateRef TypeLowering::BinaryOp(GateRef x, GateRef y)
2074 {
2075     return builder_.BinaryOp<Op, Type>(x, y);
2076 }
2077 
DoubleToTaggedDoublePtr(GateRef gate)2078 GateRef TypeLowering::DoubleToTaggedDoublePtr(GateRef gate)
2079 {
2080     return builder_.DoubleToTaggedDoublePtr(gate);
2081 }
2082 
ChangeInt32ToFloat64(GateRef gate)2083 GateRef TypeLowering::ChangeInt32ToFloat64(GateRef gate)
2084 {
2085     return builder_.ChangeInt32ToFloat64(gate);
2086 }
2087 
TruncDoubleToInt(GateRef gate)2088 GateRef TypeLowering::TruncDoubleToInt(GateRef gate)
2089 {
2090     return builder_.TruncInt64ToInt32(builder_.TruncFloatToInt64(gate));
2091 }
2092 
Int32Mod(GateRef left,GateRef right)2093 GateRef TypeLowering::Int32Mod(GateRef left, GateRef right)
2094 {
2095     return builder_.BinaryArithmetic(circuit_->Smod(), MachineType::I32, left, right);
2096 }
2097 
DoubleMod(GateRef left,GateRef right)2098 GateRef TypeLowering::DoubleMod(GateRef left, GateRef right)
2099 {
2100     return builder_.BinaryArithmetic(circuit_->Fmod(), MachineType::F64, left, right);
2101 }
2102 
IntToTaggedIntPtr(GateRef x)2103 GateRef TypeLowering::IntToTaggedIntPtr(GateRef x)
2104 {
2105     GateRef val = builder_.SExtInt32ToInt64(x);
2106     return builder_.ToTaggedIntPtr(val);
2107 }
2108 
Less(GateRef left,GateRef right)2109 GateRef TypeLowering::Less(GateRef left, GateRef right)
2110 {
2111     auto env = builder_.GetCurrentEnvironment();
2112     Label entry(&builder_);
2113     env->SubCfgEntry(&entry);
2114     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
2115     Label leftIsInt(&builder_);
2116     Label leftOrRightNotInt(&builder_);
2117     Label leftLessRight(&builder_);
2118     Label leftGreaterEqRight(&builder_);
2119     Label exit(&builder_);
2120     builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftOrRightNotInt);
2121     builder_.Bind(&leftIsInt);
2122     {
2123         Label rightIsInt(&builder_);
2124         builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &leftOrRightNotInt);
2125         builder_.Bind(&rightIsInt);
2126         {
2127             GateRef intLeft = builder_.GetInt32OfTInt(left);
2128             GateRef intRight = builder_.GetInt32OfTInt(right);
2129             builder_.Branch(builder_.Int32LessThan(intLeft, intRight), &leftLessRight, &leftGreaterEqRight);
2130         }
2131     }
2132     builder_.Bind(&leftOrRightNotInt);
2133     {
2134         Label leftIsNumber(&builder_);
2135         builder_.Branch(builder_.TaggedIsNumber(left), &leftIsNumber, &exit);
2136         builder_.Bind(&leftIsNumber);
2137         {
2138             Label rightIsNumber(&builder_);
2139             builder_.Branch(builder_.TaggedIsNumber(right), &rightIsNumber, &exit);
2140             builder_.Bind(&rightIsNumber);
2141             {
2142                 // fast path
2143                 DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0.0));
2144                 DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0.0));
2145                 Label leftIsInt1(&builder_);
2146                 Label leftNotInt1(&builder_);
2147                 Label exit1(&builder_);
2148                 Label exit2(&builder_);
2149                 Label rightIsInt1(&builder_);
2150                 Label rightNotInt1(&builder_);
2151                 builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
2152                 builder_.Bind(&leftIsInt1);
2153                 {
2154                     doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2155                     builder_.Jump(&exit1);
2156                 }
2157                 builder_.Bind(&leftNotInt1);
2158                 {
2159                     doubleLeft = builder_.GetDoubleOfTDouble(left);
2160                     builder_.Jump(&exit1);
2161                 }
2162                 builder_.Bind(&exit1);
2163                 builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
2164                 builder_.Bind(&rightIsInt1);
2165                 {
2166                     doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2167                     builder_.Jump(&exit2);
2168                 }
2169                 builder_.Bind(&rightNotInt1);
2170                 {
2171                     doubleRight = builder_.GetDoubleOfTDouble(right);
2172                     builder_.Jump(&exit2);
2173                 }
2174                 builder_.Bind(&exit2);
2175                 builder_.Branch(builder_.DoubleLessThan(*doubleLeft, *doubleRight), &leftLessRight,
2176                                 &leftGreaterEqRight);
2177             }
2178         }
2179     }
2180     builder_.Bind(&leftLessRight);
2181     {
2182         result = builder_.TaggedTrue();
2183         builder_.Jump(&exit);
2184     }
2185     builder_.Bind(&leftGreaterEqRight);
2186     {
2187         result = builder_.TaggedFalse();
2188         builder_.Jump(&exit);
2189     }
2190     builder_.Bind(&exit);
2191     auto ret = *result;
2192     env->SubCfgExit();
2193     return ret;
2194 }
2195 
LessEq(GateRef left,GateRef right)2196 GateRef TypeLowering::LessEq(GateRef left, GateRef right)
2197 {
2198     auto env = builder_.GetCurrentEnvironment();
2199     Label entry(&builder_);
2200     env->SubCfgEntry(&entry);
2201     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2202     Label leftIsInt(&builder_);
2203     Label leftOrRightNotInt(&builder_);
2204     Label leftLessEqRight(&builder_);
2205     Label leftGreaterRight(&builder_);
2206     Label exit(&builder_);
2207     builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftOrRightNotInt);
2208     builder_.Bind(&leftIsInt);
2209     {
2210         Label rightIsInt(&builder_);
2211         builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &leftOrRightNotInt);
2212         builder_.Bind(&rightIsInt);
2213         {
2214             GateRef intLeft = builder_.GetInt32OfTInt(left);
2215             GateRef intRight = builder_.GetInt32OfTInt(right);
2216             builder_.Branch(builder_.Int32LessThanOrEqual(intLeft, intRight), &leftLessEqRight, &leftGreaterRight);
2217         }
2218     }
2219     builder_.Bind(&leftOrRightNotInt);
2220     {
2221         Label leftIsNumber(&builder_);
2222         builder_.Branch(builder_.TaggedIsNumber(left), &leftIsNumber, &exit);
2223         builder_.Bind(&leftIsNumber);
2224         {
2225             Label rightIsNumber(&builder_);
2226             builder_.Branch(builder_.TaggedIsNumber(right), &rightIsNumber, &exit);
2227             builder_.Bind(&rightIsNumber);
2228             {
2229                 // fast path
2230                 DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0.0));
2231                 DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0.0));
2232                 Label leftIsInt1(&builder_);
2233                 Label leftNotInt1(&builder_);
2234                 Label exit1(&builder_);
2235                 Label exit2(&builder_);
2236                 Label rightIsInt1(&builder_);
2237                 Label rightNotInt1(&builder_);
2238                 builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
2239                 builder_.Bind(&leftIsInt1);
2240                 {
2241                     doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2242                     builder_.Jump(&exit1);
2243                 }
2244                 builder_.Bind(&leftNotInt1);
2245                 {
2246                     doubleLeft = builder_.GetDoubleOfTDouble(left);
2247                     builder_.Jump(&exit1);
2248                 }
2249                 builder_.Bind(&exit1);
2250                 builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
2251                 builder_.Bind(&rightIsInt1);
2252                 {
2253                     doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2254                     builder_.Jump(&exit2);
2255                 }
2256                 builder_.Bind(&rightNotInt1);
2257                 {
2258                     doubleRight = builder_.GetDoubleOfTDouble(right);
2259                     builder_.Jump(&exit2);
2260                 }
2261                 builder_.Bind(&exit2);
2262                 builder_.Branch(builder_.DoubleLessThanOrEqual(*doubleLeft, *doubleRight), &leftLessEqRight,
2263                                 &leftGreaterRight);
2264             }
2265         }
2266     }
2267     builder_.Bind(&leftLessEqRight);
2268     {
2269         result = builder_.TaggedTrue();
2270         builder_.Jump(&exit);
2271     }
2272     builder_.Bind(&leftGreaterRight);
2273     {
2274         result = builder_.TaggedFalse();
2275         builder_.Jump(&exit);
2276     }
2277     builder_.Bind(&exit);
2278     auto ret = *result;
2279     env->SubCfgExit();
2280     return ret;
2281 }
2282 
FastDiv(GateRef left,GateRef right)2283 GateRef TypeLowering::FastDiv(GateRef left, GateRef right)
2284 {
2285     auto env = builder_.GetCurrentEnvironment();
2286     Label entry(&builder_);
2287     env->SubCfgEntry(&entry);
2288     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
2289     DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
2290     DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
2291     Label leftIsNumber(&builder_);
2292     Label leftNotNumberOrRightNotNumber(&builder_);
2293     Label leftIsNumberAndRightIsNumber(&builder_);
2294     Label leftIsDoubleAndRightIsDouble(&builder_);
2295     Label exit(&builder_);
2296     builder_.Branch(builder_.TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
2297     builder_.Bind(&leftIsNumber);
2298     {
2299         Label rightIsNumber(&builder_);
2300         builder_.Branch(builder_.TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
2301         builder_.Bind(&rightIsNumber);
2302         {
2303             Label leftIsInt(&builder_);
2304             Label leftNotInt(&builder_);
2305             builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftNotInt);
2306             builder_.Bind(&leftIsInt);
2307             {
2308                 doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2309                 builder_.Jump(&leftIsNumberAndRightIsNumber);
2310             }
2311             builder_.Bind(&leftNotInt);
2312             {
2313                 doubleLeft = builder_.GetDoubleOfTDouble(left);
2314                 builder_.Jump(&leftIsNumberAndRightIsNumber);
2315             }
2316         }
2317     }
2318     builder_.Bind(&leftNotNumberOrRightNotNumber);
2319     builder_.Jump(&exit);
2320     builder_.Bind(&leftIsNumberAndRightIsNumber);
2321     {
2322         Label rightIsInt(&builder_);
2323         Label rightNotInt(&builder_);
2324         builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightNotInt);
2325         builder_.Bind(&rightIsInt);
2326         {
2327             doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2328             builder_.Jump(&leftIsDoubleAndRightIsDouble);
2329         }
2330         builder_.Bind(&rightNotInt);
2331         {
2332             doubleRight = builder_.GetDoubleOfTDouble(right);
2333             builder_.Jump(&leftIsDoubleAndRightIsDouble);
2334         }
2335     }
2336     builder_.Bind(&leftIsDoubleAndRightIsDouble);
2337     {
2338         Label rightIsZero(&builder_);
2339         Label rightNotZero(&builder_);
2340         builder_.Branch(builder_.Equal(*doubleRight, builder_.Double(0.0)), &rightIsZero, &rightNotZero);
2341         builder_.Bind(&rightIsZero);
2342         {
2343             Label leftIsZero(&builder_);
2344             Label leftNotZero(&builder_);
2345             Label leftIsZeroOrNan(&builder_);
2346             Label leftNotZeroAndNotNan(&builder_);
2347             builder_.Branch(builder_.Equal(*doubleLeft, builder_.Double(0.0)), &leftIsZero, &leftNotZero);
2348             builder_.Bind(&leftIsZero);
2349             {
2350                 builder_.Jump(&leftIsZeroOrNan);
2351             }
2352             builder_.Bind(&leftNotZero);
2353             {
2354                 Label leftIsNan(&builder_);
2355                 builder_.Branch(builder_.DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan);
2356                 builder_.Bind(&leftIsNan);
2357                 {
2358                     builder_.Jump(&leftIsZeroOrNan);
2359                 }
2360             }
2361             builder_.Bind(&leftIsZeroOrNan);
2362             {
2363                 result = DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
2364                 builder_.Jump(&exit);
2365             }
2366             builder_.Bind(&leftNotZeroAndNotNan);
2367             {
2368                 GateRef intLeftTmp = builder_.CastDoubleToInt64(*doubleLeft);
2369                 GateRef intRightTmp = builder_.CastDoubleToInt64(*doubleRight);
2370                 GateRef flagBit = builder_.Int64And(builder_.Int64Xor(intLeftTmp, intRightTmp),
2371                                                     builder_.Int64(base::DOUBLE_SIGN_MASK));
2372                 GateRef tmpResult =
2373                     builder_.Int64Xor(flagBit, builder_.CastDoubleToInt64(builder_.Double(base::POSITIVE_INFINITY)));
2374                 result = DoubleToTaggedDoublePtr(builder_.CastInt64ToFloat64(tmpResult));
2375                 builder_.Jump(&exit);
2376             }
2377         }
2378         builder_.Bind(&rightNotZero);
2379         {
2380             result = DoubleToTaggedDoublePtr(
2381                 builder_.BinaryArithmetic(circuit_->Fdiv(), MachineType::F64, *doubleLeft, *doubleRight));
2382             builder_.Jump(&exit);
2383         }
2384     }
2385     builder_.Bind(&exit);
2386     auto ret = *result;
2387     env->SubCfgExit();
2388     return ret;
2389 }
2390 
ModNumbers(GateRef left,GateRef right,GateType leftType,GateType rightType)2391 GateRef TypeLowering::ModNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType)
2392 {
2393     auto env = builder_.GetCurrentEnvironment();
2394     Label entry(&builder_);
2395     env->SubCfgEntry(&entry);
2396     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
2397     DEFVAlUE(intLeft, (&builder_), VariableType::INT32(), builder_.Int32(0));
2398     DEFVAlUE(intRight, (&builder_), VariableType::INT32(), builder_.Int32(0));
2399     DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
2400     DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
2401 
2402     Label exit(&builder_);
2403     Label doFloatOp(&builder_);
2404     Label doIntOp(&builder_);
2405     Label leftIsIntRightIsDouble(&builder_);
2406     Label rightIsInt(&builder_);
2407     Label rightIsDouble(&builder_);
2408     Label leftIsInt(&builder_);
2409     Label leftIsDouble(&builder_);
2410     bool intOptAccessed = false;
2411 
2412     auto LowerIntOpInt = [&]() -> void {
2413         builder_.Jump(&doIntOp);
2414         intOptAccessed = true;
2415     };
2416     auto LowerDoubleOpInt = [&]() -> void {
2417         doubleLeft = builder_.GetDoubleOfTDouble(left);
2418         doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2419         builder_.Jump(&doFloatOp);
2420     };
2421     auto LowerIntOpDouble = [&]() -> void {
2422         doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2423         doubleRight = builder_.GetDoubleOfTDouble(right);
2424         builder_.Jump(&doFloatOp);
2425     };
2426     auto LowerDoubleOpDouble = [&]() -> void {
2427         doubleLeft = builder_.GetDoubleOfTDouble(left);
2428         doubleRight = builder_.GetDoubleOfTDouble(right);
2429         builder_.Jump(&doFloatOp);
2430     };
2431     auto LowerRightWhenLeftIsInt = [&]() -> void {
2432         if (rightType.IsIntType()) {
2433             LowerIntOpInt();
2434         } else if (rightType.IsDoubleType()) {
2435             LowerIntOpDouble();
2436         } else {
2437             builder_.Branch(builder_.TaggedIsInt(right), &doIntOp, &leftIsIntRightIsDouble);
2438             intOptAccessed = true;
2439             builder_.Bind(&leftIsIntRightIsDouble);
2440             LowerIntOpDouble();
2441         }
2442     };
2443     auto LowerRightWhenLeftIsDouble = [&]() -> void {
2444         if (rightType.IsIntType()) {
2445             LowerDoubleOpInt();
2446         } else if (rightType.IsDoubleType()) {
2447             LowerDoubleOpDouble();
2448         } else {
2449             builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightIsDouble);
2450             builder_.Bind(&rightIsInt);
2451             LowerDoubleOpInt();
2452             builder_.Bind(&rightIsDouble);
2453             LowerDoubleOpDouble();
2454         }
2455     };
2456 
2457     if (leftType.IsIntType()) {
2458         // left is int
2459         LowerRightWhenLeftIsInt();
2460     } else if (leftType.IsDoubleType()) {
2461         // left is double
2462         LowerRightWhenLeftIsDouble();
2463     } else {
2464         // left is number and need typecheck in runtime
2465         builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftIsDouble);
2466         builder_.Bind(&leftIsInt);
2467         LowerRightWhenLeftIsInt();
2468         builder_.Bind(&leftIsDouble);
2469         LowerRightWhenLeftIsDouble();
2470     }
2471     if (intOptAccessed) {
2472         builder_.Bind(&doIntOp);
2473         {
2474             intLeft = builder_.GetInt32OfTInt(left);
2475             intRight = builder_.GetInt32OfTInt(right);
2476             doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2477             doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2478             Label leftGreaterZero(&builder_);
2479             builder_.Branch(builder_.Int32GreaterThan(*intLeft, builder_.Int32(0)),
2480                             &leftGreaterZero, &doFloatOp);
2481             builder_.Bind(&leftGreaterZero);
2482             {
2483                 Label rightGreaterZero(&builder_);
2484                 builder_.Branch(builder_.Int32GreaterThan(*intRight, builder_.Int32(0)),
2485                                 &rightGreaterZero, &doFloatOp);
2486                 builder_.Bind(&rightGreaterZero);
2487                 {
2488                     result = IntToTaggedIntPtr(Int32Mod(*intLeft, *intRight));
2489                     builder_.Jump(&exit);
2490                 }
2491             }
2492         }
2493     }
2494     builder_.Bind(&doFloatOp);
2495     {
2496         Label rightNotZero(&builder_);
2497         Label rightIsZeroOrNanOrLeftIsNanOrInf(&builder_);
2498         Label rightNotZeroAndNanAndLeftNotNanAndInf(&builder_);
2499         builder_.Branch(builder_.Equal(*doubleRight, builder_.Double(0.0)), &rightIsZeroOrNanOrLeftIsNanOrInf,
2500                         &rightNotZero);
2501         builder_.Bind(&rightNotZero);
2502         {
2503             Label rightNotNan(&builder_);
2504             builder_.Branch(builder_.DoubleIsNAN(*doubleRight), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotNan);
2505             builder_.Bind(&rightNotNan);
2506             {
2507                 Label leftNotNan(&builder_);
2508                 builder_.Branch(builder_.DoubleIsNAN(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &leftNotNan);
2509                 builder_.Bind(&leftNotNan);
2510                 builder_.Branch(builder_.DoubleIsINF(*doubleLeft),
2511                                 &rightIsZeroOrNanOrLeftIsNanOrInf,
2512                                 &rightNotZeroAndNanAndLeftNotNanAndInf);
2513             }
2514         }
2515         builder_.Bind(&rightIsZeroOrNanOrLeftIsNanOrInf);
2516         {
2517             result = DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
2518             builder_.Jump(&exit);
2519         }
2520         builder_.Bind(&rightNotZeroAndNanAndLeftNotNanAndInf);
2521         {
2522             Label leftNotZero(&builder_);
2523             Label leftIsZeroOrRightIsInf(&builder_);
2524             builder_.Branch(builder_.Equal(*doubleLeft, builder_.Double(0.0)), &leftIsZeroOrRightIsInf,
2525                             &leftNotZero);
2526             builder_.Bind(&leftNotZero);
2527             {
2528                 Label rightNotInf(&builder_);
2529                 builder_.Branch(builder_.DoubleIsINF(*doubleRight), &leftIsZeroOrRightIsInf, &rightNotInf);
2530                 builder_.Bind(&rightNotInf);
2531                 {
2532                     GateRef glue = acc_.GetGlueFromArgList();
2533                     result = builder_.CallNGCRuntime(
2534                         glue, RTSTUB_ID(FloatMod), Gate::InvalidGateRef, {*doubleLeft, *doubleRight});
2535                     builder_.Jump(&exit);
2536                 }
2537             }
2538             builder_.Bind(&leftIsZeroOrRightIsInf);
2539             {
2540                 result = DoubleToTaggedDoublePtr(*doubleLeft);
2541                 builder_.Jump(&exit);
2542             }
2543         }
2544     }
2545     builder_.Bind(&exit);
2546     auto ret = *result;
2547     env->SubCfgExit();
2548     return ret;
2549 }
2550 
DivNumbers(GateRef left,GateRef right,GateType leftType,GateType rightType)2551 GateRef TypeLowering::DivNumbers(GateRef left, GateRef right,
2552                                  GateType leftType, GateType rightType)
2553 {
2554     auto env = builder_.GetCurrentEnvironment();
2555     Label entry(&builder_);
2556     env->SubCfgEntry(&entry);
2557     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
2558     DEFVAlUE(doubleLeft, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
2559     DEFVAlUE(doubleRight, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
2560     Label doFloatOp(&builder_);
2561     Label leftIsIntRightIsInt(&builder_);
2562     Label leftIsIntRightIsDouble(&builder_);
2563     Label rightIsInt(&builder_);
2564     Label rightIsDouble(&builder_);
2565     Label leftIsInt(&builder_);
2566     Label leftIsDouble(&builder_);
2567     Label exit(&builder_);
2568 
2569     auto LowerIntOpInt = [&]() -> void {
2570         doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2571         doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2572         builder_.Jump(&doFloatOp);
2573     };
2574     auto LowerDoubleOpInt = [&]() -> void {
2575         doubleLeft = builder_.GetDoubleOfTDouble(left);
2576         doubleRight = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(right));
2577         builder_.Jump(&doFloatOp);
2578     };
2579     auto LowerIntOpDouble = [&]() -> void {
2580         doubleLeft = ChangeInt32ToFloat64(builder_.GetInt32OfTInt(left));
2581         doubleRight = builder_.GetDoubleOfTDouble(right);
2582         builder_.Jump(&doFloatOp);
2583     };
2584     auto LowerDoubleOpDouble = [&]() -> void {
2585         doubleLeft = builder_.GetDoubleOfTDouble(left);
2586         doubleRight = builder_.GetDoubleOfTDouble(right);
2587         builder_.Jump(&doFloatOp);
2588     };
2589     auto LowerRightWhenLeftIsInt = [&]() -> void {
2590         if (rightType.IsIntType()) {
2591             LowerIntOpInt();
2592         } else if (rightType.IsDoubleType()) {
2593             LowerIntOpDouble();
2594         } else {
2595             builder_.Branch(builder_.TaggedIsInt(right), &leftIsIntRightIsInt, &leftIsIntRightIsDouble);
2596             builder_.Bind(&leftIsIntRightIsInt);
2597             LowerIntOpInt();
2598             builder_.Bind(&leftIsIntRightIsDouble);
2599             LowerIntOpDouble();
2600         }
2601     };
2602     auto LowerRightWhenLeftIsDouble = [&]() -> void {
2603         if (rightType.IsIntType()) {
2604             LowerDoubleOpInt();
2605         } else if (rightType.IsDoubleType()) {
2606             LowerDoubleOpDouble();
2607         } else {
2608             builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &rightIsDouble);
2609             builder_.Bind(&rightIsInt);
2610             LowerDoubleOpInt();
2611             builder_.Bind(&rightIsDouble);
2612             LowerDoubleOpDouble();
2613         }
2614     };
2615 
2616     if (leftType.IsIntType()) {
2617         // left is int
2618         LowerRightWhenLeftIsInt();
2619     } else if (leftType.IsDoubleType()) {
2620         // left is double
2621         LowerRightWhenLeftIsDouble();
2622     } else {
2623         // left is number and need typecheck in runtime
2624         builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftIsDouble);
2625         builder_.Bind(&leftIsInt);
2626         LowerRightWhenLeftIsInt();
2627         builder_.Bind(&leftIsDouble);
2628         LowerRightWhenLeftIsDouble();
2629     }
2630 
2631     builder_.Bind(&doFloatOp);
2632     {
2633         Label rightIsZero(&builder_);
2634         Label rightNotZero(&builder_);
2635         builder_.Branch(builder_.Equal(*doubleRight, builder_.Double(0.0)), &rightIsZero, &rightNotZero);
2636         builder_.Bind(&rightIsZero);
2637         {
2638             Label leftIsZero(&builder_);
2639             Label leftNotZero(&builder_);
2640             Label leftIsZeroOrNan(&builder_);
2641             Label leftNotZeroAndNotNan(&builder_);
2642             builder_.Branch(builder_.Equal(*doubleLeft, builder_.Double(0.0)), &leftIsZero, &leftNotZero);
2643             builder_.Bind(&leftIsZero);
2644             {
2645                 builder_.Jump(&leftIsZeroOrNan);
2646             }
2647             builder_.Bind(&leftNotZero);
2648             {
2649                 Label leftIsNan(&builder_);
2650                 builder_.Branch(builder_.DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan);
2651                 builder_.Bind(&leftIsNan);
2652                 {
2653                     builder_.Jump(&leftIsZeroOrNan);
2654                 }
2655             }
2656             builder_.Bind(&leftIsZeroOrNan);
2657             {
2658                 result = DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
2659                 builder_.Jump(&exit);
2660             }
2661             builder_.Bind(&leftNotZeroAndNotNan);
2662             {
2663                 GateRef intLeftTmp = builder_.CastDoubleToInt64(*doubleLeft);
2664                 GateRef intRightTmp = builder_.CastDoubleToInt64(*doubleRight);
2665                 GateRef flagBit = builder_.Int64And(builder_.Int64Xor(intLeftTmp, intRightTmp),
2666                                                     builder_.Int64(base::DOUBLE_SIGN_MASK));
2667                 GateRef tmpResult =
2668                     builder_.Int64Xor(flagBit, builder_.CastDoubleToInt64(builder_.Double(base::POSITIVE_INFINITY)));
2669                 result = DoubleToTaggedDoublePtr(builder_.CastInt64ToFloat64(tmpResult));
2670                 builder_.Jump(&exit);
2671             }
2672         }
2673         builder_.Bind(&rightNotZero);
2674         {
2675             result = DoubleToTaggedDoublePtr(
2676                 builder_.BinaryArithmetic(circuit_->Fdiv(), MachineType::F64, *doubleLeft, *doubleRight));
2677             builder_.Jump(&exit);
2678         }
2679     }
2680     builder_.Bind(&exit);
2681     auto ret = *result;
2682     env->SubCfgExit();
2683     return ret;
2684 }
2685 
FastEqual(GateRef left,GateRef right)2686 GateRef TypeLowering::FastEqual(GateRef left, GateRef right)
2687 {
2688     auto env = builder_.GetCurrentEnvironment();
2689     Label entry(&builder_);
2690     env->SubCfgEntry(&entry);
2691 
2692     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
2693     Label leftEqRight(&builder_);
2694     Label leftNotEqRight(&builder_);
2695     Label exit(&builder_);
2696 
2697     builder_.Branch(builder_.Equal(left, right), &leftEqRight, &leftNotEqRight);
2698     builder_.Bind(&leftEqRight);
2699     {
2700         Label leftIsDouble(&builder_);
2701         Label leftNotDoubleOrLeftNotNan(&builder_);
2702         builder_.Branch(builder_.TaggedIsDouble(left), &leftIsDouble, &leftNotDoubleOrLeftNotNan);
2703         builder_.Bind(&leftIsDouble);
2704         {
2705             GateRef doubleLeft = builder_.GetDoubleOfTDouble(left);
2706             Label leftIsNan(&builder_);
2707             builder_.Branch(builder_.DoubleIsNAN(doubleLeft), &leftIsNan, &leftNotDoubleOrLeftNotNan);
2708             builder_.Bind(&leftIsNan);
2709             {
2710                 result = builder_.TaggedFalse();
2711                 builder_.Jump(&exit);
2712             }
2713         }
2714         builder_.Bind(&leftNotDoubleOrLeftNotNan);
2715         {
2716             result = builder_.TaggedTrue();
2717             builder_.Jump(&exit);
2718         }
2719     }
2720     builder_.Bind(&leftNotEqRight);
2721     {
2722         Label leftIsNumber(&builder_);
2723         Label leftNotNumberOrLeftNotIntOrRightNotInt(&builder_);
2724         builder_.Branch(builder_.TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrLeftNotIntOrRightNotInt);
2725         builder_.Bind(&leftIsNumber);
2726         {
2727             Label leftIsInt(&builder_);
2728             builder_.Branch(builder_.TaggedIsInt(left), &leftIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
2729             {
2730                 builder_.Bind(&leftIsInt);
2731                 {
2732                     Label rightIsInt(&builder_);
2733                     builder_.Branch(builder_.TaggedIsInt(right), &rightIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt);
2734                     builder_.Bind(&rightIsInt);
2735                     {
2736                         result = builder_.TaggedFalse();
2737                         builder_.Jump(&exit);
2738                     }
2739                 }
2740             }
2741         }
2742         builder_.Bind(&leftNotNumberOrLeftNotIntOrRightNotInt);
2743         {
2744             Label rightIsUndefinedOrNull(&builder_);
2745             Label leftOrRightNotUndefinedOrNull(&builder_);
2746             builder_.Branch(builder_.TaggedIsUndefinedOrNull(right), &rightIsUndefinedOrNull,
2747                             &leftOrRightNotUndefinedOrNull);
2748             builder_.Bind(&rightIsUndefinedOrNull);
2749             {
2750                 Label leftIsHeapObject(&builder_);
2751                 Label leftNotHeapObject(&builder_);
2752                 builder_.Branch(builder_.TaggedIsHeapObject(left), &leftIsHeapObject, &leftNotHeapObject);
2753                 builder_.Bind(&leftIsHeapObject);
2754                 {
2755                     result = builder_.TaggedFalse();
2756                     builder_.Jump(&exit);
2757                 }
2758                 builder_.Bind(&leftNotHeapObject);
2759                 {
2760                     Label leftIsUndefinedOrNull(&builder_);
2761                     builder_.Branch(builder_.TaggedIsUndefinedOrNull(left), &leftIsUndefinedOrNull,
2762                                     &leftOrRightNotUndefinedOrNull);
2763                     builder_.Bind(&leftIsUndefinedOrNull);
2764                     {
2765                         result = builder_.TaggedTrue();
2766                         builder_.Jump(&exit);
2767                     }
2768                 }
2769             }
2770             builder_.Bind(&leftOrRightNotUndefinedOrNull);
2771             {
2772                 Label leftIsBoolean(&builder_);
2773                 Label leftNotBooleanOrRightNotSpecial(&builder_);
2774                 builder_.Branch(builder_.TaggedIsBoolean(left), &leftIsBoolean, &leftNotBooleanOrRightNotSpecial);
2775                 builder_.Bind(&leftIsBoolean);
2776                 {
2777                     Label rightIsSpecial(&builder_);
2778                     builder_.Branch(builder_.TaggedIsSpecial(right), &rightIsSpecial, &leftNotBooleanOrRightNotSpecial);
2779                     builder_.Bind(&rightIsSpecial);
2780                     {
2781                         result = builder_.TaggedFalse();
2782                         builder_.Jump(&exit);
2783                     }
2784                 }
2785                 builder_.Bind(&leftNotBooleanOrRightNotSpecial);
2786                 {
2787                     builder_.Jump(&exit);
2788                 }
2789             }
2790         }
2791     }
2792     builder_.Bind(&exit);
2793     auto ret = *result;
2794     env->SubCfgExit();
2795     return ret;
2796 }
2797 
LowerTypedCallBuitin(GateRef gate)2798 void TypeLowering::LowerTypedCallBuitin(GateRef gate)
2799 {
2800     BuiltinLowering lowering(circuit_);
2801     lowering.LowerTypedCallBuitin(gate);
2802 }
2803 
LowerCallTargetCheck(GateRef gate)2804 void TypeLowering::LowerCallTargetCheck(GateRef gate)
2805 {
2806     Environment env(gate, circuit_, &builder_);
2807     GateRef frameState = GetFrameState(gate);
2808 
2809     BuiltinLowering lowering(circuit_);
2810     GateRef funcheck = lowering.LowerCallTargetCheck(&env, gate);
2811     GateRef paracheck = lowering.CheckPara(gate);
2812     GateRef check = builder_.BoolAnd(paracheck, funcheck);
2813     builder_.DeoptCheck(check, frameState, DeoptType::NOTCALLTGT);
2814 
2815     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
2816 }
2817 
LowerTypedNewAllocateThis(GateRef gate,GateRef glue)2818 void TypeLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
2819 {
2820     Environment env(gate, circuit_, &builder_);
2821     ArgumentAccessor argAcc(circuit_);
2822     GateRef jsFunc = argAcc.GetCommonArgGate(CommonArgIdx::FUNC);
2823 
2824     GateRef ctor = acc_.GetValueIn(gate, 0);
2825 
2826     DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2827     Label allocate(&builder_);
2828     Label exit(&builder_);
2829 
2830     GateRef isBase = builder_.IsBase(ctor);
2831     builder_.Branch(isBase, &allocate, &exit);
2832     builder_.Bind(&allocate);
2833     {
2834         // add typecheck to detect protoOrHclass is equal with ihclass,
2835         // if pass typecheck: 1.no need to check whether hclass is valid 2.no need to check return result
2836         GateRef protoOrHclass = builder_.Load(VariableType::JS_ANY(), ctor,
2837                                               builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
2838         GateRef ihclassIndex = acc_.GetValueIn(gate, 1);
2839         GateRef ihclass = GetObjectFromConstPool(jsFunc, ihclassIndex);
2840         GateRef check = builder_.Equal(protoOrHclass, ihclass);
2841         GateRef frameState = GetFrameState(gate);
2842         builder_.DeoptCheck(check, frameState);
2843 
2844         NewObjectStubBuilder stubBuilder(&env);
2845         stubBuilder.SetGule(glue);
2846         stubBuilder.NewJSObject(&thisObj, &exit, protoOrHclass);
2847     }
2848     builder_.Bind(&exit);
2849     builder_.SetDepend(*thisObj);
2850     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *thisObj);
2851 }
2852 
LowerTypedSuperAllocateThis(GateRef gate,GateRef glue)2853 void TypeLowering::LowerTypedSuperAllocateThis(GateRef gate, GateRef glue)
2854 {
2855     Environment env(gate, circuit_, &builder_);
2856     GateRef superCtor = acc_.GetValueIn(gate, 0);
2857     GateRef newTarget = acc_.GetValueIn(gate, 1);
2858 
2859     DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2860     Label allocate(&builder_);
2861     Label exit(&builder_);
2862 
2863     GateRef isBase = builder_.IsBase(superCtor);
2864     builder_.Branch(isBase, &allocate, &exit);
2865     builder_.Bind(&allocate);
2866     {
2867         GateRef protoOrHclass = builder_.Load(VariableType::JS_ANY(), newTarget,
2868                                               builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
2869         GateRef check = builder_.IsJSHClass(protoOrHclass);
2870         GateRef frameState = GetFrameState(gate);
2871         builder_.DeoptCheck(check, frameState);
2872 
2873         NewObjectStubBuilder stubBuilder(&env);
2874         stubBuilder.SetGule(glue);
2875         stubBuilder.NewJSObject(&thisObj, &exit, protoOrHclass);
2876     }
2877     builder_.Bind(&exit);
2878     builder_.SetDepend(*thisObj);
2879     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *thisObj);
2880 }
2881 
LowerGetSuperConstructor(GateRef gate)2882 void TypeLowering::LowerGetSuperConstructor(GateRef gate)
2883 {
2884     Environment env(gate, circuit_, &builder_);
2885     GateRef ctor = acc_.GetValueIn(gate, 0);
2886     GateRef hclass = builder_.LoadHClass(ctor);
2887     GateRef protoOffset = builder_.IntPtr(JSHClass::PROTOTYPE_OFFSET);
2888     GateRef superCtor = builder_.Load(VariableType::JS_ANY(), hclass, protoOffset);
2889     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), superCtor);
2890 }
2891 }  // namespace panda::ecmascript
2892