js-builtin-reducer.cc revision f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3
1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/compiler/js-builtin-reducer.h" 6 7#include "src/compilation-dependencies.h" 8#include "src/compiler/access-builder.h" 9#include "src/compiler/js-graph.h" 10#include "src/compiler/node-matchers.h" 11#include "src/compiler/node-properties.h" 12#include "src/compiler/simplified-operator.h" 13#include "src/compiler/type-cache.h" 14#include "src/compiler/types.h" 15#include "src/objects-inl.h" 16 17namespace v8 { 18namespace internal { 19namespace compiler { 20 21 22// Helper class to access JSCallFunction nodes that are potential candidates 23// for reduction when they have a BuiltinFunctionId associated with them. 24class JSCallReduction { 25 public: 26 explicit JSCallReduction(Node* node) : node_(node) {} 27 28 // Determines whether the node is a JSCallFunction operation that targets a 29 // constant callee being a well-known builtin with a BuiltinFunctionId. 30 bool HasBuiltinFunctionId() { 31 if (node_->opcode() != IrOpcode::kJSCallFunction) return false; 32 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); 33 if (!m.HasValue() || !m.Value()->IsJSFunction()) return false; 34 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 35 return function->shared()->HasBuiltinFunctionId(); 36 } 37 38 // Retrieves the BuiltinFunctionId as described above. 39 BuiltinFunctionId GetBuiltinFunctionId() { 40 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 41 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); 42 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 43 return function->shared()->builtin_function_id(); 44 } 45 46 bool ReceiverMatches(Type* type) { 47 return NodeProperties::GetType(receiver())->Is(type); 48 } 49 50 // Determines whether the call takes zero inputs. 51 bool InputsMatchZero() { return GetJSCallArity() == 0; } 52 53 // Determines whether the call takes one input of the given type. 54 bool InputsMatchOne(Type* t1) { 55 return GetJSCallArity() == 1 && 56 NodeProperties::GetType(GetJSCallInput(0))->Is(t1); 57 } 58 59 // Determines whether the call takes two inputs of the given types. 60 bool InputsMatchTwo(Type* t1, Type* t2) { 61 return GetJSCallArity() == 2 && 62 NodeProperties::GetType(GetJSCallInput(0))->Is(t1) && 63 NodeProperties::GetType(GetJSCallInput(1))->Is(t2); 64 } 65 66 // Determines whether the call takes inputs all of the given type. 67 bool InputsMatchAll(Type* t) { 68 for (int i = 0; i < GetJSCallArity(); i++) { 69 if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) { 70 return false; 71 } 72 } 73 return true; 74 } 75 76 Node* receiver() { return NodeProperties::GetValueInput(node_, 1); } 77 Node* left() { return GetJSCallInput(0); } 78 Node* right() { return GetJSCallInput(1); } 79 80 int GetJSCallArity() { 81 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 82 // Skip first (i.e. callee) and second (i.e. receiver) operand. 83 return node_->op()->ValueInputCount() - 2; 84 } 85 86 Node* GetJSCallInput(int index) { 87 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 88 DCHECK_LT(index, GetJSCallArity()); 89 // Skip first (i.e. callee) and second (i.e. receiver) operand. 90 return NodeProperties::GetValueInput(node_, index + 2); 91 } 92 93 private: 94 Node* node_; 95}; 96 97JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph, 98 Flags flags, 99 CompilationDependencies* dependencies) 100 : AdvancedReducer(editor), 101 dependencies_(dependencies), 102 flags_(flags), 103 jsgraph_(jsgraph), 104 type_cache_(TypeCache::Get()) {} 105 106namespace { 107 108MaybeHandle<Map> GetMapWitness(Node* node) { 109 Node* receiver = NodeProperties::GetValueInput(node, 1); 110 Node* effect = NodeProperties::GetEffectInput(node); 111 // Check if the {node} is dominated by a CheckMaps with a single map 112 // for the {receiver}, and if so use that map for the lowering below. 113 for (Node* dominator = effect;;) { 114 if (dominator->opcode() == IrOpcode::kCheckMaps && 115 dominator->InputAt(0) == receiver) { 116 if (dominator->op()->ValueInputCount() == 2) { 117 HeapObjectMatcher m(dominator->InputAt(1)); 118 if (m.HasValue()) return Handle<Map>::cast(m.Value()); 119 } 120 return MaybeHandle<Map>(); 121 } 122 if (dominator->op()->EffectInputCount() != 1) { 123 // Didn't find any appropriate CheckMaps node. 124 return MaybeHandle<Map>(); 125 } 126 dominator = NodeProperties::GetEffectInput(dominator); 127 } 128} 129 130// TODO(turbofan): This was copied from Crankshaft, might be too restrictive. 131bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) { 132 DCHECK(!jsarray_map->is_dictionary_map()); 133 Isolate* isolate = jsarray_map->GetIsolate(); 134 Handle<Name> length_string = isolate->factory()->length_string(); 135 DescriptorArray* descriptors = jsarray_map->instance_descriptors(); 136 int number = 137 descriptors->SearchWithCache(isolate, *length_string, *jsarray_map); 138 DCHECK_NE(DescriptorArray::kNotFound, number); 139 return descriptors->GetDetails(number).IsReadOnly(); 140} 141 142// TODO(turbofan): This was copied from Crankshaft, might be too restrictive. 143bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) { 144 Isolate* const isolate = receiver_map->GetIsolate(); 145 if (!receiver_map->prototype()->IsJSArray()) return false; 146 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()), 147 isolate); 148 // Ensure that all prototypes of the {receiver} are stable. 149 for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver); 150 !it.IsAtEnd(); it.Advance()) { 151 Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it); 152 if (!current->map()->is_stable()) return false; 153 } 154 return receiver_map->instance_type() == JS_ARRAY_TYPE && 155 IsFastElementsKind(receiver_map->elements_kind()) && 156 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && 157 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && 158 isolate->IsFastArrayConstructorPrototypeChainIntact() && 159 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && 160 !IsReadOnlyLengthDescriptor(receiver_map); 161} 162 163} // namespace 164 165// ES6 section 22.1.3.17 Array.prototype.pop ( ) 166Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { 167 Handle<Map> receiver_map; 168 Node* receiver = NodeProperties::GetValueInput(node, 1); 169 Node* effect = NodeProperties::GetEffectInput(node); 170 Node* control = NodeProperties::GetControlInput(node); 171 // TODO(turbofan): Extend this to also handle fast (holey) double elements 172 // once we got the hole NaN mess sorted out in TurboFan/V8. 173 if (GetMapWitness(node).ToHandle(&receiver_map) && 174 CanInlineArrayResizeOperation(receiver_map) && 175 IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) { 176 // Install code dependencies on the {receiver} prototype maps and the 177 // global array protector cell. 178 dependencies()->AssumePropertyCell(factory()->array_protector()); 179 dependencies()->AssumePrototypeMapsStable(receiver_map); 180 181 // Load the "length" property of the {receiver}. 182 Node* length = effect = graph()->NewNode( 183 simplified()->LoadField( 184 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 185 receiver, effect, control); 186 187 // Check if the {receiver} has any elements. 188 Node* check = graph()->NewNode(simplified()->NumberEqual(), length, 189 jsgraph()->ZeroConstant()); 190 Node* branch = 191 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 192 193 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 194 Node* etrue = effect; 195 Node* vtrue = jsgraph()->UndefinedConstant(); 196 197 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 198 Node* efalse = effect; 199 Node* vfalse; 200 { 201 // Load the elements backing store from the {receiver}. 202 Node* elements = efalse = graph()->NewNode( 203 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 204 receiver, efalse, if_false); 205 206 // Ensure that we aren't popping from a copy-on-write backing store. 207 elements = efalse = 208 graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver, 209 elements, efalse, if_false); 210 211 // Compute the new {length}. 212 length = graph()->NewNode(simplified()->NumberSubtract(), length, 213 jsgraph()->OneConstant()); 214 215 // Store the new {length} to the {receiver}. 216 efalse = graph()->NewNode( 217 simplified()->StoreField( 218 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 219 receiver, length, efalse, if_false); 220 221 // Load the last entry from the {elements}. 222 vfalse = efalse = graph()->NewNode( 223 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement( 224 receiver_map->elements_kind())), 225 elements, length, efalse, if_false); 226 227 // Store a hole to the element we just removed from the {receiver}. 228 efalse = graph()->NewNode( 229 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( 230 GetHoleyElementsKind(receiver_map->elements_kind()))), 231 elements, length, jsgraph()->TheHoleConstant(), efalse, if_false); 232 } 233 234 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 235 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 236 Node* value = 237 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 238 vtrue, vfalse, control); 239 240 // Convert the hole to undefined. Do this last, so that we can optimize 241 // conversion operator via some smart strength reduction in many cases. 242 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { 243 value = 244 graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); 245 } 246 247 ReplaceWithValue(node, value, effect, control); 248 return Replace(value); 249 } 250 return NoChange(); 251} 252 253// ES6 section 22.1.3.18 Array.prototype.push ( ) 254Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) { 255 Handle<Map> receiver_map; 256 // We need exactly target, receiver and value parameters. 257 if (node->op()->ValueInputCount() != 3) return NoChange(); 258 Node* receiver = NodeProperties::GetValueInput(node, 1); 259 Node* effect = NodeProperties::GetEffectInput(node); 260 Node* control = NodeProperties::GetControlInput(node); 261 Node* value = NodeProperties::GetValueInput(node, 2); 262 if (GetMapWitness(node).ToHandle(&receiver_map) && 263 CanInlineArrayResizeOperation(receiver_map)) { 264 // Install code dependencies on the {receiver} prototype maps and the 265 // global array protector cell. 266 dependencies()->AssumePropertyCell(factory()->array_protector()); 267 dependencies()->AssumePrototypeMapsStable(receiver_map); 268 269 // TODO(turbofan): Perform type checks on the {value}. We are not guaranteed 270 // to learn from these checks in case they fail, as the witness (i.e. the 271 // map check from the LoadIC for a.push) might not be executed in baseline 272 // code (after we stored the value in the builtin and thereby changed the 273 // elements kind of a) before be decide to optimize this function again. We 274 // currently don't have a proper way to deal with this; the proper solution 275 // here is to learn on deopt, i.e. disable Array.prototype.push inlining 276 // for this function. 277 if (IsFastSmiElementsKind(receiver_map->elements_kind())) { 278 value = effect = 279 graph()->NewNode(simplified()->CheckSmi(), value, effect, control); 280 } else if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { 281 value = effect = 282 graph()->NewNode(simplified()->CheckNumber(), value, effect, control); 283 // Make sure we do not store signaling NaNs into double arrays. 284 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); 285 } 286 287 // Load the "length" property of the {receiver}. 288 Node* length = effect = graph()->NewNode( 289 simplified()->LoadField( 290 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 291 receiver, effect, control); 292 293 // Load the elements backing store of the {receiver}. 294 Node* elements = effect = graph()->NewNode( 295 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, 296 effect, control); 297 298 // TODO(turbofan): Check if we need to grow the {elements} backing store. 299 // This will deopt if we cannot grow the array further, and we currently 300 // don't necessarily learn from it. See the comment on the value type check 301 // above. 302 GrowFastElementsFlags flags = GrowFastElementsFlag::kArrayObject; 303 if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { 304 flags |= GrowFastElementsFlag::kDoubleElements; 305 } 306 elements = effect = 307 graph()->NewNode(simplified()->MaybeGrowFastElements(flags), receiver, 308 elements, length, length, effect, control); 309 310 // Append the value to the {elements}. 311 effect = graph()->NewNode( 312 simplified()->StoreElement( 313 AccessBuilder::ForFixedArrayElement(receiver_map->elements_kind())), 314 elements, length, value, effect, control); 315 316 // Return the new length of the {receiver}. 317 value = graph()->NewNode(simplified()->NumberAdd(), length, 318 jsgraph()->OneConstant()); 319 320 ReplaceWithValue(node, value, effect, control); 321 return Replace(value); 322 } 323 return NoChange(); 324} 325 326namespace { 327 328bool HasInstanceTypeWitness(Node* receiver, Node* effect, 329 InstanceType instance_type) { 330 for (Node* dominator = effect;;) { 331 if (dominator->opcode() == IrOpcode::kCheckMaps && 332 dominator->InputAt(0) == receiver) { 333 // Check if all maps have the given {instance_type}. 334 for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { 335 Node* const map = NodeProperties::GetValueInput(dominator, i); 336 Type* const map_type = NodeProperties::GetType(map); 337 if (!map_type->IsConstant()) return false; 338 Handle<Map> const map_value = 339 Handle<Map>::cast(map_type->AsConstant()->Value()); 340 if (map_value->instance_type() != instance_type) return false; 341 } 342 return true; 343 } 344 switch (dominator->opcode()) { 345 case IrOpcode::kStoreField: { 346 FieldAccess const& access = FieldAccessOf(dominator->op()); 347 if (access.base_is_tagged == kTaggedBase && 348 access.offset == HeapObject::kMapOffset) { 349 return false; 350 } 351 break; 352 } 353 case IrOpcode::kStoreElement: 354 case IrOpcode::kStoreTypedElement: 355 break; 356 default: { 357 DCHECK_EQ(1, dominator->op()->EffectOutputCount()); 358 if (dominator->op()->EffectInputCount() != 1 || 359 !dominator->op()->HasProperty(Operator::kNoWrite)) { 360 // Didn't find any appropriate CheckMaps node. 361 return false; 362 } 363 break; 364 } 365 } 366 dominator = NodeProperties::GetEffectInput(dominator); 367 } 368} 369 370} // namespace 371 372// ES6 section 20.3.4.10 Date.prototype.getTime ( ) 373Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) { 374 Node* receiver = NodeProperties::GetValueInput(node, 1); 375 Node* effect = NodeProperties::GetEffectInput(node); 376 Node* control = NodeProperties::GetControlInput(node); 377 if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) { 378 Node* value = effect = graph()->NewNode( 379 simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver, 380 effect, control); 381 ReplaceWithValue(node, value, effect, control); 382 return Replace(value); 383 } 384 return NoChange(); 385} 386 387// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) 388Reduction JSBuiltinReducer::ReduceFunctionHasInstance(Node* node) { 389 Node* receiver = NodeProperties::GetValueInput(node, 1); 390 Node* object = (node->op()->ValueInputCount() >= 3) 391 ? NodeProperties::GetValueInput(node, 2) 392 : jsgraph()->UndefinedConstant(); 393 Node* context = NodeProperties::GetContextInput(node); 394 Node* frame_state = NodeProperties::GetFrameStateInput(node); 395 Node* effect = NodeProperties::GetEffectInput(node); 396 Node* control = NodeProperties::GetControlInput(node); 397 398 // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the 399 // stack trace doesn't contain the @@hasInstance call; we have the 400 // corresponding bug in the baseline case. Some massaging of the frame 401 // state would be necessary here. 402 403 // Morph this {node} into a JSOrdinaryHasInstance node. 404 node->ReplaceInput(0, receiver); 405 node->ReplaceInput(1, object); 406 node->ReplaceInput(2, context); 407 node->ReplaceInput(3, frame_state); 408 node->ReplaceInput(4, effect); 409 node->ReplaceInput(5, control); 410 node->TrimInputCount(6); 411 NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); 412 return Changed(node); 413} 414 415// ES6 section 18.2.2 isFinite ( number ) 416Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) { 417 JSCallReduction r(node); 418 if (r.InputsMatchOne(Type::PlainPrimitive())) { 419 // isFinite(a:plain-primitive) -> NumberEqual(a', a') 420 // where a' = NumberSubtract(ToNumber(a), ToNumber(a)) 421 Node* input = ToNumber(r.GetJSCallInput(0)); 422 Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input); 423 Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff); 424 return Replace(value); 425 } 426 return NoChange(); 427} 428 429// ES6 section 18.2.3 isNaN ( number ) 430Reduction JSBuiltinReducer::ReduceGlobalIsNaN(Node* node) { 431 JSCallReduction r(node); 432 if (r.InputsMatchOne(Type::PlainPrimitive())) { 433 // isNaN(a:plain-primitive) -> BooleanNot(NumberEqual(a', a')) 434 // where a' = ToNumber(a) 435 Node* input = ToNumber(r.GetJSCallInput(0)); 436 Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input); 437 Node* value = graph()->NewNode(simplified()->BooleanNot(), check); 438 return Replace(value); 439 } 440 return NoChange(); 441} 442 443// ES6 section 20.2.2.1 Math.abs ( x ) 444Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { 445 JSCallReduction r(node); 446 if (r.InputsMatchOne(Type::PlainPrimitive())) { 447 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a)) 448 Node* input = ToNumber(r.GetJSCallInput(0)); 449 Node* value = graph()->NewNode(simplified()->NumberAbs(), input); 450 return Replace(value); 451 } 452 return NoChange(); 453} 454 455// ES6 section 20.2.2.2 Math.acos ( x ) 456Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) { 457 JSCallReduction r(node); 458 if (r.InputsMatchOne(Type::PlainPrimitive())) { 459 // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a)) 460 Node* input = ToNumber(r.GetJSCallInput(0)); 461 Node* value = graph()->NewNode(simplified()->NumberAcos(), input); 462 return Replace(value); 463 } 464 return NoChange(); 465} 466 467// ES6 section 20.2.2.3 Math.acosh ( x ) 468Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) { 469 JSCallReduction r(node); 470 if (r.InputsMatchOne(Type::PlainPrimitive())) { 471 // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a)) 472 Node* input = ToNumber(r.GetJSCallInput(0)); 473 Node* value = graph()->NewNode(simplified()->NumberAcosh(), input); 474 return Replace(value); 475 } 476 return NoChange(); 477} 478 479// ES6 section 20.2.2.4 Math.asin ( x ) 480Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) { 481 JSCallReduction r(node); 482 if (r.InputsMatchOne(Type::PlainPrimitive())) { 483 // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a)) 484 Node* input = ToNumber(r.GetJSCallInput(0)); 485 Node* value = graph()->NewNode(simplified()->NumberAsin(), input); 486 return Replace(value); 487 } 488 return NoChange(); 489} 490 491// ES6 section 20.2.2.5 Math.asinh ( x ) 492Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) { 493 JSCallReduction r(node); 494 if (r.InputsMatchOne(Type::PlainPrimitive())) { 495 // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a)) 496 Node* input = ToNumber(r.GetJSCallInput(0)); 497 Node* value = graph()->NewNode(simplified()->NumberAsinh(), input); 498 return Replace(value); 499 } 500 return NoChange(); 501} 502 503// ES6 section 20.2.2.6 Math.atan ( x ) 504Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) { 505 JSCallReduction r(node); 506 if (r.InputsMatchOne(Type::PlainPrimitive())) { 507 // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a)) 508 Node* input = ToNumber(r.GetJSCallInput(0)); 509 Node* value = graph()->NewNode(simplified()->NumberAtan(), input); 510 return Replace(value); 511 } 512 return NoChange(); 513} 514 515// ES6 section 20.2.2.7 Math.atanh ( x ) 516Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) { 517 JSCallReduction r(node); 518 if (r.InputsMatchOne(Type::PlainPrimitive())) { 519 // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a)) 520 Node* input = ToNumber(r.GetJSCallInput(0)); 521 Node* value = graph()->NewNode(simplified()->NumberAtanh(), input); 522 return Replace(value); 523 } 524 return NoChange(); 525} 526 527// ES6 section 20.2.2.8 Math.atan2 ( y, x ) 528Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) { 529 JSCallReduction r(node); 530 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 531 // Math.atan2(a:plain-primitive, 532 // b:plain-primitive) -> NumberAtan2(ToNumber(a), 533 // ToNumber(b)) 534 Node* left = ToNumber(r.left()); 535 Node* right = ToNumber(r.right()); 536 Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right); 537 return Replace(value); 538 } 539 return NoChange(); 540} 541 542// ES6 section 20.2.2.10 Math.ceil ( x ) 543Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) { 544 JSCallReduction r(node); 545 if (r.InputsMatchOne(Type::PlainPrimitive())) { 546 // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a)) 547 Node* input = ToNumber(r.GetJSCallInput(0)); 548 Node* value = graph()->NewNode(simplified()->NumberCeil(), input); 549 return Replace(value); 550 } 551 return NoChange(); 552} 553 554// ES6 section 20.2.2.11 Math.clz32 ( x ) 555Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) { 556 JSCallReduction r(node); 557 if (r.InputsMatchOne(Type::PlainPrimitive())) { 558 // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a)) 559 Node* input = ToUint32(r.GetJSCallInput(0)); 560 Node* value = graph()->NewNode(simplified()->NumberClz32(), input); 561 return Replace(value); 562 } 563 return NoChange(); 564} 565 566// ES6 section 20.2.2.12 Math.cos ( x ) 567Reduction JSBuiltinReducer::ReduceMathCos(Node* node) { 568 JSCallReduction r(node); 569 if (r.InputsMatchOne(Type::PlainPrimitive())) { 570 // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a)) 571 Node* input = ToNumber(r.GetJSCallInput(0)); 572 Node* value = graph()->NewNode(simplified()->NumberCos(), input); 573 return Replace(value); 574 } 575 return NoChange(); 576} 577 578// ES6 section 20.2.2.13 Math.cosh ( x ) 579Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) { 580 JSCallReduction r(node); 581 if (r.InputsMatchOne(Type::PlainPrimitive())) { 582 // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a)) 583 Node* input = ToNumber(r.GetJSCallInput(0)); 584 Node* value = graph()->NewNode(simplified()->NumberCosh(), input); 585 return Replace(value); 586 } 587 return NoChange(); 588} 589 590// ES6 section 20.2.2.14 Math.exp ( x ) 591Reduction JSBuiltinReducer::ReduceMathExp(Node* node) { 592 JSCallReduction r(node); 593 if (r.InputsMatchOne(Type::PlainPrimitive())) { 594 // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a)) 595 Node* input = ToNumber(r.GetJSCallInput(0)); 596 Node* value = graph()->NewNode(simplified()->NumberExp(), input); 597 return Replace(value); 598 } 599 return NoChange(); 600} 601 602// ES6 section 20.2.2.15 Math.expm1 ( x ) 603Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) { 604 JSCallReduction r(node); 605 if (r.InputsMatchOne(Type::Number())) { 606 // Math.expm1(a:number) -> NumberExpm1(a) 607 Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left()); 608 return Replace(value); 609 } 610 return NoChange(); 611} 612 613// ES6 section 20.2.2.16 Math.floor ( x ) 614Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) { 615 JSCallReduction r(node); 616 if (r.InputsMatchOne(Type::PlainPrimitive())) { 617 // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a)) 618 Node* input = ToNumber(r.GetJSCallInput(0)); 619 Node* value = graph()->NewNode(simplified()->NumberFloor(), input); 620 return Replace(value); 621 } 622 return NoChange(); 623} 624 625// ES6 section 20.2.2.17 Math.fround ( x ) 626Reduction JSBuiltinReducer::ReduceMathFround(Node* node) { 627 JSCallReduction r(node); 628 if (r.InputsMatchOne(Type::PlainPrimitive())) { 629 // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a)) 630 Node* input = ToNumber(r.GetJSCallInput(0)); 631 Node* value = graph()->NewNode(simplified()->NumberFround(), input); 632 return Replace(value); 633 } 634 return NoChange(); 635} 636 637// ES6 section 20.2.2.19 Math.imul ( x, y ) 638Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { 639 JSCallReduction r(node); 640 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 641 // Math.imul(a:plain-primitive, 642 // b:plain-primitive) -> NumberImul(ToUint32(a), 643 // ToUint32(b)) 644 Node* left = ToUint32(r.left()); 645 Node* right = ToUint32(r.right()); 646 Node* value = graph()->NewNode(simplified()->NumberImul(), left, right); 647 return Replace(value); 648 } 649 return NoChange(); 650} 651 652// ES6 section 20.2.2.20 Math.log ( x ) 653Reduction JSBuiltinReducer::ReduceMathLog(Node* node) { 654 JSCallReduction r(node); 655 if (r.InputsMatchOne(Type::PlainPrimitive())) { 656 // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a)) 657 Node* input = ToNumber(r.GetJSCallInput(0)); 658 Node* value = graph()->NewNode(simplified()->NumberLog(), input); 659 return Replace(value); 660 } 661 return NoChange(); 662} 663 664// ES6 section 20.2.2.21 Math.log1p ( x ) 665Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) { 666 JSCallReduction r(node); 667 if (r.InputsMatchOne(Type::PlainPrimitive())) { 668 // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a)) 669 Node* input = ToNumber(r.GetJSCallInput(0)); 670 Node* value = graph()->NewNode(simplified()->NumberLog1p(), input); 671 return Replace(value); 672 } 673 return NoChange(); 674} 675 676// ES6 section 20.2.2.22 Math.log10 ( x ) 677Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) { 678 JSCallReduction r(node); 679 if (r.InputsMatchOne(Type::Number())) { 680 // Math.log10(a:number) -> NumberLog10(a) 681 Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left()); 682 return Replace(value); 683 } 684 return NoChange(); 685} 686 687// ES6 section 20.2.2.23 Math.log2 ( x ) 688Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) { 689 JSCallReduction r(node); 690 if (r.InputsMatchOne(Type::Number())) { 691 // Math.log2(a:number) -> NumberLog(a) 692 Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left()); 693 return Replace(value); 694 } 695 return NoChange(); 696} 697 698// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values ) 699Reduction JSBuiltinReducer::ReduceMathMax(Node* node) { 700 JSCallReduction r(node); 701 if (r.InputsMatchZero()) { 702 // Math.max() -> -Infinity 703 return Replace(jsgraph()->Constant(-V8_INFINITY)); 704 } 705 if (r.InputsMatchAll(Type::PlainPrimitive())) { 706 // Math.max(a:plain-primitive, b:plain-primitive, ...) 707 Node* value = ToNumber(r.GetJSCallInput(0)); 708 for (int i = 1; i < r.GetJSCallArity(); i++) { 709 Node* input = ToNumber(r.GetJSCallInput(i)); 710 value = graph()->NewNode(simplified()->NumberMax(), value, input); 711 } 712 return Replace(value); 713 } 714 return NoChange(); 715} 716 717// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values ) 718Reduction JSBuiltinReducer::ReduceMathMin(Node* node) { 719 JSCallReduction r(node); 720 if (r.InputsMatchZero()) { 721 // Math.min() -> Infinity 722 return Replace(jsgraph()->Constant(V8_INFINITY)); 723 } 724 if (r.InputsMatchAll(Type::PlainPrimitive())) { 725 // Math.min(a:plain-primitive, b:plain-primitive, ...) 726 Node* value = ToNumber(r.GetJSCallInput(0)); 727 for (int i = 1; i < r.GetJSCallArity(); i++) { 728 Node* input = ToNumber(r.GetJSCallInput(i)); 729 value = graph()->NewNode(simplified()->NumberMin(), value, input); 730 } 731 return Replace(value); 732 } 733 return NoChange(); 734} 735 736// ES6 section 20.2.2.26 Math.pow ( x, y ) 737Reduction JSBuiltinReducer::ReduceMathPow(Node* node) { 738 JSCallReduction r(node); 739 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 740 // Math.pow(a:plain-primitive, 741 // b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b)) 742 Node* left = ToNumber(r.left()); 743 Node* right = ToNumber(r.right()); 744 Node* value = graph()->NewNode(simplified()->NumberPow(), left, right); 745 return Replace(value); 746 } 747 return NoChange(); 748} 749 750// ES6 section 20.2.2.28 Math.round ( x ) 751Reduction JSBuiltinReducer::ReduceMathRound(Node* node) { 752 JSCallReduction r(node); 753 if (r.InputsMatchOne(Type::PlainPrimitive())) { 754 // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a)) 755 Node* input = ToNumber(r.GetJSCallInput(0)); 756 Node* value = graph()->NewNode(simplified()->NumberRound(), input); 757 return Replace(value); 758 } 759 return NoChange(); 760} 761 762// ES6 section 20.2.2.9 Math.cbrt ( x ) 763Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) { 764 JSCallReduction r(node); 765 if (r.InputsMatchOne(Type::Number())) { 766 // Math.cbrt(a:number) -> NumberCbrt(a) 767 Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left()); 768 return Replace(value); 769 } 770 return NoChange(); 771} 772 773// ES6 section 20.2.2.29 Math.sign ( x ) 774Reduction JSBuiltinReducer::ReduceMathSign(Node* node) { 775 JSCallReduction r(node); 776 if (r.InputsMatchOne(Type::PlainPrimitive())) { 777 // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a)) 778 Node* input = ToNumber(r.GetJSCallInput(0)); 779 Node* value = graph()->NewNode(simplified()->NumberSign(), input); 780 return Replace(value); 781 } 782 return NoChange(); 783} 784 785// ES6 section 20.2.2.30 Math.sin ( x ) 786Reduction JSBuiltinReducer::ReduceMathSin(Node* node) { 787 JSCallReduction r(node); 788 if (r.InputsMatchOne(Type::PlainPrimitive())) { 789 // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a)) 790 Node* input = ToNumber(r.GetJSCallInput(0)); 791 Node* value = graph()->NewNode(simplified()->NumberSin(), input); 792 return Replace(value); 793 } 794 return NoChange(); 795} 796 797// ES6 section 20.2.2.31 Math.sinh ( x ) 798Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) { 799 JSCallReduction r(node); 800 if (r.InputsMatchOne(Type::PlainPrimitive())) { 801 // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a)) 802 Node* input = ToNumber(r.GetJSCallInput(0)); 803 Node* value = graph()->NewNode(simplified()->NumberSinh(), input); 804 return Replace(value); 805 } 806 return NoChange(); 807} 808 809// ES6 section 20.2.2.32 Math.sqrt ( x ) 810Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) { 811 JSCallReduction r(node); 812 if (r.InputsMatchOne(Type::PlainPrimitive())) { 813 // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a)) 814 Node* input = ToNumber(r.GetJSCallInput(0)); 815 Node* value = graph()->NewNode(simplified()->NumberSqrt(), input); 816 return Replace(value); 817 } 818 return NoChange(); 819} 820 821// ES6 section 20.2.2.33 Math.tan ( x ) 822Reduction JSBuiltinReducer::ReduceMathTan(Node* node) { 823 JSCallReduction r(node); 824 if (r.InputsMatchOne(Type::PlainPrimitive())) { 825 // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a)) 826 Node* input = ToNumber(r.GetJSCallInput(0)); 827 Node* value = graph()->NewNode(simplified()->NumberTan(), input); 828 return Replace(value); 829 } 830 return NoChange(); 831} 832 833// ES6 section 20.2.2.34 Math.tanh ( x ) 834Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) { 835 JSCallReduction r(node); 836 if (r.InputsMatchOne(Type::PlainPrimitive())) { 837 // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a)) 838 Node* input = ToNumber(r.GetJSCallInput(0)); 839 Node* value = graph()->NewNode(simplified()->NumberTanh(), input); 840 return Replace(value); 841 } 842 return NoChange(); 843} 844 845// ES6 section 20.2.2.35 Math.trunc ( x ) 846Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) { 847 JSCallReduction r(node); 848 if (r.InputsMatchOne(Type::PlainPrimitive())) { 849 // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a)) 850 Node* input = ToNumber(r.GetJSCallInput(0)); 851 Node* value = graph()->NewNode(simplified()->NumberTrunc(), input); 852 return Replace(value); 853 } 854 return NoChange(); 855} 856 857// ES6 section 20.1.2.2 Number.isFinite ( number ) 858Reduction JSBuiltinReducer::ReduceNumberIsFinite(Node* node) { 859 JSCallReduction r(node); 860 if (r.InputsMatchOne(Type::Number())) { 861 // Number.isFinite(a:number) -> NumberEqual(a', a') 862 // where a' = NumberSubtract(a, a) 863 Node* input = r.GetJSCallInput(0); 864 Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input); 865 Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff); 866 return Replace(value); 867 } 868 return NoChange(); 869} 870 871// ES6 section 20.1.2.3 Number.isInteger ( number ) 872Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) { 873 JSCallReduction r(node); 874 if (r.InputsMatchOne(Type::Number())) { 875 // Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0) 876 // where x' = NumberTrunc(x) 877 Node* input = r.GetJSCallInput(0); 878 Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input); 879 Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc); 880 Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, 881 jsgraph()->ZeroConstant()); 882 return Replace(value); 883 } 884 return NoChange(); 885} 886 887// ES6 section 20.1.2.4 Number.isNaN ( number ) 888Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) { 889 JSCallReduction r(node); 890 if (r.InputsMatchOne(Type::Number())) { 891 // Number.isNaN(a:number) -> BooleanNot(NumberEqual(a, a)) 892 Node* input = r.GetJSCallInput(0); 893 Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input); 894 Node* value = graph()->NewNode(simplified()->BooleanNot(), check); 895 return Replace(value); 896 } 897 return NoChange(); 898} 899 900// ES6 section 20.1.2.5 Number.isSafeInteger ( number ) 901Reduction JSBuiltinReducer::ReduceNumberIsSafeInteger(Node* node) { 902 JSCallReduction r(node); 903 if (r.InputsMatchOne(type_cache_.kSafeInteger)) { 904 // Number.isInteger(x:safe-integer) -> #true 905 Node* value = jsgraph()->TrueConstant(); 906 return Replace(value); 907 } 908 return NoChange(); 909} 910 911// ES6 section 20.1.2.13 Number.parseInt ( string, radix ) 912Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) { 913 JSCallReduction r(node); 914 if (r.InputsMatchOne(type_cache_.kSafeInteger) || 915 r.InputsMatchTwo(type_cache_.kSafeInteger, 916 type_cache_.kZeroOrUndefined) || 917 r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) { 918 // Number.parseInt(a:safe-integer) -> NumberToInt32(a) 919 // Number.parseInt(a:safe-integer,b:#0\/undefined) -> NumberToInt32(a) 920 // Number.parseInt(a:safe-integer,b:#10\/undefined) -> NumberToInt32(a) 921 Node* input = r.GetJSCallInput(0); 922 Node* value = graph()->NewNode(simplified()->NumberToInt32(), input); 923 return Replace(value); 924 } 925 return NoChange(); 926} 927 928// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) 929Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { 930 JSCallReduction r(node); 931 if (r.InputsMatchOne(Type::PlainPrimitive())) { 932 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) 933 Node* input = ToNumber(r.GetJSCallInput(0)); 934 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); 935 return Replace(value); 936 } 937 return NoChange(); 938} 939 940namespace { 941 942Node* GetStringWitness(Node* node) { 943 Node* receiver = NodeProperties::GetValueInput(node, 1); 944 Type* receiver_type = NodeProperties::GetType(receiver); 945 Node* effect = NodeProperties::GetEffectInput(node); 946 if (receiver_type->Is(Type::String())) return receiver; 947 // Check if the {node} is dominated by a CheckString renaming for 948 // it's {receiver}, and if so use that renaming as {receiver} for 949 // the lowering below. 950 for (Node* dominator = effect;;) { 951 if (dominator->opcode() == IrOpcode::kCheckString && 952 dominator->InputAt(0) == receiver) { 953 return dominator; 954 } 955 if (dominator->op()->EffectInputCount() != 1) { 956 // Didn't find any appropriate CheckString node. 957 return nullptr; 958 } 959 dominator = NodeProperties::GetEffectInput(dominator); 960 } 961} 962 963} // namespace 964 965// ES6 section 21.1.3.1 String.prototype.charAt ( pos ) 966Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { 967 // We need at least target, receiver and index parameters. 968 if (node->op()->ValueInputCount() >= 3) { 969 Node* index = NodeProperties::GetValueInput(node, 2); 970 Type* index_type = NodeProperties::GetType(index); 971 Node* effect = NodeProperties::GetEffectInput(node); 972 Node* control = NodeProperties::GetControlInput(node); 973 974 if (index_type->Is(Type::Unsigned32())) { 975 if (Node* receiver = GetStringWitness(node)) { 976 // Determine the {receiver} length. 977 Node* receiver_length = effect = graph()->NewNode( 978 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 979 effect, control); 980 981 // Check if {index} is less than {receiver} length. 982 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, 983 receiver_length); 984 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 985 check, control); 986 987 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 988 Node* vtrue; 989 { 990 // Load the character from the {receiver}. 991 vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver, 992 index, if_true); 993 994 // Return it as single character string. 995 vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue); 996 } 997 998 // Return the empty string otherwise. 999 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1000 Node* vfalse = jsgraph()->EmptyStringConstant(); 1001 1002 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1003 Node* value = 1004 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1005 vtrue, vfalse, control); 1006 1007 ReplaceWithValue(node, value, effect, control); 1008 return Replace(value); 1009 } 1010 } 1011 } 1012 1013 return NoChange(); 1014} 1015 1016// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) 1017Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { 1018 // We need at least target, receiver and index parameters. 1019 if (node->op()->ValueInputCount() >= 3) { 1020 Node* index = NodeProperties::GetValueInput(node, 2); 1021 Type* index_type = NodeProperties::GetType(index); 1022 Node* effect = NodeProperties::GetEffectInput(node); 1023 Node* control = NodeProperties::GetControlInput(node); 1024 1025 if (index_type->Is(Type::Unsigned32())) { 1026 if (Node* receiver = GetStringWitness(node)) { 1027 // Determine the {receiver} length. 1028 Node* receiver_length = effect = graph()->NewNode( 1029 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 1030 effect, control); 1031 1032 // Check if {index} is less than {receiver} length. 1033 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, 1034 receiver_length); 1035 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1036 check, control); 1037 1038 // Load the character from the {receiver}. 1039 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1040 Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), 1041 receiver, index, if_true); 1042 1043 // Return NaN otherwise. 1044 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1045 Node* vfalse = jsgraph()->NaNConstant(); 1046 1047 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1048 Node* value = 1049 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1050 vtrue, vfalse, control); 1051 1052 ReplaceWithValue(node, value, effect, control); 1053 return Replace(value); 1054 } 1055 } 1056 } 1057 1058 return NoChange(); 1059} 1060 1061Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) { 1062 Node* receiver = NodeProperties::GetValueInput(node, 1); 1063 Node* effect = NodeProperties::GetEffectInput(node); 1064 Node* control = NodeProperties::GetControlInput(node); 1065 Node* context = NodeProperties::GetContextInput(node); 1066 if (HasInstanceTypeWitness(receiver, effect, JS_STRING_ITERATOR_TYPE)) { 1067 Node* string = effect = graph()->NewNode( 1068 simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()), 1069 receiver, effect, control); 1070 Node* index = effect = graph()->NewNode( 1071 simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()), 1072 receiver, effect, control); 1073 Node* length = effect = graph()->NewNode( 1074 simplified()->LoadField(AccessBuilder::ForStringLength()), string, 1075 effect, control); 1076 1077 // branch0: if (index < length) 1078 Node* check0 = 1079 graph()->NewNode(simplified()->NumberLessThan(), index, length); 1080 Node* branch0 = 1081 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 1082 1083 Node* etrue0 = effect; 1084 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1085 Node* done_true; 1086 Node* vtrue0; 1087 { 1088 done_true = jsgraph()->FalseConstant(); 1089 Node* lead = graph()->NewNode(simplified()->StringCharCodeAt(), string, 1090 index, if_true0); 1091 1092 // branch1: if ((lead & 0xFC00) === 0xD800) 1093 Node* check1 = graph()->NewNode( 1094 simplified()->NumberEqual(), 1095 graph()->NewNode(simplified()->NumberBitwiseAnd(), lead, 1096 jsgraph()->Int32Constant(0xFC00)), 1097 jsgraph()->Int32Constant(0xD800)); 1098 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1099 check1, if_true0); 1100 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1101 Node* vtrue1; 1102 { 1103 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, 1104 jsgraph()->OneConstant()); 1105 // branch2: if ((index + 1) < length) 1106 Node* check2 = graph()->NewNode(simplified()->NumberLessThan(), 1107 next_index, length); 1108 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1109 check2, if_true1); 1110 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 1111 Node* vtrue2; 1112 { 1113 Node* trail = graph()->NewNode(simplified()->StringCharCodeAt(), 1114 string, next_index, if_true2); 1115 // branch3: if ((trail & 0xFC00) === 0xDC00) 1116 Node* check3 = graph()->NewNode( 1117 simplified()->NumberEqual(), 1118 graph()->NewNode(simplified()->NumberBitwiseAnd(), trail, 1119 jsgraph()->Int32Constant(0xFC00)), 1120 jsgraph()->Int32Constant(0xDC00)); 1121 Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1122 check3, if_true2); 1123 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); 1124 Node* vtrue3; 1125 { 1126 vtrue3 = graph()->NewNode( 1127 simplified()->NumberBitwiseOr(), 1128// Need to swap the order for big-endian platforms 1129#if V8_TARGET_BIG_ENDIAN 1130 graph()->NewNode(simplified()->NumberShiftLeft(), lead, 1131 jsgraph()->Int32Constant(16)), 1132 trail); 1133#else 1134 graph()->NewNode(simplified()->NumberShiftLeft(), trail, 1135 jsgraph()->Int32Constant(16)), 1136 lead); 1137#endif 1138 } 1139 1140 Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3); 1141 Node* vfalse3 = lead; 1142 if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3); 1143 vtrue2 = 1144 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), 1145 vtrue3, vfalse3, if_true2); 1146 } 1147 1148 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); 1149 Node* vfalse2 = lead; 1150 if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); 1151 vtrue1 = 1152 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), 1153 vtrue2, vfalse2, if_true1); 1154 } 1155 1156 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1157 Node* vfalse1 = lead; 1158 if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); 1159 vtrue0 = 1160 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), 1161 vtrue1, vfalse1, if_true0); 1162 vtrue0 = graph()->NewNode( 1163 simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), vtrue0); 1164 1165 // Update iterator.[[NextIndex]] 1166 Node* char_length = etrue0 = graph()->NewNode( 1167 simplified()->LoadField(AccessBuilder::ForStringLength()), vtrue0, 1168 etrue0, if_true0); 1169 index = graph()->NewNode(simplified()->NumberAdd(), index, char_length); 1170 etrue0 = graph()->NewNode( 1171 simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()), 1172 receiver, index, etrue0, if_true0); 1173 } 1174 1175 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1176 Node* done_false; 1177 Node* vfalse0; 1178 { 1179 vfalse0 = jsgraph()->UndefinedConstant(); 1180 done_false = jsgraph()->TrueConstant(); 1181 } 1182 1183 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 1184 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control); 1185 Node* value = 1186 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1187 vtrue0, vfalse0, control); 1188 Node* done = 1189 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1190 done_true, done_false, control); 1191 1192 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), 1193 value, done, context, effect); 1194 1195 ReplaceWithValue(node, value, effect, control); 1196 return Replace(value); 1197 } 1198 return NoChange(); 1199} 1200 1201Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor( 1202 Node* node, InstanceType instance_type, FieldAccess const& access) { 1203 Node* receiver = NodeProperties::GetValueInput(node, 1); 1204 Node* effect = NodeProperties::GetEffectInput(node); 1205 Node* control = NodeProperties::GetControlInput(node); 1206 if (HasInstanceTypeWitness(receiver, effect, instance_type)) { 1207 // Load the {receiver}s field. 1208 Node* receiver_value = effect = graph()->NewNode( 1209 simplified()->LoadField(access), receiver, effect, control); 1210 1211 // Check if the {receiver}s buffer was neutered. 1212 Node* receiver_buffer = effect = graph()->NewNode( 1213 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 1214 receiver, effect, control); 1215 Node* check = effect = 1216 graph()->NewNode(simplified()->ArrayBufferWasNeutered(), 1217 receiver_buffer, effect, control); 1218 1219 // Default to zero if the {receiver}s buffer was neutered. 1220 Node* value = graph()->NewNode( 1221 common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), 1222 check, jsgraph()->ZeroConstant(), receiver_value); 1223 1224 ReplaceWithValue(node, value, effect, control); 1225 return Replace(value); 1226 } 1227 return NoChange(); 1228} 1229 1230Reduction JSBuiltinReducer::Reduce(Node* node) { 1231 Reduction reduction = NoChange(); 1232 JSCallReduction r(node); 1233 1234 // Dispatch according to the BuiltinFunctionId if present. 1235 if (!r.HasBuiltinFunctionId()) return NoChange(); 1236 switch (r.GetBuiltinFunctionId()) { 1237 case kArrayPop: 1238 return ReduceArrayPop(node); 1239 case kArrayPush: 1240 return ReduceArrayPush(node); 1241 case kDateGetTime: 1242 return ReduceDateGetTime(node); 1243 case kFunctionHasInstance: 1244 return ReduceFunctionHasInstance(node); 1245 break; 1246 case kGlobalIsFinite: 1247 reduction = ReduceGlobalIsFinite(node); 1248 break; 1249 case kGlobalIsNaN: 1250 reduction = ReduceGlobalIsNaN(node); 1251 break; 1252 case kMathAbs: 1253 reduction = ReduceMathAbs(node); 1254 break; 1255 case kMathAcos: 1256 reduction = ReduceMathAcos(node); 1257 break; 1258 case kMathAcosh: 1259 reduction = ReduceMathAcosh(node); 1260 break; 1261 case kMathAsin: 1262 reduction = ReduceMathAsin(node); 1263 break; 1264 case kMathAsinh: 1265 reduction = ReduceMathAsinh(node); 1266 break; 1267 case kMathAtan: 1268 reduction = ReduceMathAtan(node); 1269 break; 1270 case kMathAtanh: 1271 reduction = ReduceMathAtanh(node); 1272 break; 1273 case kMathAtan2: 1274 reduction = ReduceMathAtan2(node); 1275 break; 1276 case kMathCbrt: 1277 reduction = ReduceMathCbrt(node); 1278 break; 1279 case kMathCeil: 1280 reduction = ReduceMathCeil(node); 1281 break; 1282 case kMathClz32: 1283 reduction = ReduceMathClz32(node); 1284 break; 1285 case kMathCos: 1286 reduction = ReduceMathCos(node); 1287 break; 1288 case kMathCosh: 1289 reduction = ReduceMathCosh(node); 1290 break; 1291 case kMathExp: 1292 reduction = ReduceMathExp(node); 1293 break; 1294 case kMathExpm1: 1295 reduction = ReduceMathExpm1(node); 1296 break; 1297 case kMathFloor: 1298 reduction = ReduceMathFloor(node); 1299 break; 1300 case kMathFround: 1301 reduction = ReduceMathFround(node); 1302 break; 1303 case kMathImul: 1304 reduction = ReduceMathImul(node); 1305 break; 1306 case kMathLog: 1307 reduction = ReduceMathLog(node); 1308 break; 1309 case kMathLog1p: 1310 reduction = ReduceMathLog1p(node); 1311 break; 1312 case kMathLog10: 1313 reduction = ReduceMathLog10(node); 1314 break; 1315 case kMathLog2: 1316 reduction = ReduceMathLog2(node); 1317 break; 1318 case kMathMax: 1319 reduction = ReduceMathMax(node); 1320 break; 1321 case kMathMin: 1322 reduction = ReduceMathMin(node); 1323 break; 1324 case kMathPow: 1325 reduction = ReduceMathPow(node); 1326 break; 1327 case kMathRound: 1328 reduction = ReduceMathRound(node); 1329 break; 1330 case kMathSign: 1331 reduction = ReduceMathSign(node); 1332 break; 1333 case kMathSin: 1334 reduction = ReduceMathSin(node); 1335 break; 1336 case kMathSinh: 1337 reduction = ReduceMathSinh(node); 1338 break; 1339 case kMathSqrt: 1340 reduction = ReduceMathSqrt(node); 1341 break; 1342 case kMathTan: 1343 reduction = ReduceMathTan(node); 1344 break; 1345 case kMathTanh: 1346 reduction = ReduceMathTanh(node); 1347 break; 1348 case kMathTrunc: 1349 reduction = ReduceMathTrunc(node); 1350 break; 1351 case kNumberIsFinite: 1352 reduction = ReduceNumberIsFinite(node); 1353 break; 1354 case kNumberIsInteger: 1355 reduction = ReduceNumberIsInteger(node); 1356 break; 1357 case kNumberIsNaN: 1358 reduction = ReduceNumberIsNaN(node); 1359 break; 1360 case kNumberIsSafeInteger: 1361 reduction = ReduceNumberIsSafeInteger(node); 1362 break; 1363 case kNumberParseInt: 1364 reduction = ReduceNumberParseInt(node); 1365 break; 1366 case kStringFromCharCode: 1367 reduction = ReduceStringFromCharCode(node); 1368 break; 1369 case kStringCharAt: 1370 return ReduceStringCharAt(node); 1371 case kStringCharCodeAt: 1372 return ReduceStringCharCodeAt(node); 1373 case kStringIteratorNext: 1374 return ReduceStringIteratorNext(node); 1375 case kDataViewByteLength: 1376 return ReduceArrayBufferViewAccessor( 1377 node, JS_DATA_VIEW_TYPE, 1378 AccessBuilder::ForJSArrayBufferViewByteLength()); 1379 case kDataViewByteOffset: 1380 return ReduceArrayBufferViewAccessor( 1381 node, JS_DATA_VIEW_TYPE, 1382 AccessBuilder::ForJSArrayBufferViewByteOffset()); 1383 case kTypedArrayByteLength: 1384 return ReduceArrayBufferViewAccessor( 1385 node, JS_TYPED_ARRAY_TYPE, 1386 AccessBuilder::ForJSArrayBufferViewByteLength()); 1387 case kTypedArrayByteOffset: 1388 return ReduceArrayBufferViewAccessor( 1389 node, JS_TYPED_ARRAY_TYPE, 1390 AccessBuilder::ForJSArrayBufferViewByteOffset()); 1391 case kTypedArrayLength: 1392 return ReduceArrayBufferViewAccessor( 1393 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); 1394 default: 1395 break; 1396 } 1397 1398 // Replace builtin call assuming replacement nodes are pure values that don't 1399 // produce an effect. Replaces {node} with {reduction} and relaxes effects. 1400 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); 1401 1402 return reduction; 1403} 1404 1405Node* JSBuiltinReducer::ToNumber(Node* input) { 1406 Type* input_type = NodeProperties::GetType(input); 1407 if (input_type->Is(Type::Number())) return input; 1408 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input); 1409} 1410 1411Node* JSBuiltinReducer::ToUint32(Node* input) { 1412 input = ToNumber(input); 1413 Type* input_type = NodeProperties::GetType(input); 1414 if (input_type->Is(Type::Unsigned32())) return input; 1415 return graph()->NewNode(simplified()->NumberToUint32(), input); 1416} 1417 1418Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } 1419 1420Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); } 1421 1422Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); } 1423 1424 1425CommonOperatorBuilder* JSBuiltinReducer::common() const { 1426 return jsgraph()->common(); 1427} 1428 1429 1430SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { 1431 return jsgraph()->simplified(); 1432} 1433 1434JSOperatorBuilder* JSBuiltinReducer::javascript() const { 1435 return jsgraph()->javascript(); 1436} 1437 1438} // namespace compiler 1439} // namespace internal 1440} // namespace v8 1441