1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/compiler/js-typed-lowering.h" 6 7 #include "src/ast/modules.h" 8 #include "src/builtins/builtins-utils.h" 9 #include "src/code-factory.h" 10 #include "src/compilation-dependencies.h" 11 #include "src/compiler/access-builder.h" 12 #include "src/compiler/js-graph.h" 13 #include "src/compiler/linkage.h" 14 #include "src/compiler/node-matchers.h" 15 #include "src/compiler/node-properties.h" 16 #include "src/compiler/operator-properties.h" 17 #include "src/compiler/type-cache.h" 18 #include "src/compiler/types.h" 19 20 namespace v8 { 21 namespace internal { 22 namespace compiler { 23 24 // A helper class to simplify the process of reducing a single binop node with a 25 // JSOperator. This class manages the rewriting of context, control, and effect 26 // dependencies during lowering of a binop and contains numerous helper 27 // functions for matching the types of inputs to an operation. 28 class JSBinopReduction final { 29 public: 30 JSBinopReduction(JSTypedLowering* lowering, Node* node) 31 : lowering_(lowering), node_(node) {} 32 33 bool GetBinaryNumberOperationHint(NumberOperationHint* hint) { 34 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) { 35 DCHECK_NE(0, node_->op()->ControlOutputCount()); 36 DCHECK_EQ(1, node_->op()->EffectOutputCount()); 37 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node_->op())); 38 switch (BinaryOperationHintOf(node_->op())) { 39 case BinaryOperationHint::kSignedSmall: 40 *hint = NumberOperationHint::kSignedSmall; 41 return true; 42 case BinaryOperationHint::kSigned32: 43 *hint = NumberOperationHint::kSigned32; 44 return true; 45 case BinaryOperationHint::kNumberOrOddball: 46 *hint = NumberOperationHint::kNumberOrOddball; 47 return true; 48 case BinaryOperationHint::kAny: 49 case BinaryOperationHint::kNone: 50 case BinaryOperationHint::kString: 51 break; 52 } 53 } 54 return false; 55 } 56 57 bool GetCompareNumberOperationHint(NumberOperationHint* hint) { 58 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) { 59 DCHECK_EQ(1, node_->op()->EffectOutputCount()); 60 switch (CompareOperationHintOf(node_->op())) { 61 case CompareOperationHint::kSignedSmall: 62 *hint = NumberOperationHint::kSignedSmall; 63 return true; 64 case CompareOperationHint::kNumber: 65 *hint = NumberOperationHint::kNumber; 66 return true; 67 case CompareOperationHint::kNumberOrOddball: 68 *hint = NumberOperationHint::kNumberOrOddball; 69 return true; 70 case CompareOperationHint::kAny: 71 case CompareOperationHint::kNone: 72 break; 73 } 74 } 75 return false; 76 } 77 78 // Check if a string addition will definitely result in creating a ConsString, 79 // i.e. if the combined length of the resulting string exceeds the ConsString 80 // minimum length. 81 bool ShouldCreateConsString() { 82 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); 83 if (BothInputsAre(Type::String()) || 84 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && 85 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { 86 HeapObjectBinopMatcher m(node_); 87 if (m.right().HasValue() && m.right().Value()->IsString()) { 88 Handle<String> right_string = Handle<String>::cast(m.right().Value()); 89 if (right_string->length() >= ConsString::kMinLength) return true; 90 } 91 if (m.left().HasValue() && m.left().Value()->IsString()) { 92 Handle<String> left_string = Handle<String>::cast(m.left().Value()); 93 if (left_string->length() >= ConsString::kMinLength) { 94 // The invariant for ConsString requires the left hand side to be 95 // a sequential or external string if the right hand side is the 96 // empty string. Since we don't know anything about the right hand 97 // side here, we must ensure that the left hand side satisfy the 98 // constraints independent of the right hand side. 99 return left_string->IsSeqString() || left_string->IsExternalString(); 100 } 101 } 102 } 103 return false; 104 } 105 106 void ConvertInputsToNumber() { 107 // To convert the inputs to numbers, we have to provide frame states 108 // for lazy bailouts in the ToNumber conversions. 109 // We use a little hack here: we take the frame state before the binary 110 // operation and use it to construct the frame states for the conversion 111 // so that after the deoptimization, the binary operation IC gets 112 // already converted values from full code. This way we are sure that we 113 // will not re-do any of the side effects. 114 115 Node* left_input = nullptr; 116 Node* right_input = nullptr; 117 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive()); 118 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive()); 119 bool handles_exception = NodeProperties::IsExceptionalCall(node_); 120 121 if (!left_is_primitive && !right_is_primitive && handles_exception) { 122 ConvertBothInputsToNumber(&left_input, &right_input); 123 } else { 124 left_input = left_is_primitive 125 ? ConvertPlainPrimitiveToNumber(left()) 126 : ConvertSingleInputToNumber( 127 left(), CreateFrameStateForLeftInput()); 128 right_input = 129 right_is_primitive 130 ? ConvertPlainPrimitiveToNumber(right()) 131 : ConvertSingleInputToNumber( 132 right(), CreateFrameStateForRightInput(left_input)); 133 } 134 135 node_->ReplaceInput(0, left_input); 136 node_->ReplaceInput(1, right_input); 137 } 138 139 void ConvertInputsToUI32(Signedness left_signedness, 140 Signedness right_signedness) { 141 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); 142 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); 143 } 144 145 void SwapInputs() { 146 Node* l = left(); 147 Node* r = right(); 148 node_->ReplaceInput(0, r); 149 node_->ReplaceInput(1, l); 150 } 151 152 // Remove all effect and control inputs and outputs to this node and change 153 // to the pure operator {op}, possibly inserting a boolean inversion. 154 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, 155 Type* type = Type::Any()) { 156 DCHECK_EQ(0, op->EffectInputCount()); 157 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 158 DCHECK_EQ(0, op->ControlInputCount()); 159 DCHECK_EQ(2, op->ValueInputCount()); 160 161 // Remove the effects from the node, and update its effect/control usages. 162 if (node_->op()->EffectInputCount() > 0) { 163 lowering_->RelaxEffectsAndControls(node_); 164 } 165 // Remove the inputs corresponding to context, effect, and control. 166 NodeProperties::RemoveNonValueInputs(node_); 167 // Finally, update the operator to the new one. 168 NodeProperties::ChangeOp(node_, op); 169 170 // TODO(jarin): Replace the explicit typing hack with a call to some method 171 // that encapsulates changing the operator and re-typing. 172 Type* node_type = NodeProperties::GetType(node_); 173 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone())); 174 175 if (invert) { 176 // Insert an boolean not to invert the value. 177 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 178 node_->ReplaceUses(value); 179 // Note: ReplaceUses() smashes all uses, so smash it back here. 180 value->ReplaceInput(0, node_); 181 return lowering_->Replace(value); 182 } 183 return lowering_->Changed(node_); 184 } 185 186 Reduction ChangeToSpeculativeOperator(const Operator* op, bool invert, 187 Type* upper_bound) { 188 DCHECK_EQ(1, op->EffectInputCount()); 189 DCHECK_EQ(1, op->EffectOutputCount()); 190 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 191 DCHECK_EQ(1, op->ControlInputCount()); 192 DCHECK_EQ(0, op->ControlOutputCount()); 193 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op)); 194 DCHECK_EQ(2, op->ValueInputCount()); 195 196 DCHECK_EQ(1, node_->op()->EffectInputCount()); 197 DCHECK_EQ(1, node_->op()->EffectOutputCount()); 198 DCHECK_EQ(1, node_->op()->ControlInputCount()); 199 DCHECK_EQ(2, node_->op()->ValueInputCount()); 200 201 // Reconnect the control output to bypass the IfSuccess node and 202 // possibly disconnect from the IfException node. 203 for (Edge edge : node_->use_edges()) { 204 Node* const user = edge.from(); 205 DCHECK(!user->IsDead()); 206 if (NodeProperties::IsControlEdge(edge)) { 207 if (user->opcode() == IrOpcode::kIfSuccess) { 208 user->ReplaceUses(NodeProperties::GetControlInput(node_)); 209 user->Kill(); 210 } else { 211 DCHECK_EQ(user->opcode(), IrOpcode::kIfException); 212 edge.UpdateTo(jsgraph()->Dead()); 213 } 214 } 215 } 216 217 // Remove the frame state and the context. 218 if (OperatorProperties::HasFrameStateInput(node_->op())) { 219 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_)); 220 } 221 node_->RemoveInput(NodeProperties::FirstContextIndex(node_)); 222 223 NodeProperties::ChangeOp(node_, op); 224 225 // Update the type to number. 226 Type* node_type = NodeProperties::GetType(node_); 227 NodeProperties::SetType(node_, 228 Type::Intersect(node_type, upper_bound, zone())); 229 230 if (invert) { 231 // Insert an boolean not to invert the value. 232 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 233 node_->ReplaceUses(value); 234 // Note: ReplaceUses() smashes all uses, so smash it back here. 235 value->ReplaceInput(0, node_); 236 return lowering_->Replace(value); 237 } 238 return lowering_->Changed(node_); 239 } 240 241 Reduction ChangeToPureOperator(const Operator* op, Type* type) { 242 return ChangeToPureOperator(op, false, type); 243 } 244 245 Reduction ChangeToSpeculativeOperator(const Operator* op, Type* type) { 246 return ChangeToSpeculativeOperator(op, false, type); 247 } 248 249 const Operator* NumberOp() { 250 switch (node_->opcode()) { 251 case IrOpcode::kJSAdd: 252 return simplified()->NumberAdd(); 253 case IrOpcode::kJSSubtract: 254 return simplified()->NumberSubtract(); 255 case IrOpcode::kJSMultiply: 256 return simplified()->NumberMultiply(); 257 case IrOpcode::kJSDivide: 258 return simplified()->NumberDivide(); 259 case IrOpcode::kJSModulus: 260 return simplified()->NumberModulus(); 261 case IrOpcode::kJSBitwiseAnd: 262 return simplified()->NumberBitwiseAnd(); 263 case IrOpcode::kJSBitwiseOr: 264 return simplified()->NumberBitwiseOr(); 265 case IrOpcode::kJSBitwiseXor: 266 return simplified()->NumberBitwiseXor(); 267 case IrOpcode::kJSShiftLeft: 268 return simplified()->NumberShiftLeft(); 269 case IrOpcode::kJSShiftRight: 270 return simplified()->NumberShiftRight(); 271 case IrOpcode::kJSShiftRightLogical: 272 return simplified()->NumberShiftRightLogical(); 273 default: 274 break; 275 } 276 UNREACHABLE(); 277 return nullptr; 278 } 279 280 const Operator* SpeculativeNumberOp(NumberOperationHint hint) { 281 switch (node_->opcode()) { 282 case IrOpcode::kJSAdd: 283 return simplified()->SpeculativeNumberAdd(hint); 284 case IrOpcode::kJSSubtract: 285 return simplified()->SpeculativeNumberSubtract(hint); 286 case IrOpcode::kJSMultiply: 287 return simplified()->SpeculativeNumberMultiply(hint); 288 case IrOpcode::kJSDivide: 289 return simplified()->SpeculativeNumberDivide(hint); 290 case IrOpcode::kJSModulus: 291 return simplified()->SpeculativeNumberModulus(hint); 292 case IrOpcode::kJSBitwiseAnd: 293 return simplified()->SpeculativeNumberBitwiseAnd(hint); 294 case IrOpcode::kJSBitwiseOr: 295 return simplified()->SpeculativeNumberBitwiseOr(hint); 296 case IrOpcode::kJSBitwiseXor: 297 return simplified()->SpeculativeNumberBitwiseXor(hint); 298 case IrOpcode::kJSShiftLeft: 299 return simplified()->SpeculativeNumberShiftLeft(hint); 300 case IrOpcode::kJSShiftRight: 301 return simplified()->SpeculativeNumberShiftRight(hint); 302 case IrOpcode::kJSShiftRightLogical: 303 return simplified()->SpeculativeNumberShiftRightLogical(hint); 304 default: 305 break; 306 } 307 UNREACHABLE(); 308 return nullptr; 309 } 310 311 bool LeftInputIs(Type* t) { return left_type()->Is(t); } 312 313 bool RightInputIs(Type* t) { return right_type()->Is(t); } 314 315 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } 316 317 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); } 318 319 bool OneInputCannotBe(Type* t) { 320 return !left_type()->Maybe(t) || !right_type()->Maybe(t); 321 } 322 323 bool NeitherInputCanBe(Type* t) { 324 return !left_type()->Maybe(t) && !right_type()->Maybe(t); 325 } 326 327 Node* effect() { return NodeProperties::GetEffectInput(node_); } 328 Node* control() { return NodeProperties::GetControlInput(node_); } 329 Node* context() { return NodeProperties::GetContextInput(node_); } 330 Node* left() { return NodeProperties::GetValueInput(node_, 0); } 331 Node* right() { return NodeProperties::GetValueInput(node_, 1); } 332 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); } 333 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); } 334 Type* type() { return NodeProperties::GetType(node_); } 335 336 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } 337 Graph* graph() const { return lowering_->graph(); } 338 JSGraph* jsgraph() { return lowering_->jsgraph(); } 339 JSOperatorBuilder* javascript() { return lowering_->javascript(); } 340 CommonOperatorBuilder* common() { return jsgraph()->common(); } 341 Zone* zone() const { return graph()->zone(); } 342 343 private: 344 JSTypedLowering* lowering_; // The containing lowering instance. 345 Node* node_; // The original node. 346 347 Node* CreateFrameStateForLeftInput() { 348 // Deoptimization is disabled => return dummy frame state instead. 349 Node* dummy_state = NodeProperties::GetFrameStateInput(node_); 350 DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone()); 351 return dummy_state; 352 } 353 354 Node* CreateFrameStateForRightInput(Node* converted_left) { 355 // Deoptimization is disabled => return dummy frame state instead. 356 Node* dummy_state = NodeProperties::GetFrameStateInput(node_); 357 DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone()); 358 return dummy_state; 359 } 360 361 Node* ConvertPlainPrimitiveToNumber(Node* node) { 362 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); 363 // Avoid inserting too many eager ToNumber() operations. 364 Reduction const reduction = lowering_->ReduceJSToNumberInput(node); 365 if (reduction.Changed()) return reduction.replacement(); 366 if (NodeProperties::GetType(node)->Is(Type::Number())) { 367 return node; 368 } 369 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node); 370 } 371 372 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) { 373 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); 374 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(), 375 frame_state, effect(), control()); 376 Node* const if_success = graph()->NewNode(common()->IfSuccess(), n); 377 NodeProperties::ReplaceControlInput(node_, if_success); 378 NodeProperties::ReplaceUses(node_, node_, node_, node_, n); 379 update_effect(n); 380 return n; 381 } 382 383 void ConvertBothInputsToNumber(Node** left_result, Node** right_result) { 384 Node* projections[2]; 385 386 // Find {IfSuccess} and {IfException} continuations of the operation. 387 NodeProperties::CollectControlProjections(node_, projections, 2); 388 Node* if_exception = projections[1]; 389 Node* if_success = projections[0]; 390 391 // Insert two ToNumber() operations that both potentially throw. 392 Node* left_state = CreateFrameStateForLeftInput(); 393 Node* left_conv = 394 graph()->NewNode(javascript()->ToNumber(), left(), context(), 395 left_state, effect(), control()); 396 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv); 397 Node* right_state = CreateFrameStateForRightInput(left_conv); 398 Node* right_conv = 399 graph()->NewNode(javascript()->ToNumber(), right(), context(), 400 right_state, left_conv, left_success); 401 Node* left_exception = 402 graph()->NewNode(common()->IfException(), left_conv, left_conv); 403 Node* right_exception = 404 graph()->NewNode(common()->IfException(), right_conv, right_conv); 405 NodeProperties::ReplaceControlInput(if_success, right_conv); 406 update_effect(right_conv); 407 408 // Wire conversions to existing {IfException} continuation. 409 Node* exception_merge = if_exception; 410 Node* exception_value = 411 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 412 left_exception, right_exception, exception_merge); 413 Node* exception_effect = 414 graph()->NewNode(common()->EffectPhi(2), left_exception, 415 right_exception, exception_merge); 416 for (Edge edge : exception_merge->use_edges()) { 417 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect); 418 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value); 419 } 420 NodeProperties::RemoveType(exception_merge); 421 exception_merge->ReplaceInput(0, left_exception); 422 exception_merge->ReplaceInput(1, right_exception); 423 NodeProperties::ChangeOp(exception_merge, common()->Merge(2)); 424 425 *left_result = left_conv; 426 *right_result = right_conv; 427 } 428 429 Node* ConvertToUI32(Node* node, Signedness signedness) { 430 // Avoid introducing too many eager NumberToXXnt32() operations. 431 Type* type = NodeProperties::GetType(node); 432 if (signedness == kSigned) { 433 if (!type->Is(Type::Signed32())) { 434 node = graph()->NewNode(simplified()->NumberToInt32(), node); 435 } 436 } else { 437 DCHECK_EQ(kUnsigned, signedness); 438 if (!type->Is(Type::Unsigned32())) { 439 node = graph()->NewNode(simplified()->NumberToUint32(), node); 440 } 441 } 442 return node; 443 } 444 445 void update_effect(Node* effect) { 446 NodeProperties::ReplaceEffectInput(node_, effect); 447 } 448 }; 449 450 451 // TODO(turbofan): js-typed-lowering improvements possible 452 // - immediately put in type bounds for all new nodes 453 // - relax effects from generic but not-side-effecting operations 454 455 JSTypedLowering::JSTypedLowering(Editor* editor, 456 CompilationDependencies* dependencies, 457 Flags flags, JSGraph* jsgraph, Zone* zone) 458 : AdvancedReducer(editor), 459 dependencies_(dependencies), 460 flags_(flags), 461 jsgraph_(jsgraph), 462 the_hole_type_( 463 Type::HeapConstant(factory()->the_hole_value(), graph()->zone())), 464 type_cache_(TypeCache::Get()) { 465 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { 466 double min = kMinInt / (1 << k); 467 double max = kMaxInt / (1 << k); 468 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); 469 } 470 } 471 472 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { 473 JSBinopReduction r(this, node); 474 NumberOperationHint hint; 475 if (r.GetBinaryNumberOperationHint(&hint)) { 476 if (hint == NumberOperationHint::kNumberOrOddball && 477 r.BothInputsAre(Type::PlainPrimitive()) && 478 r.NeitherInputCanBe(Type::StringOrReceiver())) { 479 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 480 r.ConvertInputsToNumber(); 481 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 482 } 483 return r.ChangeToSpeculativeOperator( 484 simplified()->SpeculativeNumberAdd(hint), Type::Number()); 485 } 486 if (r.BothInputsAre(Type::Number())) { 487 // JSAdd(x:number, y:number) => NumberAdd(x, y) 488 r.ConvertInputsToNumber(); 489 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 490 } 491 if ((r.BothInputsAre(Type::PlainPrimitive()) || 492 !(flags() & kDeoptimizationEnabled)) && 493 r.NeitherInputCanBe(Type::StringOrReceiver())) { 494 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 495 r.ConvertInputsToNumber(); 496 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 497 } 498 if (r.OneInputIs(Type::String())) { 499 if (r.ShouldCreateConsString()) { 500 return ReduceCreateConsString(node); 501 } 502 StringAddFlags flags = STRING_ADD_CHECK_NONE; 503 if (!r.LeftInputIs(Type::String())) { 504 flags = STRING_ADD_CONVERT_LEFT; 505 } else if (!r.RightInputIs(Type::String())) { 506 flags = STRING_ADD_CONVERT_RIGHT; 507 } 508 // JSAdd(x:string, y) => CallStub[StringAdd](x, y) 509 // JSAdd(x, y:string) => CallStub[StringAdd](x, y) 510 Callable const callable = 511 CodeFactory::StringAdd(isolate(), flags, NOT_TENURED); 512 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 513 isolate(), graph()->zone(), callable.descriptor(), 0, 514 CallDescriptor::kNeedsFrameState, node->op()->properties()); 515 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 516 node->InsertInput(graph()->zone(), 0, 517 jsgraph()->HeapConstant(callable.code())); 518 NodeProperties::ChangeOp(node, common()->Call(desc)); 519 return Changed(node); 520 } 521 return NoChange(); 522 } 523 524 Reduction JSTypedLowering::ReduceNumberBinop(Node* node) { 525 JSBinopReduction r(this, node); 526 NumberOperationHint hint; 527 if (r.GetBinaryNumberOperationHint(&hint)) { 528 if (hint == NumberOperationHint::kNumberOrOddball && 529 r.BothInputsAre(Type::NumberOrOddball())) { 530 r.ConvertInputsToNumber(); 531 return r.ChangeToPureOperator(r.NumberOp(), Type::Number()); 532 } 533 return r.ChangeToSpeculativeOperator(r.SpeculativeNumberOp(hint), 534 Type::Number()); 535 } 536 if (r.BothInputsAre(Type::PlainPrimitive()) || 537 !(flags() & kDeoptimizationEnabled)) { 538 r.ConvertInputsToNumber(); 539 return r.ChangeToPureOperator(r.NumberOp(), Type::Number()); 540 } 541 return NoChange(); 542 } 543 544 Reduction JSTypedLowering::ReduceInt32Binop(Node* node) { 545 JSBinopReduction r(this, node); 546 NumberOperationHint hint; 547 if (r.GetBinaryNumberOperationHint(&hint)) { 548 return r.ChangeToSpeculativeOperator(r.SpeculativeNumberOp(hint), 549 Type::Signed32()); 550 } 551 if (r.BothInputsAre(Type::PlainPrimitive()) || 552 !(flags() & kDeoptimizationEnabled)) { 553 r.ConvertInputsToNumber(); 554 r.ConvertInputsToUI32(kSigned, kSigned); 555 return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32()); 556 } 557 return NoChange(); 558 } 559 560 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) { 561 JSBinopReduction r(this, node); 562 NumberOperationHint hint; 563 if (r.GetBinaryNumberOperationHint(&hint)) { 564 return r.ChangeToSpeculativeOperator( 565 r.SpeculativeNumberOp(hint), 566 signedness == kUnsigned ? Type::Unsigned32() : Type::Signed32()); 567 } 568 if (r.BothInputsAre(Type::PlainPrimitive()) || 569 !(flags() & kDeoptimizationEnabled)) { 570 r.ConvertInputsToNumber(); 571 r.ConvertInputsToUI32(signedness, kUnsigned); 572 return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned 573 ? Type::Unsigned32() 574 : Type::Signed32()); 575 } 576 return NoChange(); 577 } 578 579 Reduction JSTypedLowering::ReduceCreateConsString(Node* node) { 580 Node* first = NodeProperties::GetValueInput(node, 0); 581 Node* second = NodeProperties::GetValueInput(node, 1); 582 Node* context = NodeProperties::GetContextInput(node); 583 Node* frame_state = NodeProperties::GetFrameStateInput(node); 584 Node* effect = NodeProperties::GetEffectInput(node); 585 Node* control = NodeProperties::GetControlInput(node); 586 587 // Make sure {first} is actually a String. 588 Type* first_type = NodeProperties::GetType(first); 589 if (!first_type->Is(Type::String())) { 590 first = effect = 591 graph()->NewNode(simplified()->CheckString(), first, effect, control); 592 first_type = NodeProperties::GetType(first); 593 } 594 595 // Make sure {second} is actually a String. 596 Type* second_type = NodeProperties::GetType(second); 597 if (!second_type->Is(Type::String())) { 598 second = effect = 599 graph()->NewNode(simplified()->CheckString(), second, effect, control); 600 second_type = NodeProperties::GetType(second); 601 } 602 603 // Determine the {first} length. 604 HeapObjectBinopMatcher m(node); 605 Node* first_length = 606 (m.left().HasValue() && m.left().Value()->IsString()) 607 ? jsgraph()->Constant( 608 Handle<String>::cast(m.left().Value())->length()) 609 : effect = graph()->NewNode( 610 simplified()->LoadField(AccessBuilder::ForStringLength()), 611 first, effect, control); 612 613 // Determine the {second} length. 614 Node* second_length = 615 (m.right().HasValue() && m.right().Value()->IsString()) 616 ? jsgraph()->Constant( 617 Handle<String>::cast(m.right().Value())->length()) 618 : effect = graph()->NewNode( 619 simplified()->LoadField(AccessBuilder::ForStringLength()), 620 second, effect, control); 621 622 // Compute the resulting length. 623 Node* length = 624 graph()->NewNode(simplified()->NumberAdd(), first_length, second_length); 625 626 // Check if we would overflow the allowed maximum string length. 627 Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(), length, 628 jsgraph()->Constant(String::kMaxLength)); 629 if (isolate()->IsStringLengthOverflowIntact()) { 630 // Add a code dependency on the string length overflow protector. 631 dependencies()->AssumePropertyCell(factory()->string_length_protector()); 632 633 // We can just deoptimize if the {check} fails. Besides generating a 634 // shorter code sequence than the version below, this has the additional 635 // benefit of not holding on to the lazy {frame_state} and thus potentially 636 // reduces the number of live ranges and allows for more truncations. 637 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); 638 } else { 639 Node* branch = 640 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 641 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 642 Node* efalse = effect; 643 { 644 // Throw a RangeError in case of overflow. 645 Node* vfalse = efalse = graph()->NewNode( 646 javascript()->CallRuntime(Runtime::kThrowInvalidStringLength), 647 context, frame_state, efalse, if_false); 648 if_false = graph()->NewNode(common()->IfSuccess(), vfalse); 649 if_false = graph()->NewNode(common()->Throw(), vfalse, efalse, if_false); 650 // TODO(bmeurer): This should be on the AdvancedReducer somehow. 651 NodeProperties::MergeControlToEnd(graph(), common(), if_false); 652 Revisit(graph()->end()); 653 654 // Update potential {IfException} uses of {node} to point to the 655 // %ThrowInvalidStringLength runtime call node instead. 656 for (Edge edge : node->use_edges()) { 657 if (edge.from()->opcode() == IrOpcode::kIfException) { 658 DCHECK(NodeProperties::IsControlEdge(edge) || 659 NodeProperties::IsEffectEdge(edge)); 660 edge.UpdateTo(vfalse); 661 Revisit(edge.from()); 662 } 663 } 664 } 665 control = graph()->NewNode(common()->IfTrue(), branch); 666 } 667 668 // Figure out the map for the resulting ConsString. 669 // TODO(turbofan): We currently just use the cons_string_map here for 670 // the sake of simplicity; we could also try to be smarter here and 671 // use the one_byte_cons_string_map instead when the resulting ConsString 672 // contains only one byte characters. 673 Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map()); 674 675 // Allocate the resulting ConsString. 676 effect = graph()->NewNode( 677 common()->BeginRegion(RegionObservability::kNotObservable), effect); 678 Node* value = effect = 679 graph()->NewNode(simplified()->Allocate(NOT_TENURED), 680 jsgraph()->Constant(ConsString::kSize), effect, control); 681 NodeProperties::SetType(value, Type::OtherString()); 682 effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), 683 value, value_map, effect, control); 684 effect = graph()->NewNode( 685 simplified()->StoreField(AccessBuilder::ForNameHashField()), value, 686 jsgraph()->Constant(Name::kEmptyHashField), effect, control); 687 effect = graph()->NewNode( 688 simplified()->StoreField(AccessBuilder::ForStringLength()), value, length, 689 effect, control); 690 effect = graph()->NewNode( 691 simplified()->StoreField(AccessBuilder::ForConsStringFirst()), value, 692 first, effect, control); 693 effect = graph()->NewNode( 694 simplified()->StoreField(AccessBuilder::ForConsStringSecond()), value, 695 second, effect, control); 696 697 // Morph the {node} into a {FinishRegion}. 698 ReplaceWithValue(node, node, node, control); 699 node->ReplaceInput(0, value); 700 node->ReplaceInput(1, effect); 701 node->TrimInputCount(2); 702 NodeProperties::ChangeOp(node, common()->FinishRegion()); 703 return Changed(node); 704 } 705 706 Reduction JSTypedLowering::ReduceJSComparison(Node* node) { 707 JSBinopReduction r(this, node); 708 if (r.BothInputsAre(Type::String())) { 709 // If both inputs are definitely strings, perform a string comparison. 710 const Operator* stringOp; 711 switch (node->opcode()) { 712 case IrOpcode::kJSLessThan: 713 stringOp = simplified()->StringLessThan(); 714 break; 715 case IrOpcode::kJSGreaterThan: 716 stringOp = simplified()->StringLessThan(); 717 r.SwapInputs(); // a > b => b < a 718 break; 719 case IrOpcode::kJSLessThanOrEqual: 720 stringOp = simplified()->StringLessThanOrEqual(); 721 break; 722 case IrOpcode::kJSGreaterThanOrEqual: 723 stringOp = simplified()->StringLessThanOrEqual(); 724 r.SwapInputs(); // a >= b => b <= a 725 break; 726 default: 727 return NoChange(); 728 } 729 r.ChangeToPureOperator(stringOp); 730 return Changed(node); 731 } 732 733 NumberOperationHint hint; 734 const Operator* less_than; 735 const Operator* less_than_or_equal; 736 if (r.BothInputsAre(Type::Signed32()) || 737 r.BothInputsAre(Type::Unsigned32())) { 738 less_than = simplified()->NumberLessThan(); 739 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 740 } else if (r.GetCompareNumberOperationHint(&hint)) { 741 less_than = simplified()->SpeculativeNumberLessThan(hint); 742 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint); 743 } else if (r.OneInputCannotBe(Type::StringOrReceiver()) && 744 (r.BothInputsAre(Type::PlainPrimitive()) || 745 !(flags() & kDeoptimizationEnabled))) { 746 r.ConvertInputsToNumber(); 747 less_than = simplified()->NumberLessThan(); 748 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 749 } else { 750 return NoChange(); 751 } 752 const Operator* comparison; 753 switch (node->opcode()) { 754 case IrOpcode::kJSLessThan: 755 comparison = less_than; 756 break; 757 case IrOpcode::kJSGreaterThan: 758 comparison = less_than; 759 r.SwapInputs(); // a > b => b < a 760 break; 761 case IrOpcode::kJSLessThanOrEqual: 762 comparison = less_than_or_equal; 763 break; 764 case IrOpcode::kJSGreaterThanOrEqual: 765 comparison = less_than_or_equal; 766 r.SwapInputs(); // a >= b => b <= a 767 break; 768 default: 769 return NoChange(); 770 } 771 if (comparison->EffectInputCount() > 0) { 772 return r.ChangeToSpeculativeOperator(comparison, Type::Boolean()); 773 } else { 774 return r.ChangeToPureOperator(comparison); 775 } 776 } 777 778 Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) { 779 Node* const input = node->InputAt(0); 780 Type* type = NodeProperties::GetType(input); 781 Factory* const f = factory(); 782 if (type->Is(Type::Boolean())) { 783 return Replace(jsgraph()->Constant(f->boolean_string())); 784 } else if (type->Is(Type::Number())) { 785 return Replace(jsgraph()->Constant(f->number_string())); 786 } else if (type->Is(Type::String())) { 787 return Replace(jsgraph()->Constant(f->string_string())); 788 } else if (type->Is(Type::Symbol())) { 789 return Replace(jsgraph()->Constant(f->symbol_string())); 790 } else if (type->Is(Type::Union(Type::Undefined(), Type::OtherUndetectable(), 791 graph()->zone()))) { 792 return Replace(jsgraph()->Constant(f->undefined_string())); 793 } else if (type->Is(Type::Null())) { 794 return Replace(jsgraph()->Constant(f->object_string())); 795 } else if (type->Is(Type::Function())) { 796 return Replace(jsgraph()->Constant(f->function_string())); 797 } else if (type->IsHeapConstant()) { 798 return Replace(jsgraph()->Constant( 799 Object::TypeOf(isolate(), type->AsHeapConstant()->Value()))); 800 } else if (type->IsOtherNumberConstant()) { 801 return Replace(jsgraph()->Constant(f->number_string())); 802 } 803 804 return NoChange(); 805 } 806 807 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) { 808 HeapObjectBinopMatcher m(node); 809 if (m.left().IsJSTypeOf() && m.right().HasValue() && 810 m.right().Value()->IsString()) { 811 Node* replacement; 812 Node* input = m.left().InputAt(0); 813 Handle<String> value = Handle<String>::cast(m.right().Value()); 814 if (String::Equals(value, factory()->boolean_string())) { 815 replacement = 816 graph()->NewNode(common()->Select(MachineRepresentation::kTagged), 817 graph()->NewNode(simplified()->ReferenceEqual(), 818 input, jsgraph()->TrueConstant()), 819 jsgraph()->TrueConstant(), 820 graph()->NewNode(simplified()->ReferenceEqual(), 821 input, jsgraph()->FalseConstant())); 822 } else if (String::Equals(value, factory()->function_string())) { 823 replacement = graph()->NewNode(simplified()->ObjectIsCallable(), input); 824 } else if (String::Equals(value, factory()->number_string())) { 825 replacement = graph()->NewNode(simplified()->ObjectIsNumber(), input); 826 } else if (String::Equals(value, factory()->string_string())) { 827 replacement = graph()->NewNode(simplified()->ObjectIsString(), input); 828 } else if (String::Equals(value, factory()->undefined_string())) { 829 replacement = graph()->NewNode( 830 common()->Select(MachineRepresentation::kTagged), 831 graph()->NewNode(simplified()->ReferenceEqual(), input, 832 jsgraph()->NullConstant()), 833 jsgraph()->FalseConstant(), 834 graph()->NewNode(simplified()->ObjectIsUndetectable(), input)); 835 } else { 836 return NoChange(); 837 } 838 if (invert) { 839 replacement = graph()->NewNode(simplified()->BooleanNot(), replacement); 840 } 841 ReplaceWithValue(node, replacement); 842 return Replace(replacement); 843 } 844 return NoChange(); 845 } 846 847 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { 848 Reduction const reduction = ReduceJSEqualTypeOf(node, invert); 849 if (reduction.Changed()) return reduction; 850 851 JSBinopReduction r(this, node); 852 853 if (r.BothInputsAre(Type::String())) { 854 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); 855 } 856 if (r.BothInputsAre(Type::Boolean())) { 857 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 858 } 859 if (r.BothInputsAre(Type::Receiver())) { 860 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 861 } 862 if (r.OneInputIs(Type::Undetectable())) { 863 RelaxEffectsAndControls(node); 864 node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1); 865 node->TrimInputCount(1); 866 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable()); 867 if (invert) { 868 // Insert an boolean not to invert the value. 869 Node* value = graph()->NewNode(simplified()->BooleanNot(), node); 870 node->ReplaceUses(value); 871 // Note: ReplaceUses() smashes all uses, so smash it back here. 872 value->ReplaceInput(0, node); 873 return Replace(value); 874 } 875 return Changed(node); 876 } 877 878 NumberOperationHint hint; 879 if (r.BothInputsAre(Type::Signed32()) || 880 r.BothInputsAre(Type::Unsigned32())) { 881 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 882 } else if (r.GetCompareNumberOperationHint(&hint)) { 883 return r.ChangeToSpeculativeOperator( 884 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); 885 } else if (r.BothInputsAre(Type::Number())) { 886 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 887 } 888 return NoChange(); 889 } 890 891 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { 892 JSBinopReduction r(this, node); 893 if (r.left() == r.right()) { 894 // x === x is always true if x != NaN 895 if (!r.left_type()->Maybe(Type::NaN())) { 896 Node* replacement = jsgraph()->BooleanConstant(!invert); 897 ReplaceWithValue(node, replacement); 898 return Replace(replacement); 899 } 900 } 901 if (r.OneInputCannotBe(Type::NumberOrSimdOrString())) { 902 // For values with canonical representation (i.e. neither String, nor 903 // Simd128Value nor Number) an empty type intersection means the values 904 // cannot be strictly equal. 905 if (!r.left_type()->Maybe(r.right_type())) { 906 Node* replacement = jsgraph()->BooleanConstant(invert); 907 ReplaceWithValue(node, replacement); 908 return Replace(replacement); 909 } 910 } 911 912 Reduction const reduction = ReduceJSEqualTypeOf(node, invert); 913 if (reduction.Changed()) return reduction; 914 915 if (r.OneInputIs(the_hole_type_)) { 916 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 917 } 918 if (r.OneInputIs(Type::Undefined())) { 919 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 920 } 921 if (r.OneInputIs(Type::Null())) { 922 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 923 } 924 if (r.OneInputIs(Type::Boolean())) { 925 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 926 } 927 if (r.OneInputIs(Type::Object())) { 928 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 929 } 930 if (r.OneInputIs(Type::Receiver())) { 931 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 932 } 933 if (r.BothInputsAre(Type::Unique())) { 934 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); 935 } 936 if (r.BothInputsAre(Type::String())) { 937 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); 938 } 939 940 NumberOperationHint hint; 941 if (r.BothInputsAre(Type::Signed32()) || 942 r.BothInputsAre(Type::Unsigned32())) { 943 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 944 } else if (r.GetCompareNumberOperationHint(&hint)) { 945 return r.ChangeToSpeculativeOperator( 946 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); 947 } else if (r.BothInputsAre(Type::Number())) { 948 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 949 } 950 return NoChange(); 951 } 952 953 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { 954 Node* const input = node->InputAt(0); 955 Type* const input_type = NodeProperties::GetType(input); 956 if (input_type->Is(Type::Boolean())) { 957 // JSToBoolean(x:boolean) => x 958 return Replace(input); 959 } else if (input_type->Is(Type::OrderedNumber())) { 960 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0)) 961 RelaxEffectsAndControls(node); 962 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input, 963 jsgraph()->ZeroConstant())); 964 node->TrimInputCount(1); 965 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); 966 return Changed(node); 967 } else if (input_type->Is(Type::Number())) { 968 // JSToBoolean(x:number) => NumberToBoolean(x) 969 RelaxEffectsAndControls(node); 970 node->TrimInputCount(1); 971 NodeProperties::ChangeOp(node, simplified()->NumberToBoolean()); 972 return Changed(node); 973 } 974 return NoChange(); 975 } 976 977 Reduction JSTypedLowering::ReduceJSToInteger(Node* node) { 978 Node* const input = NodeProperties::GetValueInput(node, 0); 979 Type* const input_type = NodeProperties::GetType(input); 980 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) { 981 // JSToInteger(x:integer) => x 982 ReplaceWithValue(node, input); 983 return Replace(input); 984 } 985 return NoChange(); 986 } 987 988 Reduction JSTypedLowering::ReduceJSToName(Node* node) { 989 Node* const input = NodeProperties::GetValueInput(node, 0); 990 Type* const input_type = NodeProperties::GetType(input); 991 if (input_type->Is(Type::Name())) { 992 // JSToName(x:name) => x 993 ReplaceWithValue(node, input); 994 return Replace(input); 995 } 996 return NoChange(); 997 } 998 999 Reduction JSTypedLowering::ReduceJSToLength(Node* node) { 1000 Node* input = NodeProperties::GetValueInput(node, 0); 1001 Type* input_type = NodeProperties::GetType(input); 1002 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) { 1003 if (input_type->Max() <= 0.0) { 1004 input = jsgraph()->ZeroConstant(); 1005 } else if (input_type->Min() >= kMaxSafeInteger) { 1006 input = jsgraph()->Constant(kMaxSafeInteger); 1007 } else { 1008 if (input_type->Min() <= 0.0) { 1009 input = graph()->NewNode(simplified()->NumberMax(), 1010 jsgraph()->ZeroConstant(), input); 1011 } 1012 if (input_type->Max() > kMaxSafeInteger) { 1013 input = graph()->NewNode(simplified()->NumberMin(), 1014 jsgraph()->Constant(kMaxSafeInteger), input); 1015 } 1016 } 1017 ReplaceWithValue(node, input); 1018 return Replace(input); 1019 } 1020 return NoChange(); 1021 } 1022 1023 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { 1024 // Try constant-folding of JSToNumber with constant inputs. 1025 Type* input_type = NodeProperties::GetType(input); 1026 if (input_type->Is(Type::String())) { 1027 HeapObjectMatcher m(input); 1028 if (m.HasValue() && m.Value()->IsString()) { 1029 Handle<Object> input_value = m.Value(); 1030 return Replace(jsgraph()->Constant( 1031 String::ToNumber(Handle<String>::cast(input_value)))); 1032 } 1033 } 1034 if (input_type->IsHeapConstant()) { 1035 Handle<Object> input_value = input_type->AsHeapConstant()->Value(); 1036 if (input_value->IsOddball()) { 1037 return Replace(jsgraph()->Constant( 1038 Oddball::ToNumber(Handle<Oddball>::cast(input_value)))); 1039 } 1040 } 1041 if (input_type->Is(Type::Number())) { 1042 // JSToNumber(x:number) => x 1043 return Changed(input); 1044 } 1045 if (input_type->Is(Type::Undefined())) { 1046 // JSToNumber(undefined) => #NaN 1047 return Replace(jsgraph()->NaNConstant()); 1048 } 1049 if (input_type->Is(Type::Null())) { 1050 // JSToNumber(null) => #0 1051 return Replace(jsgraph()->ZeroConstant()); 1052 } 1053 return NoChange(); 1054 } 1055 1056 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { 1057 // Try to reduce the input first. 1058 Node* const input = node->InputAt(0); 1059 Reduction reduction = ReduceJSToNumberInput(input); 1060 if (reduction.Changed()) { 1061 ReplaceWithValue(node, reduction.replacement()); 1062 return reduction; 1063 } 1064 Type* const input_type = NodeProperties::GetType(input); 1065 if (input_type->Is(Type::PlainPrimitive())) { 1066 RelaxEffectsAndControls(node); 1067 node->TrimInputCount(1); 1068 NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber()); 1069 return Changed(node); 1070 } 1071 return NoChange(); 1072 } 1073 1074 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { 1075 if (input->opcode() == IrOpcode::kJSToString) { 1076 // Recursively try to reduce the input first. 1077 Reduction result = ReduceJSToString(input); 1078 if (result.Changed()) return result; 1079 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) 1080 } 1081 Type* input_type = NodeProperties::GetType(input); 1082 if (input_type->Is(Type::String())) { 1083 return Changed(input); // JSToString(x:string) => x 1084 } 1085 if (input_type->Is(Type::Boolean())) { 1086 return Replace(graph()->NewNode( 1087 common()->Select(MachineRepresentation::kTagged), input, 1088 jsgraph()->HeapConstant(factory()->true_string()), 1089 jsgraph()->HeapConstant(factory()->false_string()))); 1090 } 1091 if (input_type->Is(Type::Undefined())) { 1092 return Replace(jsgraph()->HeapConstant(factory()->undefined_string())); 1093 } 1094 if (input_type->Is(Type::Null())) { 1095 return Replace(jsgraph()->HeapConstant(factory()->null_string())); 1096 } 1097 // TODO(turbofan): js-typed-lowering of ToString(x:number) 1098 return NoChange(); 1099 } 1100 1101 Reduction JSTypedLowering::ReduceJSToString(Node* node) { 1102 // Try to reduce the input first. 1103 Node* const input = node->InputAt(0); 1104 Reduction reduction = ReduceJSToStringInput(input); 1105 if (reduction.Changed()) { 1106 ReplaceWithValue(node, reduction.replacement()); 1107 return reduction; 1108 } 1109 return NoChange(); 1110 } 1111 1112 Reduction JSTypedLowering::ReduceJSToObject(Node* node) { 1113 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode()); 1114 Node* receiver = NodeProperties::GetValueInput(node, 0); 1115 Type* receiver_type = NodeProperties::GetType(receiver); 1116 Node* context = NodeProperties::GetContextInput(node); 1117 Node* frame_state = NodeProperties::GetFrameStateInput(node); 1118 Node* effect = NodeProperties::GetEffectInput(node); 1119 Node* control = NodeProperties::GetControlInput(node); 1120 if (receiver_type->Is(Type::Receiver())) { 1121 ReplaceWithValue(node, receiver, effect, control); 1122 return Replace(receiver); 1123 } 1124 1125 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks. 1126 if (receiver_type->Maybe(Type::NullOrUndefined()) && 1127 NodeProperties::IsExceptionalCall(node)) { 1128 // ToObject throws for null or undefined inputs. 1129 return NoChange(); 1130 } 1131 1132 // Check whether {receiver} is a spec object. 1133 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver); 1134 Node* branch = 1135 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 1136 1137 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1138 Node* etrue = effect; 1139 Node* rtrue = receiver; 1140 1141 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1142 Node* efalse = effect; 1143 Node* rfalse; 1144 { 1145 // Convert {receiver} using the ToObjectStub. 1146 Callable callable = CodeFactory::ToObject(isolate()); 1147 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 1148 isolate(), graph()->zone(), callable.descriptor(), 0, 1149 CallDescriptor::kNeedsFrameState, node->op()->properties()); 1150 rfalse = efalse = graph()->NewNode( 1151 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), 1152 receiver, context, frame_state, efalse, if_false); 1153 if_false = graph()->NewNode(common()->IfSuccess(), rfalse); 1154 } 1155 1156 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1157 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 1158 1159 // Morph the {node} into an appropriate Phi. 1160 ReplaceWithValue(node, node, effect, control); 1161 node->ReplaceInput(0, rtrue); 1162 node->ReplaceInput(1, rfalse); 1163 node->ReplaceInput(2, control); 1164 node->TrimInputCount(3); 1165 NodeProperties::ChangeOp(node, 1166 common()->Phi(MachineRepresentation::kTagged, 2)); 1167 return Changed(node); 1168 } 1169 1170 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { 1171 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); 1172 Node* receiver = NodeProperties::GetValueInput(node, 0); 1173 Type* receiver_type = NodeProperties::GetType(receiver); 1174 Node* effect = NodeProperties::GetEffectInput(node); 1175 Node* control = NodeProperties::GetControlInput(node); 1176 Handle<Name> name = NamedAccessOf(node->op()).name(); 1177 // Optimize "length" property of strings. 1178 if (name.is_identical_to(factory()->length_string()) && 1179 receiver_type->Is(Type::String())) { 1180 Node* value = effect = graph()->NewNode( 1181 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 1182 effect, control); 1183 ReplaceWithValue(node, value, effect); 1184 return Replace(value); 1185 } 1186 return NoChange(); 1187 } 1188 1189 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { 1190 Node* key = NodeProperties::GetValueInput(node, 1); 1191 Node* base = NodeProperties::GetValueInput(node, 0); 1192 Type* key_type = NodeProperties::GetType(key); 1193 HeapObjectMatcher mbase(base); 1194 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) { 1195 Handle<JSTypedArray> const array = 1196 Handle<JSTypedArray>::cast(mbase.Value()); 1197 if (!array->GetBuffer()->was_neutered()) { 1198 array->GetBuffer()->set_is_neuterable(false); 1199 BufferAccess const access(array->type()); 1200 size_t const k = 1201 ElementSizeLog2Of(access.machine_type().representation()); 1202 double const byte_length = array->byte_length()->Number(); 1203 CHECK_LT(k, arraysize(shifted_int32_ranges_)); 1204 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { 1205 // JSLoadProperty(typed-array, int32) 1206 Handle<FixedTypedArrayBase> elements = 1207 Handle<FixedTypedArrayBase>::cast(handle(array->elements())); 1208 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); 1209 Node* length = jsgraph()->Constant(byte_length); 1210 Node* effect = NodeProperties::GetEffectInput(node); 1211 Node* control = NodeProperties::GetControlInput(node); 1212 // Check if we can avoid the bounds check. 1213 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) { 1214 Node* load = graph()->NewNode( 1215 simplified()->LoadElement( 1216 AccessBuilder::ForTypedArrayElement(array->type(), true)), 1217 buffer, key, effect, control); 1218 ReplaceWithValue(node, load, load); 1219 return Replace(load); 1220 } 1221 // Compute byte offset. 1222 Node* offset = 1223 (k == 0) ? key : graph()->NewNode( 1224 simplified()->NumberShiftLeft(), key, 1225 jsgraph()->Constant(static_cast<double>(k))); 1226 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer, 1227 offset, length, effect, control); 1228 ReplaceWithValue(node, load, load); 1229 return Replace(load); 1230 } 1231 } 1232 } 1233 return NoChange(); 1234 } 1235 1236 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { 1237 Node* key = NodeProperties::GetValueInput(node, 1); 1238 Node* base = NodeProperties::GetValueInput(node, 0); 1239 Node* value = NodeProperties::GetValueInput(node, 2); 1240 Type* key_type = NodeProperties::GetType(key); 1241 Type* value_type = NodeProperties::GetType(value); 1242 HeapObjectMatcher mbase(base); 1243 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) { 1244 Handle<JSTypedArray> const array = 1245 Handle<JSTypedArray>::cast(mbase.Value()); 1246 if (!array->GetBuffer()->was_neutered()) { 1247 array->GetBuffer()->set_is_neuterable(false); 1248 BufferAccess const access(array->type()); 1249 size_t const k = 1250 ElementSizeLog2Of(access.machine_type().representation()); 1251 double const byte_length = array->byte_length()->Number(); 1252 CHECK_LT(k, arraysize(shifted_int32_ranges_)); 1253 if (access.external_array_type() != kExternalUint8ClampedArray && 1254 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { 1255 // JSLoadProperty(typed-array, int32) 1256 Handle<FixedTypedArrayBase> elements = 1257 Handle<FixedTypedArrayBase>::cast(handle(array->elements())); 1258 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); 1259 Node* length = jsgraph()->Constant(byte_length); 1260 Node* context = NodeProperties::GetContextInput(node); 1261 Node* effect = NodeProperties::GetEffectInput(node); 1262 Node* control = NodeProperties::GetControlInput(node); 1263 // Convert to a number first. 1264 if (!value_type->Is(Type::Number())) { 1265 Reduction number_reduction = ReduceJSToNumberInput(value); 1266 if (number_reduction.Changed()) { 1267 value = number_reduction.replacement(); 1268 } else { 1269 Node* frame_state_for_to_number = 1270 NodeProperties::FindFrameStateBefore(node); 1271 value = effect = 1272 graph()->NewNode(javascript()->ToNumber(), value, context, 1273 frame_state_for_to_number, effect, control); 1274 control = graph()->NewNode(common()->IfSuccess(), value); 1275 } 1276 } 1277 // Check if we can avoid the bounds check. 1278 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) { 1279 RelaxControls(node); 1280 node->ReplaceInput(0, buffer); 1281 DCHECK_EQ(key, node->InputAt(1)); 1282 node->ReplaceInput(2, value); 1283 node->ReplaceInput(3, effect); 1284 node->ReplaceInput(4, control); 1285 node->TrimInputCount(5); 1286 NodeProperties::ChangeOp( 1287 node, 1288 simplified()->StoreElement( 1289 AccessBuilder::ForTypedArrayElement(array->type(), true))); 1290 return Changed(node); 1291 } 1292 // Compute byte offset. 1293 Node* offset = 1294 (k == 0) ? key : graph()->NewNode( 1295 simplified()->NumberShiftLeft(), key, 1296 jsgraph()->Constant(static_cast<double>(k))); 1297 // Turn into a StoreBuffer operation. 1298 RelaxControls(node); 1299 node->ReplaceInput(0, buffer); 1300 node->ReplaceInput(1, offset); 1301 node->ReplaceInput(2, length); 1302 node->ReplaceInput(3, value); 1303 node->ReplaceInput(4, effect); 1304 node->ReplaceInput(5, control); 1305 node->TrimInputCount(6); 1306 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access)); 1307 return Changed(node); 1308 } 1309 } 1310 } 1311 return NoChange(); 1312 } 1313 1314 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { 1315 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); 1316 Node* constructor = NodeProperties::GetValueInput(node, 0); 1317 Type* constructor_type = NodeProperties::GetType(constructor); 1318 Node* object = NodeProperties::GetValueInput(node, 1); 1319 Node* context = NodeProperties::GetContextInput(node); 1320 Node* frame_state = NodeProperties::GetFrameStateInput(node); 1321 Node* effect = NodeProperties::GetEffectInput(node); 1322 Node* control = NodeProperties::GetControlInput(node); 1323 1324 // Check if the {constructor} is a (known) JSFunction. 1325 if (!constructor_type->IsHeapConstant() || 1326 !constructor_type->AsHeapConstant()->Value()->IsJSFunction()) { 1327 return NoChange(); 1328 } 1329 Handle<JSFunction> function = 1330 Handle<JSFunction>::cast(constructor_type->AsHeapConstant()->Value()); 1331 1332 // Check if the {function} already has an initial map (i.e. the 1333 // {function} has been used as a constructor at least once). 1334 if (!function->has_initial_map()) return NoChange(); 1335 1336 // Check if the {function}s "prototype" is a JSReceiver. 1337 if (!function->prototype()->IsJSReceiver()) return NoChange(); 1338 1339 // Install a code dependency on the {function}s initial map. 1340 Handle<Map> initial_map(function->initial_map(), isolate()); 1341 dependencies()->AssumeInitialMapCantChange(initial_map); 1342 1343 Node* prototype = 1344 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); 1345 1346 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object); 1347 Node* branch0 = 1348 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); 1349 1350 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1351 Node* etrue0 = effect; 1352 Node* vtrue0 = jsgraph()->FalseConstant(); 1353 1354 control = graph()->NewNode(common()->IfFalse(), branch0); 1355 1356 // Loop through the {object}s prototype chain looking for the {prototype}. 1357 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); 1358 Node* eloop = effect = 1359 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); 1360 Node* vloop = object = graph()->NewNode( 1361 common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop); 1362 // TODO(jarin): This is a very ugly hack to work-around the super-smart 1363 // implicit typing of the Phi, which goes completely nuts if the {object} 1364 // is for example a HeapConstant. 1365 NodeProperties::SetType(vloop, Type::NonInternal()); 1366 1367 // Load the {object} map and instance type. 1368 Node* object_map = effect = 1369 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, 1370 effect, control); 1371 Node* object_instance_type = effect = graph()->NewNode( 1372 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map, 1373 effect, control); 1374 1375 // Check if the {object} is a special receiver, because for special 1376 // receivers, i.e. proxies or API objects that need access checks, 1377 // we have to use the %HasInPrototypeChain runtime function instead. 1378 Node* check1 = graph()->NewNode( 1379 simplified()->NumberLessThanOrEqual(), object_instance_type, 1380 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE)); 1381 Node* branch1 = 1382 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); 1383 1384 control = graph()->NewNode(common()->IfFalse(), branch1); 1385 1386 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1387 Node* etrue1 = effect; 1388 Node* vtrue1; 1389 1390 // Check if the {object} is not a receiver at all. 1391 Node* check10 = 1392 graph()->NewNode(simplified()->NumberLessThan(), object_instance_type, 1393 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE)); 1394 Node* branch10 = 1395 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1); 1396 1397 // A primitive value cannot match the {prototype} we're looking for. 1398 if_true1 = graph()->NewNode(common()->IfTrue(), branch10); 1399 vtrue1 = jsgraph()->FalseConstant(); 1400 1401 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10); 1402 Node* efalse1 = etrue1; 1403 Node* vfalse1; 1404 { 1405 // Slow path, need to call the %HasInPrototypeChain runtime function. 1406 vfalse1 = efalse1 = graph()->NewNode( 1407 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object, 1408 prototype, context, frame_state, efalse1, if_false1); 1409 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); 1410 1411 // Replace any potential IfException on {node} to catch exceptions 1412 // from this %HasInPrototypeChain runtime call instead. 1413 for (Edge edge : node->use_edges()) { 1414 if (edge.from()->opcode() == IrOpcode::kIfException) { 1415 edge.UpdateTo(vfalse1); 1416 Revisit(edge.from()); 1417 } 1418 } 1419 } 1420 1421 // Load the {object} prototype. 1422 Node* object_prototype = effect = graph()->NewNode( 1423 simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map, 1424 effect, control); 1425 1426 // Check if we reached the end of {object}s prototype chain. 1427 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), 1428 object_prototype, jsgraph()->NullConstant()); 1429 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control); 1430 1431 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 1432 Node* etrue2 = effect; 1433 Node* vtrue2 = jsgraph()->FalseConstant(); 1434 1435 control = graph()->NewNode(common()->IfFalse(), branch2); 1436 1437 // Check if we reached the {prototype}. 1438 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(), 1439 object_prototype, prototype); 1440 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control); 1441 1442 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); 1443 Node* etrue3 = effect; 1444 Node* vtrue3 = jsgraph()->TrueConstant(); 1445 1446 control = graph()->NewNode(common()->IfFalse(), branch3); 1447 1448 // Close the loop. 1449 vloop->ReplaceInput(1, object_prototype); 1450 eloop->ReplaceInput(1, effect); 1451 loop->ReplaceInput(1, control); 1452 1453 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2, 1454 if_true3, if_false1); 1455 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2, 1456 etrue3, efalse1, control); 1457 1458 // Morph the {node} into an appropriate Phi. 1459 ReplaceWithValue(node, node, effect, control); 1460 node->ReplaceInput(0, vtrue0); 1461 node->ReplaceInput(1, vtrue1); 1462 node->ReplaceInput(2, vtrue2); 1463 node->ReplaceInput(3, vtrue3); 1464 node->ReplaceInput(4, vfalse1); 1465 node->ReplaceInput(5, control); 1466 node->TrimInputCount(6); 1467 NodeProperties::ChangeOp(node, 1468 common()->Phi(MachineRepresentation::kTagged, 5)); 1469 return Changed(node); 1470 } 1471 1472 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { 1473 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); 1474 ContextAccess const& access = ContextAccessOf(node->op()); 1475 Node* effect = NodeProperties::GetEffectInput(node); 1476 Node* control = graph()->start(); 1477 for (size_t i = 0; i < access.depth(); ++i) { 1478 Node* previous = effect = graph()->NewNode( 1479 simplified()->LoadField( 1480 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)), 1481 NodeProperties::GetValueInput(node, 0), effect, control); 1482 node->ReplaceInput(0, previous); 1483 } 1484 node->ReplaceInput(1, effect); 1485 node->ReplaceInput(2, control); 1486 NodeProperties::ChangeOp( 1487 node, 1488 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index()))); 1489 return Changed(node); 1490 } 1491 1492 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { 1493 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); 1494 ContextAccess const& access = ContextAccessOf(node->op()); 1495 Node* effect = NodeProperties::GetEffectInput(node); 1496 Node* control = graph()->start(); 1497 for (size_t i = 0; i < access.depth(); ++i) { 1498 Node* previous = effect = graph()->NewNode( 1499 simplified()->LoadField( 1500 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)), 1501 NodeProperties::GetValueInput(node, 0), effect, control); 1502 node->ReplaceInput(0, previous); 1503 } 1504 node->RemoveInput(2); 1505 node->ReplaceInput(2, effect); 1506 NodeProperties::ChangeOp( 1507 node, 1508 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index()))); 1509 return Changed(node); 1510 } 1511 1512 Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) { 1513 DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode()); 1514 Node* effect = NodeProperties::GetEffectInput(node); 1515 Node* control = NodeProperties::GetControlInput(node); 1516 1517 int32_t cell_index = OpParameter<int32_t>(node); 1518 Node* module = NodeProperties::GetValueInput(node, 0); 1519 1520 Node* array; 1521 int index; 1522 if (ModuleDescriptor::GetCellIndexKind(cell_index) == 1523 ModuleDescriptor::kExport) { 1524 array = effect = graph()->NewNode( 1525 simplified()->LoadField(AccessBuilder::ForModuleRegularExports()), 1526 module, effect, control); 1527 index = cell_index - 1; 1528 } else { 1529 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 1530 ModuleDescriptor::kImport); 1531 array = effect = graph()->NewNode( 1532 simplified()->LoadField(AccessBuilder::ForModuleRegularImports()), 1533 module, effect, control); 1534 index = -cell_index - 1; 1535 } 1536 1537 Node* cell = effect = graph()->NewNode( 1538 simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array, 1539 effect, control); 1540 1541 Node* value = effect = 1542 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()), 1543 cell, effect, control); 1544 1545 ReplaceWithValue(node, value, effect, control); 1546 return Changed(value); 1547 } 1548 1549 Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) { 1550 DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode()); 1551 Node* effect = NodeProperties::GetEffectInput(node); 1552 Node* control = NodeProperties::GetControlInput(node); 1553 1554 int32_t cell_index = OpParameter<int32_t>(node); 1555 Node* module = NodeProperties::GetValueInput(node, 0); 1556 Node* value = NodeProperties::GetValueInput(node, 1); 1557 1558 Node* array; 1559 int index; 1560 if (ModuleDescriptor::GetCellIndexKind(cell_index) == 1561 ModuleDescriptor::kExport) { 1562 array = effect = graph()->NewNode( 1563 simplified()->LoadField(AccessBuilder::ForModuleRegularExports()), 1564 module, effect, control); 1565 index = cell_index - 1; 1566 } else { 1567 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 1568 ModuleDescriptor::kImport); 1569 array = effect = graph()->NewNode( 1570 simplified()->LoadField(AccessBuilder::ForModuleRegularImports()), 1571 module, effect, control); 1572 index = -cell_index - 1; 1573 } 1574 1575 Node* cell = effect = graph()->NewNode( 1576 simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array, 1577 effect, control); 1578 1579 effect = 1580 graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()), 1581 cell, value, effect, control); 1582 1583 ReplaceWithValue(node, effect, effect, control); 1584 return Changed(value); 1585 } 1586 1587 Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { 1588 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode()); 1589 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op()); 1590 Node* receiver = NodeProperties::GetValueInput(node, 0); 1591 Type* receiver_type = NodeProperties::GetType(receiver); 1592 Node* context = NodeProperties::GetContextInput(node); 1593 Type* context_type = NodeProperties::GetType(context); 1594 Node* frame_state = NodeProperties::GetFrameStateInput(node); 1595 Node* effect = NodeProperties::GetEffectInput(node); 1596 Node* control = NodeProperties::GetControlInput(node); 1597 1598 // Check if {receiver} is known to be a receiver. 1599 if (receiver_type->Is(Type::Receiver())) { 1600 ReplaceWithValue(node, receiver, effect, control); 1601 return Replace(receiver); 1602 } 1603 1604 // If the {receiver} is known to be null or undefined, we can just replace it 1605 // with the global proxy unconditionally. 1606 if (receiver_type->Is(Type::NullOrUndefined()) || 1607 mode == ConvertReceiverMode::kNullOrUndefined) { 1608 if (context_type->IsHeapConstant()) { 1609 Handle<JSObject> global_proxy( 1610 Handle<Context>::cast(context_type->AsHeapConstant()->Value()) 1611 ->global_proxy(), 1612 isolate()); 1613 receiver = jsgraph()->Constant(global_proxy); 1614 } else { 1615 Node* native_context = effect = graph()->NewNode( 1616 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1617 context, context, effect); 1618 receiver = effect = graph()->NewNode( 1619 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), 1620 native_context, native_context, effect); 1621 } 1622 ReplaceWithValue(node, receiver, effect, control); 1623 return Replace(receiver); 1624 } 1625 1626 // If {receiver} cannot be null or undefined we can skip a few checks. 1627 if (!receiver_type->Maybe(Type::NullOrUndefined()) || 1628 mode == ConvertReceiverMode::kNotNullOrUndefined) { 1629 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver); 1630 Node* branch = 1631 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 1632 1633 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1634 Node* etrue = effect; 1635 Node* rtrue = receiver; 1636 1637 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1638 Node* efalse = effect; 1639 Node* rfalse; 1640 { 1641 // Convert {receiver} using the ToObjectStub. 1642 Callable callable = CodeFactory::ToObject(isolate()); 1643 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 1644 isolate(), graph()->zone(), callable.descriptor(), 0, 1645 CallDescriptor::kNeedsFrameState, node->op()->properties()); 1646 rfalse = efalse = graph()->NewNode( 1647 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), 1648 receiver, context, frame_state, efalse); 1649 } 1650 1651 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1652 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 1653 1654 // Morph the {node} into an appropriate Phi. 1655 ReplaceWithValue(node, node, effect, control); 1656 node->ReplaceInput(0, rtrue); 1657 node->ReplaceInput(1, rfalse); 1658 node->ReplaceInput(2, control); 1659 node->TrimInputCount(3); 1660 NodeProperties::ChangeOp(node, 1661 common()->Phi(MachineRepresentation::kTagged, 2)); 1662 return Changed(node); 1663 } 1664 1665 // Check if {receiver} is already a JSReceiver. 1666 Node* check0 = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver); 1667 Node* branch0 = 1668 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 1669 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1670 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1671 1672 // Check {receiver} for undefined. 1673 Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver, 1674 jsgraph()->UndefinedConstant()); 1675 Node* branch1 = 1676 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_false0); 1677 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1678 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1679 1680 // Check {receiver} for null. 1681 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), receiver, 1682 jsgraph()->NullConstant()); 1683 Node* branch2 = 1684 graph()->NewNode(common()->Branch(BranchHint::kFalse), check2, if_false1); 1685 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 1686 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); 1687 1688 // We just use {receiver} directly. 1689 Node* if_noop = if_true0; 1690 Node* enoop = effect; 1691 Node* rnoop = receiver; 1692 1693 // Convert {receiver} using ToObject. 1694 Node* if_convert = if_false2; 1695 Node* econvert = effect; 1696 Node* rconvert; 1697 { 1698 // Convert {receiver} using the ToObjectStub. 1699 Callable callable = CodeFactory::ToObject(isolate()); 1700 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 1701 isolate(), graph()->zone(), callable.descriptor(), 0, 1702 CallDescriptor::kNeedsFrameState, node->op()->properties()); 1703 rconvert = econvert = graph()->NewNode( 1704 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), 1705 receiver, context, frame_state, econvert); 1706 } 1707 1708 // Replace {receiver} with global proxy of {context}. 1709 Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2); 1710 Node* eglobal = effect; 1711 Node* rglobal; 1712 { 1713 if (context_type->IsHeapConstant()) { 1714 Handle<JSObject> global_proxy( 1715 Handle<Context>::cast(context_type->AsHeapConstant()->Value()) 1716 ->global_proxy(), 1717 isolate()); 1718 rglobal = jsgraph()->Constant(global_proxy); 1719 } else { 1720 Node* native_context = eglobal = graph()->NewNode( 1721 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1722 context, context, eglobal); 1723 rglobal = eglobal = graph()->NewNode( 1724 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), 1725 native_context, native_context, eglobal); 1726 } 1727 } 1728 1729 control = 1730 graph()->NewNode(common()->Merge(3), if_noop, if_convert, if_global); 1731 effect = graph()->NewNode(common()->EffectPhi(3), enoop, econvert, eglobal, 1732 control); 1733 // Morph the {node} into an appropriate Phi. 1734 ReplaceWithValue(node, node, effect, control); 1735 node->ReplaceInput(0, rnoop); 1736 node->ReplaceInput(1, rconvert); 1737 node->ReplaceInput(2, rglobal); 1738 node->ReplaceInput(3, control); 1739 node->TrimInputCount(4); 1740 NodeProperties::ChangeOp(node, 1741 common()->Phi(MachineRepresentation::kTagged, 3)); 1742 return Changed(node); 1743 } 1744 1745 namespace { 1746 1747 void ReduceBuiltin(Isolate* isolate, JSGraph* jsgraph, Node* node, 1748 int builtin_index, int arity, CallDescriptor::Flags flags) { 1749 // Patch {node} to a direct CEntryStub call. 1750 // 1751 // ----------- A r g u m e n t s ----------- 1752 // -- 0: CEntryStub 1753 // --- Stack args --- 1754 // -- 1: receiver 1755 // -- [2, 2 + n[: the n actual arguments passed to the builtin 1756 // -- 2 + n: argc, including the receiver and implicit args (Smi) 1757 // -- 2 + n + 1: target 1758 // -- 2 + n + 2: new_target 1759 // --- Register args --- 1760 // -- 2 + n + 3: the C entry point 1761 // -- 2 + n + 4: argc (Int32) 1762 // ----------------------------------- 1763 1764 // The logic contained here is mirrored in Builtins::Generate_Adaptor. 1765 // Keep these in sync. 1766 1767 const bool is_construct = (node->opcode() == IrOpcode::kJSCallConstruct); 1768 1769 DCHECK(Builtins::HasCppImplementation(builtin_index)); 1770 DCHECK_EQ(0, flags & CallDescriptor::kSupportsTailCalls); 1771 1772 Node* target = NodeProperties::GetValueInput(node, 0); 1773 Node* new_target = is_construct 1774 ? NodeProperties::GetValueInput(node, arity + 1) 1775 : jsgraph->UndefinedConstant(); 1776 1777 // API and CPP builtins are implemented in C++, and we can inline both. 1778 // CPP builtins create a builtin exit frame, API builtins don't. 1779 const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index); 1780 1781 Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack, 1782 has_builtin_exit_frame); 1783 node->ReplaceInput(0, stub); 1784 1785 Zone* zone = jsgraph->zone(); 1786 if (is_construct) { 1787 // Unify representations between construct and call nodes. 1788 // Remove new target and add receiver as a stack parameter. 1789 Node* receiver = jsgraph->UndefinedConstant(); 1790 node->RemoveInput(arity + 1); 1791 node->InsertInput(zone, 1, receiver); 1792 } 1793 1794 const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver; 1795 Node* argc_node = jsgraph->Constant(argc); 1796 1797 static const int kStubAndReceiver = 2; 1798 int cursor = arity + kStubAndReceiver; 1799 node->InsertInput(zone, cursor++, argc_node); 1800 node->InsertInput(zone, cursor++, target); 1801 node->InsertInput(zone, cursor++, new_target); 1802 1803 Address entry = Builtins::CppEntryOf(builtin_index); 1804 ExternalReference entry_ref(ExternalReference(entry, isolate)); 1805 Node* entry_node = jsgraph->ExternalConstant(entry_ref); 1806 1807 node->InsertInput(zone, cursor++, entry_node); 1808 node->InsertInput(zone, cursor++, argc_node); 1809 1810 static const int kReturnCount = 1; 1811 const char* debug_name = Builtins::name(builtin_index); 1812 Operator::Properties properties = node->op()->properties(); 1813 CallDescriptor* desc = Linkage::GetCEntryStubCallDescriptor( 1814 zone, kReturnCount, argc, debug_name, properties, flags); 1815 1816 NodeProperties::ChangeOp(node, jsgraph->common()->Call(desc)); 1817 } 1818 1819 bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) { 1820 static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; 1821 const int num_decl_parms = shared->internal_formal_parameter_count(); 1822 return (num_decl_parms != arity && num_decl_parms != sentinel); 1823 } 1824 1825 } // namespace 1826 1827 Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) { 1828 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); 1829 CallConstructParameters const& p = CallConstructParametersOf(node->op()); 1830 DCHECK_LE(2u, p.arity()); 1831 int const arity = static_cast<int>(p.arity() - 2); 1832 Node* target = NodeProperties::GetValueInput(node, 0); 1833 Type* target_type = NodeProperties::GetType(target); 1834 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); 1835 Node* effect = NodeProperties::GetEffectInput(node); 1836 Node* control = NodeProperties::GetControlInput(node); 1837 1838 // Check if {target} is a known JSFunction. 1839 if (target_type->IsHeapConstant() && 1840 target_type->AsHeapConstant()->Value()->IsJSFunction()) { 1841 Handle<JSFunction> function = 1842 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value()); 1843 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 1844 const int builtin_index = shared->construct_stub()->builtin_index(); 1845 const bool is_builtin = (builtin_index != -1); 1846 1847 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 1848 1849 if (is_builtin && Builtins::HasCppImplementation(builtin_index) && 1850 !NeedsArgumentAdaptorFrame(shared, arity)) { 1851 // Patch {node} to a direct CEntryStub call. 1852 1853 // Load the context from the {target}. 1854 Node* context = effect = graph()->NewNode( 1855 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), 1856 target, effect, control); 1857 NodeProperties::ReplaceContextInput(node, context); 1858 1859 // Update the effect dependency for the {node}. 1860 NodeProperties::ReplaceEffectInput(node, effect); 1861 1862 ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags); 1863 } else { 1864 // Patch {node} to an indirect call via the {function}s construct stub. 1865 Callable callable(handle(shared->construct_stub(), isolate()), 1866 ConstructStubDescriptor(isolate())); 1867 node->RemoveInput(arity + 1); 1868 node->InsertInput(graph()->zone(), 0, 1869 jsgraph()->HeapConstant(callable.code())); 1870 node->InsertInput(graph()->zone(), 2, new_target); 1871 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); 1872 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 1873 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant()); 1874 NodeProperties::ChangeOp( 1875 node, common()->Call(Linkage::GetStubCallDescriptor( 1876 isolate(), graph()->zone(), callable.descriptor(), 1877 1 + arity, flags))); 1878 } 1879 return Changed(node); 1880 } 1881 1882 // Check if {target} is a JSFunction. 1883 if (target_type->Is(Type::Function())) { 1884 // Patch {node} to an indirect call via the ConstructFunction builtin. 1885 Callable callable = CodeFactory::ConstructFunction(isolate()); 1886 node->RemoveInput(arity + 1); 1887 node->InsertInput(graph()->zone(), 0, 1888 jsgraph()->HeapConstant(callable.code())); 1889 node->InsertInput(graph()->zone(), 2, new_target); 1890 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); 1891 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 1892 NodeProperties::ChangeOp( 1893 node, common()->Call(Linkage::GetStubCallDescriptor( 1894 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 1895 CallDescriptor::kNeedsFrameState))); 1896 return Changed(node); 1897 } 1898 1899 return NoChange(); 1900 } 1901 1902 1903 Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { 1904 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); 1905 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); 1906 int const arity = static_cast<int>(p.arity() - 2); 1907 ConvertReceiverMode convert_mode = p.convert_mode(); 1908 Node* target = NodeProperties::GetValueInput(node, 0); 1909 Type* target_type = NodeProperties::GetType(target); 1910 Node* receiver = NodeProperties::GetValueInput(node, 1); 1911 Type* receiver_type = NodeProperties::GetType(receiver); 1912 Node* effect = NodeProperties::GetEffectInput(node); 1913 Node* control = NodeProperties::GetControlInput(node); 1914 Node* frame_state = NodeProperties::FindFrameStateBefore(node); 1915 1916 // Try to infer receiver {convert_mode} from {receiver} type. 1917 if (receiver_type->Is(Type::NullOrUndefined())) { 1918 convert_mode = ConvertReceiverMode::kNullOrUndefined; 1919 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) { 1920 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; 1921 } 1922 1923 // Check if {target} is a known JSFunction. 1924 if (target_type->IsHeapConstant() && 1925 target_type->AsHeapConstant()->Value()->IsJSFunction()) { 1926 Handle<JSFunction> function = 1927 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value()); 1928 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 1929 const int builtin_index = shared->code()->builtin_index(); 1930 const bool is_builtin = (builtin_index != -1); 1931 1932 // Class constructors are callable, but [[Call]] will raise an exception. 1933 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 1934 if (IsClassConstructor(shared->kind())) return NoChange(); 1935 1936 // Load the context from the {target}. 1937 Node* context = effect = graph()->NewNode( 1938 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target, 1939 effect, control); 1940 NodeProperties::ReplaceContextInput(node, context); 1941 1942 // Check if we need to convert the {receiver}. 1943 if (is_sloppy(shared->language_mode()) && !shared->native() && 1944 !receiver_type->Is(Type::Receiver())) { 1945 receiver = effect = 1946 graph()->NewNode(javascript()->ConvertReceiver(convert_mode), 1947 receiver, context, frame_state, effect, control); 1948 NodeProperties::ReplaceValueInput(node, receiver, 1); 1949 } 1950 1951 // Update the effect dependency for the {node}. 1952 NodeProperties::ReplaceEffectInput(node, effect); 1953 1954 // Compute flags for the call. 1955 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 1956 if (p.tail_call_mode() == TailCallMode::kAllow) { 1957 flags |= CallDescriptor::kSupportsTailCalls; 1958 } 1959 1960 Node* new_target = jsgraph()->UndefinedConstant(); 1961 Node* argument_count = jsgraph()->Constant(arity); 1962 if (NeedsArgumentAdaptorFrame(shared, arity)) { 1963 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline. 1964 Callable callable = CodeFactory::ArgumentAdaptor(isolate()); 1965 node->InsertInput(graph()->zone(), 0, 1966 jsgraph()->HeapConstant(callable.code())); 1967 node->InsertInput(graph()->zone(), 2, new_target); 1968 node->InsertInput(graph()->zone(), 3, argument_count); 1969 node->InsertInput( 1970 graph()->zone(), 4, 1971 jsgraph()->Constant(shared->internal_formal_parameter_count())); 1972 NodeProperties::ChangeOp( 1973 node, common()->Call(Linkage::GetStubCallDescriptor( 1974 isolate(), graph()->zone(), callable.descriptor(), 1975 1 + arity, flags))); 1976 } else if (is_builtin && Builtins::HasCppImplementation(builtin_index) && 1977 ((flags & CallDescriptor::kSupportsTailCalls) == 0)) { 1978 // Patch {node} to a direct CEntryStub call. 1979 ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags); 1980 } else { 1981 // Patch {node} to a direct call. 1982 node->InsertInput(graph()->zone(), arity + 2, new_target); 1983 node->InsertInput(graph()->zone(), arity + 3, argument_count); 1984 NodeProperties::ChangeOp(node, 1985 common()->Call(Linkage::GetJSCallDescriptor( 1986 graph()->zone(), false, 1 + arity, flags))); 1987 } 1988 return Changed(node); 1989 } 1990 1991 // Check if {target} is a JSFunction. 1992 if (target_type->Is(Type::Function())) { 1993 // Compute flags for the call. 1994 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 1995 if (p.tail_call_mode() == TailCallMode::kAllow) { 1996 flags |= CallDescriptor::kSupportsTailCalls; 1997 } 1998 1999 // Patch {node} to an indirect call via the CallFunction builtin. 2000 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode); 2001 node->InsertInput(graph()->zone(), 0, 2002 jsgraph()->HeapConstant(callable.code())); 2003 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity)); 2004 NodeProperties::ChangeOp( 2005 node, common()->Call(Linkage::GetStubCallDescriptor( 2006 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 2007 flags))); 2008 return Changed(node); 2009 } 2010 2011 // Maybe we did at least learn something about the {receiver}. 2012 if (p.convert_mode() != convert_mode) { 2013 NodeProperties::ChangeOp( 2014 node, javascript()->CallFunction(p.arity(), p.frequency(), p.feedback(), 2015 convert_mode, p.tail_call_mode())); 2016 return Changed(node); 2017 } 2018 2019 return NoChange(); 2020 } 2021 2022 2023 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { 2024 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode()); 2025 Node* receiver = NodeProperties::GetValueInput(node, 0); 2026 Node* cache_array = NodeProperties::GetValueInput(node, 1); 2027 Node* cache_type = NodeProperties::GetValueInput(node, 2); 2028 Node* index = NodeProperties::GetValueInput(node, 3); 2029 Node* context = NodeProperties::GetContextInput(node); 2030 Node* frame_state = NodeProperties::GetFrameStateInput(node); 2031 Node* effect = NodeProperties::GetEffectInput(node); 2032 Node* control = NodeProperties::GetControlInput(node); 2033 2034 // Load the next {key} from the {cache_array}. 2035 Node* key = effect = graph()->NewNode( 2036 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), 2037 cache_array, index, effect, control); 2038 2039 // Load the map of the {receiver}. 2040 Node* receiver_map = effect = 2041 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 2042 receiver, effect, control); 2043 2044 // Check if the expected map still matches that of the {receiver}. 2045 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map, 2046 cache_type); 2047 Node* branch0 = 2048 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 2049 2050 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 2051 Node* etrue0; 2052 Node* vtrue0; 2053 { 2054 // Don't need filtering since expected map still matches that of the 2055 // {receiver}. 2056 etrue0 = effect; 2057 vtrue0 = key; 2058 } 2059 2060 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 2061 Node* efalse0; 2062 Node* vfalse0; 2063 { 2064 // Filter the {key} to check if it's still a valid property of the 2065 // {receiver} (does the ToName conversion implicitly). 2066 Callable const callable = CodeFactory::ForInFilter(isolate()); 2067 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 2068 isolate(), graph()->zone(), callable.descriptor(), 0, 2069 CallDescriptor::kNeedsFrameState); 2070 vfalse0 = efalse0 = graph()->NewNode( 2071 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), key, 2072 receiver, context, frame_state, effect, if_false0); 2073 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0); 2074 } 2075 2076 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 2077 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); 2078 ReplaceWithValue(node, node, effect, control); 2079 node->ReplaceInput(0, vtrue0); 2080 node->ReplaceInput(1, vfalse0); 2081 node->ReplaceInput(2, control); 2082 node->TrimInputCount(3); 2083 NodeProperties::ChangeOp(node, 2084 common()->Phi(MachineRepresentation::kTagged, 2)); 2085 return Changed(node); 2086 } 2087 2088 Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) { 2089 DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode()); 2090 Node* generator = NodeProperties::GetValueInput(node, 0); 2091 Node* continuation = NodeProperties::GetValueInput(node, 1); 2092 Node* offset = NodeProperties::GetValueInput(node, 2); 2093 Node* context = NodeProperties::GetContextInput(node); 2094 Node* effect = NodeProperties::GetEffectInput(node); 2095 Node* control = NodeProperties::GetControlInput(node); 2096 int register_count = OpParameter<int>(node); 2097 2098 FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectOperandStack(); 2099 FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext(); 2100 FieldAccess continuation_field = 2101 AccessBuilder::ForJSGeneratorObjectContinuation(); 2102 FieldAccess input_or_debug_pos_field = 2103 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos(); 2104 2105 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field), 2106 generator, effect, control); 2107 2108 for (int i = 0; i < register_count; ++i) { 2109 Node* value = NodeProperties::GetValueInput(node, 3 + i); 2110 effect = graph()->NewNode( 2111 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array, 2112 value, effect, control); 2113 } 2114 2115 effect = graph()->NewNode(simplified()->StoreField(context_field), generator, 2116 context, effect, control); 2117 effect = graph()->NewNode(simplified()->StoreField(continuation_field), 2118 generator, continuation, effect, control); 2119 effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field), 2120 generator, offset, effect, control); 2121 2122 ReplaceWithValue(node, effect, effect, control); 2123 return Changed(effect); 2124 } 2125 2126 Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) { 2127 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode()); 2128 Node* generator = NodeProperties::GetValueInput(node, 0); 2129 Node* effect = NodeProperties::GetEffectInput(node); 2130 Node* control = NodeProperties::GetControlInput(node); 2131 2132 FieldAccess continuation_field = 2133 AccessBuilder::ForJSGeneratorObjectContinuation(); 2134 2135 Node* continuation = effect = graph()->NewNode( 2136 simplified()->LoadField(continuation_field), generator, effect, control); 2137 Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting); 2138 effect = graph()->NewNode(simplified()->StoreField(continuation_field), 2139 generator, executing, effect, control); 2140 2141 ReplaceWithValue(node, continuation, effect, control); 2142 return Changed(continuation); 2143 } 2144 2145 Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) { 2146 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode()); 2147 Node* generator = NodeProperties::GetValueInput(node, 0); 2148 Node* effect = NodeProperties::GetEffectInput(node); 2149 Node* control = NodeProperties::GetControlInput(node); 2150 int index = OpParameter<int>(node); 2151 2152 FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectOperandStack(); 2153 FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index); 2154 2155 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field), 2156 generator, effect, control); 2157 Node* element = effect = graph()->NewNode( 2158 simplified()->LoadField(element_field), array, effect, control); 2159 Node* stale = jsgraph()->StaleRegisterConstant(); 2160 effect = graph()->NewNode(simplified()->StoreField(element_field), array, 2161 stale, effect, control); 2162 2163 ReplaceWithValue(node, element, effect, control); 2164 return Changed(element); 2165 } 2166 2167 Reduction JSTypedLowering::Reduce(Node* node) { 2168 switch (node->opcode()) { 2169 case IrOpcode::kJSEqual: 2170 return ReduceJSEqual(node, false); 2171 case IrOpcode::kJSNotEqual: 2172 return ReduceJSEqual(node, true); 2173 case IrOpcode::kJSStrictEqual: 2174 return ReduceJSStrictEqual(node, false); 2175 case IrOpcode::kJSStrictNotEqual: 2176 return ReduceJSStrictEqual(node, true); 2177 case IrOpcode::kJSLessThan: // fall through 2178 case IrOpcode::kJSGreaterThan: // fall through 2179 case IrOpcode::kJSLessThanOrEqual: // fall through 2180 case IrOpcode::kJSGreaterThanOrEqual: 2181 return ReduceJSComparison(node); 2182 case IrOpcode::kJSBitwiseOr: 2183 case IrOpcode::kJSBitwiseXor: 2184 case IrOpcode::kJSBitwiseAnd: 2185 return ReduceInt32Binop(node); 2186 case IrOpcode::kJSShiftLeft: 2187 case IrOpcode::kJSShiftRight: 2188 return ReduceUI32Shift(node, kSigned); 2189 case IrOpcode::kJSShiftRightLogical: 2190 return ReduceUI32Shift(node, kUnsigned); 2191 case IrOpcode::kJSAdd: 2192 return ReduceJSAdd(node); 2193 case IrOpcode::kJSSubtract: 2194 case IrOpcode::kJSMultiply: 2195 case IrOpcode::kJSDivide: 2196 case IrOpcode::kJSModulus: 2197 return ReduceNumberBinop(node); 2198 case IrOpcode::kJSOrdinaryHasInstance: 2199 return ReduceJSOrdinaryHasInstance(node); 2200 case IrOpcode::kJSToBoolean: 2201 return ReduceJSToBoolean(node); 2202 case IrOpcode::kJSToInteger: 2203 return ReduceJSToInteger(node); 2204 case IrOpcode::kJSToLength: 2205 return ReduceJSToLength(node); 2206 case IrOpcode::kJSToName: 2207 return ReduceJSToName(node); 2208 case IrOpcode::kJSToNumber: 2209 return ReduceJSToNumber(node); 2210 case IrOpcode::kJSToString: 2211 return ReduceJSToString(node); 2212 case IrOpcode::kJSToObject: 2213 return ReduceJSToObject(node); 2214 case IrOpcode::kJSTypeOf: 2215 return ReduceJSTypeOf(node); 2216 case IrOpcode::kJSLoadNamed: 2217 return ReduceJSLoadNamed(node); 2218 case IrOpcode::kJSLoadProperty: 2219 return ReduceJSLoadProperty(node); 2220 case IrOpcode::kJSStoreProperty: 2221 return ReduceJSStoreProperty(node); 2222 case IrOpcode::kJSLoadContext: 2223 return ReduceJSLoadContext(node); 2224 case IrOpcode::kJSStoreContext: 2225 return ReduceJSStoreContext(node); 2226 case IrOpcode::kJSLoadModule: 2227 return ReduceJSLoadModule(node); 2228 case IrOpcode::kJSStoreModule: 2229 return ReduceJSStoreModule(node); 2230 case IrOpcode::kJSConvertReceiver: 2231 return ReduceJSConvertReceiver(node); 2232 case IrOpcode::kJSCallConstruct: 2233 return ReduceJSCallConstruct(node); 2234 case IrOpcode::kJSCallFunction: 2235 return ReduceJSCallFunction(node); 2236 case IrOpcode::kJSForInNext: 2237 return ReduceJSForInNext(node); 2238 case IrOpcode::kJSGeneratorStore: 2239 return ReduceJSGeneratorStore(node); 2240 case IrOpcode::kJSGeneratorRestoreContinuation: 2241 return ReduceJSGeneratorRestoreContinuation(node); 2242 case IrOpcode::kJSGeneratorRestoreRegister: 2243 return ReduceJSGeneratorRestoreRegister(node); 2244 default: 2245 break; 2246 } 2247 return NoChange(); 2248 } 2249 2250 2251 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } 2252 2253 2254 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); } 2255 2256 2257 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); } 2258 2259 2260 JSOperatorBuilder* JSTypedLowering::javascript() const { 2261 return jsgraph()->javascript(); 2262 } 2263 2264 2265 CommonOperatorBuilder* JSTypedLowering::common() const { 2266 return jsgraph()->common(); 2267 } 2268 2269 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const { 2270 return jsgraph()->simplified(); 2271 } 2272 2273 2274 CompilationDependencies* JSTypedLowering::dependencies() const { 2275 return dependencies_; 2276 } 2277 2278 } // namespace compiler 2279 } // namespace internal 2280 } // namespace v8 2281