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, ¬Overflow);
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(¬Overflow);
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, ¬Overflow);
1485 builder_.Bind(¬Overflow);
1486 {
1487 builder_.Branch(builder_.Int64LessThan(res, min), &overflow, ¬OverflowOrUnderflow);
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(¬OverflowOrUnderflow);
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, ¬Overflow);
1613 builder_.Bind(&overflow);
1614 {
1615 result = builder_.DoubleToTaggedDoublePtr(builder_.ChangeUInt32ToFloat64(res));
1616 builder_.Jump(&exit);
1617 }
1618 builder_.Bind(¬Overflow);
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, ¬Overflow);
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(¬Overflow);
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, ¬Underflow);
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(¬Underflow);
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