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