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/compiler/state-values-utils.h" 15 #include "src/type-cache.h" 16 #include "src/types.h" 17 18 namespace v8 { 19 namespace internal { 20 namespace compiler { 21 22 namespace { 23 24 // A helper class to construct inline allocations on the simplified operator 25 // level. This keeps track of the effect chain for initial stores on a newly 26 // allocated object and also provides helpers for commonly allocated objects. 27 class AllocationBuilder final { 28 public: 29 AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control) 30 : jsgraph_(jsgraph), 31 allocation_(nullptr), 32 effect_(effect), 33 control_(control) {} 34 35 // Primitive allocation of static size. 36 void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) { 37 effect_ = graph()->NewNode(common()->BeginRegion(), effect_); 38 allocation_ = 39 graph()->NewNode(simplified()->Allocate(pretenure), 40 jsgraph()->Constant(size), effect_, control_); 41 effect_ = allocation_; 42 } 43 44 // Primitive store into a field. 45 void Store(const FieldAccess& access, Node* value) { 46 effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_, 47 value, effect_, control_); 48 } 49 50 // Primitive store into an element. 51 void Store(ElementAccess const& access, Node* index, Node* value) { 52 effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_, 53 index, value, effect_, control_); 54 } 55 56 // Compound allocation of a FixedArray. 57 void AllocateArray(int length, Handle<Map> map, 58 PretenureFlag pretenure = NOT_TENURED) { 59 DCHECK(map->instance_type() == FIXED_ARRAY_TYPE || 60 map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE); 61 int size = (map->instance_type() == FIXED_ARRAY_TYPE) 62 ? FixedArray::SizeFor(length) 63 : FixedDoubleArray::SizeFor(length); 64 Allocate(size, pretenure); 65 Store(AccessBuilder::ForMap(), map); 66 Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length)); 67 } 68 69 // Compound store of a constant into a field. 70 void Store(const FieldAccess& access, Handle<Object> value) { 71 Store(access, jsgraph()->Constant(value)); 72 } 73 74 void FinishAndChange(Node* node) { 75 NodeProperties::SetType(allocation_, NodeProperties::GetType(node)); 76 node->ReplaceInput(0, allocation_); 77 node->ReplaceInput(1, effect_); 78 node->TrimInputCount(2); 79 NodeProperties::ChangeOp(node, common()->FinishRegion()); 80 } 81 82 Node* Finish() { 83 return graph()->NewNode(common()->FinishRegion(), allocation_, effect_); 84 } 85 86 protected: 87 JSGraph* jsgraph() { return jsgraph_; } 88 Graph* graph() { return jsgraph_->graph(); } 89 CommonOperatorBuilder* common() { return jsgraph_->common(); } 90 SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); } 91 92 private: 93 JSGraph* const jsgraph_; 94 Node* allocation_; 95 Node* effect_; 96 Node* control_; 97 }; 98 99 } // namespace 100 101 102 // A helper class to simplify the process of reducing a single binop node with a 103 // JSOperator. This class manages the rewriting of context, control, and effect 104 // dependencies during lowering of a binop and contains numerous helper 105 // functions for matching the types of inputs to an operation. 106 class JSBinopReduction final { 107 public: 108 JSBinopReduction(JSTypedLowering* lowering, Node* node) 109 : lowering_(lowering), node_(node) {} 110 111 void ConvertInputsToNumber(Node* frame_state) { 112 // To convert the inputs to numbers, we have to provide frame states 113 // for lazy bailouts in the ToNumber conversions. 114 // We use a little hack here: we take the frame state before the binary 115 // operation and use it to construct the frame states for the conversion 116 // so that after the deoptimization, the binary operation IC gets 117 // already converted values from full code. This way we are sure that we 118 // will not re-do any of the side effects. 119 120 Node* left_input = nullptr; 121 Node* right_input = nullptr; 122 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive()); 123 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive()); 124 bool handles_exception = NodeProperties::IsExceptionalCall(node_); 125 126 if (!left_is_primitive && !right_is_primitive && handles_exception) { 127 ConvertBothInputsToNumber(&left_input, &right_input, frame_state); 128 } else { 129 left_input = left_is_primitive 130 ? ConvertPlainPrimitiveToNumber(left()) 131 : ConvertSingleInputToNumber( 132 left(), CreateFrameStateForLeftInput(frame_state)); 133 right_input = right_is_primitive 134 ? ConvertPlainPrimitiveToNumber(right()) 135 : ConvertSingleInputToNumber( 136 right(), CreateFrameStateForRightInput( 137 frame_state, left_input)); 138 } 139 140 node_->ReplaceInput(0, left_input); 141 node_->ReplaceInput(1, right_input); 142 } 143 144 void ConvertInputsToUI32(Signedness left_signedness, 145 Signedness right_signedness) { 146 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); 147 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); 148 } 149 150 void SwapInputs() { 151 Node* l = left(); 152 Node* r = right(); 153 node_->ReplaceInput(0, r); 154 node_->ReplaceInput(1, l); 155 } 156 157 // Remove all effect and control inputs and outputs to this node and change 158 // to the pure operator {op}, possibly inserting a boolean inversion. 159 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, 160 Type* type = Type::Any()) { 161 DCHECK_EQ(0, op->EffectInputCount()); 162 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 163 DCHECK_EQ(0, op->ControlInputCount()); 164 DCHECK_EQ(2, op->ValueInputCount()); 165 166 // Remove the effects from the node, and update its effect/control usages. 167 if (node_->op()->EffectInputCount() > 0) { 168 lowering_->RelaxEffectsAndControls(node_); 169 } 170 // Remove the inputs corresponding to context, effect, and control. 171 NodeProperties::RemoveNonValueInputs(node_); 172 // Finally, update the operator to the new one. 173 NodeProperties::ChangeOp(node_, op); 174 175 // TODO(jarin): Replace the explicit typing hack with a call to some method 176 // that encapsulates changing the operator and re-typing. 177 Type* node_type = NodeProperties::GetType(node_); 178 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone())); 179 180 if (invert) { 181 // Insert an boolean not to invert the value. 182 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 183 node_->ReplaceUses(value); 184 // Note: ReplaceUses() smashes all uses, so smash it back here. 185 value->ReplaceInput(0, node_); 186 return lowering_->Replace(value); 187 } 188 return lowering_->Changed(node_); 189 } 190 191 Reduction ChangeToStringComparisonOperator(const Operator* op, 192 bool invert = false) { 193 if (node_->op()->ControlInputCount() > 0) { 194 lowering_->RelaxControls(node_); 195 } 196 // String comparison operators need effect and control inputs, so copy them 197 // over. 198 Node* effect = NodeProperties::GetEffectInput(node_); 199 Node* control = NodeProperties::GetControlInput(node_); 200 node_->ReplaceInput(2, effect); 201 node_->ReplaceInput(3, control); 202 203 node_->TrimInputCount(4); 204 NodeProperties::ChangeOp(node_, op); 205 206 if (invert) { 207 // Insert a boolean-not to invert the value. 208 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 209 node_->ReplaceUses(value); 210 // Note: ReplaceUses() smashes all uses, so smash it back here. 211 value->ReplaceInput(0, node_); 212 return lowering_->Replace(value); 213 } 214 return lowering_->Changed(node_); 215 } 216 217 Reduction ChangeToPureOperator(const Operator* op, Type* type) { 218 return ChangeToPureOperator(op, false, type); 219 } 220 221 // TODO(turbofan): Strong mode should be killed soonish! 222 bool IsStrong() const { 223 if (node_->opcode() == IrOpcode::kJSLessThan || 224 node_->opcode() == IrOpcode::kJSLessThanOrEqual || 225 node_->opcode() == IrOpcode::kJSGreaterThan || 226 node_->opcode() == IrOpcode::kJSGreaterThanOrEqual) { 227 return is_strong(OpParameter<LanguageMode>(node_)); 228 } 229 return is_strong(BinaryOperationParametersOf(node_->op()).language_mode()); 230 } 231 232 bool LeftInputIs(Type* t) { return left_type()->Is(t); } 233 234 bool RightInputIs(Type* t) { return right_type()->Is(t); } 235 236 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } 237 238 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); } 239 240 bool OneInputCannotBe(Type* t) { 241 return !left_type()->Maybe(t) || !right_type()->Maybe(t); 242 } 243 244 bool NeitherInputCanBe(Type* t) { 245 return !left_type()->Maybe(t) && !right_type()->Maybe(t); 246 } 247 248 Node* effect() { return NodeProperties::GetEffectInput(node_); } 249 Node* control() { return NodeProperties::GetControlInput(node_); } 250 Node* context() { return NodeProperties::GetContextInput(node_); } 251 Node* left() { return NodeProperties::GetValueInput(node_, 0); } 252 Node* right() { return NodeProperties::GetValueInput(node_, 1); } 253 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); } 254 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); } 255 256 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } 257 Graph* graph() const { return lowering_->graph(); } 258 JSGraph* jsgraph() { return lowering_->jsgraph(); } 259 JSOperatorBuilder* javascript() { return lowering_->javascript(); } 260 MachineOperatorBuilder* machine() { return lowering_->machine(); } 261 CommonOperatorBuilder* common() { return jsgraph()->common(); } 262 Zone* zone() const { return graph()->zone(); } 263 264 private: 265 JSTypedLowering* lowering_; // The containing lowering instance. 266 Node* node_; // The original node. 267 268 Node* CreateFrameStateForLeftInput(Node* frame_state) { 269 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 270 271 if (state_info.bailout_id() == BailoutId::None()) { 272 // Dummy frame state => just leave it as is. 273 return frame_state; 274 } 275 276 // If the frame state is already the right one, just return it. 277 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt && 278 state_info.state_combine().GetOffsetToPokeAt() == 1) { 279 return frame_state; 280 } 281 282 // Here, we smash the result of the conversion into the slot just below 283 // the stack top. This is the slot that full code uses to store the 284 // left operand. 285 const Operator* op = jsgraph()->common()->FrameState( 286 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(1), 287 state_info.function_info()); 288 289 return graph()->NewNode(op, 290 frame_state->InputAt(kFrameStateParametersInput), 291 frame_state->InputAt(kFrameStateLocalsInput), 292 frame_state->InputAt(kFrameStateStackInput), 293 frame_state->InputAt(kFrameStateContextInput), 294 frame_state->InputAt(kFrameStateFunctionInput), 295 frame_state->InputAt(kFrameStateOuterStateInput)); 296 } 297 298 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) { 299 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 300 301 if (state_info.bailout_id() == BailoutId::None()) { 302 // Dummy frame state => just leave it as is. 303 return frame_state; 304 } 305 306 // Create a frame state that stores the result of the operation to the 307 // top of the stack (i.e., the slot used for the right operand). 308 const Operator* op = jsgraph()->common()->FrameState( 309 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(0), 310 state_info.function_info()); 311 312 // Change the left operand {converted_left} on the expression stack. 313 Node* stack = frame_state->InputAt(2); 314 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues); 315 DCHECK_GE(stack->InputCount(), 2); 316 317 // TODO(jarin) Allocate in a local zone or a reusable buffer. 318 NodeVector new_values(stack->InputCount(), zone()); 319 for (int i = 0; i < stack->InputCount(); i++) { 320 if (i == stack->InputCount() - 2) { 321 new_values[i] = converted_left; 322 } else { 323 new_values[i] = stack->InputAt(i); 324 } 325 } 326 Node* new_stack = 327 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front()); 328 329 return graph()->NewNode( 330 op, frame_state->InputAt(kFrameStateParametersInput), 331 frame_state->InputAt(kFrameStateLocalsInput), new_stack, 332 frame_state->InputAt(kFrameStateContextInput), 333 frame_state->InputAt(kFrameStateFunctionInput), 334 frame_state->InputAt(kFrameStateOuterStateInput)); 335 } 336 337 Node* ConvertPlainPrimitiveToNumber(Node* node) { 338 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); 339 // Avoid inserting too many eager ToNumber() operations. 340 Reduction const reduction = lowering_->ReduceJSToNumberInput(node); 341 if (reduction.Changed()) return reduction.replacement(); 342 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. 343 return graph()->NewNode( 344 javascript()->ToNumber(), node, jsgraph()->NoContextConstant(), 345 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); 346 } 347 348 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) { 349 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive())); 350 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(), 351 frame_state, effect(), control()); 352 NodeProperties::ReplaceUses(node_, node_, node_, n, n); 353 update_effect(n); 354 return n; 355 } 356 357 void ConvertBothInputsToNumber(Node** left_result, Node** right_result, 358 Node* frame_state) { 359 Node* projections[2]; 360 361 // Find {IfSuccess} and {IfException} continuations of the operation. 362 NodeProperties::CollectControlProjections(node_, projections, 2); 363 IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]); 364 Node* if_exception = projections[1]; 365 Node* if_success = projections[0]; 366 367 // Insert two ToNumber() operations that both potentially throw. 368 Node* left_state = CreateFrameStateForLeftInput(frame_state); 369 Node* left_conv = 370 graph()->NewNode(javascript()->ToNumber(), left(), context(), 371 left_state, effect(), control()); 372 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv); 373 Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv); 374 Node* right_conv = 375 graph()->NewNode(javascript()->ToNumber(), right(), context(), 376 right_state, left_conv, left_success); 377 Node* left_exception = 378 graph()->NewNode(common()->IfException(hint), left_conv, left_conv); 379 Node* right_exception = 380 graph()->NewNode(common()->IfException(hint), right_conv, right_conv); 381 NodeProperties::ReplaceControlInput(if_success, right_conv); 382 update_effect(right_conv); 383 384 // Wire conversions to existing {IfException} continuation. 385 Node* exception_merge = if_exception; 386 Node* exception_value = 387 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 388 left_exception, right_exception, exception_merge); 389 Node* exception_effect = 390 graph()->NewNode(common()->EffectPhi(2), left_exception, 391 right_exception, exception_merge); 392 for (Edge edge : exception_merge->use_edges()) { 393 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect); 394 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value); 395 } 396 NodeProperties::RemoveType(exception_merge); 397 exception_merge->ReplaceInput(0, left_exception); 398 exception_merge->ReplaceInput(1, right_exception); 399 NodeProperties::ChangeOp(exception_merge, common()->Merge(2)); 400 401 *left_result = left_conv; 402 *right_result = right_conv; 403 } 404 405 Node* ConvertToUI32(Node* node, Signedness signedness) { 406 // Avoid introducing too many eager NumberToXXnt32() operations. 407 Type* type = NodeProperties::GetType(node); 408 if (signedness == kSigned) { 409 if (!type->Is(Type::Signed32())) { 410 node = graph()->NewNode(simplified()->NumberToInt32(), node); 411 } 412 } else { 413 DCHECK_EQ(kUnsigned, signedness); 414 if (!type->Is(Type::Unsigned32())) { 415 node = graph()->NewNode(simplified()->NumberToUint32(), node); 416 } 417 } 418 return node; 419 } 420 421 void update_effect(Node* effect) { 422 NodeProperties::ReplaceEffectInput(node_, effect); 423 } 424 }; 425 426 427 // TODO(turbofan): js-typed-lowering improvements possible 428 // - immediately put in type bounds for all new nodes 429 // - relax effects from generic but not-side-effecting operations 430 431 432 JSTypedLowering::JSTypedLowering(Editor* editor, 433 CompilationDependencies* dependencies, 434 Flags flags, JSGraph* jsgraph, Zone* zone) 435 : AdvancedReducer(editor), 436 dependencies_(dependencies), 437 flags_(flags), 438 jsgraph_(jsgraph), 439 true_type_(Type::Constant(factory()->true_value(), graph()->zone())), 440 false_type_(Type::Constant(factory()->false_value(), graph()->zone())), 441 the_hole_type_( 442 Type::Constant(factory()->the_hole_value(), graph()->zone())), 443 type_cache_(TypeCache::Get()) { 444 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { 445 double min = kMinInt / (1 << k); 446 double max = kMaxInt / (1 << k); 447 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); 448 } 449 } 450 451 452 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { 453 if (flags() & kDisableBinaryOpReduction) return NoChange(); 454 455 JSBinopReduction r(this, node); 456 if (r.BothInputsAre(Type::Number())) { 457 // JSAdd(x:number, y:number) => NumberAdd(x, y) 458 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 459 } 460 if (r.NeitherInputCanBe(Type::StringOrReceiver()) && !r.IsStrong()) { 461 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 462 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 463 r.ConvertInputsToNumber(frame_state); 464 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 465 } 466 if (r.BothInputsAre(Type::String())) { 467 // JSAdd(x:string, y:string) => CallStub[StringAdd](x, y) 468 Callable const callable = 469 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); 470 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 471 isolate(), graph()->zone(), callable.descriptor(), 0, 472 CallDescriptor::kNeedsFrameState, node->op()->properties()); 473 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op())); 474 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1); 475 node->InsertInput(graph()->zone(), 0, 476 jsgraph()->HeapConstant(callable.code())); 477 NodeProperties::ChangeOp(node, common()->Call(desc)); 478 return Changed(node); 479 } 480 return NoChange(); 481 } 482 483 484 Reduction JSTypedLowering::ReduceJSModulus(Node* node) { 485 if (flags() & kDisableBinaryOpReduction) return NoChange(); 486 487 JSBinopReduction r(this, node); 488 if (r.BothInputsAre(Type::Number())) { 489 // JSModulus(x:number, x:number) => NumberModulus(x, y) 490 return r.ChangeToPureOperator(simplified()->NumberModulus(), 491 Type::Number()); 492 } 493 return NoChange(); 494 } 495 496 497 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, 498 const Operator* numberOp) { 499 if (flags() & kDisableBinaryOpReduction) return NoChange(); 500 501 JSBinopReduction r(this, node); 502 if (r.IsStrong() || numberOp == simplified()->NumberModulus()) { 503 if (r.BothInputsAre(Type::Number())) { 504 return r.ChangeToPureOperator(numberOp, Type::Number()); 505 } 506 return NoChange(); 507 } 508 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 509 r.ConvertInputsToNumber(frame_state); 510 return r.ChangeToPureOperator(numberOp, Type::Number()); 511 } 512 513 514 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { 515 if (flags() & kDisableBinaryOpReduction) return NoChange(); 516 517 JSBinopReduction r(this, node); 518 if (r.IsStrong()) { 519 if (r.BothInputsAre(Type::Number())) { 520 r.ConvertInputsToUI32(kSigned, kSigned); 521 return r.ChangeToPureOperator(intOp, Type::Integral32()); 522 } 523 return NoChange(); 524 } 525 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 526 r.ConvertInputsToNumber(frame_state); 527 r.ConvertInputsToUI32(kSigned, kSigned); 528 return r.ChangeToPureOperator(intOp, Type::Integral32()); 529 } 530 531 532 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, 533 Signedness left_signedness, 534 const Operator* shift_op) { 535 if (flags() & kDisableBinaryOpReduction) return NoChange(); 536 537 JSBinopReduction r(this, node); 538 if (r.IsStrong()) { 539 if (r.BothInputsAre(Type::Number())) { 540 r.ConvertInputsToUI32(left_signedness, kUnsigned); 541 return r.ChangeToPureOperator(shift_op); 542 } 543 return NoChange(); 544 } 545 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 546 r.ConvertInputsToNumber(frame_state); 547 r.ConvertInputsToUI32(left_signedness, kUnsigned); 548 return r.ChangeToPureOperator(shift_op); 549 } 550 551 552 Reduction JSTypedLowering::ReduceJSComparison(Node* node) { 553 if (flags() & kDisableBinaryOpReduction) return NoChange(); 554 555 JSBinopReduction r(this, node); 556 if (r.BothInputsAre(Type::String())) { 557 // If both inputs are definitely strings, perform a string comparison. 558 const Operator* stringOp; 559 switch (node->opcode()) { 560 case IrOpcode::kJSLessThan: 561 stringOp = simplified()->StringLessThan(); 562 break; 563 case IrOpcode::kJSGreaterThan: 564 stringOp = simplified()->StringLessThan(); 565 r.SwapInputs(); // a > b => b < a 566 break; 567 case IrOpcode::kJSLessThanOrEqual: 568 stringOp = simplified()->StringLessThanOrEqual(); 569 break; 570 case IrOpcode::kJSGreaterThanOrEqual: 571 stringOp = simplified()->StringLessThanOrEqual(); 572 r.SwapInputs(); // a >= b => b <= a 573 break; 574 default: 575 return NoChange(); 576 } 577 r.ChangeToStringComparisonOperator(stringOp); 578 return Changed(node); 579 } 580 if (r.OneInputCannotBe(Type::StringOrReceiver())) { 581 const Operator* less_than; 582 const Operator* less_than_or_equal; 583 if (r.BothInputsAre(Type::Unsigned32())) { 584 less_than = machine()->Uint32LessThan(); 585 less_than_or_equal = machine()->Uint32LessThanOrEqual(); 586 } else if (r.BothInputsAre(Type::Signed32())) { 587 less_than = machine()->Int32LessThan(); 588 less_than_or_equal = machine()->Int32LessThanOrEqual(); 589 } else { 590 // TODO(turbofan): mixed signed/unsigned int32 comparisons. 591 if (r.IsStrong() && !r.BothInputsAre(Type::Number())) { 592 return NoChange(); 593 } 594 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 595 r.ConvertInputsToNumber(frame_state); 596 less_than = simplified()->NumberLessThan(); 597 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 598 } 599 const Operator* comparison; 600 switch (node->opcode()) { 601 case IrOpcode::kJSLessThan: 602 comparison = less_than; 603 break; 604 case IrOpcode::kJSGreaterThan: 605 comparison = less_than; 606 r.SwapInputs(); // a > b => b < a 607 break; 608 case IrOpcode::kJSLessThanOrEqual: 609 comparison = less_than_or_equal; 610 break; 611 case IrOpcode::kJSGreaterThanOrEqual: 612 comparison = less_than_or_equal; 613 r.SwapInputs(); // a >= b => b <= a 614 break; 615 default: 616 return NoChange(); 617 } 618 return r.ChangeToPureOperator(comparison); 619 } 620 // TODO(turbofan): relax/remove effects of this operator in other cases. 621 return NoChange(); // Keep a generic comparison. 622 } 623 624 625 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { 626 if (flags() & kDisableBinaryOpReduction) return NoChange(); 627 628 JSBinopReduction r(this, node); 629 630 if (r.BothInputsAre(Type::Number())) { 631 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 632 } 633 if (r.BothInputsAre(Type::String())) { 634 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(), 635 invert); 636 } 637 if (r.BothInputsAre(Type::Boolean())) { 638 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()), 639 invert); 640 } 641 if (r.BothInputsAre(Type::Receiver())) { 642 return r.ChangeToPureOperator( 643 simplified()->ReferenceEqual(Type::Receiver()), invert); 644 } 645 if (r.OneInputIs(Type::NullOrUndefined())) { 646 Callable const callable = CodeFactory::CompareNilIC(isolate(), kNullValue); 647 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 648 isolate(), graph()->zone(), callable.descriptor(), 0, 649 CallDescriptor::kNeedsFrameState, node->op()->properties()); 650 node->RemoveInput(r.LeftInputIs(Type::NullOrUndefined()) ? 0 : 1); 651 node->InsertInput(graph()->zone(), 0, 652 jsgraph()->HeapConstant(callable.code())); 653 NodeProperties::ChangeOp(node, common()->Call(desc)); 654 if (invert) { 655 // Insert an boolean not to invert the value. 656 Node* value = graph()->NewNode(simplified()->BooleanNot(), node); 657 node->ReplaceUses(value); 658 // Note: ReplaceUses() smashes all uses, so smash it back here. 659 value->ReplaceInput(0, node); 660 return Replace(value); 661 } 662 return Changed(node); 663 } 664 return NoChange(); 665 } 666 667 668 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { 669 if (flags() & kDisableBinaryOpReduction) return NoChange(); 670 671 JSBinopReduction r(this, node); 672 if (r.left() == r.right()) { 673 // x === x is always true if x != NaN 674 if (!r.left_type()->Maybe(Type::NaN())) { 675 Node* replacement = jsgraph()->BooleanConstant(!invert); 676 ReplaceWithValue(node, replacement); 677 return Replace(replacement); 678 } 679 } 680 if (r.OneInputCannotBe(Type::NumberOrString())) { 681 // For values with canonical representation (i.e. not string nor number) an 682 // empty type intersection means the values cannot be strictly equal. 683 if (!r.left_type()->Maybe(r.right_type())) { 684 Node* replacement = jsgraph()->BooleanConstant(invert); 685 ReplaceWithValue(node, replacement); 686 return Replace(replacement); 687 } 688 } 689 if (r.OneInputIs(the_hole_type_)) { 690 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_), 691 invert); 692 } 693 if (r.OneInputIs(Type::Undefined())) { 694 return r.ChangeToPureOperator( 695 simplified()->ReferenceEqual(Type::Undefined()), invert); 696 } 697 if (r.OneInputIs(Type::Null())) { 698 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()), 699 invert); 700 } 701 if (r.OneInputIs(Type::Boolean())) { 702 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()), 703 invert); 704 } 705 if (r.OneInputIs(Type::Object())) { 706 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()), 707 invert); 708 } 709 if (r.OneInputIs(Type::Receiver())) { 710 return r.ChangeToPureOperator( 711 simplified()->ReferenceEqual(Type::Receiver()), invert); 712 } 713 if (r.BothInputsAre(Type::Unique())) { 714 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()), 715 invert); 716 } 717 if (r.BothInputsAre(Type::String())) { 718 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(), 719 invert); 720 } 721 if (r.BothInputsAre(Type::Number())) { 722 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 723 } 724 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types) 725 return NoChange(); 726 } 727 728 729 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { 730 Node* const input = node->InputAt(0); 731 Type* const input_type = NodeProperties::GetType(input); 732 Node* const effect = NodeProperties::GetEffectInput(node); 733 if (input_type->Is(Type::Boolean())) { 734 // JSToBoolean(x:boolean) => x 735 ReplaceWithValue(node, input, effect); 736 return Replace(input); 737 } else if (input_type->Is(Type::OrderedNumber())) { 738 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0)) 739 RelaxEffectsAndControls(node); 740 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input, 741 jsgraph()->ZeroConstant())); 742 node->TrimInputCount(1); 743 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); 744 return Changed(node); 745 } else if (input_type->Is(Type::String())) { 746 // JSToBoolean(x:string) => NumberLessThan(#0,x.length) 747 FieldAccess const access = AccessBuilder::ForStringLength(); 748 Node* length = graph()->NewNode(simplified()->LoadField(access), input, 749 effect, graph()->start()); 750 ReplaceWithValue(node, node, length); 751 node->ReplaceInput(0, jsgraph()->ZeroConstant()); 752 node->ReplaceInput(1, length); 753 node->TrimInputCount(2); 754 NodeProperties::ChangeOp(node, simplified()->NumberLessThan()); 755 return Changed(node); 756 } 757 return NoChange(); 758 } 759 760 761 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { 762 if (input->opcode() == IrOpcode::kJSToNumber) { 763 // Recursively try to reduce the input first. 764 Reduction result = ReduceJSToNumber(input); 765 if (result.Changed()) return result; 766 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) 767 } 768 // Check for ToNumber truncation of signaling NaN to undefined mapping. 769 if (input->opcode() == IrOpcode::kSelect) { 770 Node* check = NodeProperties::GetValueInput(input, 0); 771 Node* vtrue = NodeProperties::GetValueInput(input, 1); 772 Type* vtrue_type = NodeProperties::GetType(vtrue); 773 Node* vfalse = NodeProperties::GetValueInput(input, 2); 774 Type* vfalse_type = NodeProperties::GetType(vfalse); 775 if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) { 776 if (check->opcode() == IrOpcode::kNumberIsHoleNaN && 777 check->InputAt(0) == vfalse) { 778 // JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x 779 return Replace(vfalse); 780 } 781 } 782 } 783 // Check if we have a cached conversion. 784 Type* input_type = NodeProperties::GetType(input); 785 if (input_type->Is(Type::Number())) { 786 // JSToNumber(x:number) => x 787 return Changed(input); 788 } 789 if (input_type->Is(Type::Undefined())) { 790 // JSToNumber(undefined) => #NaN 791 return Replace(jsgraph()->NaNConstant()); 792 } 793 if (input_type->Is(Type::Null())) { 794 // JSToNumber(null) => #0 795 return Replace(jsgraph()->ZeroConstant()); 796 } 797 if (input_type->Is(Type::Boolean())) { 798 // JSToNumber(x:boolean) => BooleanToNumber(x) 799 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input)); 800 } 801 // TODO(turbofan): js-typed-lowering of ToNumber(x:string) 802 return NoChange(); 803 } 804 805 806 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { 807 // Try to reduce the input first. 808 Node* const input = node->InputAt(0); 809 Reduction reduction = ReduceJSToNumberInput(input); 810 if (reduction.Changed()) { 811 ReplaceWithValue(node, reduction.replacement()); 812 return reduction; 813 } 814 Type* const input_type = NodeProperties::GetType(input); 815 if (input_type->Is(Type::PlainPrimitive())) { 816 if (NodeProperties::GetContextInput(node) != 817 jsgraph()->NoContextConstant() || 818 NodeProperties::GetEffectInput(node) != graph()->start() || 819 NodeProperties::GetControlInput(node) != graph()->start()) { 820 // JSToNumber(x:plain-primitive,context,effect,control) 821 // => JSToNumber(x,no-context,start,start) 822 RelaxEffectsAndControls(node); 823 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); 824 NodeProperties::ReplaceControlInput(node, graph()->start()); 825 NodeProperties::ReplaceEffectInput(node, graph()->start()); 826 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 827 NodeProperties::ReplaceFrameStateInput(node, 0, 828 jsgraph()->EmptyFrameState()); 829 return Changed(node); 830 } 831 } 832 return NoChange(); 833 } 834 835 836 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { 837 if (input->opcode() == IrOpcode::kJSToString) { 838 // Recursively try to reduce the input first. 839 Reduction result = ReduceJSToString(input); 840 if (result.Changed()) return result; 841 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) 842 } 843 Type* input_type = NodeProperties::GetType(input); 844 if (input_type->Is(Type::String())) { 845 return Changed(input); // JSToString(x:string) => x 846 } 847 if (input_type->Is(Type::Boolean())) { 848 return Replace(graph()->NewNode( 849 common()->Select(MachineRepresentation::kTagged), input, 850 jsgraph()->HeapConstant(factory()->true_string()), 851 jsgraph()->HeapConstant(factory()->false_string()))); 852 } 853 if (input_type->Is(Type::Undefined())) { 854 return Replace(jsgraph()->HeapConstant(factory()->undefined_string())); 855 } 856 if (input_type->Is(Type::Null())) { 857 return Replace(jsgraph()->HeapConstant(factory()->null_string())); 858 } 859 // TODO(turbofan): js-typed-lowering of ToString(x:number) 860 return NoChange(); 861 } 862 863 864 Reduction JSTypedLowering::ReduceJSToString(Node* node) { 865 // Try to reduce the input first. 866 Node* const input = node->InputAt(0); 867 Reduction reduction = ReduceJSToStringInput(input); 868 if (reduction.Changed()) { 869 ReplaceWithValue(node, reduction.replacement()); 870 return reduction; 871 } 872 return NoChange(); 873 } 874 875 876 Reduction JSTypedLowering::ReduceJSToObject(Node* node) { 877 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode()); 878 Node* receiver = NodeProperties::GetValueInput(node, 0); 879 Type* receiver_type = NodeProperties::GetType(receiver); 880 Node* context = NodeProperties::GetContextInput(node); 881 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 882 Node* effect = NodeProperties::GetEffectInput(node); 883 Node* control = NodeProperties::GetControlInput(node); 884 if (!receiver_type->Is(Type::Receiver())) { 885 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks. 886 if (receiver_type->Maybe(Type::NullOrUndefined()) && 887 NodeProperties::IsExceptionalCall(node)) { 888 // ToObject throws for null or undefined inputs. 889 return NoChange(); 890 } 891 892 // Check whether {receiver} is a Smi. 893 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 894 Node* branch0 = 895 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); 896 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 897 Node* etrue0 = effect; 898 899 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 900 Node* efalse0 = effect; 901 902 // Determine the instance type of {receiver}. 903 Node* receiver_map = efalse0 = 904 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 905 receiver, efalse0, if_false0); 906 Node* receiver_instance_type = efalse0 = graph()->NewNode( 907 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 908 receiver_map, efalse0, if_false0); 909 910 // Check whether {receiver} is a spec object. 911 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 912 Node* check1 = 913 graph()->NewNode(machine()->Uint32LessThanOrEqual(), 914 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE), 915 receiver_instance_type); 916 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 917 check1, if_false0); 918 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 919 Node* etrue1 = efalse0; 920 921 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 922 Node* efalse1 = efalse0; 923 924 // Convert {receiver} using the ToObjectStub. 925 Node* if_convert = 926 graph()->NewNode(common()->Merge(2), if_true0, if_false1); 927 Node* econvert = 928 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert); 929 Node* rconvert; 930 { 931 Callable callable = CodeFactory::ToObject(isolate()); 932 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 933 isolate(), graph()->zone(), callable.descriptor(), 0, 934 CallDescriptor::kNeedsFrameState, node->op()->properties()); 935 rconvert = econvert = graph()->NewNode( 936 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), 937 receiver, context, frame_state, econvert, if_convert); 938 } 939 940 // The {receiver} is already a spec object. 941 Node* if_done = if_true1; 942 Node* edone = etrue1; 943 Node* rdone = receiver; 944 945 control = graph()->NewNode(common()->Merge(2), if_convert, if_done); 946 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control); 947 receiver = 948 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 949 rconvert, rdone, control); 950 } 951 ReplaceWithValue(node, receiver, effect, control); 952 return Changed(receiver); 953 } 954 955 956 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { 957 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); 958 Node* receiver = NodeProperties::GetValueInput(node, 0); 959 Type* receiver_type = NodeProperties::GetType(receiver); 960 Node* effect = NodeProperties::GetEffectInput(node); 961 Node* control = NodeProperties::GetControlInput(node); 962 Handle<Name> name = NamedAccessOf(node->op()).name(); 963 // Optimize "length" property of strings. 964 if (name.is_identical_to(factory()->length_string()) && 965 receiver_type->Is(Type::String())) { 966 Node* value = effect = graph()->NewNode( 967 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 968 effect, control); 969 ReplaceWithValue(node, value, effect); 970 return Replace(value); 971 } 972 // Optimize "prototype" property of functions. 973 if (name.is_identical_to(factory()->prototype_string()) && 974 receiver_type->IsConstant() && 975 receiver_type->AsConstant()->Value()->IsJSFunction()) { 976 // TODO(turbofan): This lowering might not kick in if we ever lower 977 // the C++ accessor for "prototype" in an earlier optimization pass. 978 Handle<JSFunction> function = 979 Handle<JSFunction>::cast(receiver_type->AsConstant()->Value()); 980 if (function->has_initial_map()) { 981 // We need to add a code dependency on the initial map of the {function} 982 // in order to be notified about changes to the "prototype" of {function}, 983 // so it doesn't make sense to continue unless deoptimization is enabled. 984 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 985 Handle<Map> initial_map(function->initial_map(), isolate()); 986 dependencies()->AssumeInitialMapCantChange(initial_map); 987 Node* value = 988 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); 989 ReplaceWithValue(node, value); 990 return Replace(value); 991 } 992 } 993 return NoChange(); 994 } 995 996 997 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { 998 Node* key = NodeProperties::GetValueInput(node, 1); 999 Node* base = NodeProperties::GetValueInput(node, 0); 1000 Type* key_type = NodeProperties::GetType(key); 1001 HeapObjectMatcher mbase(base); 1002 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) { 1003 Handle<JSTypedArray> const array = 1004 Handle<JSTypedArray>::cast(mbase.Value()); 1005 if (!array->GetBuffer()->was_neutered()) { 1006 array->GetBuffer()->set_is_neuterable(false); 1007 BufferAccess const access(array->type()); 1008 size_t const k = 1009 ElementSizeLog2Of(access.machine_type().representation()); 1010 double const byte_length = array->byte_length()->Number(); 1011 CHECK_LT(k, arraysize(shifted_int32_ranges_)); 1012 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { 1013 // JSLoadProperty(typed-array, int32) 1014 Handle<FixedTypedArrayBase> elements = 1015 Handle<FixedTypedArrayBase>::cast(handle(array->elements())); 1016 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); 1017 Node* length = jsgraph()->Constant(byte_length); 1018 Node* effect = NodeProperties::GetEffectInput(node); 1019 Node* control = NodeProperties::GetControlInput(node); 1020 // Check if we can avoid the bounds check. 1021 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) { 1022 Node* load = graph()->NewNode( 1023 simplified()->LoadElement( 1024 AccessBuilder::ForTypedArrayElement(array->type(), true)), 1025 buffer, key, effect, control); 1026 ReplaceWithValue(node, load, load); 1027 return Replace(load); 1028 } 1029 // Compute byte offset. 1030 Node* offset = Word32Shl(key, static_cast<int>(k)); 1031 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer, 1032 offset, length, effect, control); 1033 ReplaceWithValue(node, load, load); 1034 return Replace(load); 1035 } 1036 } 1037 } 1038 return NoChange(); 1039 } 1040 1041 1042 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { 1043 Node* key = NodeProperties::GetValueInput(node, 1); 1044 Node* base = NodeProperties::GetValueInput(node, 0); 1045 Node* value = NodeProperties::GetValueInput(node, 2); 1046 Type* key_type = NodeProperties::GetType(key); 1047 Type* value_type = NodeProperties::GetType(value); 1048 HeapObjectMatcher mbase(base); 1049 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) { 1050 Handle<JSTypedArray> const array = 1051 Handle<JSTypedArray>::cast(mbase.Value()); 1052 if (!array->GetBuffer()->was_neutered()) { 1053 array->GetBuffer()->set_is_neuterable(false); 1054 BufferAccess const access(array->type()); 1055 size_t const k = 1056 ElementSizeLog2Of(access.machine_type().representation()); 1057 double const byte_length = array->byte_length()->Number(); 1058 CHECK_LT(k, arraysize(shifted_int32_ranges_)); 1059 if (access.external_array_type() != kExternalUint8ClampedArray && 1060 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { 1061 // JSLoadProperty(typed-array, int32) 1062 Handle<FixedTypedArrayBase> elements = 1063 Handle<FixedTypedArrayBase>::cast(handle(array->elements())); 1064 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); 1065 Node* length = jsgraph()->Constant(byte_length); 1066 Node* context = NodeProperties::GetContextInput(node); 1067 Node* effect = NodeProperties::GetEffectInput(node); 1068 Node* control = NodeProperties::GetControlInput(node); 1069 // Convert to a number first. 1070 if (!value_type->Is(Type::Number())) { 1071 Reduction number_reduction = ReduceJSToNumberInput(value); 1072 if (number_reduction.Changed()) { 1073 value = number_reduction.replacement(); 1074 } else { 1075 Node* frame_state_for_to_number = 1076 NodeProperties::GetFrameStateInput(node, 1); 1077 value = effect = 1078 graph()->NewNode(javascript()->ToNumber(), value, context, 1079 frame_state_for_to_number, effect, control); 1080 } 1081 } 1082 // Check if we can avoid the bounds check. 1083 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) { 1084 RelaxControls(node); 1085 node->ReplaceInput(0, buffer); 1086 DCHECK_EQ(key, node->InputAt(1)); 1087 node->ReplaceInput(2, value); 1088 node->ReplaceInput(3, effect); 1089 node->ReplaceInput(4, control); 1090 node->TrimInputCount(5); 1091 NodeProperties::ChangeOp( 1092 node, 1093 simplified()->StoreElement( 1094 AccessBuilder::ForTypedArrayElement(array->type(), true))); 1095 return Changed(node); 1096 } 1097 // Compute byte offset. 1098 Node* offset = Word32Shl(key, static_cast<int>(k)); 1099 // Turn into a StoreBuffer operation. 1100 RelaxControls(node); 1101 node->ReplaceInput(0, buffer); 1102 node->ReplaceInput(1, offset); 1103 node->ReplaceInput(2, length); 1104 node->ReplaceInput(3, value); 1105 node->ReplaceInput(4, effect); 1106 node->ReplaceInput(5, control); 1107 node->TrimInputCount(6); 1108 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access)); 1109 return Changed(node); 1110 } 1111 } 1112 } 1113 return NoChange(); 1114 } 1115 1116 1117 Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { 1118 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); 1119 Node* const context = NodeProperties::GetContextInput(node); 1120 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0); 1121 1122 // If deoptimization is disabled, we cannot optimize. 1123 if (!(flags() & kDeoptimizationEnabled) || 1124 (flags() & kDisableBinaryOpReduction)) { 1125 return NoChange(); 1126 } 1127 1128 // If we are in a try block, don't optimize since the runtime call 1129 // in the proxy case can throw. 1130 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); 1131 1132 JSBinopReduction r(this, node); 1133 Node* effect = r.effect(); 1134 Node* control = r.control(); 1135 1136 if (!r.right_type()->IsConstant() || 1137 !r.right_type()->AsConstant()->Value()->IsJSFunction()) { 1138 return NoChange(); 1139 } 1140 1141 Handle<JSFunction> function = 1142 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value()); 1143 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 1144 1145 if (!function->IsConstructor() || 1146 function->map()->has_non_instance_prototype()) { 1147 return NoChange(); 1148 } 1149 1150 JSFunction::EnsureHasInitialMap(function); 1151 DCHECK(function->has_initial_map()); 1152 Handle<Map> initial_map(function->initial_map(), isolate()); 1153 this->dependencies()->AssumeInitialMapCantChange(initial_map); 1154 Node* prototype = 1155 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); 1156 1157 Node* if_is_smi = nullptr; 1158 Node* e_is_smi = nullptr; 1159 // If the left hand side is an object, no smi check is needed. 1160 if (r.left_type()->Maybe(Type::TaggedSigned())) { 1161 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left()); 1162 Node* branch_is_smi = 1163 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control); 1164 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi); 1165 e_is_smi = effect; 1166 control = graph()->NewNode(common()->IfFalse(), branch_is_smi); 1167 } 1168 1169 Node* object_map = effect = 1170 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 1171 r.left(), effect, control); 1172 1173 // Loop through the {object}s prototype chain looking for the {prototype}. 1174 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); 1175 1176 Node* loop_effect = effect = 1177 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); 1178 1179 Node* loop_object_map = 1180 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1181 object_map, r.left(), loop); 1182 1183 // Check if the lhs needs access checks. 1184 Node* map_bit_field = effect = 1185 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()), 1186 loop_object_map, loop_effect, control); 1187 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded; 1188 Node* is_access_check_needed_num = 1189 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field, 1190 jsgraph()->Uint32Constant(is_access_check_needed_bit)); 1191 Node* is_access_check_needed = 1192 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num, 1193 jsgraph()->Uint32Constant(is_access_check_needed_bit)); 1194 1195 Node* branch_is_access_check_needed = graph()->NewNode( 1196 common()->Branch(BranchHint::kFalse), is_access_check_needed, control); 1197 Node* if_is_access_check_needed = 1198 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed); 1199 Node* e_is_access_check_needed = effect; 1200 1201 control = 1202 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed); 1203 1204 // Check if the lhs is a proxy. 1205 Node* map_instance_type = effect = graph()->NewNode( 1206 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 1207 loop_object_map, loop_effect, control); 1208 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type, 1209 jsgraph()->Uint32Constant(JS_PROXY_TYPE)); 1210 Node* branch_is_proxy = 1211 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control); 1212 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy); 1213 Node* e_is_proxy = effect; 1214 1215 1216 Node* runtime_has_in_proto_chain = control = graph()->NewNode( 1217 common()->Merge(2), if_is_access_check_needed, if_is_proxy); 1218 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed, 1219 e_is_proxy, control); 1220 1221 // If we need an access check or the object is a Proxy, make a runtime call 1222 // to finish the lowering. 1223 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode( 1224 javascript()->CallRuntime(Runtime::kHasInPrototypeChain, 2), r.left(), 1225 prototype, context, frame_state, effect, control); 1226 1227 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy); 1228 1229 Node* object_prototype = effect = graph()->NewNode( 1230 simplified()->LoadField(AccessBuilder::ForMapPrototype()), 1231 loop_object_map, loop_effect, control); 1232 1233 // Check if object prototype is equal to function prototype. 1234 Node* eq_proto = 1235 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()), 1236 object_prototype, prototype); 1237 Node* branch_eq_proto = 1238 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control); 1239 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto); 1240 Node* e_eq_proto = effect; 1241 1242 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto); 1243 1244 // If not, check if object prototype is the null prototype. 1245 Node* null_proto = 1246 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()), 1247 object_prototype, jsgraph()->NullConstant()); 1248 Node* branch_null_proto = graph()->NewNode( 1249 common()->Branch(BranchHint::kFalse), null_proto, control); 1250 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto); 1251 Node* e_null_proto = effect; 1252 1253 control = graph()->NewNode(common()->IfFalse(), branch_null_proto); 1254 Node* load_object_map = effect = 1255 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 1256 object_prototype, effect, control); 1257 // Close the loop. 1258 loop_effect->ReplaceInput(1, effect); 1259 loop_object_map->ReplaceInput(1, load_object_map); 1260 loop->ReplaceInput(1, control); 1261 1262 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain, 1263 if_eq_proto, if_null_proto); 1264 effect = graph()->NewNode(common()->EffectPhi(3), 1265 bool_result_runtime_has_in_proto_chain_case, 1266 e_eq_proto, e_null_proto, control); 1267 1268 Node* result = graph()->NewNode( 1269 common()->Phi(MachineRepresentation::kTagged, 3), 1270 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(), 1271 jsgraph()->FalseConstant(), control); 1272 1273 if (if_is_smi != nullptr) { 1274 DCHECK_NOT_NULL(e_is_smi); 1275 control = graph()->NewNode(common()->Merge(2), if_is_smi, control); 1276 effect = 1277 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control); 1278 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1279 jsgraph()->FalseConstant(), result, control); 1280 } 1281 1282 ReplaceWithValue(node, result, effect, control); 1283 return Changed(result); 1284 } 1285 1286 1287 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { 1288 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); 1289 ContextAccess const& access = ContextAccessOf(node->op()); 1290 Node* effect = NodeProperties::GetEffectInput(node); 1291 Node* control = graph()->start(); 1292 for (size_t i = 0; i < access.depth(); ++i) { 1293 Node* previous = effect = graph()->NewNode( 1294 simplified()->LoadField( 1295 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)), 1296 NodeProperties::GetValueInput(node, 0), effect, control); 1297 node->ReplaceInput(0, previous); 1298 } 1299 node->ReplaceInput(1, effect); 1300 node->ReplaceInput(2, control); 1301 NodeProperties::ChangeOp( 1302 node, 1303 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index()))); 1304 return Changed(node); 1305 } 1306 1307 1308 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { 1309 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); 1310 ContextAccess const& access = ContextAccessOf(node->op()); 1311 Node* effect = NodeProperties::GetEffectInput(node); 1312 Node* control = graph()->start(); 1313 for (size_t i = 0; i < access.depth(); ++i) { 1314 Node* previous = effect = graph()->NewNode( 1315 simplified()->LoadField( 1316 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)), 1317 NodeProperties::GetValueInput(node, 0), effect, control); 1318 node->ReplaceInput(0, previous); 1319 } 1320 node->RemoveInput(2); 1321 node->ReplaceInput(2, effect); 1322 NodeProperties::ChangeOp( 1323 node, 1324 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index()))); 1325 return Changed(node); 1326 } 1327 1328 1329 Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { 1330 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode()); 1331 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op()); 1332 Node* receiver = NodeProperties::GetValueInput(node, 0); 1333 Type* receiver_type = NodeProperties::GetType(receiver); 1334 Node* context = NodeProperties::GetContextInput(node); 1335 Type* context_type = NodeProperties::GetType(context); 1336 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 1337 Node* effect = NodeProperties::GetEffectInput(node); 1338 Node* control = NodeProperties::GetControlInput(node); 1339 if (!receiver_type->Is(Type::Receiver())) { 1340 if (receiver_type->Is(Type::NullOrUndefined()) || 1341 mode == ConvertReceiverMode::kNullOrUndefined) { 1342 if (context_type->IsConstant()) { 1343 Handle<JSObject> global_proxy( 1344 Handle<Context>::cast(context_type->AsConstant()->Value()) 1345 ->global_proxy(), 1346 isolate()); 1347 receiver = jsgraph()->Constant(global_proxy); 1348 } else { 1349 Node* native_context = effect = graph()->NewNode( 1350 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1351 context, context, effect); 1352 receiver = effect = graph()->NewNode( 1353 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), 1354 native_context, native_context, effect); 1355 } 1356 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) || 1357 mode == ConvertReceiverMode::kNotNullOrUndefined) { 1358 receiver = effect = 1359 graph()->NewNode(javascript()->ToObject(), receiver, context, 1360 frame_state, effect, control); 1361 } else { 1362 // Check {receiver} for undefined. 1363 Node* check0 = 1364 graph()->NewNode(simplified()->ReferenceEqual(receiver_type), 1365 receiver, jsgraph()->UndefinedConstant()); 1366 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1367 check0, control); 1368 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1369 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1370 1371 // Check {receiver} for null. 1372 Node* check1 = 1373 graph()->NewNode(simplified()->ReferenceEqual(receiver_type), 1374 receiver, jsgraph()->NullConstant()); 1375 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1376 check1, if_false0); 1377 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1378 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1379 1380 // Convert {receiver} using ToObject. 1381 Node* if_convert = if_false1; 1382 Node* econvert = effect; 1383 Node* rconvert; 1384 { 1385 rconvert = econvert = 1386 graph()->NewNode(javascript()->ToObject(), receiver, context, 1387 frame_state, econvert, if_convert); 1388 } 1389 1390 // Replace {receiver} with global proxy of {context}. 1391 Node* if_global = 1392 graph()->NewNode(common()->Merge(2), if_true0, if_true1); 1393 Node* eglobal = effect; 1394 Node* rglobal; 1395 { 1396 if (context_type->IsConstant()) { 1397 Handle<JSObject> global_proxy( 1398 Handle<Context>::cast(context_type->AsConstant()->Value()) 1399 ->global_proxy(), 1400 isolate()); 1401 rglobal = jsgraph()->Constant(global_proxy); 1402 } else { 1403 Node* native_context = eglobal = graph()->NewNode( 1404 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1405 context, context, eglobal); 1406 rglobal = eglobal = graph()->NewNode( 1407 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), 1408 native_context, native_context, eglobal); 1409 } 1410 } 1411 1412 control = graph()->NewNode(common()->Merge(2), if_convert, if_global); 1413 effect = 1414 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control); 1415 receiver = 1416 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1417 rconvert, rglobal, control); 1418 } 1419 } 1420 ReplaceWithValue(node, receiver, effect, control); 1421 return Changed(receiver); 1422 } 1423 1424 1425 namespace { 1426 1427 // Maximum instance size for which allocations will be inlined. 1428 const int kMaxInlineInstanceSize = 64 * kPointerSize; 1429 1430 1431 // Checks whether allocation using the given constructor can be inlined. 1432 bool IsAllocationInlineable(Handle<JSFunction> constructor) { 1433 // TODO(bmeurer): Further relax restrictions on inlining, i.e. 1434 // instance type and maybe instance size (inobject properties 1435 // are limited anyways by the runtime). 1436 return constructor->has_initial_map() && 1437 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && 1438 constructor->initial_map()->instance_size() < kMaxInlineInstanceSize; 1439 } 1440 1441 } // namespace 1442 1443 1444 Reduction JSTypedLowering::ReduceJSCreate(Node* node) { 1445 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode()); 1446 Node* const target = NodeProperties::GetValueInput(node, 0); 1447 Type* const target_type = NodeProperties::GetType(target); 1448 Node* const new_target = NodeProperties::GetValueInput(node, 1); 1449 Node* const effect = NodeProperties::GetEffectInput(node); 1450 // TODO(turbofan): Add support for NewTarget passed to JSCreate. 1451 if (target != new_target) return NoChange(); 1452 // Extract constructor function. 1453 if (target_type->IsConstant() && 1454 target_type->AsConstant()->Value()->IsJSFunction()) { 1455 Handle<JSFunction> constructor = 1456 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); 1457 DCHECK(constructor->IsConstructor()); 1458 // Force completion of inobject slack tracking before 1459 // generating code to finalize the instance size. 1460 constructor->CompleteInobjectSlackTrackingIfActive(); 1461 1462 // TODO(bmeurer): We fall back to the runtime in case we cannot inline 1463 // the allocation here, which is sort of expensive. We should think about 1464 // a soft fallback to some NewObjectCodeStub. 1465 if (IsAllocationInlineable(constructor)) { 1466 // Compute instance size from initial map of {constructor}. 1467 Handle<Map> initial_map(constructor->initial_map(), isolate()); 1468 int const instance_size = initial_map->instance_size(); 1469 1470 // Add a dependency on the {initial_map} to make sure that this code is 1471 // deoptimized whenever the {initial_map} of the {constructor} changes. 1472 dependencies()->AssumeInitialMapCantChange(initial_map); 1473 1474 // Emit code to allocate the JSObject instance for the {constructor}. 1475 AllocationBuilder a(jsgraph(), effect, graph()->start()); 1476 a.Allocate(instance_size); 1477 a.Store(AccessBuilder::ForMap(), initial_map); 1478 a.Store(AccessBuilder::ForJSObjectProperties(), 1479 jsgraph()->EmptyFixedArrayConstant()); 1480 a.Store(AccessBuilder::ForJSObjectElements(), 1481 jsgraph()->EmptyFixedArrayConstant()); 1482 for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) { 1483 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 1484 jsgraph()->UndefinedConstant()); 1485 } 1486 a.FinishAndChange(node); 1487 return Changed(node); 1488 } 1489 } 1490 return NoChange(); 1491 } 1492 1493 1494 namespace { 1495 1496 // Retrieves the frame state holding actual argument values. 1497 Node* GetArgumentsFrameState(Node* frame_state) { 1498 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput); 1499 FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state); 1500 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor 1501 ? outer_state 1502 : frame_state; 1503 } 1504 1505 } // namespace 1506 1507 1508 Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { 1509 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode()); 1510 CreateArgumentsParameters const& p = CreateArgumentsParametersOf(node->op()); 1511 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0); 1512 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput); 1513 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 1514 1515 // Use the ArgumentsAccessStub for materializing both mapped and unmapped 1516 // arguments object, but only for non-inlined (i.e. outermost) frames. 1517 if (outer_state->opcode() != IrOpcode::kFrameState) { 1518 Isolate* isolate = jsgraph()->isolate(); 1519 int parameter_count = state_info.parameter_count() - 1; 1520 int parameter_offset = parameter_count * kPointerSize; 1521 int offset = StandardFrameConstants::kCallerSPOffset + parameter_offset; 1522 Node* parameter_pointer = graph()->NewNode( 1523 machine()->IntAdd(), graph()->NewNode(machine()->LoadFramePointer()), 1524 jsgraph()->IntPtrConstant(offset)); 1525 1526 if (p.type() != CreateArgumentsParameters::kRestArray) { 1527 Handle<SharedFunctionInfo> shared; 1528 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); 1529 bool unmapped = p.type() == CreateArgumentsParameters::kUnmappedArguments; 1530 Callable callable = CodeFactory::ArgumentsAccess( 1531 isolate, unmapped, shared->has_duplicate_parameters()); 1532 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1533 isolate, graph()->zone(), callable.descriptor(), 0, 1534 CallDescriptor::kNeedsFrameState); 1535 const Operator* new_op = common()->Call(desc); 1536 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 1537 node->InsertInput(graph()->zone(), 0, stub_code); 1538 node->InsertInput(graph()->zone(), 2, 1539 jsgraph()->Constant(parameter_count)); 1540 node->InsertInput(graph()->zone(), 3, parameter_pointer); 1541 NodeProperties::ChangeOp(node, new_op); 1542 return Changed(node); 1543 } else { 1544 Callable callable = CodeFactory::RestArgumentsAccess(isolate); 1545 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1546 isolate, graph()->zone(), callable.descriptor(), 0, 1547 CallDescriptor::kNeedsFrameState); 1548 const Operator* new_op = common()->Call(desc); 1549 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 1550 node->InsertInput(graph()->zone(), 0, stub_code); 1551 node->ReplaceInput(1, jsgraph()->Constant(parameter_count)); 1552 node->InsertInput(graph()->zone(), 2, parameter_pointer); 1553 node->InsertInput(graph()->zone(), 3, 1554 jsgraph()->Constant(p.start_index())); 1555 NodeProperties::ChangeOp(node, new_op); 1556 return Changed(node); 1557 } 1558 } else if (outer_state->opcode() == IrOpcode::kFrameState) { 1559 // Use inline allocation for all mapped arguments objects within inlined 1560 // (i.e. non-outermost) frames, independent of the object size. 1561 if (p.type() == CreateArgumentsParameters::kMappedArguments) { 1562 Handle<SharedFunctionInfo> shared; 1563 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); 1564 Node* const callee = NodeProperties::GetValueInput(node, 0); 1565 Node* const control = NodeProperties::GetControlInput(node); 1566 Node* const context = NodeProperties::GetContextInput(node); 1567 Node* effect = NodeProperties::GetEffectInput(node); 1568 // TODO(mstarzinger): Duplicate parameters are not handled yet. 1569 if (shared->has_duplicate_parameters()) return NoChange(); 1570 // Choose the correct frame state and frame state info depending on 1571 // whether there conceptually is an arguments adaptor frame in the call 1572 // chain. 1573 Node* const args_state = GetArgumentsFrameState(frame_state); 1574 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); 1575 // Prepare element backing store to be used by arguments object. 1576 bool has_aliased_arguments = false; 1577 Node* const elements = AllocateAliasedArguments( 1578 effect, control, args_state, context, shared, &has_aliased_arguments); 1579 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 1580 // Load the arguments object map from the current native context. 1581 Node* const load_native_context = effect = graph()->NewNode( 1582 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1583 context, context, effect); 1584 Node* const load_arguments_map = effect = graph()->NewNode( 1585 simplified()->LoadField(AccessBuilder::ForContextSlot( 1586 has_aliased_arguments ? Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX 1587 : Context::SLOPPY_ARGUMENTS_MAP_INDEX)), 1588 load_native_context, effect, control); 1589 // Actually allocate and initialize the arguments object. 1590 AllocationBuilder a(jsgraph(), effect, control); 1591 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1592 int length = args_state_info.parameter_count() - 1; // Minus receiver. 1593 STATIC_ASSERT(Heap::kSloppyArgumentsObjectSize == 5 * kPointerSize); 1594 a.Allocate(Heap::kSloppyArgumentsObjectSize); 1595 a.Store(AccessBuilder::ForMap(), load_arguments_map); 1596 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 1597 a.Store(AccessBuilder::ForJSObjectElements(), elements); 1598 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); 1599 a.Store(AccessBuilder::ForArgumentsCallee(), callee); 1600 RelaxControls(node); 1601 a.FinishAndChange(node); 1602 return Changed(node); 1603 } else if (p.type() == CreateArgumentsParameters::kUnmappedArguments) { 1604 // Use inline allocation for all unmapped arguments objects within inlined 1605 // (i.e. non-outermost) frames, independent of the object size. 1606 Node* const control = NodeProperties::GetControlInput(node); 1607 Node* const context = NodeProperties::GetContextInput(node); 1608 Node* effect = NodeProperties::GetEffectInput(node); 1609 // Choose the correct frame state and frame state info depending on 1610 // whether there conceptually is an arguments adaptor frame in the call 1611 // chain. 1612 Node* const args_state = GetArgumentsFrameState(frame_state); 1613 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); 1614 // Prepare element backing store to be used by arguments object. 1615 Node* const elements = AllocateArguments(effect, control, args_state); 1616 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 1617 // Load the arguments object map from the current native context. 1618 Node* const load_native_context = effect = graph()->NewNode( 1619 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1620 context, context, effect); 1621 Node* const load_arguments_map = effect = graph()->NewNode( 1622 simplified()->LoadField(AccessBuilder::ForContextSlot( 1623 Context::STRICT_ARGUMENTS_MAP_INDEX)), 1624 load_native_context, effect, control); 1625 // Actually allocate and initialize the arguments object. 1626 AllocationBuilder a(jsgraph(), effect, control); 1627 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1628 int length = args_state_info.parameter_count() - 1; // Minus receiver. 1629 STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize); 1630 a.Allocate(Heap::kStrictArgumentsObjectSize); 1631 a.Store(AccessBuilder::ForMap(), load_arguments_map); 1632 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 1633 a.Store(AccessBuilder::ForJSObjectElements(), elements); 1634 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); 1635 RelaxControls(node); 1636 a.FinishAndChange(node); 1637 return Changed(node); 1638 } else if (p.type() == CreateArgumentsParameters::kRestArray) { 1639 // Use inline allocation for all unmapped arguments objects within inlined 1640 // (i.e. non-outermost) frames, independent of the object size. 1641 Node* const control = NodeProperties::GetControlInput(node); 1642 Node* const context = NodeProperties::GetContextInput(node); 1643 Node* effect = NodeProperties::GetEffectInput(node); 1644 // Choose the correct frame state and frame state info depending on 1645 // whether there conceptually is an arguments adaptor frame in the call 1646 // chain. 1647 Node* const args_state = GetArgumentsFrameState(frame_state); 1648 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); 1649 // Prepare element backing store to be used by the rest array. 1650 Node* const elements = 1651 AllocateRestArguments(effect, control, args_state, p.start_index()); 1652 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 1653 // Load the JSArray object map from the current native context. 1654 Node* const load_native_context = effect = graph()->NewNode( 1655 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1656 context, context, effect); 1657 Node* const load_jsarray_map = effect = graph()->NewNode( 1658 simplified()->LoadField(AccessBuilder::ForContextSlot( 1659 Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX)), 1660 load_native_context, effect, control); 1661 // Actually allocate and initialize the jsarray. 1662 AllocationBuilder a(jsgraph(), effect, control); 1663 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1664 1665 // -1 to minus receiver 1666 int argument_count = args_state_info.parameter_count() - 1; 1667 int length = std::max(0, argument_count - p.start_index()); 1668 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 1669 a.Allocate(JSArray::kSize); 1670 a.Store(AccessBuilder::ForMap(), load_jsarray_map); 1671 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 1672 a.Store(AccessBuilder::ForJSObjectElements(), elements); 1673 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), 1674 jsgraph()->Constant(length)); 1675 RelaxControls(node); 1676 a.FinishAndChange(node); 1677 return Changed(node); 1678 } 1679 } 1680 1681 return NoChange(); 1682 } 1683 1684 1685 Reduction JSTypedLowering::ReduceNewArray(Node* node, Node* length, 1686 int capacity, 1687 Handle<AllocationSite> site) { 1688 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 1689 Node* context = NodeProperties::GetContextInput(node); 1690 Node* effect = NodeProperties::GetEffectInput(node); 1691 Node* control = NodeProperties::GetControlInput(node); 1692 1693 // Extract transition and tenuring feedback from the {site} and add 1694 // appropriate code dependencies on the {site} if deoptimization is 1695 // enabled. 1696 PretenureFlag pretenure = site->GetPretenureMode(); 1697 ElementsKind elements_kind = site->GetElementsKind(); 1698 DCHECK(IsFastElementsKind(elements_kind)); 1699 if (flags() & kDeoptimizationEnabled) { 1700 dependencies()->AssumeTenuringDecision(site); 1701 dependencies()->AssumeTransitionStable(site); 1702 } 1703 1704 // Retrieve the initial map for the array from the appropriate native context. 1705 Node* native_context = effect = graph()->NewNode( 1706 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1707 context, context, effect); 1708 Node* js_array_map = effect = graph()->NewNode( 1709 javascript()->LoadContext(0, Context::ArrayMapIndex(elements_kind), true), 1710 native_context, native_context, effect); 1711 1712 // Setup elements and properties. 1713 Node* elements; 1714 if (capacity == 0) { 1715 elements = jsgraph()->EmptyFixedArrayConstant(); 1716 } else { 1717 elements = effect = 1718 AllocateElements(effect, control, elements_kind, capacity, pretenure); 1719 } 1720 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1721 1722 // Perform the allocation of the actual JSArray object. 1723 AllocationBuilder a(jsgraph(), effect, control); 1724 a.Allocate(JSArray::kSize, pretenure); 1725 a.Store(AccessBuilder::ForMap(), js_array_map); 1726 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 1727 a.Store(AccessBuilder::ForJSObjectElements(), elements); 1728 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); 1729 RelaxControls(node); 1730 a.FinishAndChange(node); 1731 return Changed(node); 1732 } 1733 1734 1735 Reduction JSTypedLowering::ReduceJSCreateArray(Node* node) { 1736 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 1737 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); 1738 Node* target = NodeProperties::GetValueInput(node, 0); 1739 Node* new_target = NodeProperties::GetValueInput(node, 1); 1740 1741 // TODO(bmeurer): Optimize the subclassing case. 1742 if (target != new_target) return NoChange(); 1743 1744 // Check if we have a feedback {site} on the {node}. 1745 Handle<AllocationSite> site = p.site(); 1746 if (p.site().is_null()) return NoChange(); 1747 1748 // Attempt to inline calls to the Array constructor for the relevant cases 1749 // where either no arguments are provided, or exactly one unsigned number 1750 // argument is given. 1751 if (site->CanInlineCall()) { 1752 if (p.arity() == 0) { 1753 Node* length = jsgraph()->ZeroConstant(); 1754 int capacity = JSArray::kPreallocatedArrayElements; 1755 return ReduceNewArray(node, length, capacity, site); 1756 } else if (p.arity() == 1) { 1757 Node* length = NodeProperties::GetValueInput(node, 2); 1758 Type* length_type = NodeProperties::GetType(length); 1759 if (length_type->Is(type_cache_.kElementLoopUnrollType)) { 1760 int capacity = static_cast<int>(length_type->Max()); 1761 return ReduceNewArray(node, length, capacity, site); 1762 } 1763 } 1764 } 1765 1766 // Reduce {node} to the appropriate ArrayConstructorStub backend. 1767 // Note that these stubs "behave" like JSFunctions, which means they 1768 // expect a receiver on the stack, which they remove. We just push 1769 // undefined for the receiver. 1770 ElementsKind elements_kind = site->GetElementsKind(); 1771 AllocationSiteOverrideMode override_mode = 1772 (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE) 1773 ? DISABLE_ALLOCATION_SITES 1774 : DONT_OVERRIDE; 1775 if (p.arity() == 0) { 1776 ArrayNoArgumentConstructorStub stub(isolate(), elements_kind, 1777 override_mode); 1778 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1779 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1, 1780 CallDescriptor::kNeedsFrameState); 1781 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); 1782 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); 1783 node->InsertInput(graph()->zone(), 3, jsgraph()->UndefinedConstant()); 1784 NodeProperties::ChangeOp(node, common()->Call(desc)); 1785 return Changed(node); 1786 } else if (p.arity() == 1) { 1787 // TODO(bmeurer): Optimize for the 0 length non-holey case? 1788 ArraySingleArgumentConstructorStub stub( 1789 isolate(), GetHoleyElementsKind(elements_kind), override_mode); 1790 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1791 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2, 1792 CallDescriptor::kNeedsFrameState); 1793 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); 1794 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); 1795 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(1)); 1796 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 1797 NodeProperties::ChangeOp(node, common()->Call(desc)); 1798 return Changed(node); 1799 } else { 1800 int const arity = static_cast<int>(p.arity()); 1801 ArrayNArgumentsConstructorStub stub(isolate(), elements_kind, 1802 override_mode); 1803 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1804 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1805 arity + 1, CallDescriptor::kNeedsFrameState); 1806 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); 1807 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); 1808 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity)); 1809 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 1810 NodeProperties::ChangeOp(node, common()->Call(desc)); 1811 return Changed(node); 1812 } 1813 } 1814 1815 1816 Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) { 1817 DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode()); 1818 CreateClosureParameters const& p = CreateClosureParametersOf(node->op()); 1819 Handle<SharedFunctionInfo> shared = p.shared_info(); 1820 1821 // Use the FastNewClosureStub that allocates in new space only for nested 1822 // functions that don't need literals cloning. 1823 if (p.pretenure() == NOT_TENURED && shared->num_literals() == 0) { 1824 Isolate* isolate = jsgraph()->isolate(); 1825 Callable callable = CodeFactory::FastNewClosure( 1826 isolate, shared->language_mode(), shared->kind()); 1827 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1828 isolate, graph()->zone(), callable.descriptor(), 0, 1829 CallDescriptor::kNoFlags); 1830 const Operator* new_op = common()->Call(desc); 1831 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 1832 node->InsertInput(graph()->zone(), 0, stub_code); 1833 node->InsertInput(graph()->zone(), 1, jsgraph()->HeapConstant(shared)); 1834 NodeProperties::ChangeOp(node, new_op); 1835 return Changed(node); 1836 } 1837 1838 return NoChange(); 1839 } 1840 1841 1842 Reduction JSTypedLowering::ReduceJSCreateIterResultObject(Node* node) { 1843 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode()); 1844 Node* value = NodeProperties::GetValueInput(node, 0); 1845 Node* done = NodeProperties::GetValueInput(node, 1); 1846 Node* context = NodeProperties::GetContextInput(node); 1847 Node* effect = NodeProperties::GetEffectInput(node); 1848 1849 // Load the JSIteratorResult map for the {context}. 1850 Node* native_context = effect = graph()->NewNode( 1851 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1852 context, context, effect); 1853 Node* iterator_result_map = effect = graph()->NewNode( 1854 javascript()->LoadContext(0, Context::ITERATOR_RESULT_MAP_INDEX, true), 1855 native_context, native_context, effect); 1856 1857 // Emit code to allocate the JSIteratorResult instance. 1858 AllocationBuilder a(jsgraph(), effect, graph()->start()); 1859 a.Allocate(JSIteratorResult::kSize); 1860 a.Store(AccessBuilder::ForMap(), iterator_result_map); 1861 a.Store(AccessBuilder::ForJSObjectProperties(), 1862 jsgraph()->EmptyFixedArrayConstant()); 1863 a.Store(AccessBuilder::ForJSObjectElements(), 1864 jsgraph()->EmptyFixedArrayConstant()); 1865 a.Store(AccessBuilder::ForJSIteratorResultValue(), value); 1866 a.Store(AccessBuilder::ForJSIteratorResultDone(), done); 1867 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); 1868 a.FinishAndChange(node); 1869 return Changed(node); 1870 } 1871 1872 1873 Reduction JSTypedLowering::ReduceJSCreateLiteralArray(Node* node) { 1874 DCHECK_EQ(IrOpcode::kJSCreateLiteralArray, node->opcode()); 1875 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); 1876 Handle<FixedArray> const constants = Handle<FixedArray>::cast(p.constant()); 1877 int const length = constants->length(); 1878 int const flags = p.flags(); 1879 1880 // Use the FastCloneShallowArrayStub only for shallow boilerplates up to the 1881 // initial length limit for arrays with "fast" elements kind. 1882 // TODO(rossberg): Teach strong mode to FastCloneShallowArrayStub. 1883 if ((flags & ArrayLiteral::kShallowElements) != 0 && 1884 (flags & ArrayLiteral::kIsStrong) == 0 && 1885 length < JSArray::kInitialMaxFastElementArray) { 1886 Isolate* isolate = jsgraph()->isolate(); 1887 Callable callable = CodeFactory::FastCloneShallowArray(isolate); 1888 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1889 isolate, graph()->zone(), callable.descriptor(), 0, 1890 (OperatorProperties::GetFrameStateInputCount(node->op()) != 0) 1891 ? CallDescriptor::kNeedsFrameState 1892 : CallDescriptor::kNoFlags); 1893 const Operator* new_op = common()->Call(desc); 1894 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 1895 Node* literal_index = jsgraph()->SmiConstant(p.index()); 1896 Node* constant_elements = jsgraph()->HeapConstant(constants); 1897 node->InsertInput(graph()->zone(), 0, stub_code); 1898 node->InsertInput(graph()->zone(), 2, literal_index); 1899 node->InsertInput(graph()->zone(), 3, constant_elements); 1900 NodeProperties::ChangeOp(node, new_op); 1901 return Changed(node); 1902 } 1903 1904 return NoChange(); 1905 } 1906 1907 1908 Reduction JSTypedLowering::ReduceJSCreateLiteralObject(Node* node) { 1909 DCHECK_EQ(IrOpcode::kJSCreateLiteralObject, node->opcode()); 1910 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); 1911 Handle<FixedArray> const constants = Handle<FixedArray>::cast(p.constant()); 1912 // Constants are pairs, see ObjectLiteral::properties_count(). 1913 int const length = constants->length() / 2; 1914 int const flags = p.flags(); 1915 1916 // Use the FastCloneShallowObjectStub only for shallow boilerplates without 1917 // elements up to the number of properties that the stubs can handle. 1918 if ((flags & ObjectLiteral::kShallowProperties) != 0 && 1919 length <= FastCloneShallowObjectStub::kMaximumClonedProperties) { 1920 Isolate* isolate = jsgraph()->isolate(); 1921 Callable callable = CodeFactory::FastCloneShallowObject(isolate, length); 1922 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1923 isolate, graph()->zone(), callable.descriptor(), 0, 1924 (OperatorProperties::GetFrameStateInputCount(node->op()) != 0) 1925 ? CallDescriptor::kNeedsFrameState 1926 : CallDescriptor::kNoFlags); 1927 const Operator* new_op = common()->Call(desc); 1928 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 1929 Node* literal_index = jsgraph()->SmiConstant(p.index()); 1930 Node* literal_flags = jsgraph()->SmiConstant(flags); 1931 Node* constant_elements = jsgraph()->HeapConstant(constants); 1932 node->InsertInput(graph()->zone(), 0, stub_code); 1933 node->InsertInput(graph()->zone(), 2, literal_index); 1934 node->InsertInput(graph()->zone(), 3, constant_elements); 1935 node->InsertInput(graph()->zone(), 4, literal_flags); 1936 NodeProperties::ChangeOp(node, new_op); 1937 return Changed(node); 1938 } 1939 1940 return NoChange(); 1941 } 1942 1943 1944 Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) { 1945 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode()); 1946 int slot_count = OpParameter<int>(node->op()); 1947 Node* const closure = NodeProperties::GetValueInput(node, 0); 1948 1949 // Use inline allocation for function contexts up to a size limit. 1950 if (slot_count < kFunctionContextAllocationLimit) { 1951 // JSCreateFunctionContext[slot_count < limit]](fun) 1952 Node* effect = NodeProperties::GetEffectInput(node); 1953 Node* control = NodeProperties::GetControlInput(node); 1954 Node* context = NodeProperties::GetContextInput(node); 1955 Node* extension = jsgraph()->TheHoleConstant(); 1956 Node* native_context = effect = graph()->NewNode( 1957 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 1958 context, context, effect); 1959 AllocationBuilder a(jsgraph(), effect, control); 1960 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 1961 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS; 1962 a.AllocateArray(context_length, factory()->function_context_map()); 1963 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 1964 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 1965 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 1966 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 1967 native_context); 1968 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) { 1969 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); 1970 } 1971 RelaxControls(node); 1972 a.FinishAndChange(node); 1973 return Changed(node); 1974 } 1975 1976 // Use the FastNewContextStub only for function contexts up maximum size. 1977 if (slot_count <= FastNewContextStub::kMaximumSlots) { 1978 Isolate* isolate = jsgraph()->isolate(); 1979 Callable callable = CodeFactory::FastNewContext(isolate, slot_count); 1980 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1981 isolate, graph()->zone(), callable.descriptor(), 0, 1982 CallDescriptor::kNoFlags); 1983 const Operator* new_op = common()->Call(desc); 1984 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 1985 node->InsertInput(graph()->zone(), 0, stub_code); 1986 NodeProperties::ChangeOp(node, new_op); 1987 return Changed(node); 1988 } 1989 1990 return NoChange(); 1991 } 1992 1993 1994 Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) { 1995 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode()); 1996 Node* object = NodeProperties::GetValueInput(node, 0); 1997 Node* closure = NodeProperties::GetValueInput(node, 1); 1998 Node* effect = NodeProperties::GetEffectInput(node); 1999 Node* control = NodeProperties::GetControlInput(node); 2000 Node* context = NodeProperties::GetContextInput(node); 2001 Node* native_context = effect = graph()->NewNode( 2002 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 2003 context, context, effect); 2004 AllocationBuilder a(jsgraph(), effect, control); 2005 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 2006 a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map()); 2007 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 2008 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 2009 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object); 2010 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 2011 native_context); 2012 RelaxControls(node); 2013 a.FinishAndChange(node); 2014 return Changed(node); 2015 } 2016 2017 2018 Reduction JSTypedLowering::ReduceJSCreateCatchContext(Node* node) { 2019 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode()); 2020 Handle<String> name = OpParameter<Handle<String>>(node); 2021 Node* exception = NodeProperties::GetValueInput(node, 0); 2022 Node* closure = NodeProperties::GetValueInput(node, 1); 2023 Node* effect = NodeProperties::GetEffectInput(node); 2024 Node* control = NodeProperties::GetControlInput(node); 2025 Node* context = NodeProperties::GetContextInput(node); 2026 Node* native_context = effect = graph()->NewNode( 2027 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 2028 context, context, effect); 2029 AllocationBuilder a(jsgraph(), effect, control); 2030 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 2031 a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1, 2032 factory()->catch_context_map()); 2033 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 2034 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 2035 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), name); 2036 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 2037 native_context); 2038 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX), 2039 exception); 2040 RelaxControls(node); 2041 a.FinishAndChange(node); 2042 return Changed(node); 2043 } 2044 2045 2046 Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) { 2047 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode()); 2048 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node); 2049 int context_length = scope_info->ContextLength(); 2050 Node* const closure = NodeProperties::GetValueInput(node, 0); 2051 2052 // Use inline allocation for block contexts up to a size limit. 2053 if (context_length < kBlockContextAllocationLimit) { 2054 // JSCreateBlockContext[scope[length < limit]](fun) 2055 Node* effect = NodeProperties::GetEffectInput(node); 2056 Node* control = NodeProperties::GetControlInput(node); 2057 Node* context = NodeProperties::GetContextInput(node); 2058 Node* extension = jsgraph()->Constant(scope_info); 2059 Node* native_context = effect = graph()->NewNode( 2060 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), 2061 context, context, effect); 2062 AllocationBuilder a(jsgraph(), effect, control); 2063 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 2064 a.AllocateArray(context_length, factory()->block_context_map()); 2065 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 2066 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 2067 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 2068 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 2069 native_context); 2070 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) { 2071 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); 2072 } 2073 RelaxControls(node); 2074 a.FinishAndChange(node); 2075 return Changed(node); 2076 } 2077 2078 return NoChange(); 2079 } 2080 2081 2082 Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) { 2083 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); 2084 CallConstructParameters const& p = CallConstructParametersOf(node->op()); 2085 DCHECK_LE(2u, p.arity()); 2086 int const arity = static_cast<int>(p.arity() - 2); 2087 Node* target = NodeProperties::GetValueInput(node, 0); 2088 Type* target_type = NodeProperties::GetType(target); 2089 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); 2090 2091 // Check if {target} is a known JSFunction. 2092 if (target_type->IsConstant() && 2093 target_type->AsConstant()->Value()->IsJSFunction()) { 2094 Handle<JSFunction> function = 2095 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); 2096 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 2097 2098 // Remove the eager bailout frame state. 2099 NodeProperties::RemoveFrameStateInput(node, 1); 2100 2101 // Patch {node} to an indirect call via the {function}s construct stub. 2102 Callable callable(handle(shared->construct_stub(), isolate()), 2103 ConstructStubDescriptor(isolate())); 2104 node->RemoveInput(arity + 1); 2105 node->InsertInput(graph()->zone(), 0, 2106 jsgraph()->HeapConstant(callable.code())); 2107 node->InsertInput(graph()->zone(), 2, new_target); 2108 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity)); 2109 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 2110 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant()); 2111 NodeProperties::ChangeOp( 2112 node, common()->Call(Linkage::GetStubCallDescriptor( 2113 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 2114 CallDescriptor::kNeedsFrameState))); 2115 return Changed(node); 2116 } 2117 2118 // Check if {target} is a JSFunction. 2119 if (target_type->Is(Type::Function())) { 2120 // Remove the eager bailout frame state. 2121 NodeProperties::RemoveFrameStateInput(node, 1); 2122 2123 // Patch {node} to an indirect call via the ConstructFunction builtin. 2124 Callable callable = CodeFactory::ConstructFunction(isolate()); 2125 node->RemoveInput(arity + 1); 2126 node->InsertInput(graph()->zone(), 0, 2127 jsgraph()->HeapConstant(callable.code())); 2128 node->InsertInput(graph()->zone(), 2, new_target); 2129 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity)); 2130 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 2131 NodeProperties::ChangeOp( 2132 node, common()->Call(Linkage::GetStubCallDescriptor( 2133 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 2134 CallDescriptor::kNeedsFrameState))); 2135 return Changed(node); 2136 } 2137 2138 return NoChange(); 2139 } 2140 2141 2142 Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { 2143 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); 2144 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); 2145 int const arity = static_cast<int>(p.arity() - 2); 2146 ConvertReceiverMode convert_mode = p.convert_mode(); 2147 Node* target = NodeProperties::GetValueInput(node, 0); 2148 Type* target_type = NodeProperties::GetType(target); 2149 Node* receiver = NodeProperties::GetValueInput(node, 1); 2150 Type* receiver_type = NodeProperties::GetType(receiver); 2151 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 2152 Node* effect = NodeProperties::GetEffectInput(node); 2153 Node* control = NodeProperties::GetControlInput(node); 2154 2155 // Try to infer receiver {convert_mode} from {receiver} type. 2156 if (receiver_type->Is(Type::NullOrUndefined())) { 2157 convert_mode = ConvertReceiverMode::kNullOrUndefined; 2158 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) { 2159 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; 2160 } 2161 2162 // Check if {target} is a known JSFunction. 2163 if (target_type->IsConstant() && 2164 target_type->AsConstant()->Value()->IsJSFunction()) { 2165 Handle<JSFunction> function = 2166 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); 2167 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 2168 2169 // Class constructors are callable, but [[Call]] will raise an exception. 2170 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 2171 if (IsClassConstructor(shared->kind())) return NoChange(); 2172 2173 // Load the context from the {target}. 2174 Node* context = effect = graph()->NewNode( 2175 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target, 2176 effect, control); 2177 NodeProperties::ReplaceContextInput(node, context); 2178 2179 // Check if we need to convert the {receiver}. 2180 if (is_sloppy(shared->language_mode()) && !shared->native() && 2181 !receiver_type->Is(Type::Receiver())) { 2182 receiver = effect = 2183 graph()->NewNode(javascript()->ConvertReceiver(convert_mode), 2184 receiver, context, frame_state, effect, control); 2185 NodeProperties::ReplaceValueInput(node, receiver, 1); 2186 } 2187 2188 // Update the effect dependency for the {node}. 2189 NodeProperties::ReplaceEffectInput(node, effect); 2190 2191 // Remove the eager bailout frame state. 2192 NodeProperties::RemoveFrameStateInput(node, 1); 2193 2194 // Compute flags for the call. 2195 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 2196 if (p.tail_call_mode() == TailCallMode::kAllow) { 2197 flags |= CallDescriptor::kSupportsTailCalls; 2198 } 2199 2200 Node* new_target = jsgraph()->UndefinedConstant(); 2201 Node* argument_count = jsgraph()->Int32Constant(arity); 2202 if (shared->internal_formal_parameter_count() == arity || 2203 shared->internal_formal_parameter_count() == 2204 SharedFunctionInfo::kDontAdaptArgumentsSentinel) { 2205 // Patch {node} to a direct call. 2206 node->InsertInput(graph()->zone(), arity + 2, new_target); 2207 node->InsertInput(graph()->zone(), arity + 3, argument_count); 2208 NodeProperties::ChangeOp(node, 2209 common()->Call(Linkage::GetJSCallDescriptor( 2210 graph()->zone(), false, 1 + arity, flags))); 2211 } else { 2212 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline. 2213 Callable callable = CodeFactory::ArgumentAdaptor(isolate()); 2214 node->InsertInput(graph()->zone(), 0, 2215 jsgraph()->HeapConstant(callable.code())); 2216 node->InsertInput(graph()->zone(), 2, new_target); 2217 node->InsertInput(graph()->zone(), 3, argument_count); 2218 node->InsertInput( 2219 graph()->zone(), 4, 2220 jsgraph()->Int32Constant(shared->internal_formal_parameter_count())); 2221 NodeProperties::ChangeOp( 2222 node, common()->Call(Linkage::GetStubCallDescriptor( 2223 isolate(), graph()->zone(), callable.descriptor(), 2224 1 + arity, flags))); 2225 } 2226 return Changed(node); 2227 } 2228 2229 // Check if {target} is a JSFunction. 2230 if (target_type->Is(Type::Function())) { 2231 // Remove the eager bailout frame state. 2232 NodeProperties::RemoveFrameStateInput(node, 1); 2233 2234 // Compute flags for the call. 2235 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; 2236 if (p.tail_call_mode() == TailCallMode::kAllow) { 2237 flags |= CallDescriptor::kSupportsTailCalls; 2238 } 2239 2240 // Patch {node} to an indirect call via the CallFunction builtin. 2241 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode); 2242 node->InsertInput(graph()->zone(), 0, 2243 jsgraph()->HeapConstant(callable.code())); 2244 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity)); 2245 NodeProperties::ChangeOp( 2246 node, common()->Call(Linkage::GetStubCallDescriptor( 2247 isolate(), graph()->zone(), callable.descriptor(), 1 + arity, 2248 flags))); 2249 return Changed(node); 2250 } 2251 2252 // Maybe we did at least learn something about the {receiver}. 2253 if (p.convert_mode() != convert_mode) { 2254 NodeProperties::ChangeOp( 2255 node, 2256 javascript()->CallFunction(p.arity(), p.language_mode(), p.feedback(), 2257 convert_mode, p.tail_call_mode())); 2258 return Changed(node); 2259 } 2260 2261 return NoChange(); 2262 } 2263 2264 2265 Reduction JSTypedLowering::ReduceJSForInDone(Node* node) { 2266 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode()); 2267 node->TrimInputCount(2); 2268 NodeProperties::ChangeOp(node, machine()->Word32Equal()); 2269 return Changed(node); 2270 } 2271 2272 2273 Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) { 2274 DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode()); 2275 Node* receiver = NodeProperties::GetValueInput(node, 0); 2276 Node* context = NodeProperties::GetContextInput(node); 2277 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 2278 Node* effect = NodeProperties::GetEffectInput(node); 2279 Node* control = NodeProperties::GetControlInput(node); 2280 2281 // Get the set of properties to enumerate. 2282 Node* cache_type = effect = graph()->NewNode( 2283 javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), receiver, 2284 context, frame_state, effect, control); 2285 control = graph()->NewNode(common()->IfSuccess(), cache_type); 2286 2287 Node* receiver_map = effect = 2288 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 2289 receiver, effect, control); 2290 Node* cache_type_map = effect = 2291 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 2292 cache_type, effect, control); 2293 Node* meta_map = jsgraph()->HeapConstant(factory()->meta_map()); 2294 2295 // If we got a map from the GetPropertyNamesFast runtime call, we can do a 2296 // fast modification check. Otherwise, we got a fixed array, and we have to 2297 // perform a slow check on every iteration. 2298 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 2299 cache_type_map, meta_map); 2300 Node* branch0 = 2301 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 2302 2303 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 2304 Node* cache_array_true0; 2305 Node* cache_length_true0; 2306 Node* cache_type_true0; 2307 Node* etrue0; 2308 { 2309 // Enum cache case. 2310 Node* cache_type_enum_length = etrue0 = graph()->NewNode( 2311 simplified()->LoadField(AccessBuilder::ForMapBitField3()), cache_type, 2312 effect, if_true0); 2313 cache_length_true0 = graph()->NewNode( 2314 simplified()->NumberBitwiseAnd(), cache_type_enum_length, 2315 jsgraph()->Int32Constant(Map::EnumLengthBits::kMask)); 2316 2317 Node* check1 = 2318 graph()->NewNode(machine()->Word32Equal(), cache_length_true0, 2319 jsgraph()->Int32Constant(0)); 2320 Node* branch1 = 2321 graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); 2322 2323 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 2324 Node* cache_array_true1; 2325 Node* etrue1; 2326 { 2327 // No properties to enumerate. 2328 cache_array_true1 = 2329 jsgraph()->HeapConstant(factory()->empty_fixed_array()); 2330 etrue1 = etrue0; 2331 } 2332 2333 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 2334 Node* cache_array_false1; 2335 Node* efalse1; 2336 { 2337 // Load the enumeration cache from the instance descriptors of {receiver}. 2338 Node* receiver_map_descriptors = efalse1 = graph()->NewNode( 2339 simplified()->LoadField(AccessBuilder::ForMapDescriptors()), 2340 receiver_map, etrue0, if_false1); 2341 Node* object_map_enum_cache = efalse1 = graph()->NewNode( 2342 simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()), 2343 receiver_map_descriptors, efalse1, if_false1); 2344 cache_array_false1 = efalse1 = graph()->NewNode( 2345 simplified()->LoadField( 2346 AccessBuilder::ForDescriptorArrayEnumCacheBridgeCache()), 2347 object_map_enum_cache, efalse1, if_false1); 2348 } 2349 2350 if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); 2351 etrue0 = 2352 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); 2353 cache_array_true0 = 2354 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 2355 cache_array_true1, cache_array_false1, if_true0); 2356 2357 cache_type_true0 = cache_type; 2358 } 2359 2360 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 2361 Node* cache_array_false0; 2362 Node* cache_length_false0; 2363 Node* cache_type_false0; 2364 Node* efalse0; 2365 { 2366 // FixedArray case. 2367 cache_type_false0 = jsgraph()->OneConstant(); // Smi means slow check 2368 cache_array_false0 = cache_type; 2369 cache_length_false0 = efalse0 = graph()->NewNode( 2370 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 2371 cache_array_false0, effect, if_false0); 2372 } 2373 2374 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 2375 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); 2376 Node* cache_array = 2377 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 2378 cache_array_true0, cache_array_false0, control); 2379 Node* cache_length = 2380 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 2381 cache_length_true0, cache_length_false0, control); 2382 cache_type = 2383 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 2384 cache_type_true0, cache_type_false0, control); 2385 2386 for (auto edge : node->use_edges()) { 2387 Node* const use = edge.from(); 2388 if (NodeProperties::IsEffectEdge(edge)) { 2389 edge.UpdateTo(effect); 2390 Revisit(use); 2391 } else { 2392 if (NodeProperties::IsControlEdge(edge)) { 2393 if (use->opcode() == IrOpcode::kIfSuccess) { 2394 Replace(use, control); 2395 } else if (use->opcode() == IrOpcode::kIfException) { 2396 edge.UpdateTo(cache_type_true0); 2397 continue; 2398 } else { 2399 UNREACHABLE(); 2400 } 2401 } else { 2402 DCHECK(NodeProperties::IsValueEdge(edge)); 2403 DCHECK_EQ(IrOpcode::kProjection, use->opcode()); 2404 switch (ProjectionIndexOf(use->op())) { 2405 case 0: 2406 Replace(use, cache_type); 2407 break; 2408 case 1: 2409 Replace(use, cache_array); 2410 break; 2411 case 2: 2412 Replace(use, cache_length); 2413 break; 2414 default: 2415 UNREACHABLE(); 2416 break; 2417 } 2418 } 2419 use->Kill(); 2420 } 2421 } 2422 return NoChange(); // All uses were replaced already above. 2423 } 2424 2425 2426 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { 2427 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode()); 2428 Node* receiver = NodeProperties::GetValueInput(node, 0); 2429 Node* cache_array = NodeProperties::GetValueInput(node, 1); 2430 Node* cache_type = NodeProperties::GetValueInput(node, 2); 2431 Node* index = NodeProperties::GetValueInput(node, 3); 2432 Node* context = NodeProperties::GetContextInput(node); 2433 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 2434 Node* effect = NodeProperties::GetEffectInput(node); 2435 Node* control = NodeProperties::GetControlInput(node); 2436 2437 // Load the next {key} from the {cache_array}. 2438 Node* key = effect = graph()->NewNode( 2439 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), 2440 cache_array, index, effect, control); 2441 2442 // Load the map of the {receiver}. 2443 Node* receiver_map = effect = 2444 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 2445 receiver, effect, control); 2446 2447 // Check if the expected map still matches that of the {receiver}. 2448 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 2449 receiver_map, cache_type); 2450 Node* branch0 = 2451 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 2452 2453 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 2454 Node* etrue0; 2455 Node* vtrue0; 2456 { 2457 // Don't need filtering since expected map still matches that of the 2458 // {receiver}. 2459 etrue0 = effect; 2460 vtrue0 = key; 2461 } 2462 2463 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 2464 Node* efalse0; 2465 Node* vfalse0; 2466 { 2467 // Check if the {cache_type} is zero, which indicates proxy. 2468 Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 2469 cache_type, jsgraph()->ZeroConstant()); 2470 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 2471 check1, if_false0); 2472 2473 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 2474 Node* etrue1; 2475 Node* vtrue1; 2476 { 2477 // Don't do filtering for proxies. 2478 etrue1 = effect; 2479 vtrue1 = key; 2480 } 2481 2482 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 2483 Node* efalse1; 2484 Node* vfalse1; 2485 { 2486 // Filter the {key} to check if it's still a valid property of the 2487 // {receiver} (does the ToName conversion implicitly). 2488 vfalse1 = efalse1 = graph()->NewNode( 2489 javascript()->CallRuntime(Runtime::kForInFilter, 2), receiver, key, 2490 context, frame_state, effect, if_false1); 2491 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); 2492 } 2493 2494 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); 2495 efalse0 = 2496 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); 2497 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 2498 vtrue1, vfalse1, if_false0); 2499 } 2500 2501 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 2502 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); 2503 ReplaceWithValue(node, node, effect, control); 2504 node->ReplaceInput(0, vtrue0); 2505 node->ReplaceInput(1, vfalse0); 2506 node->ReplaceInput(2, control); 2507 node->TrimInputCount(3); 2508 NodeProperties::ChangeOp(node, 2509 common()->Phi(MachineRepresentation::kTagged, 2)); 2510 return Changed(node); 2511 } 2512 2513 2514 Reduction JSTypedLowering::ReduceJSForInStep(Node* node) { 2515 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode()); 2516 node->ReplaceInput(1, jsgraph()->Int32Constant(1)); 2517 NodeProperties::ChangeOp(node, machine()->Int32Add()); 2518 return Changed(node); 2519 } 2520 2521 2522 Reduction JSTypedLowering::ReduceSelect(Node* node) { 2523 DCHECK_EQ(IrOpcode::kSelect, node->opcode()); 2524 Node* const condition = NodeProperties::GetValueInput(node, 0); 2525 Type* const condition_type = NodeProperties::GetType(condition); 2526 Node* const vtrue = NodeProperties::GetValueInput(node, 1); 2527 Type* const vtrue_type = NodeProperties::GetType(vtrue); 2528 Node* const vfalse = NodeProperties::GetValueInput(node, 2); 2529 Type* const vfalse_type = NodeProperties::GetType(vfalse); 2530 if (condition_type->Is(true_type_)) { 2531 // Select(condition:true, vtrue, vfalse) => vtrue 2532 return Replace(vtrue); 2533 } 2534 if (condition_type->Is(false_type_)) { 2535 // Select(condition:false, vtrue, vfalse) => vfalse 2536 return Replace(vfalse); 2537 } 2538 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) { 2539 // Select(condition, vtrue:true, vfalse:false) => condition 2540 return Replace(condition); 2541 } 2542 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) { 2543 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition) 2544 node->TrimInputCount(1); 2545 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); 2546 return Changed(node); 2547 } 2548 return NoChange(); 2549 } 2550 2551 2552 Reduction JSTypedLowering::Reduce(Node* node) { 2553 // Check if the output type is a singleton. In that case we already know the 2554 // result value and can simply replace the node if it's eliminable. 2555 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) && 2556 node->op()->HasProperty(Operator::kEliminatable)) { 2557 Type* upper = NodeProperties::GetType(node); 2558 if (upper->IsConstant()) { 2559 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); 2560 ReplaceWithValue(node, replacement); 2561 return Changed(replacement); 2562 } else if (upper->Is(Type::MinusZero())) { 2563 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value()); 2564 ReplaceWithValue(node, replacement); 2565 return Changed(replacement); 2566 } else if (upper->Is(Type::NaN())) { 2567 Node* replacement = jsgraph()->NaNConstant(); 2568 ReplaceWithValue(node, replacement); 2569 return Changed(replacement); 2570 } else if (upper->Is(Type::Null())) { 2571 Node* replacement = jsgraph()->NullConstant(); 2572 ReplaceWithValue(node, replacement); 2573 return Changed(replacement); 2574 } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) { 2575 Node* replacement = jsgraph()->Constant(upper->Min()); 2576 ReplaceWithValue(node, replacement); 2577 return Changed(replacement); 2578 } else if (upper->Is(Type::Undefined())) { 2579 Node* replacement = jsgraph()->UndefinedConstant(); 2580 ReplaceWithValue(node, replacement); 2581 return Changed(replacement); 2582 } 2583 } 2584 switch (node->opcode()) { 2585 case IrOpcode::kJSEqual: 2586 return ReduceJSEqual(node, false); 2587 case IrOpcode::kJSNotEqual: 2588 return ReduceJSEqual(node, true); 2589 case IrOpcode::kJSStrictEqual: 2590 return ReduceJSStrictEqual(node, false); 2591 case IrOpcode::kJSStrictNotEqual: 2592 return ReduceJSStrictEqual(node, true); 2593 case IrOpcode::kJSLessThan: // fall through 2594 case IrOpcode::kJSGreaterThan: // fall through 2595 case IrOpcode::kJSLessThanOrEqual: // fall through 2596 case IrOpcode::kJSGreaterThanOrEqual: 2597 return ReduceJSComparison(node); 2598 case IrOpcode::kJSBitwiseOr: 2599 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr()); 2600 case IrOpcode::kJSBitwiseXor: 2601 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor()); 2602 case IrOpcode::kJSBitwiseAnd: 2603 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd()); 2604 case IrOpcode::kJSShiftLeft: 2605 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft()); 2606 case IrOpcode::kJSShiftRight: 2607 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight()); 2608 case IrOpcode::kJSShiftRightLogical: 2609 return ReduceUI32Shift(node, kUnsigned, 2610 simplified()->NumberShiftRightLogical()); 2611 case IrOpcode::kJSAdd: 2612 return ReduceJSAdd(node); 2613 case IrOpcode::kJSSubtract: 2614 return ReduceNumberBinop(node, simplified()->NumberSubtract()); 2615 case IrOpcode::kJSMultiply: 2616 return ReduceNumberBinop(node, simplified()->NumberMultiply()); 2617 case IrOpcode::kJSDivide: 2618 return ReduceNumberBinop(node, simplified()->NumberDivide()); 2619 case IrOpcode::kJSModulus: 2620 return ReduceJSModulus(node); 2621 case IrOpcode::kJSToBoolean: 2622 return ReduceJSToBoolean(node); 2623 case IrOpcode::kJSToNumber: 2624 return ReduceJSToNumber(node); 2625 case IrOpcode::kJSToString: 2626 return ReduceJSToString(node); 2627 case IrOpcode::kJSToObject: 2628 return ReduceJSToObject(node); 2629 case IrOpcode::kJSLoadNamed: 2630 return ReduceJSLoadNamed(node); 2631 case IrOpcode::kJSLoadProperty: 2632 return ReduceJSLoadProperty(node); 2633 case IrOpcode::kJSStoreProperty: 2634 return ReduceJSStoreProperty(node); 2635 case IrOpcode::kJSInstanceOf: 2636 return ReduceJSInstanceOf(node); 2637 case IrOpcode::kJSLoadContext: 2638 return ReduceJSLoadContext(node); 2639 case IrOpcode::kJSStoreContext: 2640 return ReduceJSStoreContext(node); 2641 case IrOpcode::kJSConvertReceiver: 2642 return ReduceJSConvertReceiver(node); 2643 case IrOpcode::kJSCreate: 2644 return ReduceJSCreate(node); 2645 case IrOpcode::kJSCreateArguments: 2646 return ReduceJSCreateArguments(node); 2647 case IrOpcode::kJSCreateArray: 2648 return ReduceJSCreateArray(node); 2649 case IrOpcode::kJSCreateClosure: 2650 return ReduceJSCreateClosure(node); 2651 case IrOpcode::kJSCreateIterResultObject: 2652 return ReduceJSCreateIterResultObject(node); 2653 case IrOpcode::kJSCreateLiteralArray: 2654 return ReduceJSCreateLiteralArray(node); 2655 case IrOpcode::kJSCreateLiteralObject: 2656 return ReduceJSCreateLiteralObject(node); 2657 case IrOpcode::kJSCreateFunctionContext: 2658 return ReduceJSCreateFunctionContext(node); 2659 case IrOpcode::kJSCreateWithContext: 2660 return ReduceJSCreateWithContext(node); 2661 case IrOpcode::kJSCreateCatchContext: 2662 return ReduceJSCreateCatchContext(node); 2663 case IrOpcode::kJSCreateBlockContext: 2664 return ReduceJSCreateBlockContext(node); 2665 case IrOpcode::kJSCallConstruct: 2666 return ReduceJSCallConstruct(node); 2667 case IrOpcode::kJSCallFunction: 2668 return ReduceJSCallFunction(node); 2669 case IrOpcode::kJSForInDone: 2670 return ReduceJSForInDone(node); 2671 case IrOpcode::kJSForInNext: 2672 return ReduceJSForInNext(node); 2673 case IrOpcode::kJSForInPrepare: 2674 return ReduceJSForInPrepare(node); 2675 case IrOpcode::kJSForInStep: 2676 return ReduceJSForInStep(node); 2677 case IrOpcode::kSelect: 2678 return ReduceSelect(node); 2679 default: 2680 break; 2681 } 2682 return NoChange(); 2683 } 2684 2685 2686 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { 2687 if (rhs == 0) return lhs; 2688 return graph()->NewNode(machine()->Word32Shl(), lhs, 2689 jsgraph()->Int32Constant(rhs)); 2690 } 2691 2692 2693 // Helper that allocates a FixedArray holding argument values recorded in the 2694 // given {frame_state}. Serves as backing store for JSCreateArguments nodes. 2695 Node* JSTypedLowering::AllocateArguments(Node* effect, Node* control, 2696 Node* frame_state) { 2697 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 2698 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 2699 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); 2700 2701 // Prepare an iterator over argument values recorded in the frame state. 2702 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 2703 StateValuesAccess parameters_access(parameters); 2704 auto parameters_it = ++parameters_access.begin(); 2705 2706 // Actually allocate the backing store. 2707 AllocationBuilder a(jsgraph(), effect, control); 2708 a.AllocateArray(argument_count, factory()->fixed_array_map()); 2709 for (int i = 0; i < argument_count; ++i, ++parameters_it) { 2710 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 2711 } 2712 return a.Finish(); 2713 } 2714 2715 2716 // Helper that allocates a FixedArray holding argument values recorded in the 2717 // given {frame_state}. Serves as backing store for JSCreateArguments nodes. 2718 Node* JSTypedLowering::AllocateRestArguments(Node* effect, Node* control, 2719 Node* frame_state, 2720 int start_index) { 2721 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 2722 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 2723 int num_elements = std::max(0, argument_count - start_index); 2724 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant(); 2725 2726 // Prepare an iterator over argument values recorded in the frame state. 2727 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 2728 StateValuesAccess parameters_access(parameters); 2729 auto parameters_it = ++parameters_access.begin(); 2730 2731 // Skip unused arguments. 2732 for (int i = 0; i < start_index; i++) { 2733 ++parameters_it; 2734 } 2735 2736 // Actually allocate the backing store. 2737 AllocationBuilder a(jsgraph(), effect, control); 2738 a.AllocateArray(num_elements, factory()->fixed_array_map()); 2739 for (int i = 0; i < num_elements; ++i, ++parameters_it) { 2740 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 2741 } 2742 return a.Finish(); 2743 } 2744 2745 2746 // Helper that allocates a FixedArray serving as a parameter map for values 2747 // recorded in the given {frame_state}. Some elements map to slots within the 2748 // given {context}. Serves as backing store for JSCreateArguments nodes. 2749 Node* JSTypedLowering::AllocateAliasedArguments( 2750 Node* effect, Node* control, Node* frame_state, Node* context, 2751 Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) { 2752 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 2753 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 2754 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); 2755 2756 // If there is no aliasing, the arguments object elements are not special in 2757 // any way, we can just return an unmapped backing store instead. 2758 int parameter_count = shared->internal_formal_parameter_count(); 2759 if (parameter_count == 0) { 2760 return AllocateArguments(effect, control, frame_state); 2761 } 2762 2763 // Calculate number of argument values being aliased/mapped. 2764 int mapped_count = Min(argument_count, parameter_count); 2765 *has_aliased_arguments = true; 2766 2767 // Prepare an iterator over argument values recorded in the frame state. 2768 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 2769 StateValuesAccess parameters_access(parameters); 2770 auto paratemers_it = ++parameters_access.begin(); 2771 2772 // The unmapped argument values recorded in the frame state are stored yet 2773 // another indirection away and then linked into the parameter map below, 2774 // whereas mapped argument values are replaced with a hole instead. 2775 AllocationBuilder aa(jsgraph(), effect, control); 2776 aa.AllocateArray(argument_count, factory()->fixed_array_map()); 2777 for (int i = 0; i < mapped_count; ++i, ++paratemers_it) { 2778 aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant()); 2779 } 2780 for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) { 2781 aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node); 2782 } 2783 Node* arguments = aa.Finish(); 2784 2785 // Actually allocate the backing store. 2786 AllocationBuilder a(jsgraph(), arguments, control); 2787 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map()); 2788 a.Store(AccessBuilder::ForFixedArraySlot(0), context); 2789 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments); 2790 for (int i = 0; i < mapped_count; ++i) { 2791 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i; 2792 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx)); 2793 } 2794 return a.Finish(); 2795 } 2796 2797 2798 Node* JSTypedLowering::AllocateElements(Node* effect, Node* control, 2799 ElementsKind elements_kind, 2800 int capacity, PretenureFlag pretenure) { 2801 DCHECK_LE(1, capacity); 2802 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray); 2803 2804 Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind) 2805 ? factory()->fixed_double_array_map() 2806 : factory()->fixed_array_map(); 2807 ElementAccess access = IsFastDoubleElementsKind(elements_kind) 2808 ? AccessBuilder::ForFixedDoubleArrayElement() 2809 : AccessBuilder::ForFixedArrayElement(); 2810 Node* value = 2811 IsFastDoubleElementsKind(elements_kind) 2812 ? jsgraph()->Float64Constant(bit_cast<double>(kHoleNanInt64)) 2813 : jsgraph()->TheHoleConstant(); 2814 2815 // Actually allocate the backing store. 2816 AllocationBuilder a(jsgraph(), effect, control); 2817 a.AllocateArray(capacity, elements_map, pretenure); 2818 for (int i = 0; i < capacity; ++i) { 2819 Node* index = jsgraph()->Constant(i); 2820 a.Store(access, index, value); 2821 } 2822 return a.Finish(); 2823 } 2824 2825 2826 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } 2827 2828 2829 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); } 2830 2831 2832 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); } 2833 2834 2835 JSOperatorBuilder* JSTypedLowering::javascript() const { 2836 return jsgraph()->javascript(); 2837 } 2838 2839 2840 CommonOperatorBuilder* JSTypedLowering::common() const { 2841 return jsgraph()->common(); 2842 } 2843 2844 2845 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const { 2846 return jsgraph()->simplified(); 2847 } 2848 2849 2850 MachineOperatorBuilder* JSTypedLowering::machine() const { 2851 return jsgraph()->machine(); 2852 } 2853 2854 2855 CompilationDependencies* JSTypedLowering::dependencies() const { 2856 return dependencies_; 2857 } 2858 2859 } // namespace compiler 2860 } // namespace internal 2861 } // namespace v8 2862