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