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