js-typed-lowering.cc revision 8389745919cae02139ddc085a63c00d024269cf2
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/code-factory.h" 6#include "src/compilation-dependencies.h" 7#include "src/compiler/access-builder.h" 8#include "src/compiler/js-graph.h" 9#include "src/compiler/js-typed-lowering.h" 10#include "src/compiler/linkage.h" 11#include "src/compiler/node-matchers.h" 12#include "src/compiler/node-properties.h" 13#include "src/compiler/operator-properties.h" 14#include "src/type-cache.h" 15#include "src/types.h" 16 17namespace v8 { 18namespace internal { 19namespace compiler { 20 21// A helper class to simplify the process of reducing a single binop node with a 22// JSOperator. This class manages the rewriting of context, control, and effect 23// dependencies during lowering of a binop and contains numerous helper 24// functions for matching the types of inputs to an operation. 25class JSBinopReduction final { 26 public: 27 JSBinopReduction(JSTypedLowering* lowering, Node* node) 28 : lowering_(lowering), node_(node) {} 29 30 void ConvertInputsToNumber(Node* frame_state) { 31 // To convert the inputs to numbers, we have to provide frame states 32 // for lazy bailouts in the ToNumber conversions. 33 // We use a little hack here: we take the frame state before the binary 34 // operation and use it to construct the frame states for the conversion 35 // so that after the deoptimization, the binary operation IC gets 36 // already converted values from full code. This way we are sure that we 37 // will not re-do any of the side effects. 38 39 Node* left_input = nullptr; 40 Node* right_input = nullptr; 41 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive()); 42 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive()); 43 bool handles_exception = NodeProperties::IsExceptionalCall(node_); 44 45 if (!left_is_primitive && !right_is_primitive && handles_exception) { 46 ConvertBothInputsToNumber(&left_input, &right_input, frame_state); 47 } else { 48 left_input = left_is_primitive 49 ? ConvertPlainPrimitiveToNumber(left()) 50 : ConvertSingleInputToNumber( 51 left(), CreateFrameStateForLeftInput(frame_state)); 52 right_input = right_is_primitive 53 ? ConvertPlainPrimitiveToNumber(right()) 54 : ConvertSingleInputToNumber( 55 right(), CreateFrameStateForRightInput( 56 frame_state, left_input)); 57 } 58 59 node_->ReplaceInput(0, left_input); 60 node_->ReplaceInput(1, right_input); 61 } 62 63 void ConvertInputsToUI32(Signedness left_signedness, 64 Signedness right_signedness) { 65 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); 66 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); 67 } 68 69 void SwapInputs() { 70 Node* l = left(); 71 Node* r = right(); 72 node_->ReplaceInput(0, r); 73 node_->ReplaceInput(1, l); 74 } 75 76 // Remove all effect and control inputs and outputs to this node and change 77 // to the pure operator {op}, possibly inserting a boolean inversion. 78 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, 79 Type* type = Type::Any()) { 80 DCHECK_EQ(0, op->EffectInputCount()); 81 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 82 DCHECK_EQ(0, op->ControlInputCount()); 83 DCHECK_EQ(2, op->ValueInputCount()); 84 85 // Remove the effects from the node, and update its effect/control usages. 86 if (node_->op()->EffectInputCount() > 0) { 87 lowering_->RelaxEffectsAndControls(node_); 88 } 89 // Remove the inputs corresponding to context, effect, and control. 90 NodeProperties::RemoveNonValueInputs(node_); 91 // Finally, update the operator to the new one. 92 NodeProperties::ChangeOp(node_, op); 93 94 // TODO(jarin): Replace the explicit typing hack with a call to some method 95 // that encapsulates changing the operator and re-typing. 96 Type* node_type = NodeProperties::GetType(node_); 97 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone())); 98 99 if (invert) { 100 // Insert an boolean not to invert the value. 101 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 102 node_->ReplaceUses(value); 103 // Note: ReplaceUses() smashes all uses, so smash it back here. 104 value->ReplaceInput(0, node_); 105 return lowering_->Replace(value); 106 } 107 return lowering_->Changed(node_); 108 } 109 110 Reduction ChangeToStringComparisonOperator(const Operator* op, 111 bool invert = false) { 112 if (node_->op()->ControlInputCount() > 0) { 113 lowering_->RelaxControls(node_); 114 } 115 // String comparison operators need effect and control inputs, so copy them 116 // over. 117 Node* effect = NodeProperties::GetEffectInput(node_); 118 Node* control = NodeProperties::GetControlInput(node_); 119 node_->ReplaceInput(2, effect); 120 node_->ReplaceInput(3, control); 121 122 node_->TrimInputCount(4); 123 NodeProperties::ChangeOp(node_, op); 124 125 if (invert) { 126 // Insert a boolean-not to invert the value. 127 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 128 node_->ReplaceUses(value); 129 // Note: ReplaceUses() smashes all uses, so smash it back here. 130 value->ReplaceInput(0, node_); 131 return lowering_->Replace(value); 132 } 133 return lowering_->Changed(node_); 134 } 135 136 Reduction ChangeToPureOperator(const Operator* op, Type* type) { 137 return ChangeToPureOperator(op, false, type); 138 } 139 140 bool LeftInputIs(Type* t) { return left_type()->Is(t); } 141 142 bool RightInputIs(Type* t) { return right_type()->Is(t); } 143 144 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } 145 146 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); } 147 148 bool OneInputCannotBe(Type* t) { 149 return !left_type()->Maybe(t) || !right_type()->Maybe(t); 150 } 151 152 bool NeitherInputCanBe(Type* t) { 153 return !left_type()->Maybe(t) && !right_type()->Maybe(t); 154 } 155 156 Node* effect() { return NodeProperties::GetEffectInput(node_); } 157 Node* control() { return NodeProperties::GetControlInput(node_); } 158 Node* context() { return NodeProperties::GetContextInput(node_); } 159 Node* left() { return NodeProperties::GetValueInput(node_, 0); } 160 Node* right() { return NodeProperties::GetValueInput(node_, 1); } 161 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); } 162 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); } 163 164 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } 165 Graph* graph() const { return lowering_->graph(); } 166 JSGraph* jsgraph() { return lowering_->jsgraph(); } 167 JSOperatorBuilder* javascript() { return lowering_->javascript(); } 168 MachineOperatorBuilder* machine() { return lowering_->machine(); } 169 CommonOperatorBuilder* common() { return jsgraph()->common(); } 170 Zone* zone() const { return graph()->zone(); } 171 172 private: 173 JSTypedLowering* lowering_; // The containing lowering instance. 174 Node* node_; // The original node. 175 176 Node* CreateFrameStateForLeftInput(Node* frame_state) { 177 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 178 179 if (state_info.bailout_id() == BailoutId::None()) { 180 // Dummy frame state => just leave it as is. 181 return frame_state; 182 } 183 184 // If the frame state is already the right one, just return it. 185 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt && 186 state_info.state_combine().GetOffsetToPokeAt() == 1) { 187 return frame_state; 188 } 189 190 // Here, we smash the result of the conversion into the slot just below 191 // the stack top. This is the slot that full code uses to store the 192 // left operand. 193 const Operator* op = jsgraph()->common()->FrameState( 194 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(1), 195 state_info.function_info()); 196 197 return graph()->NewNode(op, 198 frame_state->InputAt(kFrameStateParametersInput), 199 frame_state->InputAt(kFrameStateLocalsInput), 200 frame_state->InputAt(kFrameStateStackInput), 201 frame_state->InputAt(kFrameStateContextInput), 202 frame_state->InputAt(kFrameStateFunctionInput), 203 frame_state->InputAt(kFrameStateOuterStateInput)); 204 } 205 206 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) { 207 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 208 209 if (state_info.bailout_id() == BailoutId::None()) { 210 // Dummy frame state => just leave it as is. 211 return frame_state; 212 } 213 214 // Create a frame state that stores the result of the operation to the 215 // top of the stack (i.e., the slot used for the right operand). 216 const Operator* op = jsgraph()->common()->FrameState( 217 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(0), 218 state_info.function_info()); 219 220 // Change the left operand {converted_left} on the expression stack. 221 Node* stack = frame_state->InputAt(2); 222 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues); 223 DCHECK_GE(stack->InputCount(), 2); 224 225 // TODO(jarin) Allocate in a local zone or a reusable buffer. 226 NodeVector new_values(stack->InputCount(), zone()); 227 for (int i = 0; i < stack->InputCount(); i++) { 228 if (i == stack->InputCount() - 2) { 229 new_values[i] = converted_left; 230 } else { 231 new_values[i] = stack->InputAt(i); 232 } 233 } 234 Node* new_stack = 235 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front()); 236 237 return graph()->NewNode( 238 op, frame_state->InputAt(kFrameStateParametersInput), 239 frame_state->InputAt(kFrameStateLocalsInput), new_stack, 240 frame_state->InputAt(kFrameStateContextInput), 241 frame_state->InputAt(kFrameStateFunctionInput), 242 frame_state->InputAt(kFrameStateOuterStateInput)); 243 } 244 245 Node* ConvertPlainPrimitiveToNumber(Node* node) { 246 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); 247 // Avoid inserting too many eager ToNumber() operations. 248 Reduction const reduction = lowering_->ReduceJSToNumberInput(node); 249 if (reduction.Changed()) return reduction.replacement(); 250 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. 251 return graph()->NewNode( 252 javascript()->ToNumber(), node, jsgraph()->NoContextConstant(), 253 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); 254 } 255 256 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) { 257 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); 258 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(), 259 frame_state, effect(), control()); 260 NodeProperties::ReplaceUses(node_, node_, node_, n, n); 261 update_effect(n); 262 return n; 263 } 264 265 void ConvertBothInputsToNumber(Node** left_result, Node** right_result, 266 Node* frame_state) { 267 Node* projections[2]; 268 269 // Find {IfSuccess} and {IfException} continuations of the operation. 270 NodeProperties::CollectControlProjections(node_, projections, 2); 271 IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]); 272 Node* if_exception = projections[1]; 273 Node* if_success = projections[0]; 274 275 // Insert two ToNumber() operations that both potentially throw. 276 Node* left_state = CreateFrameStateForLeftInput(frame_state); 277 Node* left_conv = 278 graph()->NewNode(javascript()->ToNumber(), left(), context(), 279 left_state, effect(), control()); 280 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv); 281 Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv); 282 Node* right_conv = 283 graph()->NewNode(javascript()->ToNumber(), right(), context(), 284 right_state, left_conv, left_success); 285 Node* left_exception = 286 graph()->NewNode(common()->IfException(hint), left_conv, left_conv); 287 Node* right_exception = 288 graph()->NewNode(common()->IfException(hint), right_conv, right_conv); 289 NodeProperties::ReplaceControlInput(if_success, right_conv); 290 update_effect(right_conv); 291 292 // Wire conversions to existing {IfException} continuation. 293 Node* exception_merge = if_exception; 294 Node* exception_value = 295 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 296 left_exception, right_exception, exception_merge); 297 Node* exception_effect = 298 graph()->NewNode(common()->EffectPhi(2), left_exception, 299 right_exception, exception_merge); 300 for (Edge edge : exception_merge->use_edges()) { 301 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect); 302 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value); 303 } 304 NodeProperties::RemoveType(exception_merge); 305 exception_merge->ReplaceInput(0, left_exception); 306 exception_merge->ReplaceInput(1, right_exception); 307 NodeProperties::ChangeOp(exception_merge, common()->Merge(2)); 308 309 *left_result = left_conv; 310 *right_result = right_conv; 311 } 312 313 Node* ConvertToUI32(Node* node, Signedness signedness) { 314 // Avoid introducing too many eager NumberToXXnt32() operations. 315 Type* type = NodeProperties::GetType(node); 316 if (signedness == kSigned) { 317 if (!type->Is(Type::Signed32())) { 318 node = graph()->NewNode(simplified()->NumberToInt32(), node); 319 } 320 } else { 321 DCHECK_EQ(kUnsigned, signedness); 322 if (!type->Is(Type::Unsigned32())) { 323 node = graph()->NewNode(simplified()->NumberToUint32(), node); 324 } 325 } 326 return node; 327 } 328 329 void update_effect(Node* effect) { 330 NodeProperties::ReplaceEffectInput(node_, effect); 331 } 332}; 333 334 335// TODO(turbofan): js-typed-lowering improvements possible 336// - immediately put in type bounds for all new nodes 337// - relax effects from generic but not-side-effecting operations 338 339 340JSTypedLowering::JSTypedLowering(Editor* editor, 341 CompilationDependencies* dependencies, 342 Flags flags, JSGraph* jsgraph, Zone* zone) 343 : AdvancedReducer(editor), 344 dependencies_(dependencies), 345 flags_(flags), 346 jsgraph_(jsgraph), 347 true_type_(Type::Constant(factory()->true_value(), graph()->zone())), 348 false_type_(Type::Constant(factory()->false_value(), graph()->zone())), 349 the_hole_type_( 350 Type::Constant(factory()->the_hole_value(), graph()->zone())), 351 type_cache_(TypeCache::Get()) { 352 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { 353 double min = kMinInt / (1 << k); 354 double max = kMaxInt / (1 << k); 355 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); 356 } 357} 358 359 360Reduction JSTypedLowering::ReduceJSAdd(Node* node) { 361 if (flags() & kDisableBinaryOpReduction) return NoChange(); 362 363 JSBinopReduction r(this, node); 364 if (r.BothInputsAre(Type::Number())) { 365 // JSAdd(x:number, y:number) => NumberAdd(x, y) 366 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 367 } 368 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { 369 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 370 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 371 r.ConvertInputsToNumber(frame_state); 372 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 373 } 374 if (r.BothInputsAre(Type::String())) { 375 // JSAdd(x:string, y:string) => CallStub[StringAdd](x, y) 376 Callable const callable = 377 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); 378 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 379 isolate(), graph()->zone(), callable.descriptor(), 0, 380 CallDescriptor::kNeedsFrameState, node->op()->properties()); 381 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op())); 382 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1); 383 node->InsertInput(graph()->zone(), 0, 384 jsgraph()->HeapConstant(callable.code())); 385 NodeProperties::ChangeOp(node, common()->Call(desc)); 386 return Changed(node); 387 } 388 return NoChange(); 389} 390 391 392Reduction JSTypedLowering::ReduceJSModulus(Node* node) { 393 if (flags() & kDisableBinaryOpReduction) return NoChange(); 394 395 JSBinopReduction r(this, node); 396 if (r.BothInputsAre(Type::Number())) { 397 // JSModulus(x:number, x:number) => NumberModulus(x, y) 398 return r.ChangeToPureOperator(simplified()->NumberModulus(), 399 Type::Number()); 400 } 401 return NoChange(); 402} 403 404 405Reduction JSTypedLowering::ReduceNumberBinop(Node* node, 406 const Operator* numberOp) { 407 if (flags() & kDisableBinaryOpReduction) return NoChange(); 408 409 JSBinopReduction r(this, node); 410 if (numberOp == simplified()->NumberModulus()) { 411 if (r.BothInputsAre(Type::Number())) { 412 return r.ChangeToPureOperator(numberOp, Type::Number()); 413 } 414 return NoChange(); 415 } 416 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 417 r.ConvertInputsToNumber(frame_state); 418 return r.ChangeToPureOperator(numberOp, Type::Number()); 419} 420 421 422Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { 423 if (flags() & kDisableBinaryOpReduction) return NoChange(); 424 425 JSBinopReduction r(this, node); 426 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 427 r.ConvertInputsToNumber(frame_state); 428 r.ConvertInputsToUI32(kSigned, kSigned); 429 return r.ChangeToPureOperator(intOp, Type::Integral32()); 430} 431 432 433Reduction JSTypedLowering::ReduceUI32Shift(Node* node, 434 Signedness left_signedness, 435 const Operator* shift_op) { 436 if (flags() & kDisableBinaryOpReduction) return NoChange(); 437 438 JSBinopReduction r(this, node); 439 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 440 r.ConvertInputsToNumber(frame_state); 441 r.ConvertInputsToUI32(left_signedness, kUnsigned); 442 return r.ChangeToPureOperator(shift_op); 443} 444 445 446Reduction JSTypedLowering::ReduceJSComparison(Node* node) { 447 if (flags() & kDisableBinaryOpReduction) return NoChange(); 448 449 JSBinopReduction r(this, node); 450 if (r.BothInputsAre(Type::String())) { 451 // If both inputs are definitely strings, perform a string comparison. 452 const Operator* stringOp; 453 switch (node->opcode()) { 454 case IrOpcode::kJSLessThan: 455 stringOp = simplified()->StringLessThan(); 456 break; 457 case IrOpcode::kJSGreaterThan: 458 stringOp = simplified()->StringLessThan(); 459 r.SwapInputs(); // a > b => b < a 460 break; 461 case IrOpcode::kJSLessThanOrEqual: 462 stringOp = simplified()->StringLessThanOrEqual(); 463 break; 464 case IrOpcode::kJSGreaterThanOrEqual: 465 stringOp = simplified()->StringLessThanOrEqual(); 466 r.SwapInputs(); // a >= b => b <= a 467 break; 468 default: 469 return NoChange(); 470 } 471 r.ChangeToStringComparisonOperator(stringOp); 472 return Changed(node); 473 } 474 if (r.OneInputCannotBe(Type::StringOrReceiver())) { 475 const Operator* less_than; 476 const Operator* less_than_or_equal; 477 if (r.BothInputsAre(Type::Unsigned32())) { 478 less_than = machine()->Uint32LessThan(); 479 less_than_or_equal = machine()->Uint32LessThanOrEqual(); 480 } else if (r.BothInputsAre(Type::Signed32())) { 481 less_than = machine()->Int32LessThan(); 482 less_than_or_equal = machine()->Int32LessThanOrEqual(); 483 } else { 484 // TODO(turbofan): mixed signed/unsigned int32 comparisons. 485 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 486 r.ConvertInputsToNumber(frame_state); 487 less_than = simplified()->NumberLessThan(); 488 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 489 } 490 const Operator* comparison; 491 switch (node->opcode()) { 492 case IrOpcode::kJSLessThan: 493 comparison = less_than; 494 break; 495 case IrOpcode::kJSGreaterThan: 496 comparison = less_than; 497 r.SwapInputs(); // a > b => b < a 498 break; 499 case IrOpcode::kJSLessThanOrEqual: 500 comparison = less_than_or_equal; 501 break; 502 case IrOpcode::kJSGreaterThanOrEqual: 503 comparison = less_than_or_equal; 504 r.SwapInputs(); // a >= b => b <= a 505 break; 506 default: 507 return NoChange(); 508 } 509 return r.ChangeToPureOperator(comparison); 510 } 511 // TODO(turbofan): relax/remove effects of this operator in other cases. 512 return NoChange(); // Keep a generic comparison. 513} 514 515 516Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { 517 if (flags() & kDisableBinaryOpReduction) return NoChange(); 518 519 JSBinopReduction r(this, node); 520 521 if (r.BothInputsAre(Type::Number())) { 522 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 523 } 524 if (r.BothInputsAre(Type::String())) { 525 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(), 526 invert); 527 } 528 if (r.BothInputsAre(Type::Boolean())) { 529 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()), 530 invert); 531 } 532 if (r.BothInputsAre(Type::Receiver())) { 533 return r.ChangeToPureOperator( 534 simplified()->ReferenceEqual(Type::Receiver()), invert); 535 } 536 if (r.OneInputIs(Type::NullOrUndefined())) { 537 Callable const callable = CodeFactory::CompareNilIC(isolate(), kNullValue); 538 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 539 isolate(), graph()->zone(), callable.descriptor(), 0, 540 CallDescriptor::kNeedsFrameState, node->op()->properties()); 541 node->RemoveInput(r.LeftInputIs(Type::NullOrUndefined()) ? 0 : 1); 542 node->InsertInput(graph()->zone(), 0, 543 jsgraph()->HeapConstant(callable.code())); 544 NodeProperties::ChangeOp(node, common()->Call(desc)); 545 if (invert) { 546 // Insert an boolean not to invert the value. 547 Node* value = graph()->NewNode(simplified()->BooleanNot(), node); 548 node->ReplaceUses(value); 549 // Note: ReplaceUses() smashes all uses, so smash it back here. 550 value->ReplaceInput(0, node); 551 return Replace(value); 552 } 553 return Changed(node); 554 } 555 return NoChange(); 556} 557 558 559Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { 560 if (flags() & kDisableBinaryOpReduction) return NoChange(); 561 562 JSBinopReduction r(this, node); 563 if (r.left() == r.right()) { 564 // x === x is always true if x != NaN 565 if (!r.left_type()->Maybe(Type::NaN())) { 566 Node* replacement = jsgraph()->BooleanConstant(!invert); 567 ReplaceWithValue(node, replacement); 568 return Replace(replacement); 569 } 570 } 571 if (r.OneInputCannotBe(Type::NumberOrString())) { 572 // For values with canonical representation (i.e. not string nor number) an 573 // empty type intersection means the values cannot be strictly equal. 574 if (!r.left_type()->Maybe(r.right_type())) { 575 Node* replacement = jsgraph()->BooleanConstant(invert); 576 ReplaceWithValue(node, replacement); 577 return Replace(replacement); 578 } 579 } 580 if (r.OneInputIs(the_hole_type_)) { 581 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_), 582 invert); 583 } 584 if (r.OneInputIs(Type::Undefined())) { 585 return r.ChangeToPureOperator( 586 simplified()->ReferenceEqual(Type::Undefined()), invert); 587 } 588 if (r.OneInputIs(Type::Null())) { 589 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()), 590 invert); 591 } 592 if (r.OneInputIs(Type::Boolean())) { 593 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()), 594 invert); 595 } 596 if (r.OneInputIs(Type::Object())) { 597 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()), 598 invert); 599 } 600 if (r.OneInputIs(Type::Receiver())) { 601 return r.ChangeToPureOperator( 602 simplified()->ReferenceEqual(Type::Receiver()), invert); 603 } 604 if (r.BothInputsAre(Type::Unique())) { 605 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()), 606 invert); 607 } 608 if (r.BothInputsAre(Type::String())) { 609 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(), 610 invert); 611 } 612 if (r.BothInputsAre(Type::Number())) { 613 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 614 } 615 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types) 616 return NoChange(); 617} 618 619 620Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { 621 Node* const input = node->InputAt(0); 622 Type* const input_type = NodeProperties::GetType(input); 623 Node* const effect = NodeProperties::GetEffectInput(node); 624 if (input_type->Is(Type::Boolean())) { 625 // JSToBoolean(x:boolean) => x 626 ReplaceWithValue(node, input, effect); 627 return Replace(input); 628 } else if (input_type->Is(Type::OrderedNumber())) { 629 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0)) 630 RelaxEffectsAndControls(node); 631 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input, 632 jsgraph()->ZeroConstant())); 633 node->TrimInputCount(1); 634 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); 635 return Changed(node); 636 } else if (input_type->Is(Type::String())) { 637 // JSToBoolean(x:string) => NumberLessThan(#0,x.length) 638 FieldAccess const access = AccessBuilder::ForStringLength(); 639 Node* length = graph()->NewNode(simplified()->LoadField(access), input, 640 effect, graph()->start()); 641 ReplaceWithValue(node, node, length); 642 node->ReplaceInput(0, jsgraph()->ZeroConstant()); 643 node->ReplaceInput(1, length); 644 node->TrimInputCount(2); 645 NodeProperties::ChangeOp(node, simplified()->NumberLessThan()); 646 return Changed(node); 647 } 648 return NoChange(); 649} 650 651 652Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { 653 if (input->opcode() == IrOpcode::kJSToNumber) { 654 // Recursively try to reduce the input first. 655 Reduction result = ReduceJSToNumber(input); 656 if (result.Changed()) return result; 657 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) 658 } 659 // Check for ToNumber truncation of signaling NaN to undefined mapping. 660 if (input->opcode() == IrOpcode::kSelect) { 661 Node* check = NodeProperties::GetValueInput(input, 0); 662 Node* vtrue = NodeProperties::GetValueInput(input, 1); 663 Type* vtrue_type = NodeProperties::GetType(vtrue); 664 Node* vfalse = NodeProperties::GetValueInput(input, 2); 665 Type* vfalse_type = NodeProperties::GetType(vfalse); 666 if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) { 667 if (check->opcode() == IrOpcode::kNumberIsHoleNaN && 668 check->InputAt(0) == vfalse) { 669 // JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x 670 return Replace(vfalse); 671 } 672 } 673 } 674 // Try constant-folding of JSToNumber with constant inputs. 675 Type* input_type = NodeProperties::GetType(input); 676 if (input_type->IsConstant()) { 677 Handle<Object> input_value = input_type->AsConstant()->Value(); 678 if (input_value->IsString()) { 679 return Replace(jsgraph()->Constant( 680 String::ToNumber(Handle<String>::cast(input_value)))); 681 } else if (input_value->IsOddball()) { 682 return Replace(jsgraph()->Constant( 683 Oddball::ToNumber(Handle<Oddball>::cast(input_value)))); 684 } 685 } 686 if (input_type->Is(Type::Number())) { 687 // JSToNumber(x:number) => x 688 return Changed(input); 689 } 690 if (input_type->Is(Type::Undefined())) { 691 // JSToNumber(undefined) => #NaN 692 return Replace(jsgraph()->NaNConstant()); 693 } 694 if (input_type->Is(Type::Null())) { 695 // JSToNumber(null) => #0 696 return Replace(jsgraph()->ZeroConstant()); 697 } 698 if (input_type->Is(Type::Boolean())) { 699 // JSToNumber(x:boolean) => BooleanToNumber(x) 700 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input)); 701 } 702 // TODO(turbofan): js-typed-lowering of ToNumber(x:string) 703 return NoChange(); 704} 705 706 707Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { 708 // Try to reduce the input first. 709 Node* const input = node->InputAt(0); 710 Reduction reduction = ReduceJSToNumberInput(input); 711 if (reduction.Changed()) { 712 ReplaceWithValue(node, reduction.replacement()); 713 return reduction; 714 } 715 Type* const input_type = NodeProperties::GetType(input); 716 if (input_type->Is(Type::PlainPrimitive())) { 717 if (NodeProperties::GetContextInput(node) != 718 jsgraph()->NoContextConstant() || 719 NodeProperties::GetEffectInput(node) != graph()->start() || 720 NodeProperties::GetControlInput(node) != graph()->start()) { 721 // JSToNumber(x:plain-primitive,context,effect,control) 722 // => JSToNumber(x,no-context,start,start) 723 RelaxEffectsAndControls(node); 724 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); 725 NodeProperties::ReplaceControlInput(node, graph()->start()); 726 NodeProperties::ReplaceEffectInput(node, graph()->start()); 727 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 728 NodeProperties::ReplaceFrameStateInput(node, 0, 729 jsgraph()->EmptyFrameState()); 730 return Changed(node); 731 } 732 } 733 return NoChange(); 734} 735 736 737Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { 738 if (input->opcode() == IrOpcode::kJSToString) { 739 // Recursively try to reduce the input first. 740 Reduction result = ReduceJSToString(input); 741 if (result.Changed()) return result; 742 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) 743 } 744 Type* input_type = NodeProperties::GetType(input); 745 if (input_type->Is(Type::String())) { 746 return Changed(input); // JSToString(x:string) => x 747 } 748 if (input_type->Is(Type::Boolean())) { 749 return Replace(graph()->NewNode( 750 common()->Select(MachineRepresentation::kTagged), input, 751 jsgraph()->HeapConstant(factory()->true_string()), 752 jsgraph()->HeapConstant(factory()->false_string()))); 753 } 754 if (input_type->Is(Type::Undefined())) { 755 return Replace(jsgraph()->HeapConstant(factory()->undefined_string())); 756 } 757 if (input_type->Is(Type::Null())) { 758 return Replace(jsgraph()->HeapConstant(factory()->null_string())); 759 } 760 // TODO(turbofan): js-typed-lowering of ToString(x:number) 761 return NoChange(); 762} 763 764 765Reduction JSTypedLowering::ReduceJSToString(Node* node) { 766 // Try to reduce the input first. 767 Node* const input = node->InputAt(0); 768 Reduction reduction = ReduceJSToStringInput(input); 769 if (reduction.Changed()) { 770 ReplaceWithValue(node, reduction.replacement()); 771 return reduction; 772 } 773 return NoChange(); 774} 775 776 777Reduction JSTypedLowering::ReduceJSToObject(Node* node) { 778 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode()); 779 Node* receiver = NodeProperties::GetValueInput(node, 0); 780 Type* receiver_type = NodeProperties::GetType(receiver); 781 Node* context = NodeProperties::GetContextInput(node); 782 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 783 Node* effect = NodeProperties::GetEffectInput(node); 784 Node* control = NodeProperties::GetControlInput(node); 785 if (!receiver_type->Is(Type::Receiver())) { 786 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks. 787 if (receiver_type->Maybe(Type::NullOrUndefined()) && 788 NodeProperties::IsExceptionalCall(node)) { 789 // ToObject throws for null or undefined inputs. 790 return NoChange(); 791 } 792 793 // Check whether {receiver} is a Smi. 794 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 795 Node* branch0 = 796 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); 797 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 798 Node* etrue0 = effect; 799 800 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 801 Node* efalse0 = effect; 802 803 // Determine the instance type of {receiver}. 804 Node* receiver_map = efalse0 = 805 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 806 receiver, efalse0, if_false0); 807 Node* receiver_instance_type = efalse0 = graph()->NewNode( 808 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 809 receiver_map, efalse0, if_false0); 810 811 // Check whether {receiver} is a spec object. 812 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 813 Node* check1 = 814 graph()->NewNode(machine()->Uint32LessThanOrEqual(), 815 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE), 816 receiver_instance_type); 817 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 818 check1, if_false0); 819 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 820 Node* etrue1 = efalse0; 821 822 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 823 Node* efalse1 = efalse0; 824 825 // Convert {receiver} using the ToObjectStub. 826 Node* if_convert = 827 graph()->NewNode(common()->Merge(2), if_true0, if_false1); 828 Node* econvert = 829 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert); 830 Node* rconvert; 831 { 832 Callable callable = CodeFactory::ToObject(isolate()); 833 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 834 isolate(), graph()->zone(), callable.descriptor(), 0, 835 CallDescriptor::kNeedsFrameState, node->op()->properties()); 836 rconvert = econvert = graph()->NewNode( 837 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), 838 receiver, context, frame_state, econvert, if_convert); 839 } 840 841 // The {receiver} is already a spec object. 842 Node* if_done = if_true1; 843 Node* edone = etrue1; 844 Node* rdone = receiver; 845 846 control = graph()->NewNode(common()->Merge(2), if_convert, if_done); 847 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control); 848 receiver = 849 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 850 rconvert, rdone, control); 851 } 852 ReplaceWithValue(node, receiver, effect, control); 853 return Changed(receiver); 854} 855 856 857Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { 858 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); 859 Node* receiver = NodeProperties::GetValueInput(node, 0); 860 Type* receiver_type = NodeProperties::GetType(receiver); 861 Node* effect = NodeProperties::GetEffectInput(node); 862 Node* control = NodeProperties::GetControlInput(node); 863 Handle<Name> name = NamedAccessOf(node->op()).name(); 864 // Optimize "length" property of strings. 865 if (name.is_identical_to(factory()->length_string()) && 866 receiver_type->Is(Type::String())) { 867 Node* value = effect = graph()->NewNode( 868 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 869 effect, control); 870 ReplaceWithValue(node, value, effect); 871 return Replace(value); 872 } 873 // Optimize "prototype" property of functions. 874 if (name.is_identical_to(factory()->prototype_string()) && 875 receiver_type->IsConstant() && 876 receiver_type->AsConstant()->Value()->IsJSFunction()) { 877 // TODO(turbofan): This lowering might not kick in if we ever lower 878 // the C++ accessor for "prototype" in an earlier optimization pass. 879 Handle<JSFunction> function = 880 Handle<JSFunction>::cast(receiver_type->AsConstant()->Value()); 881 if (function->has_initial_map()) { 882 // We need to add a code dependency on the initial map of the {function} 883 // in order to be notified about changes to the "prototype" of {function}, 884 // so it doesn't make sense to continue unless deoptimization is enabled. 885 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 886 Handle<Map> initial_map(function->initial_map(), isolate()); 887 dependencies()->AssumeInitialMapCantChange(initial_map); 888 Node* value = 889 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); 890 ReplaceWithValue(node, value); 891 return Replace(value); 892 } 893 } 894 return NoChange(); 895} 896 897 898Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { 899 Node* key = NodeProperties::GetValueInput(node, 1); 900 Node* base = NodeProperties::GetValueInput(node, 0); 901 Type* key_type = NodeProperties::GetType(key); 902 HeapObjectMatcher mbase(base); 903 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) { 904 Handle<JSTypedArray> const array = 905 Handle<JSTypedArray>::cast(mbase.Value()); 906 if (!array->GetBuffer()->was_neutered()) { 907 array->GetBuffer()->set_is_neuterable(false); 908 BufferAccess const access(array->type()); 909 size_t const k = 910 ElementSizeLog2Of(access.machine_type().representation()); 911 double const byte_length = array->byte_length()->Number(); 912 CHECK_LT(k, arraysize(shifted_int32_ranges_)); 913 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { 914 // JSLoadProperty(typed-array, int32) 915 Handle<FixedTypedArrayBase> elements = 916 Handle<FixedTypedArrayBase>::cast(handle(array->elements())); 917 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); 918 Node* length = jsgraph()->Constant(byte_length); 919 Node* effect = NodeProperties::GetEffectInput(node); 920 Node* control = NodeProperties::GetControlInput(node); 921 // Check if we can avoid the bounds check. 922 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) { 923 Node* load = graph()->NewNode( 924 simplified()->LoadElement( 925 AccessBuilder::ForTypedArrayElement(array->type(), true)), 926 buffer, key, effect, control); 927 ReplaceWithValue(node, load, load); 928 return Replace(load); 929 } 930 // Compute byte offset. 931 Node* offset = Word32Shl(key, static_cast<int>(k)); 932 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer, 933 offset, length, effect, control); 934 ReplaceWithValue(node, load, load); 935 return Replace(load); 936 } 937 } 938 } 939 return NoChange(); 940} 941 942 943Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { 944 Node* key = NodeProperties::GetValueInput(node, 1); 945 Node* base = NodeProperties::GetValueInput(node, 0); 946 Node* value = NodeProperties::GetValueInput(node, 2); 947 Type* key_type = NodeProperties::GetType(key); 948 Type* value_type = NodeProperties::GetType(value); 949 HeapObjectMatcher mbase(base); 950 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) { 951 Handle<JSTypedArray> const array = 952 Handle<JSTypedArray>::cast(mbase.Value()); 953 if (!array->GetBuffer()->was_neutered()) { 954 array->GetBuffer()->set_is_neuterable(false); 955 BufferAccess const access(array->type()); 956 size_t const k = 957 ElementSizeLog2Of(access.machine_type().representation()); 958 double const byte_length = array->byte_length()->Number(); 959 CHECK_LT(k, arraysize(shifted_int32_ranges_)); 960 if (access.external_array_type() != kExternalUint8ClampedArray && 961 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { 962 // JSLoadProperty(typed-array, int32) 963 Handle<FixedTypedArrayBase> elements = 964 Handle<FixedTypedArrayBase>::cast(handle(array->elements())); 965 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); 966 Node* length = jsgraph()->Constant(byte_length); 967 Node* context = NodeProperties::GetContextInput(node); 968 Node* effect = NodeProperties::GetEffectInput(node); 969 Node* control = NodeProperties::GetControlInput(node); 970 // Convert to a number first. 971 if (!value_type->Is(Type::Number())) { 972 Reduction number_reduction = ReduceJSToNumberInput(value); 973 if (number_reduction.Changed()) { 974 value = number_reduction.replacement(); 975 } else { 976 Node* frame_state_for_to_number = 977 NodeProperties::GetFrameStateInput(node, 1); 978 value = effect = 979 graph()->NewNode(javascript()->ToNumber(), value, context, 980 frame_state_for_to_number, effect, control); 981 } 982 } 983 // Check if we can avoid the bounds check. 984 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) { 985 RelaxControls(node); 986 node->ReplaceInput(0, buffer); 987 DCHECK_EQ(key, node->InputAt(1)); 988 node->ReplaceInput(2, value); 989 node->ReplaceInput(3, effect); 990 node->ReplaceInput(4, control); 991 node->TrimInputCount(5); 992 NodeProperties::ChangeOp( 993 node, 994 simplified()->StoreElement( 995 AccessBuilder::ForTypedArrayElement(array->type(), true))); 996 return Changed(node); 997 } 998 // Compute byte offset. 999 Node* offset = Word32Shl(key, static_cast<int>(k)); 1000 // Turn into a StoreBuffer operation. 1001 RelaxControls(node); 1002 node->ReplaceInput(0, buffer); 1003 node->ReplaceInput(1, offset); 1004 node->ReplaceInput(2, length); 1005 node->ReplaceInput(3, value); 1006 node->ReplaceInput(4, effect); 1007 node->ReplaceInput(5, control); 1008 node->TrimInputCount(6); 1009 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access)); 1010 return Changed(node); 1011 } 1012 } 1013 } 1014 return NoChange(); 1015} 1016 1017 1018Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { 1019 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); 1020 Node* const context = NodeProperties::GetContextInput(node); 1021 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0); 1022 1023 // If deoptimization is disabled, we cannot optimize. 1024 if (!(flags() & kDeoptimizationEnabled) || 1025 (flags() & kDisableBinaryOpReduction)) { 1026 return NoChange(); 1027 } 1028 1029 // If we are in a try block, don't optimize since the runtime call 1030 // in the proxy case can throw. 1031 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); 1032 1033 JSBinopReduction r(this, node); 1034 Node* effect = r.effect(); 1035 Node* control = r.control(); 1036 1037 if (!r.right_type()->IsConstant() || 1038 !r.right_type()->AsConstant()->Value()->IsJSFunction()) { 1039 return NoChange(); 1040 } 1041 1042 Handle<JSFunction> function = 1043 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value()); 1044 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 1045 1046 if (!function->IsConstructor() || 1047 function->map()->has_non_instance_prototype()) { 1048 return NoChange(); 1049 } 1050 1051 JSFunction::EnsureHasInitialMap(function); 1052 DCHECK(function->has_initial_map()); 1053 Handle<Map> initial_map(function->initial_map(), isolate()); 1054 this->dependencies()->AssumeInitialMapCantChange(initial_map); 1055 Node* prototype = 1056 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); 1057 1058 Node* if_is_smi = nullptr; 1059 Node* e_is_smi = nullptr; 1060 // If the left hand side is an object, no smi check is needed. 1061 if (r.left_type()->Maybe(Type::TaggedSigned())) { 1062 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left()); 1063 Node* branch_is_smi = 1064 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control); 1065 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi); 1066 e_is_smi = effect; 1067 control = graph()->NewNode(common()->IfFalse(), branch_is_smi); 1068 } 1069 1070 Node* object_map = effect = 1071 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 1072 r.left(), effect, control); 1073 1074 // Loop through the {object}s prototype chain looking for the {prototype}. 1075 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); 1076 1077 Node* loop_effect = effect = 1078 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); 1079 1080 Node* loop_object_map = 1081 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1082 object_map, r.left(), loop); 1083 1084 // Check if the lhs needs access checks. 1085 Node* map_bit_field = effect = 1086 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()), 1087 loop_object_map, loop_effect, control); 1088 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded; 1089 Node* is_access_check_needed_num = 1090 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field, 1091 jsgraph()->Uint32Constant(is_access_check_needed_bit)); 1092 Node* is_access_check_needed = 1093 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num, 1094 jsgraph()->Uint32Constant(is_access_check_needed_bit)); 1095 1096 Node* branch_is_access_check_needed = graph()->NewNode( 1097 common()->Branch(BranchHint::kFalse), is_access_check_needed, control); 1098 Node* if_is_access_check_needed = 1099 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed); 1100 Node* e_is_access_check_needed = effect; 1101 1102 control = 1103 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed); 1104 1105 // Check if the lhs is a proxy. 1106 Node* map_instance_type = effect = graph()->NewNode( 1107 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 1108 loop_object_map, loop_effect, control); 1109 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type, 1110 jsgraph()->Uint32Constant(JS_PROXY_TYPE)); 1111 Node* branch_is_proxy = 1112 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control); 1113 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy); 1114 Node* e_is_proxy = effect; 1115 1116 1117 Node* runtime_has_in_proto_chain = control = graph()->NewNode( 1118 common()->Merge(2), if_is_access_check_needed, if_is_proxy); 1119 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed, 1120 e_is_proxy, control); 1121 1122 // If we need an access check or the object is a Proxy, make a runtime call 1123 // to finish the lowering. 1124 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode( 1125 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(), 1126 prototype, context, frame_state, effect, control); 1127 1128 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy); 1129 1130 Node* object_prototype = effect = graph()->NewNode( 1131 simplified()->LoadField(AccessBuilder::ForMapPrototype()), 1132 loop_object_map, loop_effect, control); 1133 1134 // Check if object prototype is equal to function prototype. 1135 Node* eq_proto = 1136 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()), 1137 object_prototype, prototype); 1138 Node* branch_eq_proto = 1139 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control); 1140 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto); 1141 Node* e_eq_proto = effect; 1142 1143 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto); 1144 1145 // If not, check if object prototype is the null prototype. 1146 Node* null_proto = 1147 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()), 1148 object_prototype, jsgraph()->NullConstant()); 1149 Node* branch_null_proto = graph()->NewNode( 1150 common()->Branch(BranchHint::kFalse), null_proto, control); 1151 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto); 1152 Node* e_null_proto = effect; 1153 1154 control = graph()->NewNode(common()->IfFalse(), branch_null_proto); 1155 Node* load_object_map = effect = 1156 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 1157 object_prototype, effect, control); 1158 // Close the loop. 1159 loop_effect->ReplaceInput(1, effect); 1160 loop_object_map->ReplaceInput(1, load_object_map); 1161 loop->ReplaceInput(1, control); 1162 1163 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain, 1164 if_eq_proto, if_null_proto); 1165 effect = graph()->NewNode(common()->EffectPhi(3), 1166 bool_result_runtime_has_in_proto_chain_case, 1167 e_eq_proto, e_null_proto, control); 1168 1169 Node* result = graph()->NewNode( 1170 common()->Phi(MachineRepresentation::kTagged, 3), 1171 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(), 1172 jsgraph()->FalseConstant(), control); 1173 1174 if (if_is_smi != nullptr) { 1175 DCHECK_NOT_NULL(e_is_smi); 1176 control = graph()->NewNode(common()->Merge(2), if_is_smi, control); 1177 effect = 1178 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control); 1179 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1180 jsgraph()->FalseConstant(), result, control); 1181 } 1182 1183 ReplaceWithValue(node, result, effect, control); 1184 return Changed(result); 1185} 1186 1187 1188Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { 1189 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); 1190 ContextAccess const& access = ContextAccessOf(node->op()); 1191 Node* effect = NodeProperties::GetEffectInput(node); 1192 Node* control = graph()->start(); 1193 for (size_t i = 0; i < access.depth(); ++i) { 1194 Node* previous = effect = graph()->NewNode( 1195 simplified()->LoadField( 1196 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)), 1197 NodeProperties::GetValueInput(node, 0), effect, control); 1198 node->ReplaceInput(0, previous); 1199 } 1200 node->ReplaceInput(1, effect); 1201 node->ReplaceInput(2, control); 1202 NodeProperties::ChangeOp( 1203 node, 1204 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index()))); 1205 return Changed(node); 1206} 1207 1208 1209Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { 1210 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); 1211 ContextAccess const& access = ContextAccessOf(node->op()); 1212 Node* effect = NodeProperties::GetEffectInput(node); 1213 Node* control = graph()->start(); 1214 for (size_t i = 0; i < access.depth(); ++i) { 1215 Node* previous = effect = graph()->NewNode( 1216 simplified()->LoadField( 1217 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)), 1218 NodeProperties::GetValueInput(node, 0), effect, control); 1219 node->ReplaceInput(0, previous); 1220 } 1221 node->RemoveInput(2); 1222 node->ReplaceInput(2, effect); 1223 NodeProperties::ChangeOp( 1224 node, 1225 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index()))); 1226 return Changed(node); 1227} 1228 1229 1230Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { 1231 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode()); 1232 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op()); 1233 Node* receiver = NodeProperties::GetValueInput(node, 0); 1234 Type* receiver_type = NodeProperties::GetType(receiver); 1235 Node* context = NodeProperties::GetContextInput(node); 1236 Type* context_type = NodeProperties::GetType(context); 1237 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 1238 Node* effect = NodeProperties::GetEffectInput(node); 1239 Node* control = NodeProperties::GetControlInput(node); 1240 if (!receiver_type->Is(Type::Receiver())) { 1241 if (receiver_type->Is(Type::NullOrUndefined()) || 1242 mode == ConvertReceiverMode::kNullOrUndefined) { 1243 if (context_type->IsConstant()) { 1244 Handle<JSObject> global_proxy( 1245 Handle<Context>::cast(context_type->AsConstant()->Value()) 1246 ->global_proxy(), 1247 isolate()); 1248 receiver = jsgraph()->Constant(global_proxy); 1249 } else { 1250 Node* native_context = effect = graph()->NewNode( 1251 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1252 context, context, effect); 1253 receiver = effect = graph()->NewNode( 1254 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), 1255 native_context, native_context, effect); 1256 } 1257 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) || 1258 mode == ConvertReceiverMode::kNotNullOrUndefined) { 1259 receiver = effect = 1260 graph()->NewNode(javascript()->ToObject(), receiver, context, 1261 frame_state, effect, control); 1262 } else { 1263 // Check {receiver} for undefined. 1264 Node* check0 = 1265 graph()->NewNode(simplified()->ReferenceEqual(receiver_type), 1266 receiver, jsgraph()->UndefinedConstant()); 1267 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1268 check0, control); 1269 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1270 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1271 1272 // Check {receiver} for null. 1273 Node* check1 = 1274 graph()->NewNode(simplified()->ReferenceEqual(receiver_type), 1275 receiver, jsgraph()->NullConstant()); 1276 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1277 check1, if_false0); 1278 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1279 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1280 1281 // Convert {receiver} using ToObject. 1282 Node* if_convert = if_false1; 1283 Node* econvert = effect; 1284 Node* rconvert; 1285 { 1286 rconvert = econvert = 1287 graph()->NewNode(javascript()->ToObject(), receiver, context, 1288 frame_state, econvert, if_convert); 1289 } 1290 1291 // Replace {receiver} with global proxy of {context}. 1292 Node* if_global = 1293 graph()->NewNode(common()->Merge(2), if_true0, if_true1); 1294 Node* eglobal = effect; 1295 Node* rglobal; 1296 { 1297 if (context_type->IsConstant()) { 1298 Handle<JSObject> global_proxy( 1299 Handle<Context>::cast(context_type->AsConstant()->Value()) 1300 ->global_proxy(), 1301 isolate()); 1302 rglobal = jsgraph()->Constant(global_proxy); 1303 } else { 1304 Node* native_context = eglobal = graph()->NewNode( 1305 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1306 context, context, eglobal); 1307 rglobal = eglobal = graph()->NewNode( 1308 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), 1309 native_context, native_context, eglobal); 1310 } 1311 } 1312 1313 control = graph()->NewNode(common()->Merge(2), if_convert, if_global); 1314 effect = 1315 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control); 1316 receiver = 1317 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1318 rconvert, rglobal, control); 1319 } 1320 } 1321 ReplaceWithValue(node, receiver, effect, control); 1322 return Changed(receiver); 1323} 1324 1325 1326Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) { 1327 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); 1328 CallConstructParameters const& p = CallConstructParametersOf(node->op()); 1329 DCHECK_LE(2u, p.arity()); 1330 int const arity = static_cast<int>(p.arity() - 2); 1331 Node* target = NodeProperties::GetValueInput(node, 0); 1332 Type* target_type = NodeProperties::GetType(target); 1333 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); 1334 1335 // Check if {target} is a known JSFunction. 1336 if (target_type->IsConstant() && 1337 target_type->AsConstant()->Value()->IsJSFunction()) { 1338 Handle<JSFunction> function = 1339 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); 1340 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 1341 1342 // Remove the eager bailout frame state. 1343 NodeProperties::RemoveFrameStateInput(node, 1); 1344 1345 // Patch {node} to an indirect call via the {function}s construct stub. 1346 Callable callable(handle(shared->construct_stub(), isolate()), 1347 ConstructStubDescriptor(isolate())); 1348 node->RemoveInput(arity + 1); 1349 node->InsertInput(graph()->zone(), 0, 1350 jsgraph()->HeapConstant(callable.code())); 1351 node->InsertInput(graph()->zone(), 2, new_target); 1352 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity)); 1353 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 1354 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant()); 1355 NodeProperties::ChangeOp( 1356 node, common()->Call(Linkage::GetStubCallDescriptor( 1357 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 1358 CallDescriptor::kNeedsFrameState))); 1359 return Changed(node); 1360 } 1361 1362 // Check if {target} is a JSFunction. 1363 if (target_type->Is(Type::Function())) { 1364 // Remove the eager bailout frame state. 1365 NodeProperties::RemoveFrameStateInput(node, 1); 1366 1367 // Patch {node} to an indirect call via the ConstructFunction builtin. 1368 Callable callable = CodeFactory::ConstructFunction(isolate()); 1369 node->RemoveInput(arity + 1); 1370 node->InsertInput(graph()->zone(), 0, 1371 jsgraph()->HeapConstant(callable.code())); 1372 node->InsertInput(graph()->zone(), 2, new_target); 1373 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity)); 1374 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 1375 NodeProperties::ChangeOp( 1376 node, common()->Call(Linkage::GetStubCallDescriptor( 1377 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 1378 CallDescriptor::kNeedsFrameState))); 1379 return Changed(node); 1380 } 1381 1382 return NoChange(); 1383} 1384 1385 1386Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { 1387 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); 1388 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); 1389 int const arity = static_cast<int>(p.arity() - 2); 1390 ConvertReceiverMode convert_mode = p.convert_mode(); 1391 Node* target = NodeProperties::GetValueInput(node, 0); 1392 Type* target_type = NodeProperties::GetType(target); 1393 Node* receiver = NodeProperties::GetValueInput(node, 1); 1394 Type* receiver_type = NodeProperties::GetType(receiver); 1395 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 1396 Node* effect = NodeProperties::GetEffectInput(node); 1397 Node* control = NodeProperties::GetControlInput(node); 1398 1399 // Try to infer receiver {convert_mode} from {receiver} type. 1400 if (receiver_type->Is(Type::NullOrUndefined())) { 1401 convert_mode = ConvertReceiverMode::kNullOrUndefined; 1402 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) { 1403 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; 1404 } 1405 1406 // Check if {target} is a known JSFunction. 1407 if (target_type->IsConstant() && 1408 target_type->AsConstant()->Value()->IsJSFunction()) { 1409 Handle<JSFunction> function = 1410 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); 1411 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 1412 1413 // Class constructors are callable, but [[Call]] will raise an exception. 1414 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 1415 if (IsClassConstructor(shared->kind())) return NoChange(); 1416 1417 // Load the context from the {target}. 1418 Node* context = effect = graph()->NewNode( 1419 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target, 1420 effect, control); 1421 NodeProperties::ReplaceContextInput(node, context); 1422 1423 // Check if we need to convert the {receiver}. 1424 if (is_sloppy(shared->language_mode()) && !shared->native() && 1425 !receiver_type->Is(Type::Receiver())) { 1426 receiver = effect = 1427 graph()->NewNode(javascript()->ConvertReceiver(convert_mode), 1428 receiver, context, frame_state, effect, control); 1429 NodeProperties::ReplaceValueInput(node, receiver, 1); 1430 } 1431 1432 // Update the effect dependency for the {node}. 1433 NodeProperties::ReplaceEffectInput(node, effect); 1434 1435 // Remove the eager bailout frame state. 1436 NodeProperties::RemoveFrameStateInput(node, 1); 1437 1438 // Compute flags for the call. 1439 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 1440 if (p.tail_call_mode() == TailCallMode::kAllow) { 1441 flags |= CallDescriptor::kSupportsTailCalls; 1442 } 1443 1444 Node* new_target = jsgraph()->UndefinedConstant(); 1445 Node* argument_count = jsgraph()->Int32Constant(arity); 1446 if (shared->internal_formal_parameter_count() == arity || 1447 shared->internal_formal_parameter_count() == 1448 SharedFunctionInfo::kDontAdaptArgumentsSentinel) { 1449 // Patch {node} to a direct call. 1450 node->InsertInput(graph()->zone(), arity + 2, new_target); 1451 node->InsertInput(graph()->zone(), arity + 3, argument_count); 1452 NodeProperties::ChangeOp(node, 1453 common()->Call(Linkage::GetJSCallDescriptor( 1454 graph()->zone(), false, 1 + arity, flags))); 1455 } else { 1456 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline. 1457 Callable callable = CodeFactory::ArgumentAdaptor(isolate()); 1458 node->InsertInput(graph()->zone(), 0, 1459 jsgraph()->HeapConstant(callable.code())); 1460 node->InsertInput(graph()->zone(), 2, new_target); 1461 node->InsertInput(graph()->zone(), 3, argument_count); 1462 node->InsertInput( 1463 graph()->zone(), 4, 1464 jsgraph()->Int32Constant(shared->internal_formal_parameter_count())); 1465 NodeProperties::ChangeOp( 1466 node, common()->Call(Linkage::GetStubCallDescriptor( 1467 isolate(), graph()->zone(), callable.descriptor(), 1468 1 + arity, flags))); 1469 } 1470 return Changed(node); 1471 } 1472 1473 // Check if {target} is a JSFunction. 1474 if (target_type->Is(Type::Function())) { 1475 // Remove the eager bailout frame state. 1476 NodeProperties::RemoveFrameStateInput(node, 1); 1477 1478 // Compute flags for the call. 1479 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 1480 if (p.tail_call_mode() == TailCallMode::kAllow) { 1481 flags |= CallDescriptor::kSupportsTailCalls; 1482 } 1483 1484 // Patch {node} to an indirect call via the CallFunction builtin. 1485 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode); 1486 node->InsertInput(graph()->zone(), 0, 1487 jsgraph()->HeapConstant(callable.code())); 1488 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity)); 1489 NodeProperties::ChangeOp( 1490 node, common()->Call(Linkage::GetStubCallDescriptor( 1491 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 1492 flags))); 1493 return Changed(node); 1494 } 1495 1496 // Maybe we did at least learn something about the {receiver}. 1497 if (p.convert_mode() != convert_mode) { 1498 NodeProperties::ChangeOp( 1499 node, javascript()->CallFunction(p.arity(), p.feedback(), convert_mode, 1500 p.tail_call_mode())); 1501 return Changed(node); 1502 } 1503 1504 return NoChange(); 1505} 1506 1507 1508Reduction JSTypedLowering::ReduceJSForInDone(Node* node) { 1509 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode()); 1510 node->TrimInputCount(2); 1511 NodeProperties::ChangeOp(node, machine()->Word32Equal()); 1512 return Changed(node); 1513} 1514 1515 1516Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { 1517 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode()); 1518 Node* receiver = NodeProperties::GetValueInput(node, 0); 1519 Node* cache_array = NodeProperties::GetValueInput(node, 1); 1520 Node* cache_type = NodeProperties::GetValueInput(node, 2); 1521 Node* index = NodeProperties::GetValueInput(node, 3); 1522 Node* context = NodeProperties::GetContextInput(node); 1523 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 1524 Node* effect = NodeProperties::GetEffectInput(node); 1525 Node* control = NodeProperties::GetControlInput(node); 1526 1527 // Load the next {key} from the {cache_array}. 1528 Node* key = effect = graph()->NewNode( 1529 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), 1530 cache_array, index, effect, control); 1531 1532 // Load the map of the {receiver}. 1533 Node* receiver_map = effect = 1534 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 1535 receiver, effect, control); 1536 1537 // Check if the expected map still matches that of the {receiver}. 1538 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 1539 receiver_map, cache_type); 1540 Node* branch0 = 1541 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 1542 1543 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1544 Node* etrue0; 1545 Node* vtrue0; 1546 { 1547 // Don't need filtering since expected map still matches that of the 1548 // {receiver}. 1549 etrue0 = effect; 1550 vtrue0 = key; 1551 } 1552 1553 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1554 Node* efalse0; 1555 Node* vfalse0; 1556 { 1557 // Filter the {key} to check if it's still a valid property of the 1558 // {receiver} (does the ToName conversion implicitly). 1559 vfalse0 = efalse0 = graph()->NewNode( 1560 javascript()->CallRuntime(Runtime::kForInFilter), receiver, key, 1561 context, frame_state, effect, if_false0); 1562 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0); 1563 } 1564 1565 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 1566 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); 1567 ReplaceWithValue(node, node, effect, control); 1568 node->ReplaceInput(0, vtrue0); 1569 node->ReplaceInput(1, vfalse0); 1570 node->ReplaceInput(2, control); 1571 node->TrimInputCount(3); 1572 NodeProperties::ChangeOp(node, 1573 common()->Phi(MachineRepresentation::kTagged, 2)); 1574 return Changed(node); 1575} 1576 1577 1578Reduction JSTypedLowering::ReduceJSForInStep(Node* node) { 1579 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode()); 1580 node->ReplaceInput(1, jsgraph()->Int32Constant(1)); 1581 NodeProperties::ChangeOp(node, machine()->Int32Add()); 1582 return Changed(node); 1583} 1584 1585 1586Reduction JSTypedLowering::ReduceSelect(Node* node) { 1587 DCHECK_EQ(IrOpcode::kSelect, node->opcode()); 1588 Node* const condition = NodeProperties::GetValueInput(node, 0); 1589 Type* const condition_type = NodeProperties::GetType(condition); 1590 Node* const vtrue = NodeProperties::GetValueInput(node, 1); 1591 Type* const vtrue_type = NodeProperties::GetType(vtrue); 1592 Node* const vfalse = NodeProperties::GetValueInput(node, 2); 1593 Type* const vfalse_type = NodeProperties::GetType(vfalse); 1594 if (condition_type->Is(true_type_)) { 1595 // Select(condition:true, vtrue, vfalse) => vtrue 1596 return Replace(vtrue); 1597 } 1598 if (condition_type->Is(false_type_)) { 1599 // Select(condition:false, vtrue, vfalse) => vfalse 1600 return Replace(vfalse); 1601 } 1602 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) { 1603 // Select(condition, vtrue:true, vfalse:false) => condition 1604 return Replace(condition); 1605 } 1606 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) { 1607 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition) 1608 node->TrimInputCount(1); 1609 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); 1610 return Changed(node); 1611 } 1612 return NoChange(); 1613} 1614 1615 1616Reduction JSTypedLowering::Reduce(Node* node) { 1617 // Check if the output type is a singleton. In that case we already know the 1618 // result value and can simply replace the node if it's eliminable. 1619 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) && 1620 node->op()->HasProperty(Operator::kEliminatable)) { 1621 Type* upper = NodeProperties::GetType(node); 1622 if (upper->IsConstant()) { 1623 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); 1624 ReplaceWithValue(node, replacement); 1625 return Changed(replacement); 1626 } else if (upper->Is(Type::MinusZero())) { 1627 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value()); 1628 ReplaceWithValue(node, replacement); 1629 return Changed(replacement); 1630 } else if (upper->Is(Type::NaN())) { 1631 Node* replacement = jsgraph()->NaNConstant(); 1632 ReplaceWithValue(node, replacement); 1633 return Changed(replacement); 1634 } else if (upper->Is(Type::Null())) { 1635 Node* replacement = jsgraph()->NullConstant(); 1636 ReplaceWithValue(node, replacement); 1637 return Changed(replacement); 1638 } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) { 1639 Node* replacement = jsgraph()->Constant(upper->Min()); 1640 ReplaceWithValue(node, replacement); 1641 return Changed(replacement); 1642 } else if (upper->Is(Type::Undefined())) { 1643 Node* replacement = jsgraph()->UndefinedConstant(); 1644 ReplaceWithValue(node, replacement); 1645 return Changed(replacement); 1646 } 1647 } 1648 switch (node->opcode()) { 1649 case IrOpcode::kJSEqual: 1650 return ReduceJSEqual(node, false); 1651 case IrOpcode::kJSNotEqual: 1652 return ReduceJSEqual(node, true); 1653 case IrOpcode::kJSStrictEqual: 1654 return ReduceJSStrictEqual(node, false); 1655 case IrOpcode::kJSStrictNotEqual: 1656 return ReduceJSStrictEqual(node, true); 1657 case IrOpcode::kJSLessThan: // fall through 1658 case IrOpcode::kJSGreaterThan: // fall through 1659 case IrOpcode::kJSLessThanOrEqual: // fall through 1660 case IrOpcode::kJSGreaterThanOrEqual: 1661 return ReduceJSComparison(node); 1662 case IrOpcode::kJSBitwiseOr: 1663 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr()); 1664 case IrOpcode::kJSBitwiseXor: 1665 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor()); 1666 case IrOpcode::kJSBitwiseAnd: 1667 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd()); 1668 case IrOpcode::kJSShiftLeft: 1669 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft()); 1670 case IrOpcode::kJSShiftRight: 1671 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight()); 1672 case IrOpcode::kJSShiftRightLogical: 1673 return ReduceUI32Shift(node, kUnsigned, 1674 simplified()->NumberShiftRightLogical()); 1675 case IrOpcode::kJSAdd: 1676 return ReduceJSAdd(node); 1677 case IrOpcode::kJSSubtract: 1678 return ReduceNumberBinop(node, simplified()->NumberSubtract()); 1679 case IrOpcode::kJSMultiply: 1680 return ReduceNumberBinop(node, simplified()->NumberMultiply()); 1681 case IrOpcode::kJSDivide: 1682 return ReduceNumberBinop(node, simplified()->NumberDivide()); 1683 case IrOpcode::kJSModulus: 1684 return ReduceJSModulus(node); 1685 case IrOpcode::kJSToBoolean: 1686 return ReduceJSToBoolean(node); 1687 case IrOpcode::kJSToNumber: 1688 return ReduceJSToNumber(node); 1689 case IrOpcode::kJSToString: 1690 return ReduceJSToString(node); 1691 case IrOpcode::kJSToObject: 1692 return ReduceJSToObject(node); 1693 case IrOpcode::kJSLoadNamed: 1694 return ReduceJSLoadNamed(node); 1695 case IrOpcode::kJSLoadProperty: 1696 return ReduceJSLoadProperty(node); 1697 case IrOpcode::kJSStoreProperty: 1698 return ReduceJSStoreProperty(node); 1699 case IrOpcode::kJSInstanceOf: 1700 return ReduceJSInstanceOf(node); 1701 case IrOpcode::kJSLoadContext: 1702 return ReduceJSLoadContext(node); 1703 case IrOpcode::kJSStoreContext: 1704 return ReduceJSStoreContext(node); 1705 case IrOpcode::kJSConvertReceiver: 1706 return ReduceJSConvertReceiver(node); 1707 case IrOpcode::kJSCallConstruct: 1708 return ReduceJSCallConstruct(node); 1709 case IrOpcode::kJSCallFunction: 1710 return ReduceJSCallFunction(node); 1711 case IrOpcode::kJSForInDone: 1712 return ReduceJSForInDone(node); 1713 case IrOpcode::kJSForInNext: 1714 return ReduceJSForInNext(node); 1715 case IrOpcode::kJSForInStep: 1716 return ReduceJSForInStep(node); 1717 case IrOpcode::kSelect: 1718 return ReduceSelect(node); 1719 default: 1720 break; 1721 } 1722 return NoChange(); 1723} 1724 1725 1726Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { 1727 if (rhs == 0) return lhs; 1728 return graph()->NewNode(machine()->Word32Shl(), lhs, 1729 jsgraph()->Int32Constant(rhs)); 1730} 1731 1732 1733Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } 1734 1735 1736Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); } 1737 1738 1739Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); } 1740 1741 1742JSOperatorBuilder* JSTypedLowering::javascript() const { 1743 return jsgraph()->javascript(); 1744} 1745 1746 1747CommonOperatorBuilder* JSTypedLowering::common() const { 1748 return jsgraph()->common(); 1749} 1750 1751 1752SimplifiedOperatorBuilder* JSTypedLowering::simplified() const { 1753 return jsgraph()->simplified(); 1754} 1755 1756 1757MachineOperatorBuilder* JSTypedLowering::machine() const { 1758 return jsgraph()->machine(); 1759} 1760 1761 1762CompilationDependencies* JSTypedLowering::dependencies() const { 1763 return dependencies_; 1764} 1765 1766} // namespace compiler 1767} // namespace internal 1768} // namespace v8 1769