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/share_gate_meta_data.h" 17#include "ecmascript/compiler/number_gate_info.h" 18#include "ecmascript/compiler/type.h" 19#include "ecmascript/compiler/typed_hcr_lowering.h" 20#include "ecmascript/compiler/builtins_lowering.h" 21#include "ecmascript/compiler/new_object_stub_builder.h" 22#include "ecmascript/compiler/number_speculative_lowering.h" 23#include "ecmascript/deoptimizer/deoptimizer.h" 24#include "ecmascript/js_arraybuffer.h" 25#include "ecmascript/js_locale.h" 26#include "ecmascript/js_native_pointer.h" 27#include "ecmascript/js_object.h" 28 29namespace panda::ecmascript::kungfu { 30 31void NumberSpeculativeLowering::Run() 32{ 33 std::vector<GateRef> gateList; 34 acc_.GetAllGates(gateList); 35 for (auto gate : gateList) { 36 auto op = acc_.GetOpCode(gate); 37 switch (op) { 38 case OpCode::RANGE_GUARD: { 39 rangeGuardGates_.push_back(gate); 40 break; 41 } 42 default: { 43 VisitGate(gate); 44 } 45 } 46 } 47 for (auto rangeGuard : rangeGuardGates_) { 48 VisitRangeGuard(rangeGuard); 49 } 50} 51 52void NumberSpeculativeLowering::VisitGate(GateRef gate) 53{ 54 OpCode op = acc_.GetOpCode(gate); 55 switch (op) { 56 case OpCode::TYPED_BINARY_OP: { 57 VisitTypedBinaryOp(gate); 58 break; 59 } 60 case OpCode::TYPED_UNARY_OP: { 61 VisitTypedUnaryOp(gate); 62 break; 63 } 64 case OpCode::TYPED_CONDITION_JUMP: { 65 VisitTypedConditionJump(gate); 66 break; 67 } 68 case OpCode::VALUE_SELECTOR: { 69 VisitPhi(gate); 70 break; 71 } 72 case OpCode::CONSTANT: { 73 VisitConstant(gate); 74 break; 75 } 76 case OpCode::LOAD_ELEMENT: { 77 VisitLoadElement(gate); 78 break; 79 } 80 case OpCode::INDEX_CHECK: { 81 VisitIndexCheck(gate); 82 break; 83 } 84 case OpCode::RANGE_CHECK_PREDICATE: { 85 VisitRangeCheckPredicate(gate); 86 break; 87 } 88 case OpCode::LOAD_ARRAY_LENGTH: 89 case OpCode::LOAD_TYPED_ARRAY_LENGTH: { 90 VisitLoadArrayLength(gate); 91 break; 92 } 93 case OpCode::LOAD_STRING_LENGTH: { 94 VisitLoadStringLength(gate); 95 break; 96 } 97 case OpCode::LOAD_MAP_SIZE: { 98 VisitLoadMapSize(gate); 99 break; 100 } 101 case OpCode::LOAD_PROPERTY: { 102 VisitLoadProperty(gate); 103 break; 104 } 105 case OpCode::MONO_LOAD_PROPERTY_ON_PROTO: { 106 VisitLoadPropertyOnProto(gate); 107 break; 108 } 109 case OpCode::MATH_ROUND: { 110 VisitRound(gate); 111 break; 112 } 113 default: 114 break; 115 } 116} 117 118void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate) 119{ 120 Environment env(gate, circuit_, &builder_); 121 if (acc_.HasStringType(gate)) { 122 VisitStringBinaryOp(gate); 123 return; 124 } 125 auto op = acc_.GetTypedBinaryOp(gate); 126 switch (op) { 127 case TypedBinOp::TYPED_STRICTEQ: 128 case TypedBinOp::TYPED_STRICTNOTEQ: { 129 VisitStrictEqualOrStrictNotEqual(gate); 130 break; 131 } 132 case TypedBinOp::TYPED_EQ: 133 case TypedBinOp::TYPED_NOTEQ: { 134 VisitEqualOrNotEqual(gate); 135 break; 136 } 137 default: { 138 if (acc_.HasNumberType(gate)) { 139 VisitNumberBinaryOp(gate); 140 } 141 break; 142 } 143 } 144} 145 146void NumberSpeculativeLowering::VisitEqualOrNotEqual(GateRef gate) 147{ 148 if (acc_.HasNumberType(gate)) { 149 VisitNumberBinaryOp(gate); 150 } else { 151 VisitUndefinedEqOrUndefinedNotEq(gate); 152 } 153} 154 155void NumberSpeculativeLowering::VisitStrictEqualOrStrictNotEqual(GateRef gate) 156{ 157 if (acc_.HasNumberType(gate)) { 158 VisitNumberBinaryOp(gate); 159 } else { 160 VisitUndefinedStrictEqOrUndefinedStrictNotEq(gate); 161 } 162} 163 164void NumberSpeculativeLowering::VisitNumberBinaryOp(GateRef gate) 165{ 166 TypedBinOp Op = acc_.GetTypedBinaryOp(gate); 167 switch (Op) { 168 case TypedBinOp::TYPED_ADD: { 169 VisitNumberCalculate<TypedBinOp::TYPED_ADD>(gate); 170 break; 171 } 172 case TypedBinOp::TYPED_SUB: { 173 VisitNumberCalculate<TypedBinOp::TYPED_SUB>(gate); 174 break; 175 } 176 case TypedBinOp::TYPED_MUL: { 177 VisitNumberCalculate<TypedBinOp::TYPED_MUL>(gate); 178 break; 179 } 180 case TypedBinOp::TYPED_LESS: { 181 VisitNumberCompare<TypedBinOp::TYPED_LESS>(gate); 182 break; 183 } 184 case TypedBinOp::TYPED_LESSEQ: { 185 VisitNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate); 186 break; 187 } 188 case TypedBinOp::TYPED_GREATER: { 189 VisitNumberCompare<TypedBinOp::TYPED_GREATER>(gate); 190 break; 191 } 192 case TypedBinOp::TYPED_GREATEREQ: { 193 VisitNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate); 194 break; 195 } 196 case TypedBinOp::TYPED_EQ: { 197 VisitNumberCompare<TypedBinOp::TYPED_EQ>(gate); 198 break; 199 } 200 case TypedBinOp::TYPED_NOTEQ: { 201 VisitNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate); 202 break; 203 } 204 case TypedBinOp::TYPED_STRICTEQ: { 205 VisitNumberCompare<TypedBinOp::TYPED_STRICTEQ>(gate); 206 break; 207 } 208 case TypedBinOp::TYPED_STRICTNOTEQ: { 209 VisitNumberCompare<TypedBinOp::TYPED_STRICTNOTEQ>(gate); 210 break; 211 } 212 case TypedBinOp::TYPED_SHL: { 213 VisitNumberShift<TypedBinOp::TYPED_SHL>(gate); 214 break; 215 } 216 case TypedBinOp::TYPED_SHR: { 217 VisitNumberShift<TypedBinOp::TYPED_SHR>(gate); 218 break; 219 } 220 case TypedBinOp::TYPED_ASHR: { 221 VisitNumberShift<TypedBinOp::TYPED_ASHR>(gate); 222 break; 223 } 224 case TypedBinOp::TYPED_AND: { 225 VisitNumberLogical<TypedBinOp::TYPED_AND>(gate); 226 break; 227 } 228 case TypedBinOp::TYPED_OR: { 229 VisitNumberLogical<TypedBinOp::TYPED_OR>(gate); 230 break; 231 } 232 case TypedBinOp::TYPED_XOR: { 233 VisitNumberLogical<TypedBinOp::TYPED_XOR>(gate); 234 break; 235 } 236 case TypedBinOp::TYPED_DIV: { 237 VisitNumberDiv(gate); 238 break; 239 } 240 case TypedBinOp::TYPED_MOD: { 241 VisitNumberMod<TypedBinOp::TYPED_MOD>(gate); 242 break; 243 } 244 default: 245 break; 246 } 247} 248 249void NumberSpeculativeLowering::VisitTypedUnaryOp(GateRef gate) 250{ 251 Environment env(gate, circuit_, &builder_); 252 TypedUnOp Op = acc_.GetTypedUnAccessor(gate).GetTypedUnOp(); 253 switch (Op) { 254 case TypedUnOp::TYPED_INC: { 255 VisitNumberMonocular<TypedUnOp::TYPED_INC>(gate); 256 return; 257 } 258 case TypedUnOp::TYPED_DEC: { 259 VisitNumberMonocular<TypedUnOp::TYPED_DEC>(gate); 260 return; 261 } 262 case TypedUnOp::TYPED_NEG: { 263 VisitNumberMonocular<TypedUnOp::TYPED_NEG>(gate); 264 return; 265 } 266 case TypedUnOp::TYPED_ISFALSE: { 267 VisitIsTrueOrFalse(gate, false); 268 return; 269 } 270 case TypedUnOp::TYPED_ISTRUE: { 271 VisitIsTrueOrFalse(gate, true); 272 return; 273 } 274 case TypedUnOp::TYPED_NOT: { 275 VisitNumberNot(gate); 276 return; 277 } 278 default: 279 break; 280 } 281} 282 283void NumberSpeculativeLowering::VisitTypedConditionJump(GateRef gate) 284{ 285 Environment env(gate, circuit_, &builder_); 286 ParamType type = acc_.GetTypedJumpAccessor(gate).GetParamType(); 287 if (type.IsBooleanType()) { 288 VisitBooleanJump(gate); 289 } else { 290 UNREACHABLE(); 291 } 292} 293 294template<TypedBinOp Op> 295void NumberSpeculativeLowering::VisitNumberCalculate(GateRef gate) 296{ 297 GateRef left = acc_.GetValueIn(gate, 0); 298 GateRef right = acc_.GetValueIn(gate, 1); 299 TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); 300 const ParamType paramType = accessor.GetParamType(); 301 ASSERT(paramType.HasNumberType()); 302 GateRef result = Circuit::NullGate(); 303 if (paramType.IsIntType()) { 304 result = CalculateInts<Op>(left, right); // int op int 305 UpdateRange(result, GetRange(gate)); 306 acc_.SetMachineType(gate, MachineType::I32); 307 } else { 308 result = CalculateDoubles<Op>(left, right); // float op float 309 acc_.SetMachineType(gate, MachineType::F64); 310 } 311 acc_.SetGateType(gate, GateType::NJSValue()); 312 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 313} 314 315template<TypedBinOp Op> 316void NumberSpeculativeLowering::VisitNumberCompare(GateRef gate) 317{ 318 GateRef left = acc_.GetValueIn(gate, 0); 319 GateRef right = acc_.GetValueIn(gate, 1); 320 TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); 321 const ParamType paramType = accessor.GetParamType(); 322 ASSERT(paramType.HasNumberType()); 323 GateRef result = Circuit::NullGate(); 324 if (paramType.IsIntType()) { 325 result = CompareInts<Op>(left, right); // int op int 326 } else { 327 result = CompareDoubles<Op>(left, right); // float op float 328 } 329 acc_.SetMachineType(gate, MachineType::I1); 330 acc_.SetGateType(gate, GateType::NJSValue()); 331 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 332} 333 334template<TypedBinOp Op> 335void NumberSpeculativeLowering::VisitNumberShift(GateRef gate) 336{ 337 GateRef left = acc_.GetValueIn(gate, 0); 338 GateRef right = acc_.GetValueIn(gate, 1); 339 GateRef result = ShiftInts<Op>(left, right); // int op int 340 UpdateRange(result, GetRange(gate)); 341 acc_.SetMachineType(gate, MachineType::I32); 342 acc_.SetGateType(gate, GateType::NJSValue()); 343 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 344} 345 346template<TypedBinOp Op> 347void NumberSpeculativeLowering::VisitNumberLogical(GateRef gate) 348{ 349 GateRef left = acc_.GetValueIn(gate, 0); 350 GateRef right = acc_.GetValueIn(gate, 1); 351 GateRef result = LogicalInts<Op>(left, right); // int op int 352 UpdateRange(result, GetRange(gate)); 353 acc_.SetMachineType(gate, MachineType::I32); 354 acc_.SetGateType(gate, GateType::NJSValue()); 355 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 356} 357 358void NumberSpeculativeLowering::VisitNumberDiv(GateRef gate) 359{ 360 GateRef left = acc_.GetValueIn(gate, 0); 361 GateRef right = acc_.GetValueIn(gate, 1); 362 TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); 363 const ParamType paramType = accessor.GetParamType(); 364 ASSERT(paramType.HasNumberType()); 365 GateRef result = Circuit::NullGate(); 366 if (paramType.IsIntType()) { 367 result = builder_.Int32DivWithCheck(left, right); 368 acc_.SetMachineType(gate, MachineType::I32); 369 } else { 370 result = builder_.BinaryArithmetic(circuit_->Fdiv(), 371 MachineType::F64, left, right, GateType::NJSValue()); 372 acc_.SetMachineType(gate, MachineType::F64); 373 } 374 acc_.SetGateType(gate, GateType::NJSValue()); 375 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 376} 377 378template<TypedBinOp Op> 379void NumberSpeculativeLowering::VisitNumberMod(GateRef gate) 380{ 381 GateRef left = acc_.GetValueIn(gate, 0); 382 GateRef right = acc_.GetValueIn(gate, 1); 383 TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); 384 const ParamType paramType = accessor.GetParamType(); 385 ASSERT(paramType.HasNumberType()); 386 GateRef result = Circuit::NullGate(); 387 if (paramType.IsIntType()) { 388 if (GetRange(right).MaybeZero()) { 389 builder_.Int32CheckRightIsZero(right); 390 } 391 bool isNegativeZero = (GetRange(left) % GetRange(right)).MaybeZero() && GetRange(left).MaybeNegative(); 392 if (isNegativeZero) { 393 builder_.RemainderIsNegativeZero(left, right); 394 } 395 result = CalculateInts<Op>(left, right); 396 UpdateRange(result, GetRange(gate)); 397 acc_.SetMachineType(gate, MachineType::I32); 398 } else { 399 GateRef glue = acc_.GetGlueFromArgList(); 400 result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatMod), 401 Gate::InvalidGateRef, {left, right}, Circuit::NullGate()); 402 acc_.SetMachineType(gate, MachineType::F64); 403 } 404 acc_.SetGateType(gate, GateType::NJSValue()); 405 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 406} 407 408template<TypedUnOp Op> 409void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate) 410{ 411 TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); 412 ParamType type = accessor.GetParamType(); 413 ASSERT(type.HasNumberType()); 414 GateRef value = acc_.GetValueIn(gate, 0); 415 GateRef result = Circuit::NullGate(); 416 if (type.IsIntType()) { 417 if (Op == TypedUnOp::TYPED_NEG) { 418 builder_.ValueCheckNegOverflow(value); 419 } 420 result = MonocularInt<Op>(value); 421 UpdateRange(result, GetRange(gate)); 422 acc_.SetMachineType(gate, MachineType::I32); 423 } else { 424 result = MonocularDouble<Op>(value); 425 acc_.SetMachineType(gate, MachineType::F64); 426 } 427 acc_.SetGateType(gate, GateType::NJSValue()); 428 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 429} 430 431void NumberSpeculativeLowering::VisitNumberNot(GateRef gate) 432{ 433 ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetParamType().HasNumberType()); 434 GateRef value = acc_.GetValueIn(gate, 0); 435 GateRef result = builder_.Int32Not(value); 436 UpdateRange(result, GetRange(gate)); 437 acc_.SetMachineType(gate, MachineType::I32); 438 acc_.SetGateType(gate, GateType::NJSValue()); 439 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 440} 441 442void NumberSpeculativeLowering::VisitIsTrueOrFalse(GateRef gate, bool flag) 443{ 444 GateRef value = acc_.GetValueIn(gate, 0); 445 GateRef result = Circuit::NullGate(); 446 if (!flag) { 447 result = builder_.BoolNot(value); 448 } else { 449 result = value; 450 } 451 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 452} 453 454void NumberSpeculativeLowering::VisitBooleanJump(GateRef gate) 455{ 456 TypedJumpAccessor jumpAcc = acc_.GetTypedJumpAccessor(gate); 457 TypedJumpOp jumpOp = jumpAcc.GetTypedJumpOp(); 458 ASSERT((jumpOp == TypedJumpOp::TYPED_JEQZ) || (jumpOp == TypedJumpOp::TYPED_JNEZ)); 459 GateRef condition = acc_.GetValueIn(gate, 0); 460 uint32_t trueWeight = jumpAcc.GetTrueWeight(); 461 uint32_t falseWeight = jumpAcc.GetFalseWeight(); 462 if (jumpOp == TypedJumpOp::TYPED_JEQZ) { 463 std::swap(trueWeight, falseWeight); 464 condition = builder_.BoolNot(condition); 465 } 466 GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition, trueWeight, falseWeight, "booleanJump"); 467 acc_.ReplaceGate(gate, ifBranch, acc_.GetDep(gate), Circuit::NullGate()); 468} 469 470void NumberSpeculativeLowering::VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate) 471{ 472 ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ || 473 acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ); 474 GateRef left = acc_.GetValueIn(gate, 0); 475 GateRef right = acc_.GetValueIn(gate, 1); 476 ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right)); 477 GateRef result = Circuit::NullGate(); 478 if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) { 479 result = builder_.Equal(left, right); 480 } else { 481 result = builder_.NotEqual(left, right); 482 } 483 ASSERT(result != Circuit::NullGate()); 484 acc_.SetMachineType(gate, MachineType::I1); 485 acc_.SetGateType(gate, GateType::NJSValue()); 486 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 487} 488 489void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate) 490{ 491 ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ || 492 acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ); 493 GateRef left = acc_.GetValueIn(gate, 0); 494 GateRef right = acc_.GetValueIn(gate, 1); 495 ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right)); 496 GateRef valueGate = acc_.IsUndefinedOrNullOrHole(left) ? right : left; 497 GateRef result = Circuit::NullGate(); 498 if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) { 499 result = builder_.TaggedIsUndefinedOrNullOrHole(valueGate); 500 } else { 501 result = builder_.TaggedIsNotUndefinedAndNullAndHole(valueGate); 502 } 503 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 504} 505 506void NumberSpeculativeLowering::VisitConstant(GateRef gate) 507{ 508 TypeInfo output = GetOutputType(gate); 509 switch (output) { 510 case TypeInfo::INT32: { 511 int value = acc_.GetInt32FromConstant(gate); 512 GateRef constGate = GetConstInt32(value); 513 acc_.UpdateAllUses(gate, constGate); 514 break; 515 } 516 case TypeInfo::FLOAT64: { 517 double value = acc_.GetFloat64FromConstant(gate); 518 acc_.UpdateAllUses(gate, builder_.Double(value)); 519 break; 520 } 521 default: 522 break; 523 } 524} 525 526void NumberSpeculativeLowering::VisitPhi(GateRef gate) 527{ 528 TypeInfo output = GetOutputType(gate); 529 switch (output) { 530 case TypeInfo::INT1: { 531 acc_.SetGateType(gate, GateType::NJSValue()); 532 acc_.SetMachineType(gate, MachineType::I1); 533 break; 534 } 535 case TypeInfo::INT32: 536 case TypeInfo::UINT32: { 537 acc_.SetGateType(gate, GateType::NJSValue()); 538 acc_.SetMachineType(gate, MachineType::I32); 539 break; 540 } 541 case TypeInfo::FLOAT64: { 542 acc_.SetGateType(gate, GateType::NJSValue()); 543 acc_.SetMachineType(gate, MachineType::F64); 544 break; 545 } 546 case TypeInfo::CHAR: { 547 acc_.SetGateType(gate, GateType::NJSValue()); 548 acc_.SetMachineType(gate, MachineType::I32); 549 break; 550 } 551 default: 552 break; 553 } 554} 555 556void NumberSpeculativeLowering::VisitRangeCheckPredicate(GateRef gate) 557{ 558 acc_.SetGateType(gate, GateType::NJSValue()); 559 acc_.SetMachineType(gate, MachineType::I32); 560} 561 562void NumberSpeculativeLowering::VisitIndexCheck(GateRef gate) 563{ 564 acc_.SetGateType(gate, GateType::NJSValue()); 565 acc_.SetMachineType(gate, MachineType::I32); 566} 567 568void NumberSpeculativeLowering::VisitLoadArrayLength(GateRef gate) 569{ 570 acc_.SetGateType(gate, GateType::NJSValue()); 571 acc_.SetMachineType(gate, MachineType::I32); 572} 573 574void NumberSpeculativeLowering::VisitLoadStringLength(GateRef gate) 575{ 576 acc_.SetGateType(gate, GateType::NJSValue()); 577 acc_.SetMachineType(gate, MachineType::I32); 578} 579 580void NumberSpeculativeLowering::VisitLoadMapSize(GateRef gate) 581{ 582 acc_.SetGateType(gate, GateType::NJSValue()); 583 acc_.SetMachineType(gate, MachineType::I32); 584} 585 586void NumberSpeculativeLowering::VisitLoadElement(GateRef gate) 587{ 588 auto op = acc_.GetTypedLoadOp(gate); 589 switch (op) { 590 case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT: 591 case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT: 592 case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT: 593 case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT: 594 case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT: 595 case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT: 596 case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT: 597 acc_.SetMachineType(gate, MachineType::I32); 598 acc_.SetGateType(gate, GateType::NJSValue()); 599 break; 600 case TypedLoadOp::ARRAY_LOAD_HOLE_INT_ELEMENT: 601 case TypedLoadOp::ARRAY_LOAD_HOLE_DOUBLE_ELEMENT: 602 acc_.SetMachineType(gate, MachineType::I64); 603 acc_.SetGateType(gate, GateType::NJSValue()); 604 break; 605 case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT: 606 case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT: 607 acc_.SetMachineType(gate, MachineType::F64); 608 acc_.SetGateType(gate, GateType::NJSValue()); 609 break; 610 default: 611 break; 612 } 613} 614 615void NumberSpeculativeLowering::VisitLoadProperty(GateRef gate) 616{ 617 TypeInfo output = GetOutputType(gate); 618 if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) { 619 Environment env(gate, circuit_, &builder_); 620 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr 621 GateRef receiver = acc_.GetValueIn(gate, 0); 622 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); 623 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult)); 624 ASSERT(plr.IsLocal() || plr.IsFunction()); 625 626 // Hole check? 627 GateRef result = Circuit::NullGate(); 628 if (output == TypeInfo::FLOAT64) { 629 if (plr.IsInlinedProps()) { 630 result = builder_.LoadConstOffset(VariableType::FLOAT64(), receiver, plr.GetOffset()); 631 } else { 632 auto properties = 633 builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET); 634 result = builder_.GetValueFromTaggedArray( 635 VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset())); 636 } 637 acc_.SetMachineType(gate, MachineType::F64); 638 } else { 639 if (plr.IsInlinedProps()) { 640 result = builder_.LoadConstOffset(VariableType::INT32(), receiver, plr.GetOffset()); 641 } else { 642 auto properties = 643 builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET); 644 result = builder_.GetValueFromTaggedArray( 645 VariableType::INT32(), properties, builder_.Int32(plr.GetOffset())); 646 } 647 acc_.SetMachineType(gate, MachineType::I32); 648 } 649 acc_.SetGateType(gate, GateType::NJSValue()); 650 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 651 } 652} 653 654void NumberSpeculativeLowering::VisitRangeGuard(GateRef gate) 655{ 656 Environment env(gate, circuit_, &builder_); 657 GateRef inputLength = acc_.GetValueIn(gate, 0); 658 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), inputLength); 659} 660 661template<TypedBinOp Op> 662GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right) 663{ 664 GateRef res = Circuit::NullGate(); 665 RangeInfo leftRange = GetRange(left); 666 RangeInfo rightRange = GetRange(right); 667 switch (Op) { 668 case TypedBinOp::TYPED_ADD: { 669 if (!leftRange.MaybeAddOverflowOrUnderflow(rightRange)) { 670 return builder_.Int32Add(left, right, GateType::NJSValue()); 671 } 672 res = builder_.AddWithOverflow(left, right); 673 break; 674 } 675 case TypedBinOp::TYPED_SUB: { 676 if (!leftRange.MaybeSubOverflowOrUnderflow(rightRange)) { 677 return builder_.Int32Sub(left, right, GateType::NJSValue()); 678 } 679 res = builder_.SubWithOverflow(left, right); 680 break; 681 } 682 case TypedBinOp::TYPED_MUL: 683 if (!leftRange.MaybeMulOverflowOrUnderflow(rightRange)) { 684 return builder_.Int32Mul(left, right); 685 } 686 res = builder_.MulWithOverflow(left, right); 687 break; 688 case TypedBinOp::TYPED_MOD: { 689 return builder_.BinaryArithmetic(circuit_->Smod(), 690 MachineType::I32, left, right, GateType::NJSValue()); 691 break; 692 } 693 default: 694 break; 695 } 696 // DeoptCheckForOverFlow 697 builder_.OverflowCheck(res); 698 return builder_.ExtractValue(MachineType::I32, res, GetConstInt32(0)); 699} 700 701template<TypedBinOp Op> 702GateRef NumberSpeculativeLowering::CalculateDoubles(GateRef left, GateRef right) 703{ 704 GateRef res = Circuit::NullGate(); 705 switch (Op) { 706 case TypedBinOp::TYPED_ADD: 707 res = builder_.DoubleAdd(left, right, GateType::NJSValue()); 708 break; 709 case TypedBinOp::TYPED_SUB: 710 res = builder_.DoubleSub(left, right, GateType::NJSValue()); 711 break; 712 case TypedBinOp::TYPED_MUL: 713 res = builder_.DoubleMul(left, right, GateType::NJSValue()); 714 break; 715 default: 716 break; 717 } 718 return res; 719} 720 721template<TypedBinOp Op> 722GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right) 723{ 724 GateRef condition = Circuit::NullGate(); 725 switch (Op) { 726 case TypedBinOp::TYPED_LESS: 727 condition = builder_.Int32LessThan(left, right); 728 break; 729 case TypedBinOp::TYPED_LESSEQ: 730 condition = builder_.Int32LessThanOrEqual(left, right); 731 break; 732 case TypedBinOp::TYPED_GREATER: 733 condition = builder_.Int32GreaterThan(left, right); 734 break; 735 case TypedBinOp::TYPED_GREATEREQ: 736 condition = builder_.Int32GreaterThanOrEqual(left, right); 737 break; 738 case TypedBinOp::TYPED_EQ: 739 case TypedBinOp::TYPED_STRICTEQ: 740 condition = builder_.Int32Equal(left, right); 741 break; 742 case TypedBinOp::TYPED_NOTEQ: 743 case TypedBinOp::TYPED_STRICTNOTEQ: 744 condition = builder_.Int32NotEqual(left, right); 745 break; 746 default: 747 break; 748 } 749 return condition; 750} 751 752template<TypedBinOp Op> 753GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right) 754{ 755 GateRef condition = Circuit::NullGate(); 756 switch (Op) { 757 case TypedBinOp::TYPED_LESS: 758 condition = builder_.DoubleLessThan(left, right); 759 break; 760 case TypedBinOp::TYPED_LESSEQ: 761 condition = builder_.DoubleLessThanOrEqual(left, right); 762 break; 763 case TypedBinOp::TYPED_GREATER: 764 condition = builder_.DoubleGreaterThan(left, right); 765 break; 766 case TypedBinOp::TYPED_GREATEREQ: 767 condition = builder_.DoubleGreaterThanOrEqual(left, right); 768 break; 769 case TypedBinOp::TYPED_EQ: 770 case TypedBinOp::TYPED_STRICTEQ: { 771 condition = LogicAndBuilder(builder_.GetCurrentEnvironment()) 772 .And(builder_.BoolNot(builder_.DoubleIsNAN(left))) 773 .And(builder_.BoolNot(builder_.DoubleIsNAN(right))) 774 .And(builder_.DoubleEqual(left, right)) 775 .Done(); 776 break; 777 } 778 case TypedBinOp::TYPED_NOTEQ: 779 case TypedBinOp::TYPED_STRICTNOTEQ: { 780 condition = LogicOrBuilder(builder_.GetCurrentEnvironment()) 781 .Or(builder_.DoubleIsNAN(left)) 782 .Or(builder_.DoubleIsNAN(right)) 783 .Or(builder_.DoubleNotEqual(left, right)) 784 .Done(); 785 break; 786 } 787 default: 788 break; 789 } 790 return condition; 791} 792 793template<TypedBinOp Op> 794GateRef NumberSpeculativeLowering::ShiftInts(GateRef left, GateRef right) 795{ 796 GateRef value = Circuit::NullGate(); 797 GateRef bitmask = GetConstInt32(0x1f); // 0x1f: bit mask of shift value 798 GateRef shift = builder_.Int32And(right, bitmask, GateType::NJSValue()); 799 switch (Op) { 800 case TypedBinOp::TYPED_SHL: { 801 value = builder_.Int32LSL(left, shift, GateType::NJSValue()); 802 break; 803 } 804 case TypedBinOp::TYPED_SHR: { 805 value = builder_.Int32LSR(left, shift, GateType::NJSValue()); 806 RangeInfo leftRange = GetRange(left); 807 RangeInfo rightRange = GetRange(right); 808 if (!leftRange.MaybeShrOverflow(rightRange)) { 809 return value; 810 } 811 builder_.Int32UnsignedUpperBoundCheck(value, builder_.Int32(INT32_MAX)); 812 break; 813 } 814 case TypedBinOp::TYPED_ASHR: { 815 value = builder_.Int32ASR(left, shift, GateType::NJSValue()); 816 break; 817 } 818 default: 819 LOG_ECMA(FATAL) << "this branch is unreachable"; 820 UNREACHABLE(); 821 break; 822 } 823 return value; 824} 825 826template<TypedBinOp Op> 827GateRef NumberSpeculativeLowering::LogicalInts(GateRef left, GateRef right) 828{ 829 GateRef value = Circuit::NullGate(); 830 switch (Op) { 831 case TypedBinOp::TYPED_AND: { 832 value = builder_.Int32And(left, right, GateType::NJSValue()); 833 break; 834 } 835 case TypedBinOp::TYPED_OR: { 836 value = builder_.Int32Or(left, right, GateType::NJSValue()); 837 break; 838 } 839 case TypedBinOp::TYPED_XOR: { 840 value = builder_.Int32Xor(left, right, GateType::NJSValue()); 841 break; 842 } 843 default: 844 LOG_ECMA(FATAL) << "this branch is unreachable"; 845 UNREACHABLE(); 846 break; 847 } 848 return value; 849} 850 851template<TypedUnOp Op> 852GateRef NumberSpeculativeLowering::MonocularInt(GateRef value) 853{ 854 GateRef res = Circuit::NullGate(); 855 switch (Op) { 856 case TypedUnOp::TYPED_INC: 857 res = CalculateInts<TypedBinOp::TYPED_ADD>(value, GetConstInt32(1)); 858 break; 859 case TypedUnOp::TYPED_DEC: 860 res = CalculateInts<TypedBinOp::TYPED_SUB>(value, GetConstInt32(1)); 861 break; 862 case TypedUnOp::TYPED_NEG: 863 res = builder_.Int32Sub(GetConstInt32(0), value, GateType::NJSValue()); 864 break; 865 default: 866 break; 867 } 868 return res; 869} 870 871template<TypedUnOp Op> 872GateRef NumberSpeculativeLowering::MonocularDouble(GateRef value) 873{ 874 GateRef res = Circuit::NullGate(); 875 switch (Op) { 876 case TypedUnOp::TYPED_INC: 877 res = CalculateDoubles<TypedBinOp::TYPED_ADD>(value, GetConstDouble(1)); 878 break; 879 case TypedUnOp::TYPED_DEC: 880 res = CalculateDoubles<TypedBinOp::TYPED_SUB>(value, GetConstDouble(1)); 881 break; 882 case TypedUnOp::TYPED_NEG: 883 res = CalculateDoubles<TypedBinOp::TYPED_MUL>(value, GetConstDouble(-1)); 884 break; 885 default: 886 break; 887 } 888 return res; 889} 890 891void NumberSpeculativeLowering::UpdateRange(GateRef gate, const RangeInfo& range) 892{ 893 auto id = acc_.GetId(gate); 894 if (id >= rangeInfos_.size()) { 895 rangeInfos_.resize(id + 1, RangeInfo::ANY()); 896 } 897 rangeInfos_[id] = range; 898} 899 900RangeInfo NumberSpeculativeLowering::GetRange(GateRef gate) const 901{ 902 auto id = acc_.GetId(gate); 903 if (id >= rangeInfos_.size()) { 904 rangeInfos_.resize(id + 1, RangeInfo::ANY()); 905 } 906 ASSERT(!rangeInfos_[id].IsNone()); 907 return rangeInfos_[id]; 908} 909 910GateRef NumberSpeculativeLowering::GetConstInt32(int32_t v) 911{ 912 auto val = builder_.Int32(v); 913 UpdateRange(val, RangeInfo(v, v)); 914 return val; 915} 916 917GateRef NumberSpeculativeLowering::GetConstDouble(double v) 918{ 919 auto val = builder_.Double(v); 920 UpdateRange(val, RangeInfo(v, v)); 921 return val; 922} 923 924void NumberSpeculativeLowering::VisitStringBinaryOp(GateRef gate) 925{ 926 TypedBinOp Op = acc_.GetTypedBinaryOp(gate); 927 switch (Op) { 928 case TypedBinOp::TYPED_EQ: { 929 VisitStringCompare<TypedBinOp::TYPED_EQ>(gate); 930 break; 931 } 932 case TypedBinOp::TYPED_ADD: { 933 VisitStringAdd<TypedBinOp::TYPED_ADD>(gate); 934 break; 935 } 936 default: 937 LOG_COMPILER(FATAL) << "this branch is unreachable"; 938 UNREACHABLE(); 939 } 940} 941 942template<TypedBinOp Op> 943void NumberSpeculativeLowering::VisitStringCompare(GateRef gate) 944{ 945 GateRef left = acc_.GetValueIn(gate, 0); 946 GateRef right = acc_.GetValueIn(gate, 1); 947 948 GateRef result; 949 ASSERT(Op == TypedBinOp::TYPED_EQ); 950 result = builder_.StringEqual(left, right); 951 952 acc_.SetMachineType(gate, MachineType::I1); 953 acc_.SetGateType(gate, GateType::NJSValue()); 954 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 955} 956 957template<TypedBinOp Op> 958void NumberSpeculativeLowering::VisitStringAdd(GateRef gate) 959{ 960 GateRef left = acc_.GetValueIn(gate, 0); 961 GateRef right = acc_.GetValueIn(gate, 1); 962 963 GateRef result; 964 ASSERT(Op == TypedBinOp::TYPED_ADD); 965 result = builder_.StringAdd(left, right); 966 967 acc_.SetMachineType(gate, MachineType::I64); 968 acc_.SetGateType(gate, GateType::NJSValue()); 969 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 970} 971 972void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate) 973{ 974 TypeInfo output = GetOutputType(gate); 975 if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) { 976 Environment env(gate, circuit_, &builder_); 977 GateRef frameState = acc_.GetFrameState(gate); 978 GateRef receiver = acc_.GetValueIn(gate, 0); 979 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult 980 GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex 981 GateRef unsharedConstPool = acc_.GetValueIn(gate, 3); // 3: constpool 982 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult)); 983 GateRef result = Circuit::NullGate(); 984 ASSERT(plr.IsLocal() || plr.IsFunction()); 985 986 auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET); 987 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET); 988 989 auto holderHC = builder_.LoadHClassFromConstpool(unsharedConstPool, acc_.GetConstantValue(hclassIndex)); 990 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype); 991 Label exit(&builder_); 992 Label loopHead(&builder_); 993 Label loadHolder(&builder_); 994 Label lookUpProto(&builder_); 995 builder_.Jump(&loopHead); 996 997 builder_.LoopBegin(&loopHead); 998 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS7); 999 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET); 1000 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto); 1001 1002 builder_.Bind(&lookUpProto); 1003 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET); 1004 builder_.LoopEnd(&loopHead); 1005 1006 builder_.Bind(&loadHolder); 1007 if (output == TypeInfo::FLOAT64) { 1008 if (plr.IsInlinedProps()) { 1009 result = builder_.LoadConstOffset(VariableType::FLOAT64(), *current, plr.GetOffset()); 1010 } else { 1011 auto properties = 1012 builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET); 1013 result = builder_.GetValueFromTaggedArray( 1014 VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset())); 1015 } 1016 acc_.SetMachineType(gate, MachineType::F64); 1017 } else { 1018 if (plr.IsInlinedProps()) { 1019 result = builder_.LoadConstOffset(VariableType::INT32(), *current, plr.GetOffset()); 1020 } else { 1021 auto properties = 1022 builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET); 1023 result = builder_.GetValueFromTaggedArray( 1024 VariableType::INT32(), properties, builder_.Int32(plr.GetOffset())); 1025 } 1026 acc_.SetMachineType(gate, MachineType::I32); 1027 } 1028 builder_.Jump(&exit); 1029 builder_.Bind(&exit); 1030 acc_.SetGateType(gate, GateType::NJSValue()); 1031 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); 1032 } 1033} 1034 1035void NumberSpeculativeLowering::VisitRound(GateRef gate) 1036{ 1037 TypeInfo output = GetOutputType(gate); 1038 GateRef in = acc_.GetValueIn(gate, 0); 1039 if (output == TypeInfo::INT32) { 1040 acc_.ReplaceGate(gate, in); 1041 } 1042} 1043 1044} // namespace panda::ecmascript 1045