1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/compiler/access-builder.h" 6#include "src/compiler/graph-inl.h" 7#include "src/compiler/js-builtin-reducer.h" 8#include "src/compiler/js-typed-lowering.h" 9#include "src/compiler/node-aux-data-inl.h" 10#include "src/compiler/node-properties-inl.h" 11#include "src/types.h" 12 13namespace v8 { 14namespace internal { 15namespace compiler { 16 17// TODO(turbofan): js-typed-lowering improvements possible 18// - immediately put in type bounds for all new nodes 19// - relax effects from generic but not-side-effecting operations 20// - relax effects for ToNumber(mixed) 21 22 23// Relax the effects of {node} by immediately replacing effect uses of {node} 24// with the effect input to {node}. 25// TODO(turbofan): replace the effect input to {node} with {graph->start()}. 26// TODO(titzer): move into a GraphEditor? 27static void RelaxEffects(Node* node) { 28 NodeProperties::ReplaceWithValue(node, node, NULL); 29} 30 31 32JSTypedLowering::~JSTypedLowering() {} 33 34 35Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) { 36 NodeProperties::ReplaceWithValue(old, node, node); 37 return Changed(node); 38} 39 40 41// A helper class to simplify the process of reducing a single binop node with a 42// JSOperator. This class manages the rewriting of context, control, and effect 43// dependencies during lowering of a binop and contains numerous helper 44// functions for matching the types of inputs to an operation. 45class JSBinopReduction { 46 public: 47 JSBinopReduction(JSTypedLowering* lowering, Node* node) 48 : lowering_(lowering), 49 node_(node), 50 left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper), 51 right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {} 52 53 void ConvertInputsToNumber() { 54 node_->ReplaceInput(0, ConvertToNumber(left())); 55 node_->ReplaceInput(1, ConvertToNumber(right())); 56 } 57 58 void ConvertInputsToInt32(bool left_signed, bool right_signed) { 59 node_->ReplaceInput(0, ConvertToI32(left_signed, left())); 60 node_->ReplaceInput(1, ConvertToI32(right_signed, right())); 61 } 62 63 void ConvertInputsToString() { 64 node_->ReplaceInput(0, ConvertToString(left())); 65 node_->ReplaceInput(1, ConvertToString(right())); 66 } 67 68 // Convert inputs for bitwise shift operation (ES5 spec 11.7). 69 void ConvertInputsForShift(bool left_signed) { 70 node_->ReplaceInput(0, ConvertToI32(left_signed, left())); 71 Node* rnum = ConvertToI32(false, right()); 72 node_->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rnum, 73 jsgraph()->Int32Constant(0x1F))); 74 } 75 76 void SwapInputs() { 77 Node* l = left(); 78 Node* r = right(); 79 node_->ReplaceInput(0, r); 80 node_->ReplaceInput(1, l); 81 std::swap(left_type_, right_type_); 82 } 83 84 // Remove all effect and control inputs and outputs to this node and change 85 // to the pure operator {op}, possibly inserting a boolean inversion. 86 Reduction ChangeToPureOperator(const Operator* op, bool invert = false) { 87 DCHECK_EQ(0, OperatorProperties::GetEffectInputCount(op)); 88 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 89 DCHECK_EQ(0, OperatorProperties::GetControlInputCount(op)); 90 DCHECK_EQ(2, OperatorProperties::GetValueInputCount(op)); 91 92 // Remove the effects from the node, if any, and update its effect usages. 93 if (OperatorProperties::GetEffectInputCount(node_->op()) > 0) { 94 RelaxEffects(node_); 95 } 96 // Remove the inputs corresponding to context, effect, and control. 97 NodeProperties::RemoveNonValueInputs(node_); 98 // Finally, update the operator to the new one. 99 node_->set_op(op); 100 101 if (invert) { 102 // Insert an boolean not to invert the value. 103 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 104 node_->ReplaceUses(value); 105 // Note: ReplaceUses() smashes all uses, so smash it back here. 106 value->ReplaceInput(0, node_); 107 return lowering_->ReplaceWith(value); 108 } 109 return lowering_->Changed(node_); 110 } 111 112 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } 113 114 bool BothInputsAre(Type* t) { 115 return left_type_->Is(t) && right_type_->Is(t); 116 } 117 118 bool OneInputCannotBe(Type* t) { 119 return !left_type_->Maybe(t) || !right_type_->Maybe(t); 120 } 121 122 bool NeitherInputCanBe(Type* t) { 123 return !left_type_->Maybe(t) && !right_type_->Maybe(t); 124 } 125 126 Node* effect() { return NodeProperties::GetEffectInput(node_); } 127 Node* control() { return NodeProperties::GetControlInput(node_); } 128 Node* context() { return NodeProperties::GetContextInput(node_); } 129 Node* left() { return NodeProperties::GetValueInput(node_, 0); } 130 Node* right() { return NodeProperties::GetValueInput(node_, 1); } 131 Type* left_type() { return left_type_; } 132 Type* right_type() { return right_type_; } 133 134 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } 135 Graph* graph() { return lowering_->graph(); } 136 JSGraph* jsgraph() { return lowering_->jsgraph(); } 137 JSOperatorBuilder* javascript() { return lowering_->javascript(); } 138 MachineOperatorBuilder* machine() { return lowering_->machine(); } 139 140 private: 141 JSTypedLowering* lowering_; // The containing lowering instance. 142 Node* node_; // The original node. 143 Type* left_type_; // Cache of the left input's type. 144 Type* right_type_; // Cache of the right input's type. 145 146 Node* ConvertToString(Node* node) { 147 // Avoid introducing too many eager ToString() operations. 148 Reduction reduced = lowering_->ReduceJSToStringInput(node); 149 if (reduced.Changed()) return reduced.replacement(); 150 Node* n = graph()->NewNode(javascript()->ToString(), node, context(), 151 effect(), control()); 152 update_effect(n); 153 return n; 154 } 155 156 Node* ConvertToNumber(Node* node) { 157 // Avoid introducing too many eager ToNumber() operations. 158 Reduction reduced = lowering_->ReduceJSToNumberInput(node); 159 if (reduced.Changed()) return reduced.replacement(); 160 Node* n = graph()->NewNode(javascript()->ToNumber(), node, context(), 161 effect(), control()); 162 update_effect(n); 163 return n; 164 } 165 166 // Try to narrowing a double or number operation to an Int32 operation. 167 bool TryNarrowingToI32(Type* type, Node* node) { 168 switch (node->opcode()) { 169 case IrOpcode::kFloat64Add: 170 case IrOpcode::kNumberAdd: { 171 JSBinopReduction r(lowering_, node); 172 if (r.BothInputsAre(Type::Integral32())) { 173 node->set_op(lowering_->machine()->Int32Add()); 174 // TODO(titzer): narrow bounds instead of overwriting. 175 NodeProperties::SetBounds(node, Bounds(type)); 176 return true; 177 } 178 } 179 case IrOpcode::kFloat64Sub: 180 case IrOpcode::kNumberSubtract: { 181 JSBinopReduction r(lowering_, node); 182 if (r.BothInputsAre(Type::Integral32())) { 183 node->set_op(lowering_->machine()->Int32Sub()); 184 // TODO(titzer): narrow bounds instead of overwriting. 185 NodeProperties::SetBounds(node, Bounds(type)); 186 return true; 187 } 188 } 189 default: 190 return false; 191 } 192 } 193 194 Node* ConvertToI32(bool is_signed, Node* node) { 195 Type* type = is_signed ? Type::Signed32() : Type::Unsigned32(); 196 if (node->OwnedBy(node_)) { 197 // If this node {node_} has the only edge to {node}, then try narrowing 198 // its operation to an Int32 add or subtract. 199 if (TryNarrowingToI32(type, node)) return node; 200 } else { 201 // Otherwise, {node} has multiple uses. Leave it as is and let the 202 // further lowering passes deal with it, which use a full backwards 203 // fixpoint. 204 } 205 206 // Avoid introducing too many eager NumberToXXnt32() operations. 207 node = ConvertToNumber(node); 208 Type* input_type = NodeProperties::GetBounds(node).upper; 209 210 if (input_type->Is(type)) return node; // already in the value range. 211 212 const Operator* op = is_signed ? simplified()->NumberToInt32() 213 : simplified()->NumberToUint32(); 214 Node* n = graph()->NewNode(op, node); 215 return n; 216 } 217 218 void update_effect(Node* effect) { 219 NodeProperties::ReplaceEffectInput(node_, effect); 220 } 221}; 222 223 224Reduction JSTypedLowering::ReduceJSAdd(Node* node) { 225 JSBinopReduction r(this, node); 226 if (r.BothInputsAre(Type::Number())) { 227 // JSAdd(x:number, y:number) => NumberAdd(x, y) 228 return r.ChangeToPureOperator(simplified()->NumberAdd()); 229 } 230 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); 231 if (r.NeitherInputCanBe(maybe_string)) { 232 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 233 r.ConvertInputsToNumber(); 234 return r.ChangeToPureOperator(simplified()->NumberAdd()); 235 } 236#if 0 237 // TODO(turbofan): Lowering of StringAdd is disabled for now because: 238 // a) The inserted ToString operation screws up valueOf vs. toString order. 239 // b) Deoptimization at ToString doesn't have corresponding bailout id. 240 // c) Our current StringAddStub is actually non-pure and requires context. 241 if (r.OneInputIs(Type::String())) { 242 // JSAdd(x:string, y:string) => StringAdd(x, y) 243 // JSAdd(x:string, y) => StringAdd(x, ToString(y)) 244 // JSAdd(x, y:string) => StringAdd(ToString(x), y) 245 r.ConvertInputsToString(); 246 return r.ChangeToPureOperator(simplified()->StringAdd()); 247 } 248#endif 249 return NoChange(); 250} 251 252 253Reduction JSTypedLowering::ReduceNumberBinop(Node* node, 254 const Operator* numberOp) { 255 JSBinopReduction r(this, node); 256 if (r.OneInputIs(Type::Primitive())) { 257 // If at least one input is a primitive, then insert appropriate conversions 258 // to number and reduce this operator to the given numeric one. 259 // TODO(turbofan): make this heuristic configurable for code size. 260 r.ConvertInputsToNumber(); 261 return r.ChangeToPureOperator(numberOp); 262 } 263 // TODO(turbofan): relax/remove the effects of this operator in other cases. 264 return NoChange(); 265} 266 267 268Reduction JSTypedLowering::ReduceI32Binop(Node* node, bool left_signed, 269 bool right_signed, 270 const Operator* intOp) { 271 JSBinopReduction r(this, node); 272 // TODO(titzer): some Smi bitwise operations don't really require going 273 // all the way to int32, which can save tagging/untagging for some operations 274 // on some platforms. 275 // TODO(turbofan): make this heuristic configurable for code size. 276 r.ConvertInputsToInt32(left_signed, right_signed); 277 return r.ChangeToPureOperator(intOp); 278} 279 280 281Reduction JSTypedLowering::ReduceI32Shift(Node* node, bool left_signed, 282 const Operator* shift_op) { 283 JSBinopReduction r(this, node); 284 r.ConvertInputsForShift(left_signed); 285 return r.ChangeToPureOperator(shift_op); 286} 287 288 289Reduction JSTypedLowering::ReduceJSComparison(Node* node) { 290 JSBinopReduction r(this, node); 291 if (r.BothInputsAre(Type::String())) { 292 // If both inputs are definitely strings, perform a string comparison. 293 const Operator* stringOp; 294 switch (node->opcode()) { 295 case IrOpcode::kJSLessThan: 296 stringOp = simplified()->StringLessThan(); 297 break; 298 case IrOpcode::kJSGreaterThan: 299 stringOp = simplified()->StringLessThan(); 300 r.SwapInputs(); // a > b => b < a 301 break; 302 case IrOpcode::kJSLessThanOrEqual: 303 stringOp = simplified()->StringLessThanOrEqual(); 304 break; 305 case IrOpcode::kJSGreaterThanOrEqual: 306 stringOp = simplified()->StringLessThanOrEqual(); 307 r.SwapInputs(); // a >= b => b <= a 308 break; 309 default: 310 return NoChange(); 311 } 312 return r.ChangeToPureOperator(stringOp); 313 } 314 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); 315 if (r.OneInputCannotBe(maybe_string)) { 316 // If one input cannot be a string, then emit a number comparison. 317 const Operator* less_than; 318 const Operator* less_than_or_equal; 319 if (r.BothInputsAre(Type::Unsigned32())) { 320 less_than = machine()->Uint32LessThan(); 321 less_than_or_equal = machine()->Uint32LessThanOrEqual(); 322 } else if (r.BothInputsAre(Type::Signed32())) { 323 less_than = machine()->Int32LessThan(); 324 less_than_or_equal = machine()->Int32LessThanOrEqual(); 325 } else { 326 // TODO(turbofan): mixed signed/unsigned int32 comparisons. 327 r.ConvertInputsToNumber(); 328 less_than = simplified()->NumberLessThan(); 329 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 330 } 331 const Operator* comparison; 332 switch (node->opcode()) { 333 case IrOpcode::kJSLessThan: 334 comparison = less_than; 335 break; 336 case IrOpcode::kJSGreaterThan: 337 comparison = less_than; 338 r.SwapInputs(); // a > b => b < a 339 break; 340 case IrOpcode::kJSLessThanOrEqual: 341 comparison = less_than_or_equal; 342 break; 343 case IrOpcode::kJSGreaterThanOrEqual: 344 comparison = less_than_or_equal; 345 r.SwapInputs(); // a >= b => b <= a 346 break; 347 default: 348 return NoChange(); 349 } 350 return r.ChangeToPureOperator(comparison); 351 } 352 // TODO(turbofan): relax/remove effects of this operator in other cases. 353 return NoChange(); // Keep a generic comparison. 354} 355 356 357Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { 358 JSBinopReduction r(this, node); 359 360 if (r.BothInputsAre(Type::Number())) { 361 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 362 } 363 if (r.BothInputsAre(Type::String())) { 364 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); 365 } 366 if (r.BothInputsAre(Type::Receiver())) { 367 return r.ChangeToPureOperator( 368 simplified()->ReferenceEqual(Type::Receiver()), invert); 369 } 370 // TODO(turbofan): js-typed-lowering of Equal(undefined) 371 // TODO(turbofan): js-typed-lowering of Equal(null) 372 // TODO(turbofan): js-typed-lowering of Equal(boolean) 373 return NoChange(); 374} 375 376 377Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { 378 JSBinopReduction r(this, node); 379 if (r.left() == r.right()) { 380 // x === x is always true if x != NaN 381 if (!r.left_type()->Maybe(Type::NaN())) { 382 return ReplaceEagerly(node, invert ? jsgraph()->FalseConstant() 383 : jsgraph()->TrueConstant()); 384 } 385 } 386 if (!r.left_type()->Maybe(r.right_type())) { 387 // Type intersection is empty; === is always false unless both 388 // inputs could be strings (one internalized and one not). 389 if (r.OneInputCannotBe(Type::String())) { 390 return ReplaceEagerly(node, invert ? jsgraph()->TrueConstant() 391 : jsgraph()->FalseConstant()); 392 } 393 } 394 if (r.OneInputIs(Type::Undefined())) { 395 return r.ChangeToPureOperator( 396 simplified()->ReferenceEqual(Type::Undefined()), invert); 397 } 398 if (r.OneInputIs(Type::Null())) { 399 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()), 400 invert); 401 } 402 if (r.OneInputIs(Type::Boolean())) { 403 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()), 404 invert); 405 } 406 if (r.OneInputIs(Type::Object())) { 407 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()), 408 invert); 409 } 410 if (r.OneInputIs(Type::Receiver())) { 411 return r.ChangeToPureOperator( 412 simplified()->ReferenceEqual(Type::Receiver()), invert); 413 } 414 if (r.BothInputsAre(Type::String())) { 415 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); 416 } 417 if (r.BothInputsAre(Type::Number())) { 418 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 419 } 420 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types) 421 return NoChange(); 422} 423 424 425Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { 426 if (input->opcode() == IrOpcode::kJSToNumber) { 427 // Recursively try to reduce the input first. 428 Reduction result = ReduceJSToNumberInput(input->InputAt(0)); 429 if (result.Changed()) { 430 RelaxEffects(input); 431 return result; 432 } 433 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) 434 } 435 Type* input_type = NodeProperties::GetBounds(input).upper; 436 if (input_type->Is(Type::Number())) { 437 // JSToNumber(x:number) => x 438 return Changed(input); 439 } 440 if (input_type->Is(Type::Undefined())) { 441 // JSToNumber(undefined) => #NaN 442 return ReplaceWith(jsgraph()->NaNConstant()); 443 } 444 if (input_type->Is(Type::Null())) { 445 // JSToNumber(null) => #0 446 return ReplaceWith(jsgraph()->ZeroConstant()); 447 } 448 if (input_type->Is(Type::Boolean())) { 449 // JSToNumber(x:boolean) => BooleanToNumber(x) 450 return ReplaceWith( 451 graph()->NewNode(simplified()->BooleanToNumber(), input)); 452 } 453 // TODO(turbofan): js-typed-lowering of ToNumber(x:string) 454 return NoChange(); 455} 456 457 458Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { 459 if (input->opcode() == IrOpcode::kJSToString) { 460 // Recursively try to reduce the input first. 461 Reduction result = ReduceJSToStringInput(input->InputAt(0)); 462 if (result.Changed()) { 463 RelaxEffects(input); 464 return result; 465 } 466 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) 467 } 468 Type* input_type = NodeProperties::GetBounds(input).upper; 469 if (input_type->Is(Type::String())) { 470 return Changed(input); // JSToString(x:string) => x 471 } 472 if (input_type->Is(Type::Undefined())) { 473 return ReplaceWith(jsgraph()->HeapConstant( 474 graph()->zone()->isolate()->factory()->undefined_string())); 475 } 476 if (input_type->Is(Type::Null())) { 477 return ReplaceWith(jsgraph()->HeapConstant( 478 graph()->zone()->isolate()->factory()->null_string())); 479 } 480 // TODO(turbofan): js-typed-lowering of ToString(x:boolean) 481 // TODO(turbofan): js-typed-lowering of ToString(x:number) 482 return NoChange(); 483} 484 485 486Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { 487 if (input->opcode() == IrOpcode::kJSToBoolean) { 488 // Recursively try to reduce the input first. 489 Reduction result = ReduceJSToBooleanInput(input->InputAt(0)); 490 if (result.Changed()) { 491 RelaxEffects(input); 492 return result; 493 } 494 return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x) 495 } 496 Type* input_type = NodeProperties::GetBounds(input).upper; 497 if (input_type->Is(Type::Boolean())) { 498 return Changed(input); // JSToBoolean(x:boolean) => x 499 } 500 if (input_type->Is(Type::Undefined())) { 501 // JSToBoolean(undefined) => #false 502 return ReplaceWith(jsgraph()->FalseConstant()); 503 } 504 if (input_type->Is(Type::Null())) { 505 // JSToBoolean(null) => #false 506 return ReplaceWith(jsgraph()->FalseConstant()); 507 } 508 if (input_type->Is(Type::DetectableReceiver())) { 509 // JSToBoolean(x:detectable) => #true 510 return ReplaceWith(jsgraph()->TrueConstant()); 511 } 512 if (input_type->Is(Type::Undetectable())) { 513 // JSToBoolean(x:undetectable) => #false 514 return ReplaceWith(jsgraph()->FalseConstant()); 515 } 516 if (input_type->Is(Type::OrderedNumber())) { 517 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) 518 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input, 519 jsgraph()->ZeroConstant()); 520 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); 521 return ReplaceWith(inv); 522 } 523 // TODO(turbofan): js-typed-lowering of ToBoolean(string) 524 return NoChange(); 525} 526 527 528Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { 529 Node* key = NodeProperties::GetValueInput(node, 1); 530 Node* base = NodeProperties::GetValueInput(node, 0); 531 Type* key_type = NodeProperties::GetBounds(key).upper; 532 Type* base_type = NodeProperties::GetBounds(base).upper; 533 // TODO(mstarzinger): This lowering is not correct if: 534 // a) The typed array turns external (i.e. MaterializeArrayBuffer) 535 // b) The typed array or it's buffer is neutered. 536 // c) The index is out of bounds. 537 if (base_type->IsConstant() && key_type->Is(Type::Integral32()) && 538 base_type->AsConstant()->Value()->IsJSTypedArray()) { 539 // JSLoadProperty(typed-array, int32) 540 JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value()); 541 ElementsKind elements_kind = array->map()->elements_kind(); 542 ExternalArrayType type = array->type(); 543 uint32_t length; 544 CHECK(array->length()->ToUint32(&length)); 545 ElementAccess element_access; 546 Node* elements = graph()->NewNode( 547 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base, 548 NodeProperties::GetEffectInput(node)); 549 if (IsExternalArrayElementsKind(elements_kind)) { 550 elements = graph()->NewNode( 551 simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()), 552 elements, NodeProperties::GetEffectInput(node)); 553 element_access = AccessBuilder::ForTypedArrayElement(type, true); 554 } else { 555 DCHECK(IsFixedTypedArrayElementsKind(elements_kind)); 556 element_access = AccessBuilder::ForTypedArrayElement(type, false); 557 } 558 Node* value = 559 graph()->NewNode(simplified()->LoadElement(element_access), elements, 560 key, jsgraph()->Uint32Constant(length), 561 NodeProperties::GetEffectInput(node)); 562 return ReplaceEagerly(node, value); 563 } 564 return NoChange(); 565} 566 567 568Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { 569 Node* key = NodeProperties::GetValueInput(node, 1); 570 Node* base = NodeProperties::GetValueInput(node, 0); 571 Node* value = NodeProperties::GetValueInput(node, 2); 572 Type* key_type = NodeProperties::GetBounds(key).upper; 573 Type* base_type = NodeProperties::GetBounds(base).upper; 574 // TODO(mstarzinger): This lowering is not correct if: 575 // a) The typed array turns external (i.e. MaterializeArrayBuffer) 576 // b) The typed array or it's buffer is neutered. 577 if (key_type->Is(Type::Integral32()) && base_type->IsConstant() && 578 base_type->AsConstant()->Value()->IsJSTypedArray()) { 579 // JSStoreProperty(typed-array, int32, value) 580 JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value()); 581 ElementsKind elements_kind = array->map()->elements_kind(); 582 ExternalArrayType type = array->type(); 583 uint32_t length; 584 CHECK(array->length()->ToUint32(&length)); 585 ElementAccess element_access; 586 Node* elements = graph()->NewNode( 587 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base, 588 NodeProperties::GetEffectInput(node)); 589 if (IsExternalArrayElementsKind(elements_kind)) { 590 elements = graph()->NewNode( 591 simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()), 592 elements, NodeProperties::GetEffectInput(node)); 593 element_access = AccessBuilder::ForTypedArrayElement(type, true); 594 } else { 595 DCHECK(IsFixedTypedArrayElementsKind(elements_kind)); 596 element_access = AccessBuilder::ForTypedArrayElement(type, false); 597 } 598 599 Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, 600 jsgraph()->Uint32Constant(length)); 601 Node* branch = graph()->NewNode(common()->Branch(), check, 602 NodeProperties::GetControlInput(node)); 603 604 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 605 Node* store = 606 graph()->NewNode(simplified()->StoreElement(element_access), elements, 607 key, jsgraph()->Uint32Constant(length), value, 608 NodeProperties::GetEffectInput(node), if_true); 609 610 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 611 612 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); 613 Node* phi = graph()->NewNode(common()->EffectPhi(2), store, 614 NodeProperties::GetEffectInput(node), merge); 615 616 return ReplaceWith(phi); 617 } 618 return NoChange(); 619} 620 621 622static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { 623 if (reduction.Changed()) { 624 NodeProperties::ReplaceWithValue(node, reduction.replacement()); 625 return reduction; 626 } 627 return Reducer::NoChange(); 628} 629 630 631Reduction JSTypedLowering::Reduce(Node* node) { 632 switch (node->opcode()) { 633 case IrOpcode::kJSEqual: 634 return ReduceJSEqual(node, false); 635 case IrOpcode::kJSNotEqual: 636 return ReduceJSEqual(node, true); 637 case IrOpcode::kJSStrictEqual: 638 return ReduceJSStrictEqual(node, false); 639 case IrOpcode::kJSStrictNotEqual: 640 return ReduceJSStrictEqual(node, true); 641 case IrOpcode::kJSLessThan: // fall through 642 case IrOpcode::kJSGreaterThan: // fall through 643 case IrOpcode::kJSLessThanOrEqual: // fall through 644 case IrOpcode::kJSGreaterThanOrEqual: 645 return ReduceJSComparison(node); 646 case IrOpcode::kJSBitwiseOr: 647 return ReduceI32Binop(node, true, true, machine()->Word32Or()); 648 case IrOpcode::kJSBitwiseXor: 649 return ReduceI32Binop(node, true, true, machine()->Word32Xor()); 650 case IrOpcode::kJSBitwiseAnd: 651 return ReduceI32Binop(node, true, true, machine()->Word32And()); 652 case IrOpcode::kJSShiftLeft: 653 return ReduceI32Shift(node, true, machine()->Word32Shl()); 654 case IrOpcode::kJSShiftRight: 655 return ReduceI32Shift(node, true, machine()->Word32Sar()); 656 case IrOpcode::kJSShiftRightLogical: 657 return ReduceI32Shift(node, false, machine()->Word32Shr()); 658 case IrOpcode::kJSAdd: 659 return ReduceJSAdd(node); 660 case IrOpcode::kJSSubtract: 661 return ReduceNumberBinop(node, simplified()->NumberSubtract()); 662 case IrOpcode::kJSMultiply: 663 return ReduceNumberBinop(node, simplified()->NumberMultiply()); 664 case IrOpcode::kJSDivide: 665 return ReduceNumberBinop(node, simplified()->NumberDivide()); 666 case IrOpcode::kJSModulus: 667 return ReduceNumberBinop(node, simplified()->NumberModulus()); 668 case IrOpcode::kJSUnaryNot: { 669 Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); 670 Node* value; 671 if (result.Changed()) { 672 // JSUnaryNot(x:boolean) => BooleanNot(x) 673 value = 674 graph()->NewNode(simplified()->BooleanNot(), result.replacement()); 675 NodeProperties::ReplaceWithValue(node, value); 676 return Changed(value); 677 } else { 678 // JSUnaryNot(x) => BooleanNot(JSToBoolean(x)) 679 value = graph()->NewNode(simplified()->BooleanNot(), node); 680 node->set_op(javascript()->ToBoolean()); 681 NodeProperties::ReplaceWithValue(node, value, node); 682 // Note: ReplaceUses() smashes all uses, so smash it back here. 683 value->ReplaceInput(0, node); 684 return Changed(node); 685 } 686 } 687 case IrOpcode::kJSToBoolean: 688 return ReplaceWithReduction(node, 689 ReduceJSToBooleanInput(node->InputAt(0))); 690 case IrOpcode::kJSToNumber: 691 return ReplaceWithReduction(node, 692 ReduceJSToNumberInput(node->InputAt(0))); 693 case IrOpcode::kJSToString: 694 return ReplaceWithReduction(node, 695 ReduceJSToStringInput(node->InputAt(0))); 696 case IrOpcode::kJSLoadProperty: 697 return ReduceJSLoadProperty(node); 698 case IrOpcode::kJSStoreProperty: 699 return ReduceJSStoreProperty(node); 700 case IrOpcode::kJSCallFunction: 701 return JSBuiltinReducer(jsgraph()).Reduce(node); 702 default: 703 break; 704 } 705 return NoChange(); 706} 707 708} // namespace compiler 709} // namespace internal 710} // namespace v8 711