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/base/bits.h" 8 #include "src/code-factory.h" 9 #include "src/compilation-dependencies.h" 10 #include "src/compiler/access-builder.h" 11 #include "src/compiler/js-graph.h" 12 #include "src/compiler/linkage.h" 13 #include "src/compiler/node-matchers.h" 14 #include "src/compiler/node-properties.h" 15 #include "src/compiler/simplified-operator.h" 16 #include "src/compiler/type-cache.h" 17 #include "src/compiler/types.h" 18 #include "src/objects-inl.h" 19 20 namespace v8 { 21 namespace internal { 22 namespace compiler { 23 24 // Helper class to access JSCall nodes that are potential candidates 25 // for reduction when they have a BuiltinFunctionId associated with them. 26 class JSCallReduction { 27 public: 28 explicit JSCallReduction(Node* node) : node_(node) {} 29 30 // Determines whether the node is a JSCall operation that targets a 31 // constant callee being a well-known builtin with a BuiltinFunctionId. 32 bool HasBuiltinFunctionId() { 33 if (node_->opcode() != IrOpcode::kJSCall) return false; 34 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); 35 if (!m.HasValue() || !m.Value()->IsJSFunction()) return false; 36 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 37 return function->shared()->HasBuiltinFunctionId(); 38 } 39 40 // Retrieves the BuiltinFunctionId as described above. 41 BuiltinFunctionId GetBuiltinFunctionId() { 42 DCHECK_EQ(IrOpcode::kJSCall, node_->opcode()); 43 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); 44 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 45 return function->shared()->builtin_function_id(); 46 } 47 48 bool ReceiverMatches(Type* type) { 49 return NodeProperties::GetType(receiver())->Is(type); 50 } 51 52 // Determines whether the call takes zero inputs. 53 bool InputsMatchZero() { return GetJSCallArity() == 0; } 54 55 // Determines whether the call takes one input of the given type. 56 bool InputsMatchOne(Type* t1) { 57 return GetJSCallArity() == 1 && 58 NodeProperties::GetType(GetJSCallInput(0))->Is(t1); 59 } 60 61 // Determines whether the call takes two inputs of the given types. 62 bool InputsMatchTwo(Type* t1, Type* t2) { 63 return GetJSCallArity() == 2 && 64 NodeProperties::GetType(GetJSCallInput(0))->Is(t1) && 65 NodeProperties::GetType(GetJSCallInput(1))->Is(t2); 66 } 67 68 // Determines whether the call takes inputs all of the given type. 69 bool InputsMatchAll(Type* t) { 70 for (int i = 0; i < GetJSCallArity(); i++) { 71 if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) { 72 return false; 73 } 74 } 75 return true; 76 } 77 78 Node* receiver() { return NodeProperties::GetValueInput(node_, 1); } 79 Node* left() { return GetJSCallInput(0); } 80 Node* right() { return GetJSCallInput(1); } 81 82 int GetJSCallArity() { 83 DCHECK_EQ(IrOpcode::kJSCall, node_->opcode()); 84 // Skip first (i.e. callee) and second (i.e. receiver) operand. 85 return node_->op()->ValueInputCount() - 2; 86 } 87 88 Node* GetJSCallInput(int index) { 89 DCHECK_EQ(IrOpcode::kJSCall, node_->opcode()); 90 DCHECK_LT(index, GetJSCallArity()); 91 // Skip first (i.e. callee) and second (i.e. receiver) operand. 92 return NodeProperties::GetValueInput(node_, index + 2); 93 } 94 95 private: 96 Node* node_; 97 }; 98 99 JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph, 100 Flags flags, 101 CompilationDependencies* dependencies, 102 Handle<Context> native_context) 103 : AdvancedReducer(editor), 104 dependencies_(dependencies), 105 flags_(flags), 106 jsgraph_(jsgraph), 107 native_context_(native_context), 108 type_cache_(TypeCache::Get()) {} 109 110 namespace { 111 112 MaybeHandle<Map> GetMapWitness(Node* node) { 113 ZoneHandleSet<Map> maps; 114 Node* receiver = NodeProperties::GetValueInput(node, 1); 115 Node* effect = NodeProperties::GetEffectInput(node); 116 if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) { 117 if (maps.size() == 1) return MaybeHandle<Map>(maps[0]); 118 } 119 return MaybeHandle<Map>(); 120 } 121 122 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive. 123 bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) { 124 DCHECK(!jsarray_map->is_dictionary_map()); 125 Isolate* isolate = jsarray_map->GetIsolate(); 126 Handle<Name> length_string = isolate->factory()->length_string(); 127 DescriptorArray* descriptors = jsarray_map->instance_descriptors(); 128 int number = 129 descriptors->SearchWithCache(isolate, *length_string, *jsarray_map); 130 DCHECK_NE(DescriptorArray::kNotFound, number); 131 return descriptors->GetDetails(number).IsReadOnly(); 132 } 133 134 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive. 135 bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) { 136 Isolate* const isolate = receiver_map->GetIsolate(); 137 if (!receiver_map->prototype()->IsJSArray()) return false; 138 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()), 139 isolate); 140 // Ensure that all prototypes of the {receiver} are stable. 141 for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver); 142 !it.IsAtEnd(); it.Advance()) { 143 Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it); 144 if (!current->map()->is_stable()) return false; 145 } 146 return receiver_map->instance_type() == JS_ARRAY_TYPE && 147 IsFastElementsKind(receiver_map->elements_kind()) && 148 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && 149 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && 150 isolate->IsFastArrayConstructorPrototypeChainIntact() && 151 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && 152 !IsReadOnlyLengthDescriptor(receiver_map); 153 } 154 155 bool CanInlineJSArrayIteration(Handle<Map> receiver_map) { 156 Isolate* const isolate = receiver_map->GetIsolate(); 157 // Ensure that the [[Prototype]] is actually an exotic Array 158 if (!receiver_map->prototype()->IsJSArray()) return false; 159 160 // Don't inline JSArrays with slow elements of any kind 161 if (!IsFastElementsKind(receiver_map->elements_kind())) return false; 162 163 // If the receiver map has packed elements, no need to check the prototype. 164 // This requires a MapCheck where this is used. 165 if (!IsFastHoleyElementsKind(receiver_map->elements_kind())) return true; 166 167 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()), 168 isolate); 169 // Ensure all prototypes of the {receiver} are stable. 170 for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver); 171 !it.IsAtEnd(); it.Advance()) { 172 Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it); 173 if (!current->map()->is_stable()) return false; 174 } 175 176 // For holey Arrays, ensure that the array_protector cell is valid (must be 177 // a CompilationDependency), and the JSArray prototype has not been altered. 178 return receiver_map->instance_type() == JS_ARRAY_TYPE && 179 (!receiver_map->is_dictionary_map() || receiver_map->is_stable()) && 180 isolate->IsFastArrayConstructorPrototypeChainIntact() && 181 isolate->IsAnyInitialArrayPrototype(receiver_prototype); 182 } 183 184 } // namespace 185 186 Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node, 187 IterationKind kind) { 188 Handle<Map> receiver_map; 189 if (GetMapWitness(node).ToHandle(&receiver_map)) { 190 return ReduceArrayIterator(receiver_map, node, kind, 191 ArrayIteratorKind::kArray); 192 } 193 return NoChange(); 194 } 195 196 Reduction JSBuiltinReducer::ReduceTypedArrayIterator(Node* node, 197 IterationKind kind) { 198 Handle<Map> receiver_map; 199 if (GetMapWitness(node).ToHandle(&receiver_map) && 200 receiver_map->instance_type() == JS_TYPED_ARRAY_TYPE) { 201 return ReduceArrayIterator(receiver_map, node, kind, 202 ArrayIteratorKind::kTypedArray); 203 } 204 return NoChange(); 205 } 206 207 Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map, 208 Node* node, IterationKind kind, 209 ArrayIteratorKind iter_kind) { 210 Node* receiver = NodeProperties::GetValueInput(node, 1); 211 Node* effect = NodeProperties::GetEffectInput(node); 212 Node* control = NodeProperties::GetControlInput(node); 213 214 if (iter_kind == ArrayIteratorKind::kTypedArray) { 215 // See if we can skip the neutering check. 216 if (isolate()->IsArrayBufferNeuteringIntact()) { 217 // Add a code dependency so we are deoptimized in case an ArrayBuffer 218 // gets neutered. 219 dependencies()->AssumePropertyCell( 220 factory()->array_buffer_neutering_protector()); 221 } else { 222 // For JSTypedArray iterator methods, deopt if the buffer is neutered. 223 // This is potentially a deopt loop, but should be extremely unlikely. 224 DCHECK_EQ(JS_TYPED_ARRAY_TYPE, receiver_map->instance_type()); 225 Node* buffer = effect = graph()->NewNode( 226 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 227 receiver, effect, control); 228 229 // Deoptimize if the {buffer} has been neutered. 230 Node* check = effect = graph()->NewNode( 231 simplified()->ArrayBufferWasNeutered(), buffer, effect, control); 232 check = graph()->NewNode(simplified()->BooleanNot(), check); 233 effect = 234 graph()->NewNode(simplified()->CheckIf(), check, effect, control); 235 } 236 } 237 238 int map_index = -1; 239 Node* object_map = jsgraph()->UndefinedConstant(); 240 switch (receiver_map->instance_type()) { 241 case JS_ARRAY_TYPE: 242 if (kind == IterationKind::kKeys) { 243 map_index = Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX; 244 } else { 245 map_index = kind == IterationKind::kValues 246 ? Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX 247 : Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX; 248 249 if (CanInlineJSArrayIteration(receiver_map)) { 250 // Use `generic` elements for holey arrays if there may be elements 251 // on the prototype chain. 252 map_index += static_cast<int>(receiver_map->elements_kind()); 253 object_map = jsgraph()->Constant(receiver_map); 254 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { 255 Handle<JSObject> initial_array_prototype( 256 native_context()->initial_array_prototype(), isolate()); 257 dependencies()->AssumePrototypeMapsStable(receiver_map, 258 initial_array_prototype); 259 } 260 } else { 261 map_index += (Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX - 262 Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX); 263 } 264 } 265 break; 266 case JS_TYPED_ARRAY_TYPE: 267 if (kind == IterationKind::kKeys) { 268 map_index = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX; 269 } else { 270 DCHECK_GE(receiver_map->elements_kind(), UINT8_ELEMENTS); 271 DCHECK_LE(receiver_map->elements_kind(), UINT8_CLAMPED_ELEMENTS); 272 map_index = (kind == IterationKind::kValues 273 ? Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX 274 : Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX) + 275 (receiver_map->elements_kind() - UINT8_ELEMENTS); 276 } 277 break; 278 default: 279 if (kind == IterationKind::kKeys) { 280 map_index = Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX; 281 } else if (kind == IterationKind::kValues) { 282 map_index = Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX; 283 } else { 284 map_index = Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX; 285 } 286 break; 287 } 288 289 DCHECK_GE(map_index, Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX); 290 DCHECK_LE(map_index, Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX); 291 292 Handle<Map> map(Map::cast(native_context()->get(map_index)), isolate()); 293 294 // allocate new iterator 295 effect = graph()->NewNode( 296 common()->BeginRegion(RegionObservability::kNotObservable), effect); 297 Node* value = effect = graph()->NewNode( 298 simplified()->Allocate(NOT_TENURED), 299 jsgraph()->Constant(JSArrayIterator::kSize), effect, control); 300 NodeProperties::SetType(value, Type::OtherObject()); 301 effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), 302 value, jsgraph()->Constant(map), effect, control); 303 effect = graph()->NewNode( 304 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, 305 jsgraph()->EmptyFixedArrayConstant(), effect, control); 306 effect = graph()->NewNode( 307 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, 308 jsgraph()->EmptyFixedArrayConstant(), effect, control); 309 310 // attach the iterator to this object 311 effect = graph()->NewNode( 312 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()), 313 value, receiver, effect, control); 314 effect = graph()->NewNode( 315 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex()), value, 316 jsgraph()->ZeroConstant(), effect, control); 317 effect = graph()->NewNode( 318 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObjectMap()), 319 value, object_map, effect, control); 320 321 value = effect = graph()->NewNode(common()->FinishRegion(), value, effect); 322 323 // replace it 324 ReplaceWithValue(node, value, effect, control); 325 return Replace(value); 326 } 327 328 Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext( 329 Handle<Map> iterator_map, Node* node, IterationKind kind) { 330 Node* iterator = NodeProperties::GetValueInput(node, 1); 331 Node* effect = NodeProperties::GetEffectInput(node); 332 Node* control = NodeProperties::GetControlInput(node); 333 Node* context = NodeProperties::GetContextInput(node); 334 335 if (kind != IterationKind::kKeys && 336 !isolate()->IsFastArrayIterationIntact()) { 337 // Avoid deopt loops for non-key iteration if the 338 // fast_array_iteration_protector cell has been invalidated. 339 return NoChange(); 340 } 341 342 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType( 343 iterator_map->instance_type()); 344 345 if (IsFastHoleyElementsKind(elements_kind)) { 346 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 347 return NoChange(); 348 } else { 349 Handle<JSObject> initial_array_prototype( 350 native_context()->initial_array_prototype(), isolate()); 351 dependencies()->AssumePropertyCell(factory()->array_protector()); 352 } 353 } 354 355 Node* array = effect = graph()->NewNode( 356 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()), 357 iterator, effect, control); 358 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array, 359 jsgraph()->UndefinedConstant()); 360 Node* branch0 = 361 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); 362 363 Node* vdone_false0; 364 Node* vfalse0; 365 Node* efalse0 = effect; 366 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 367 { 368 // iterator.[[IteratedObject]] !== undefined, continue iterating. 369 Node* index = efalse0 = graph()->NewNode( 370 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex( 371 JS_ARRAY_TYPE, elements_kind)), 372 iterator, efalse0, if_false0); 373 374 Node* length = efalse0 = graph()->NewNode( 375 simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)), 376 array, efalse0, if_false0); 377 Node* check1 = 378 graph()->NewNode(simplified()->NumberLessThan(), index, length); 379 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 380 check1, if_false0); 381 382 Node* vdone_true1; 383 Node* vtrue1; 384 Node* etrue1 = efalse0; 385 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 386 { 387 // iterator.[[NextIndex]] < array.length, continue iterating 388 vdone_true1 = jsgraph()->FalseConstant(); 389 if (kind == IterationKind::kKeys) { 390 vtrue1 = index; 391 } else { 392 // For value/entry iteration, first step is a mapcheck to ensure 393 // inlining is still valid. 394 Node* array_map = etrue1 = 395 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 396 array, etrue1, if_true1); 397 Node* orig_map = etrue1 = 398 graph()->NewNode(simplified()->LoadField( 399 AccessBuilder::ForJSArrayIteratorObjectMap()), 400 iterator, etrue1, if_true1); 401 Node* check_map = graph()->NewNode(simplified()->ReferenceEqual(), 402 array_map, orig_map); 403 etrue1 = graph()->NewNode(simplified()->CheckIf(), check_map, etrue1, 404 if_true1); 405 } 406 407 if (kind != IterationKind::kKeys) { 408 Node* elements = etrue1 = graph()->NewNode( 409 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 410 array, etrue1, if_true1); 411 Node* value = etrue1 = graph()->NewNode( 412 simplified()->LoadElement( 413 AccessBuilder::ForFixedArrayElement(elements_kind)), 414 elements, index, etrue1, if_true1); 415 416 // Convert hole to undefined if needed. 417 if (elements_kind == FAST_HOLEY_ELEMENTS || 418 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { 419 value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), 420 value); 421 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { 422 // TODO(bmeurer): avoid deopt if not all uses of value are truncated. 423 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole; 424 value = etrue1 = graph()->NewNode( 425 simplified()->CheckFloat64Hole(mode), value, etrue1, if_true1); 426 } 427 428 if (kind == IterationKind::kEntries) { 429 // Allocate elements for key/value pair 430 vtrue1 = etrue1 = 431 graph()->NewNode(javascript()->CreateKeyValueArray(), index, 432 value, context, etrue1); 433 } else { 434 DCHECK_EQ(kind, IterationKind::kValues); 435 vtrue1 = value; 436 } 437 } 438 439 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, 440 jsgraph()->OneConstant()); 441 next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index); 442 443 etrue1 = graph()->NewNode( 444 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex( 445 JS_ARRAY_TYPE, elements_kind)), 446 iterator, next_index, etrue1, if_true1); 447 } 448 449 Node* vdone_false1; 450 Node* vfalse1; 451 Node* efalse1 = efalse0; 452 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 453 { 454 // iterator.[[NextIndex]] >= array.length, stop iterating. 455 vdone_false1 = jsgraph()->TrueConstant(); 456 vfalse1 = jsgraph()->UndefinedConstant(); 457 efalse1 = graph()->NewNode( 458 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()), 459 iterator, vfalse1, efalse1, if_false1); 460 } 461 462 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); 463 efalse0 = 464 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); 465 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 466 vtrue1, vfalse1, if_false0); 467 vdone_false0 = 468 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 469 vdone_true1, vdone_false1, if_false0); 470 } 471 472 Node* vdone_true0; 473 Node* vtrue0; 474 Node* etrue0 = effect; 475 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 476 { 477 // iterator.[[IteratedObject]] === undefined, the iterator is done. 478 vdone_true0 = jsgraph()->TrueConstant(); 479 vtrue0 = jsgraph()->UndefinedConstant(); 480 } 481 482 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0); 483 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control); 484 Node* value = 485 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 486 vfalse0, vtrue0, control); 487 Node* done = 488 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 489 vdone_false0, vdone_true0, control); 490 491 // Create IteratorResult object. 492 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), 493 value, done, context, effect); 494 ReplaceWithValue(node, value, effect, control); 495 return Replace(value); 496 } 497 498 Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext( 499 Handle<Map> iterator_map, Node* node, IterationKind kind) { 500 Node* iterator = NodeProperties::GetValueInput(node, 1); 501 Node* effect = NodeProperties::GetEffectInput(node); 502 Node* control = NodeProperties::GetControlInput(node); 503 Node* context = NodeProperties::GetContextInput(node); 504 505 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType( 506 iterator_map->instance_type()); 507 508 Node* array = effect = graph()->NewNode( 509 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()), 510 iterator, effect, control); 511 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array, 512 jsgraph()->UndefinedConstant()); 513 Node* branch0 = 514 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); 515 516 Node* vdone_false0; 517 Node* vfalse0; 518 Node* efalse0 = effect; 519 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 520 { 521 // iterator.[[IteratedObject]] !== undefined, continue iterating. 522 Node* index = efalse0 = graph()->NewNode( 523 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex( 524 JS_TYPED_ARRAY_TYPE, elements_kind)), 525 iterator, efalse0, if_false0); 526 527 // typedarray.[[ViewedArrayBuffer]] 528 Node* buffer = efalse0 = graph()->NewNode( 529 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 530 array, efalse0, if_false0); 531 532 // See if we can skip the neutering check. 533 if (isolate()->IsArrayBufferNeuteringIntact()) { 534 // Add a code dependency so we are deoptimized in case an ArrayBuffer 535 // gets neutered. 536 dependencies()->AssumePropertyCell( 537 factory()->array_buffer_neutering_protector()); 538 } else { 539 // Deoptimize if the array buffer was neutered. 540 Node* check1 = efalse0 = graph()->NewNode( 541 simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0); 542 check1 = graph()->NewNode(simplified()->BooleanNot(), check1); 543 efalse0 = 544 graph()->NewNode(simplified()->CheckIf(), check1, efalse0, if_false0); 545 } 546 547 Node* length = efalse0 = graph()->NewNode( 548 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), array, 549 efalse0, if_false0); 550 551 Node* check2 = 552 graph()->NewNode(simplified()->NumberLessThan(), index, length); 553 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 554 check2, if_false0); 555 556 Node* vdone_true2; 557 Node* vtrue2; 558 Node* etrue2 = efalse0; 559 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 560 { 561 // iterator.[[NextIndex]] < array.length, continue iterating 562 vdone_true2 = jsgraph()->FalseConstant(); 563 if (kind == IterationKind::kKeys) { 564 vtrue2 = index; 565 } 566 567 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, 568 jsgraph()->OneConstant()); 569 next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index); 570 571 etrue2 = graph()->NewNode( 572 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex( 573 JS_TYPED_ARRAY_TYPE, elements_kind)), 574 iterator, next_index, etrue2, if_true2); 575 576 if (kind != IterationKind::kKeys) { 577 Node* elements = etrue2 = graph()->NewNode( 578 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 579 array, etrue2, if_true2); 580 Node* base_ptr = etrue2 = graph()->NewNode( 581 simplified()->LoadField( 582 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), 583 elements, etrue2, if_true2); 584 Node* external_ptr = etrue2 = graph()->NewNode( 585 simplified()->LoadField( 586 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), 587 elements, etrue2, if_true2); 588 589 ExternalArrayType array_type = kExternalInt8Array; 590 switch (elements_kind) { 591 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 592 case TYPE##_ELEMENTS: \ 593 array_type = kExternal##Type##Array; \ 594 break; 595 TYPED_ARRAYS(TYPED_ARRAY_CASE) 596 default: 597 UNREACHABLE(); 598 #undef TYPED_ARRAY_CASE 599 } 600 601 Node* value = etrue2 = 602 graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer, 603 base_ptr, external_ptr, index, etrue2, if_true2); 604 605 if (kind == IterationKind::kEntries) { 606 // Allocate elements for key/value pair 607 vtrue2 = etrue2 = 608 graph()->NewNode(javascript()->CreateKeyValueArray(), index, 609 value, context, etrue2); 610 } else { 611 DCHECK(kind == IterationKind::kValues); 612 vtrue2 = value; 613 } 614 } 615 } 616 617 Node* vdone_false2; 618 Node* vfalse2; 619 Node* efalse2 = efalse0; 620 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); 621 { 622 // iterator.[[NextIndex]] >= array.length, stop iterating. 623 vdone_false2 = jsgraph()->TrueConstant(); 624 vfalse2 = jsgraph()->UndefinedConstant(); 625 efalse2 = graph()->NewNode( 626 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()), 627 iterator, vfalse2, efalse2, if_false2); 628 } 629 630 if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); 631 efalse0 = 632 graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0); 633 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 634 vtrue2, vfalse2, if_false0); 635 vdone_false0 = 636 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 637 vdone_true2, vdone_false2, if_false0); 638 } 639 640 Node* vdone_true0; 641 Node* vtrue0; 642 Node* etrue0 = effect; 643 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 644 { 645 // iterator.[[IteratedObject]] === undefined, the iterator is done. 646 vdone_true0 = jsgraph()->TrueConstant(); 647 vtrue0 = jsgraph()->UndefinedConstant(); 648 } 649 650 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0); 651 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control); 652 Node* value = 653 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 654 vfalse0, vtrue0, control); 655 Node* done = 656 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 657 vdone_false0, vdone_true0, control); 658 659 // Create IteratorResult object. 660 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), 661 value, done, context, effect); 662 ReplaceWithValue(node, value, effect, control); 663 return Replace(value); 664 } 665 666 Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { 667 Handle<Map> receiver_map; 668 if (GetMapWitness(node).ToHandle(&receiver_map)) { 669 switch (receiver_map->instance_type()) { 670 case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE: 671 return ReduceTypedArrayIteratorNext(receiver_map, node, 672 IterationKind::kKeys); 673 674 case JS_FAST_ARRAY_KEY_ITERATOR_TYPE: 675 return ReduceFastArrayIteratorNext(receiver_map, node, 676 IterationKind::kKeys); 677 678 case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: 679 case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: 680 case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE: 681 case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE: 682 case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: 683 case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: 684 case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: 685 case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE: 686 case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE: 687 return ReduceTypedArrayIteratorNext(receiver_map, node, 688 IterationKind::kEntries); 689 690 case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: 691 case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: 692 case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE: 693 case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE: 694 case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: 695 case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: 696 return ReduceFastArrayIteratorNext(receiver_map, node, 697 IterationKind::kEntries); 698 699 case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE: 700 case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE: 701 case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE: 702 case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE: 703 case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE: 704 case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE: 705 case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE: 706 case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE: 707 case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE: 708 return ReduceTypedArrayIteratorNext(receiver_map, node, 709 IterationKind::kValues); 710 711 case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE: 712 case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE: 713 case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE: 714 case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE: 715 case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: 716 case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: 717 return ReduceFastArrayIteratorNext(receiver_map, node, 718 IterationKind::kValues); 719 720 default: 721 // Slow array iterators are not reduced 722 return NoChange(); 723 } 724 } 725 return NoChange(); 726 } 727 728 // ES6 section 22.1.3.17 Array.prototype.pop ( ) 729 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { 730 Handle<Map> receiver_map; 731 Node* receiver = NodeProperties::GetValueInput(node, 1); 732 Node* effect = NodeProperties::GetEffectInput(node); 733 Node* control = NodeProperties::GetControlInput(node); 734 // TODO(turbofan): Extend this to also handle fast (holey) double elements 735 // once we got the hole NaN mess sorted out in TurboFan/V8. 736 if (GetMapWitness(node).ToHandle(&receiver_map) && 737 CanInlineArrayResizeOperation(receiver_map) && 738 IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) { 739 // Install code dependencies on the {receiver} prototype maps and the 740 // global array protector cell. 741 dependencies()->AssumePropertyCell(factory()->array_protector()); 742 dependencies()->AssumePrototypeMapsStable(receiver_map); 743 744 // Load the "length" property of the {receiver}. 745 Node* length = effect = graph()->NewNode( 746 simplified()->LoadField( 747 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 748 receiver, effect, control); 749 750 // Check if the {receiver} has any elements. 751 Node* check = graph()->NewNode(simplified()->NumberEqual(), length, 752 jsgraph()->ZeroConstant()); 753 Node* branch = 754 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 755 756 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 757 Node* etrue = effect; 758 Node* vtrue = jsgraph()->UndefinedConstant(); 759 760 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 761 Node* efalse = effect; 762 Node* vfalse; 763 { 764 // Load the elements backing store from the {receiver}. 765 Node* elements = efalse = graph()->NewNode( 766 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 767 receiver, efalse, if_false); 768 769 // Ensure that we aren't popping from a copy-on-write backing store. 770 elements = efalse = 771 graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver, 772 elements, efalse, if_false); 773 774 // Compute the new {length}. 775 length = graph()->NewNode(simplified()->NumberSubtract(), length, 776 jsgraph()->OneConstant()); 777 778 // Store the new {length} to the {receiver}. 779 efalse = graph()->NewNode( 780 simplified()->StoreField( 781 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 782 receiver, length, efalse, if_false); 783 784 // Load the last entry from the {elements}. 785 vfalse = efalse = graph()->NewNode( 786 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement( 787 receiver_map->elements_kind())), 788 elements, length, efalse, if_false); 789 790 // Store a hole to the element we just removed from the {receiver}. 791 efalse = graph()->NewNode( 792 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( 793 GetHoleyElementsKind(receiver_map->elements_kind()))), 794 elements, length, jsgraph()->TheHoleConstant(), efalse, if_false); 795 } 796 797 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 798 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 799 Node* value = 800 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 801 vtrue, vfalse, control); 802 803 // Convert the hole to undefined. Do this last, so that we can optimize 804 // conversion operator via some smart strength reduction in many cases. 805 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { 806 value = 807 graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); 808 } 809 810 ReplaceWithValue(node, value, effect, control); 811 return Replace(value); 812 } 813 return NoChange(); 814 } 815 816 // ES6 section 22.1.3.18 Array.prototype.push ( ) 817 Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) { 818 // We need exactly target, receiver and value parameters. 819 if (node->op()->ValueInputCount() != 3) return NoChange(); 820 Node* receiver = NodeProperties::GetValueInput(node, 1); 821 Node* effect = NodeProperties::GetEffectInput(node); 822 Node* control = NodeProperties::GetControlInput(node); 823 Node* value = NodeProperties::GetValueInput(node, 2); 824 ZoneHandleSet<Map> receiver_maps; 825 NodeProperties::InferReceiverMapsResult result = 826 NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps); 827 if (receiver_maps.size() != 1) return NoChange(); 828 DCHECK_NE(NodeProperties::kNoReceiverMaps, result); 829 830 // TODO(turbofan): Relax this to deal with multiple {receiver} maps. 831 Handle<Map> receiver_map = receiver_maps[0]; 832 if (CanInlineArrayResizeOperation(receiver_map)) { 833 // Install code dependencies on the {receiver} prototype maps and the 834 // global array protector cell. 835 dependencies()->AssumePropertyCell(factory()->array_protector()); 836 dependencies()->AssumePrototypeMapsStable(receiver_map); 837 838 // If the {receiver_maps} information is not reliable, we need 839 // to check that the {receiver} still has one of these maps. 840 if (result == NodeProperties::kUnreliableReceiverMaps) { 841 if (receiver_map->is_stable()) { 842 dependencies()->AssumeMapStable(receiver_map); 843 } else { 844 // TODO(turbofan): This is a potential - yet unlikely - deoptimization 845 // loop, since we might not learn from this deoptimization in baseline 846 // code. We need a way to learn from deoptimizations in optimized to 847 // address these problems. 848 effect = graph()->NewNode( 849 simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), 850 receiver, effect, control); 851 } 852 } 853 854 // TODO(turbofan): Perform type checks on the {value}. We are not guaranteed 855 // to learn from these checks in case they fail, as the witness (i.e. the 856 // map check from the LoadIC for a.push) might not be executed in baseline 857 // code (after we stored the value in the builtin and thereby changed the 858 // elements kind of a) before be decide to optimize this function again. We 859 // currently don't have a proper way to deal with this; the proper solution 860 // here is to learn on deopt, i.e. disable Array.prototype.push inlining 861 // for this function. 862 if (IsFastSmiElementsKind(receiver_map->elements_kind())) { 863 value = effect = 864 graph()->NewNode(simplified()->CheckSmi(), value, effect, control); 865 } else if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { 866 value = effect = 867 graph()->NewNode(simplified()->CheckNumber(), value, effect, control); 868 // Make sure we do not store signaling NaNs into double arrays. 869 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); 870 } 871 872 // Load the "length" property of the {receiver}. 873 Node* length = effect = graph()->NewNode( 874 simplified()->LoadField( 875 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 876 receiver, effect, control); 877 878 // Load the elements backing store of the {receiver}. 879 Node* elements = effect = graph()->NewNode( 880 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, 881 effect, control); 882 883 // TODO(turbofan): Check if we need to grow the {elements} backing store. 884 // This will deopt if we cannot grow the array further, and we currently 885 // don't necessarily learn from it. See the comment on the value type check 886 // above. 887 GrowFastElementsFlags flags = GrowFastElementsFlag::kArrayObject; 888 if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { 889 flags |= GrowFastElementsFlag::kDoubleElements; 890 } 891 elements = effect = 892 graph()->NewNode(simplified()->MaybeGrowFastElements(flags), receiver, 893 elements, length, length, effect, control); 894 895 // Append the value to the {elements}. 896 effect = graph()->NewNode( 897 simplified()->StoreElement( 898 AccessBuilder::ForFixedArrayElement(receiver_map->elements_kind())), 899 elements, length, value, effect, control); 900 901 // Return the new length of the {receiver}. 902 value = graph()->NewNode(simplified()->NumberAdd(), length, 903 jsgraph()->OneConstant()); 904 905 ReplaceWithValue(node, value, effect, control); 906 return Replace(value); 907 } 908 return NoChange(); 909 } 910 911 namespace { 912 913 bool HasInstanceTypeWitness(Node* receiver, Node* effect, 914 InstanceType instance_type) { 915 for (Node* dominator = effect;;) { 916 if (dominator->opcode() == IrOpcode::kCheckMaps && 917 NodeProperties::IsSame(dominator->InputAt(0), receiver)) { 918 ZoneHandleSet<Map> const& maps = 919 CheckMapsParametersOf(dominator->op()).maps(); 920 // Check if all maps have the given {instance_type}. 921 for (size_t i = 0; i < maps.size(); ++i) { 922 if (maps[i]->instance_type() != instance_type) return false; 923 } 924 return true; 925 } 926 // The instance type doesn't change for JSReceiver values, so we 927 // don't need to pay attention to potentially side-effecting nodes 928 // here. Strings and internal structures like FixedArray and 929 // FixedDoubleArray are weird here, but we don't use this function then. 930 DCHECK_LE(FIRST_JS_RECEIVER_TYPE, instance_type); 931 DCHECK_EQ(1, dominator->op()->EffectOutputCount()); 932 if (dominator->op()->EffectInputCount() != 1) { 933 // Didn't find any appropriate CheckMaps node. 934 return false; 935 } 936 dominator = NodeProperties::GetEffectInput(dominator); 937 } 938 } 939 940 } // namespace 941 942 // ES6 section 20.3.3.1 Date.now ( ) 943 Reduction JSBuiltinReducer::ReduceDateNow(Node* node) { 944 NodeProperties::RemoveValueInputs(node); 945 NodeProperties::ChangeOp( 946 node, javascript()->CallRuntime(Runtime::kDateCurrentTime)); 947 return Changed(node); 948 } 949 950 // ES6 section 20.3.4.10 Date.prototype.getTime ( ) 951 Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) { 952 Node* receiver = NodeProperties::GetValueInput(node, 1); 953 Node* effect = NodeProperties::GetEffectInput(node); 954 Node* control = NodeProperties::GetControlInput(node); 955 if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) { 956 Node* value = effect = graph()->NewNode( 957 simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver, 958 effect, control); 959 ReplaceWithValue(node, value, effect, control); 960 return Replace(value); 961 } 962 return NoChange(); 963 } 964 965 // ES6 section 18.2.2 isFinite ( number ) 966 Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) { 967 JSCallReduction r(node); 968 if (r.InputsMatchOne(Type::PlainPrimitive())) { 969 // isFinite(a:plain-primitive) -> NumberEqual(a', a') 970 // where a' = NumberSubtract(ToNumber(a), ToNumber(a)) 971 Node* input = ToNumber(r.GetJSCallInput(0)); 972 Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input); 973 Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff); 974 return Replace(value); 975 } 976 return NoChange(); 977 } 978 979 // ES6 section 18.2.3 isNaN ( number ) 980 Reduction JSBuiltinReducer::ReduceGlobalIsNaN(Node* node) { 981 JSCallReduction r(node); 982 if (r.InputsMatchOne(Type::PlainPrimitive())) { 983 // isNaN(a:plain-primitive) -> BooleanNot(NumberEqual(a', a')) 984 // where a' = ToNumber(a) 985 Node* input = ToNumber(r.GetJSCallInput(0)); 986 Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input); 987 Node* value = graph()->NewNode(simplified()->BooleanNot(), check); 988 return Replace(value); 989 } 990 return NoChange(); 991 } 992 993 // ES6 section 20.2.2.1 Math.abs ( x ) 994 Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { 995 JSCallReduction r(node); 996 if (r.InputsMatchOne(Type::PlainPrimitive())) { 997 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a)) 998 Node* input = ToNumber(r.GetJSCallInput(0)); 999 Node* value = graph()->NewNode(simplified()->NumberAbs(), input); 1000 return Replace(value); 1001 } 1002 return NoChange(); 1003 } 1004 1005 // ES6 section 20.2.2.2 Math.acos ( x ) 1006 Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) { 1007 JSCallReduction r(node); 1008 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1009 // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a)) 1010 Node* input = ToNumber(r.GetJSCallInput(0)); 1011 Node* value = graph()->NewNode(simplified()->NumberAcos(), input); 1012 return Replace(value); 1013 } 1014 return NoChange(); 1015 } 1016 1017 // ES6 section 20.2.2.3 Math.acosh ( x ) 1018 Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) { 1019 JSCallReduction r(node); 1020 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1021 // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a)) 1022 Node* input = ToNumber(r.GetJSCallInput(0)); 1023 Node* value = graph()->NewNode(simplified()->NumberAcosh(), input); 1024 return Replace(value); 1025 } 1026 return NoChange(); 1027 } 1028 1029 // ES6 section 20.2.2.4 Math.asin ( x ) 1030 Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) { 1031 JSCallReduction r(node); 1032 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1033 // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a)) 1034 Node* input = ToNumber(r.GetJSCallInput(0)); 1035 Node* value = graph()->NewNode(simplified()->NumberAsin(), input); 1036 return Replace(value); 1037 } 1038 return NoChange(); 1039 } 1040 1041 // ES6 section 20.2.2.5 Math.asinh ( x ) 1042 Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) { 1043 JSCallReduction r(node); 1044 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1045 // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a)) 1046 Node* input = ToNumber(r.GetJSCallInput(0)); 1047 Node* value = graph()->NewNode(simplified()->NumberAsinh(), input); 1048 return Replace(value); 1049 } 1050 return NoChange(); 1051 } 1052 1053 // ES6 section 20.2.2.6 Math.atan ( x ) 1054 Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) { 1055 JSCallReduction r(node); 1056 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1057 // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a)) 1058 Node* input = ToNumber(r.GetJSCallInput(0)); 1059 Node* value = graph()->NewNode(simplified()->NumberAtan(), input); 1060 return Replace(value); 1061 } 1062 return NoChange(); 1063 } 1064 1065 // ES6 section 20.2.2.7 Math.atanh ( x ) 1066 Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) { 1067 JSCallReduction r(node); 1068 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1069 // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a)) 1070 Node* input = ToNumber(r.GetJSCallInput(0)); 1071 Node* value = graph()->NewNode(simplified()->NumberAtanh(), input); 1072 return Replace(value); 1073 } 1074 return NoChange(); 1075 } 1076 1077 // ES6 section 20.2.2.8 Math.atan2 ( y, x ) 1078 Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) { 1079 JSCallReduction r(node); 1080 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 1081 // Math.atan2(a:plain-primitive, 1082 // b:plain-primitive) -> NumberAtan2(ToNumber(a), 1083 // ToNumber(b)) 1084 Node* left = ToNumber(r.left()); 1085 Node* right = ToNumber(r.right()); 1086 Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right); 1087 return Replace(value); 1088 } 1089 return NoChange(); 1090 } 1091 1092 // ES6 section 20.2.2.10 Math.ceil ( x ) 1093 Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) { 1094 JSCallReduction r(node); 1095 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1096 // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a)) 1097 Node* input = ToNumber(r.GetJSCallInput(0)); 1098 Node* value = graph()->NewNode(simplified()->NumberCeil(), input); 1099 return Replace(value); 1100 } 1101 return NoChange(); 1102 } 1103 1104 // ES6 section 20.2.2.11 Math.clz32 ( x ) 1105 Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) { 1106 JSCallReduction r(node); 1107 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1108 // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a)) 1109 Node* input = ToUint32(r.GetJSCallInput(0)); 1110 Node* value = graph()->NewNode(simplified()->NumberClz32(), input); 1111 return Replace(value); 1112 } 1113 return NoChange(); 1114 } 1115 1116 // ES6 section 20.2.2.12 Math.cos ( x ) 1117 Reduction JSBuiltinReducer::ReduceMathCos(Node* node) { 1118 JSCallReduction r(node); 1119 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1120 // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a)) 1121 Node* input = ToNumber(r.GetJSCallInput(0)); 1122 Node* value = graph()->NewNode(simplified()->NumberCos(), input); 1123 return Replace(value); 1124 } 1125 return NoChange(); 1126 } 1127 1128 // ES6 section 20.2.2.13 Math.cosh ( x ) 1129 Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) { 1130 JSCallReduction r(node); 1131 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1132 // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a)) 1133 Node* input = ToNumber(r.GetJSCallInput(0)); 1134 Node* value = graph()->NewNode(simplified()->NumberCosh(), input); 1135 return Replace(value); 1136 } 1137 return NoChange(); 1138 } 1139 1140 // ES6 section 20.2.2.14 Math.exp ( x ) 1141 Reduction JSBuiltinReducer::ReduceMathExp(Node* node) { 1142 JSCallReduction r(node); 1143 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1144 // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a)) 1145 Node* input = ToNumber(r.GetJSCallInput(0)); 1146 Node* value = graph()->NewNode(simplified()->NumberExp(), input); 1147 return Replace(value); 1148 } 1149 return NoChange(); 1150 } 1151 1152 // ES6 section 20.2.2.15 Math.expm1 ( x ) 1153 Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) { 1154 JSCallReduction r(node); 1155 if (r.InputsMatchOne(Type::Number())) { 1156 // Math.expm1(a:number) -> NumberExpm1(a) 1157 Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left()); 1158 return Replace(value); 1159 } 1160 return NoChange(); 1161 } 1162 1163 // ES6 section 20.2.2.16 Math.floor ( x ) 1164 Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) { 1165 JSCallReduction r(node); 1166 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1167 // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a)) 1168 Node* input = ToNumber(r.GetJSCallInput(0)); 1169 Node* value = graph()->NewNode(simplified()->NumberFloor(), input); 1170 return Replace(value); 1171 } 1172 return NoChange(); 1173 } 1174 1175 // ES6 section 20.2.2.17 Math.fround ( x ) 1176 Reduction JSBuiltinReducer::ReduceMathFround(Node* node) { 1177 JSCallReduction r(node); 1178 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1179 // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a)) 1180 Node* input = ToNumber(r.GetJSCallInput(0)); 1181 Node* value = graph()->NewNode(simplified()->NumberFround(), input); 1182 return Replace(value); 1183 } 1184 return NoChange(); 1185 } 1186 1187 // ES6 section 20.2.2.19 Math.imul ( x, y ) 1188 Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { 1189 JSCallReduction r(node); 1190 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 1191 // Math.imul(a:plain-primitive, 1192 // b:plain-primitive) -> NumberImul(ToUint32(a), 1193 // ToUint32(b)) 1194 Node* left = ToUint32(r.left()); 1195 Node* right = ToUint32(r.right()); 1196 Node* value = graph()->NewNode(simplified()->NumberImul(), left, right); 1197 return Replace(value); 1198 } 1199 return NoChange(); 1200 } 1201 1202 // ES6 section 20.2.2.20 Math.log ( x ) 1203 Reduction JSBuiltinReducer::ReduceMathLog(Node* node) { 1204 JSCallReduction r(node); 1205 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1206 // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a)) 1207 Node* input = ToNumber(r.GetJSCallInput(0)); 1208 Node* value = graph()->NewNode(simplified()->NumberLog(), input); 1209 return Replace(value); 1210 } 1211 return NoChange(); 1212 } 1213 1214 // ES6 section 20.2.2.21 Math.log1p ( x ) 1215 Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) { 1216 JSCallReduction r(node); 1217 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1218 // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a)) 1219 Node* input = ToNumber(r.GetJSCallInput(0)); 1220 Node* value = graph()->NewNode(simplified()->NumberLog1p(), input); 1221 return Replace(value); 1222 } 1223 return NoChange(); 1224 } 1225 1226 // ES6 section 20.2.2.22 Math.log10 ( x ) 1227 Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) { 1228 JSCallReduction r(node); 1229 if (r.InputsMatchOne(Type::Number())) { 1230 // Math.log10(a:number) -> NumberLog10(a) 1231 Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left()); 1232 return Replace(value); 1233 } 1234 return NoChange(); 1235 } 1236 1237 // ES6 section 20.2.2.23 Math.log2 ( x ) 1238 Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) { 1239 JSCallReduction r(node); 1240 if (r.InputsMatchOne(Type::Number())) { 1241 // Math.log2(a:number) -> NumberLog(a) 1242 Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left()); 1243 return Replace(value); 1244 } 1245 return NoChange(); 1246 } 1247 1248 // ES6 section 20.2.2.24 Math.max ( value1, value2, ...values ) 1249 Reduction JSBuiltinReducer::ReduceMathMax(Node* node) { 1250 JSCallReduction r(node); 1251 if (r.InputsMatchZero()) { 1252 // Math.max() -> -Infinity 1253 return Replace(jsgraph()->Constant(-V8_INFINITY)); 1254 } 1255 if (r.InputsMatchAll(Type::PlainPrimitive())) { 1256 // Math.max(a:plain-primitive, b:plain-primitive, ...) 1257 Node* value = ToNumber(r.GetJSCallInput(0)); 1258 for (int i = 1; i < r.GetJSCallArity(); i++) { 1259 Node* input = ToNumber(r.GetJSCallInput(i)); 1260 value = graph()->NewNode(simplified()->NumberMax(), value, input); 1261 } 1262 return Replace(value); 1263 } 1264 return NoChange(); 1265 } 1266 1267 // ES6 section 20.2.2.25 Math.min ( value1, value2, ...values ) 1268 Reduction JSBuiltinReducer::ReduceMathMin(Node* node) { 1269 JSCallReduction r(node); 1270 if (r.InputsMatchZero()) { 1271 // Math.min() -> Infinity 1272 return Replace(jsgraph()->Constant(V8_INFINITY)); 1273 } 1274 if (r.InputsMatchAll(Type::PlainPrimitive())) { 1275 // Math.min(a:plain-primitive, b:plain-primitive, ...) 1276 Node* value = ToNumber(r.GetJSCallInput(0)); 1277 for (int i = 1; i < r.GetJSCallArity(); i++) { 1278 Node* input = ToNumber(r.GetJSCallInput(i)); 1279 value = graph()->NewNode(simplified()->NumberMin(), value, input); 1280 } 1281 return Replace(value); 1282 } 1283 return NoChange(); 1284 } 1285 1286 // ES6 section 20.2.2.26 Math.pow ( x, y ) 1287 Reduction JSBuiltinReducer::ReduceMathPow(Node* node) { 1288 JSCallReduction r(node); 1289 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 1290 // Math.pow(a:plain-primitive, 1291 // b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b)) 1292 Node* left = ToNumber(r.left()); 1293 Node* right = ToNumber(r.right()); 1294 Node* value = graph()->NewNode(simplified()->NumberPow(), left, right); 1295 return Replace(value); 1296 } 1297 return NoChange(); 1298 } 1299 1300 // ES6 section 20.2.2.28 Math.round ( x ) 1301 Reduction JSBuiltinReducer::ReduceMathRound(Node* node) { 1302 JSCallReduction r(node); 1303 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1304 // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a)) 1305 Node* input = ToNumber(r.GetJSCallInput(0)); 1306 Node* value = graph()->NewNode(simplified()->NumberRound(), input); 1307 return Replace(value); 1308 } 1309 return NoChange(); 1310 } 1311 1312 // ES6 section 20.2.2.9 Math.cbrt ( x ) 1313 Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) { 1314 JSCallReduction r(node); 1315 if (r.InputsMatchOne(Type::Number())) { 1316 // Math.cbrt(a:number) -> NumberCbrt(a) 1317 Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left()); 1318 return Replace(value); 1319 } 1320 return NoChange(); 1321 } 1322 1323 // ES6 section 20.2.2.29 Math.sign ( x ) 1324 Reduction JSBuiltinReducer::ReduceMathSign(Node* node) { 1325 JSCallReduction r(node); 1326 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1327 // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a)) 1328 Node* input = ToNumber(r.GetJSCallInput(0)); 1329 Node* value = graph()->NewNode(simplified()->NumberSign(), input); 1330 return Replace(value); 1331 } 1332 return NoChange(); 1333 } 1334 1335 // ES6 section 20.2.2.30 Math.sin ( x ) 1336 Reduction JSBuiltinReducer::ReduceMathSin(Node* node) { 1337 JSCallReduction r(node); 1338 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1339 // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a)) 1340 Node* input = ToNumber(r.GetJSCallInput(0)); 1341 Node* value = graph()->NewNode(simplified()->NumberSin(), input); 1342 return Replace(value); 1343 } 1344 return NoChange(); 1345 } 1346 1347 // ES6 section 20.2.2.31 Math.sinh ( x ) 1348 Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) { 1349 JSCallReduction r(node); 1350 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1351 // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a)) 1352 Node* input = ToNumber(r.GetJSCallInput(0)); 1353 Node* value = graph()->NewNode(simplified()->NumberSinh(), input); 1354 return Replace(value); 1355 } 1356 return NoChange(); 1357 } 1358 1359 // ES6 section 20.2.2.32 Math.sqrt ( x ) 1360 Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) { 1361 JSCallReduction r(node); 1362 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1363 // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a)) 1364 Node* input = ToNumber(r.GetJSCallInput(0)); 1365 Node* value = graph()->NewNode(simplified()->NumberSqrt(), input); 1366 return Replace(value); 1367 } 1368 return NoChange(); 1369 } 1370 1371 // ES6 section 20.2.2.33 Math.tan ( x ) 1372 Reduction JSBuiltinReducer::ReduceMathTan(Node* node) { 1373 JSCallReduction r(node); 1374 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1375 // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a)) 1376 Node* input = ToNumber(r.GetJSCallInput(0)); 1377 Node* value = graph()->NewNode(simplified()->NumberTan(), input); 1378 return Replace(value); 1379 } 1380 return NoChange(); 1381 } 1382 1383 // ES6 section 20.2.2.34 Math.tanh ( x ) 1384 Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) { 1385 JSCallReduction r(node); 1386 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1387 // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a)) 1388 Node* input = ToNumber(r.GetJSCallInput(0)); 1389 Node* value = graph()->NewNode(simplified()->NumberTanh(), input); 1390 return Replace(value); 1391 } 1392 return NoChange(); 1393 } 1394 1395 // ES6 section 20.2.2.35 Math.trunc ( x ) 1396 Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) { 1397 JSCallReduction r(node); 1398 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1399 // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a)) 1400 Node* input = ToNumber(r.GetJSCallInput(0)); 1401 Node* value = graph()->NewNode(simplified()->NumberTrunc(), input); 1402 return Replace(value); 1403 } 1404 return NoChange(); 1405 } 1406 1407 // ES6 section 20.1.2.2 Number.isFinite ( number ) 1408 Reduction JSBuiltinReducer::ReduceNumberIsFinite(Node* node) { 1409 JSCallReduction r(node); 1410 if (r.InputsMatchOne(Type::Number())) { 1411 // Number.isFinite(a:number) -> NumberEqual(a', a') 1412 // where a' = NumberSubtract(a, a) 1413 Node* input = r.GetJSCallInput(0); 1414 Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input); 1415 Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff); 1416 return Replace(value); 1417 } 1418 return NoChange(); 1419 } 1420 1421 // ES6 section 20.1.2.3 Number.isInteger ( number ) 1422 Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) { 1423 JSCallReduction r(node); 1424 if (r.InputsMatchOne(Type::Number())) { 1425 // Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0) 1426 // where x' = NumberTrunc(x) 1427 Node* input = r.GetJSCallInput(0); 1428 Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input); 1429 Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc); 1430 Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, 1431 jsgraph()->ZeroConstant()); 1432 return Replace(value); 1433 } 1434 return NoChange(); 1435 } 1436 1437 // ES6 section 20.1.2.4 Number.isNaN ( number ) 1438 Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) { 1439 JSCallReduction r(node); 1440 if (r.InputsMatchOne(Type::Number())) { 1441 // Number.isNaN(a:number) -> BooleanNot(NumberEqual(a, a)) 1442 Node* input = r.GetJSCallInput(0); 1443 Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input); 1444 Node* value = graph()->NewNode(simplified()->BooleanNot(), check); 1445 return Replace(value); 1446 } 1447 return NoChange(); 1448 } 1449 1450 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) 1451 Reduction JSBuiltinReducer::ReduceNumberIsSafeInteger(Node* node) { 1452 JSCallReduction r(node); 1453 if (r.InputsMatchOne(type_cache_.kSafeInteger)) { 1454 // Number.isInteger(x:safe-integer) -> #true 1455 Node* value = jsgraph()->TrueConstant(); 1456 return Replace(value); 1457 } 1458 return NoChange(); 1459 } 1460 1461 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) 1462 Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) { 1463 JSCallReduction r(node); 1464 if (r.InputsMatchOne(type_cache_.kSafeInteger) || 1465 r.InputsMatchTwo(type_cache_.kSafeInteger, 1466 type_cache_.kZeroOrUndefined) || 1467 r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) { 1468 // Number.parseInt(a:safe-integer) -> a 1469 // Number.parseInt(a:safe-integer,b:#0\/undefined) -> a 1470 // Number.parseInt(a:safe-integer,b:#10\/undefined) -> a 1471 Node* value = r.GetJSCallInput(0); 1472 return Replace(value); 1473 } 1474 return NoChange(); 1475 } 1476 1477 // ES6 section #sec-object.create Object.create(proto, properties) 1478 Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) { 1479 // We need exactly target, receiver and value parameters. 1480 int arg_count = node->op()->ValueInputCount(); 1481 if (arg_count != 3) return NoChange(); 1482 Node* effect = NodeProperties::GetEffectInput(node); 1483 Node* control = NodeProperties::GetControlInput(node); 1484 Node* prototype = NodeProperties::GetValueInput(node, 2); 1485 Type* prototype_type = NodeProperties::GetType(prototype); 1486 Handle<Map> instance_map; 1487 if (!prototype_type->IsHeapConstant()) return NoChange(); 1488 Handle<HeapObject> prototype_const = 1489 prototype_type->AsHeapConstant()->Value(); 1490 if (!prototype_const->IsNull(isolate()) && !prototype_const->IsJSReceiver()) { 1491 return NoChange(); 1492 } 1493 instance_map = Map::GetObjectCreateMap(prototype_const); 1494 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1495 if (instance_map->is_dictionary_map()) { 1496 // Allocated an empty NameDictionary as backing store for the properties. 1497 Handle<Map> map(isolate()->heap()->hash_table_map(), isolate()); 1498 int capacity = 1499 NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity); 1500 DCHECK(base::bits::IsPowerOfTwo32(capacity)); 1501 int length = NameDictionary::EntryToIndex(capacity); 1502 int size = NameDictionary::SizeFor(length); 1503 1504 effect = graph()->NewNode( 1505 common()->BeginRegion(RegionObservability::kNotObservable), effect); 1506 1507 Node* value = effect = 1508 graph()->NewNode(simplified()->Allocate(NOT_TENURED), 1509 jsgraph()->Constant(size), effect, control); 1510 effect = 1511 graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), 1512 value, jsgraph()->HeapConstant(map), effect, control); 1513 1514 // Initialize FixedArray fields. 1515 effect = graph()->NewNode( 1516 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), value, 1517 jsgraph()->SmiConstant(length), effect, control); 1518 // Initialize HashTable fields. 1519 effect = 1520 graph()->NewNode(simplified()->StoreField( 1521 AccessBuilder::ForHashTableBaseNumberOfElements()), 1522 value, jsgraph()->SmiConstant(0), effect, control); 1523 effect = graph()->NewNode( 1524 simplified()->StoreField( 1525 AccessBuilder::ForHashTableBaseNumberOfDeletedElement()), 1526 value, jsgraph()->SmiConstant(0), effect, control); 1527 effect = graph()->NewNode( 1528 simplified()->StoreField(AccessBuilder::ForHashTableBaseCapacity()), 1529 value, jsgraph()->SmiConstant(capacity), effect, control); 1530 // Initialize Dictionary fields. 1531 Node* undefined = jsgraph()->UndefinedConstant(); 1532 effect = graph()->NewNode( 1533 simplified()->StoreField(AccessBuilder::ForDictionaryMaxNumberKey()), 1534 value, undefined, effect, control); 1535 effect = graph()->NewNode( 1536 simplified()->StoreField( 1537 AccessBuilder::ForDictionaryNextEnumerationIndex()), 1538 value, jsgraph()->SmiConstant(PropertyDetails::kInitialIndex), effect, 1539 control); 1540 // Initialize hte Properties fields. 1541 for (int index = NameDictionary::kNextEnumerationIndexIndex + 1; 1542 index < length; index++) { 1543 effect = graph()->NewNode( 1544 simplified()->StoreField( 1545 AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier)), 1546 value, undefined, effect, control); 1547 } 1548 properties = effect = 1549 graph()->NewNode(common()->FinishRegion(), value, effect); 1550 } 1551 1552 int const instance_size = instance_map->instance_size(); 1553 if (instance_size > kMaxRegularHeapObjectSize) return NoChange(); 1554 dependencies()->AssumeInitialMapCantChange(instance_map); 1555 1556 // Emit code to allocate the JSObject instance for the given 1557 // {instance_map}. 1558 effect = graph()->NewNode( 1559 common()->BeginRegion(RegionObservability::kNotObservable), effect); 1560 Node* value = effect = 1561 graph()->NewNode(simplified()->Allocate(NOT_TENURED), 1562 jsgraph()->Constant(instance_size), effect, control); 1563 effect = 1564 graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value, 1565 jsgraph()->HeapConstant(instance_map), effect, control); 1566 effect = graph()->NewNode( 1567 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, 1568 properties, effect, control); 1569 effect = graph()->NewNode( 1570 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, 1571 jsgraph()->EmptyFixedArrayConstant(), effect, control); 1572 // Initialize Object fields. 1573 Node* undefined = jsgraph()->UndefinedConstant(); 1574 for (int offset = JSObject::kHeaderSize; offset < instance_size; 1575 offset += kPointerSize) { 1576 effect = graph()->NewNode( 1577 simplified()->StoreField( 1578 AccessBuilder::ForJSObjectOffset(offset, kNoWriteBarrier)), 1579 value, undefined, effect, control); 1580 } 1581 value = effect = graph()->NewNode(common()->FinishRegion(), value, effect); 1582 1583 // replace it 1584 ReplaceWithValue(node, value, effect, control); 1585 return Replace(value); 1586 } 1587 1588 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) 1589 Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { 1590 JSCallReduction r(node); 1591 if (r.InputsMatchOne(Type::PlainPrimitive())) { 1592 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) 1593 Node* input = ToNumber(r.GetJSCallInput(0)); 1594 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); 1595 return Replace(value); 1596 } 1597 return NoChange(); 1598 } 1599 1600 namespace { 1601 1602 Node* GetStringWitness(Node* node) { 1603 Node* receiver = NodeProperties::GetValueInput(node, 1); 1604 Type* receiver_type = NodeProperties::GetType(receiver); 1605 Node* effect = NodeProperties::GetEffectInput(node); 1606 if (receiver_type->Is(Type::String())) return receiver; 1607 // Check if the {node} is dominated by a CheckString renaming for 1608 // it's {receiver}, and if so use that renaming as {receiver} for 1609 // the lowering below. 1610 for (Node* dominator = effect;;) { 1611 if (dominator->opcode() == IrOpcode::kCheckString && 1612 NodeProperties::IsSame(dominator->InputAt(0), receiver)) { 1613 return dominator; 1614 } 1615 if (dominator->op()->EffectInputCount() != 1) { 1616 // Didn't find any appropriate CheckString node. 1617 return nullptr; 1618 } 1619 dominator = NodeProperties::GetEffectInput(dominator); 1620 } 1621 } 1622 1623 } // namespace 1624 1625 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) 1626 Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { 1627 // We need at least target, receiver and index parameters. 1628 if (node->op()->ValueInputCount() >= 3) { 1629 Node* index = NodeProperties::GetValueInput(node, 2); 1630 Type* index_type = NodeProperties::GetType(index); 1631 Node* effect = NodeProperties::GetEffectInput(node); 1632 Node* control = NodeProperties::GetControlInput(node); 1633 1634 if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) { 1635 if (Node* receiver = GetStringWitness(node)) { 1636 if (!index_type->Is(Type::Unsigned32())) { 1637 // Map -0 and NaN to 0 (as per ToInteger), and the values in 1638 // the [-2^31,-1] range to the [2^31,2^32-1] range, which will 1639 // be considered out-of-bounds as well, because of the maximal 1640 // String length limit in V8. 1641 STATIC_ASSERT(String::kMaxLength <= kMaxInt); 1642 index = graph()->NewNode(simplified()->NumberToUint32(), index); 1643 } 1644 1645 // Determine the {receiver} length. 1646 Node* receiver_length = effect = graph()->NewNode( 1647 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 1648 effect, control); 1649 1650 // Check if {index} is less than {receiver} length. 1651 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, 1652 receiver_length); 1653 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1654 check, control); 1655 1656 // Return the character from the {receiver} as single character string. 1657 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1658 Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver, 1659 index, if_true); 1660 1661 // Return the empty string otherwise. 1662 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1663 Node* vfalse = jsgraph()->EmptyStringConstant(); 1664 1665 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1666 Node* value = 1667 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1668 vtrue, vfalse, control); 1669 1670 ReplaceWithValue(node, value, effect, control); 1671 return Replace(value); 1672 } 1673 } 1674 } 1675 1676 return NoChange(); 1677 } 1678 1679 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) 1680 Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { 1681 // We need at least target, receiver and index parameters. 1682 if (node->op()->ValueInputCount() >= 3) { 1683 Node* index = NodeProperties::GetValueInput(node, 2); 1684 Type* index_type = NodeProperties::GetType(index); 1685 Node* effect = NodeProperties::GetEffectInput(node); 1686 Node* control = NodeProperties::GetControlInput(node); 1687 1688 if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) { 1689 if (Node* receiver = GetStringWitness(node)) { 1690 if (!index_type->Is(Type::Unsigned32())) { 1691 // Map -0 and NaN to 0 (as per ToInteger), and the values in 1692 // the [-2^31,-1] range to the [2^31,2^32-1] range, which will 1693 // be considered out-of-bounds as well, because of the maximal 1694 // String length limit in V8. 1695 STATIC_ASSERT(String::kMaxLength <= kMaxInt); 1696 index = graph()->NewNode(simplified()->NumberToUint32(), index); 1697 } 1698 1699 // Determine the {receiver} length. 1700 Node* receiver_length = effect = graph()->NewNode( 1701 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 1702 effect, control); 1703 1704 // Check if {index} is less than {receiver} length. 1705 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, 1706 receiver_length); 1707 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1708 check, control); 1709 1710 // Load the character from the {receiver}. 1711 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1712 Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), 1713 receiver, index, if_true); 1714 1715 // Return NaN otherwise. 1716 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1717 Node* vfalse = jsgraph()->NaNConstant(); 1718 1719 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1720 Node* value = 1721 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1722 vtrue, vfalse, control); 1723 1724 ReplaceWithValue(node, value, effect, control); 1725 return Replace(value); 1726 } 1727 } 1728 } 1729 1730 return NoChange(); 1731 } 1732 1733 // ES6 String.prototype.indexOf(searchString [, position]) 1734 // #sec-string.prototype.indexof 1735 Reduction JSBuiltinReducer::ReduceStringIndexOf(Node* node) { 1736 // We need at least target, receiver and search_string parameters. 1737 if (node->op()->ValueInputCount() >= 3) { 1738 Node* search_string = NodeProperties::GetValueInput(node, 2); 1739 Type* search_string_type = NodeProperties::GetType(search_string); 1740 Node* position = (node->op()->ValueInputCount() >= 4) 1741 ? NodeProperties::GetValueInput(node, 3) 1742 : jsgraph()->ZeroConstant(); 1743 Type* position_type = NodeProperties::GetType(position); 1744 1745 if (search_string_type->Is(Type::String()) && 1746 position_type->Is(Type::SignedSmall())) { 1747 if (Node* receiver = GetStringWitness(node)) { 1748 RelaxEffectsAndControls(node); 1749 node->ReplaceInput(0, receiver); 1750 node->ReplaceInput(1, search_string); 1751 node->ReplaceInput(2, position); 1752 node->TrimInputCount(3); 1753 NodeProperties::ChangeOp(node, simplified()->StringIndexOf()); 1754 return Changed(node); 1755 } 1756 } 1757 } 1758 return NoChange(); 1759 } 1760 1761 Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) { 1762 if (Node* receiver = GetStringWitness(node)) { 1763 Node* effect = NodeProperties::GetEffectInput(node); 1764 Node* control = NodeProperties::GetControlInput(node); 1765 1766 Node* map = jsgraph()->HeapConstant( 1767 handle(native_context()->string_iterator_map(), isolate())); 1768 1769 // allocate new iterator 1770 effect = graph()->NewNode( 1771 common()->BeginRegion(RegionObservability::kNotObservable), effect); 1772 Node* value = effect = graph()->NewNode( 1773 simplified()->Allocate(NOT_TENURED), 1774 jsgraph()->Constant(JSStringIterator::kSize), effect, control); 1775 NodeProperties::SetType(value, Type::OtherObject()); 1776 effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), 1777 value, map, effect, control); 1778 effect = graph()->NewNode( 1779 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, 1780 jsgraph()->EmptyFixedArrayConstant(), effect, control); 1781 effect = graph()->NewNode( 1782 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, 1783 jsgraph()->EmptyFixedArrayConstant(), effect, control); 1784 1785 // attach the iterator to this string 1786 effect = graph()->NewNode( 1787 simplified()->StoreField(AccessBuilder::ForJSStringIteratorString()), 1788 value, receiver, effect, control); 1789 effect = graph()->NewNode( 1790 simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()), 1791 value, jsgraph()->SmiConstant(0), effect, control); 1792 1793 value = effect = graph()->NewNode(common()->FinishRegion(), value, effect); 1794 1795 // replace it 1796 ReplaceWithValue(node, value, effect, control); 1797 return Replace(value); 1798 } 1799 return NoChange(); 1800 } 1801 1802 Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) { 1803 Node* receiver = NodeProperties::GetValueInput(node, 1); 1804 Node* effect = NodeProperties::GetEffectInput(node); 1805 Node* control = NodeProperties::GetControlInput(node); 1806 Node* context = NodeProperties::GetContextInput(node); 1807 if (HasInstanceTypeWitness(receiver, effect, JS_STRING_ITERATOR_TYPE)) { 1808 Node* string = effect = graph()->NewNode( 1809 simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()), 1810 receiver, effect, control); 1811 Node* index = effect = graph()->NewNode( 1812 simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()), 1813 receiver, effect, control); 1814 Node* length = effect = graph()->NewNode( 1815 simplified()->LoadField(AccessBuilder::ForStringLength()), string, 1816 effect, control); 1817 1818 // branch0: if (index < length) 1819 Node* check0 = 1820 graph()->NewNode(simplified()->NumberLessThan(), index, length); 1821 Node* branch0 = 1822 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); 1823 1824 Node* etrue0 = effect; 1825 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1826 Node* done_true; 1827 Node* vtrue0; 1828 { 1829 done_true = jsgraph()->FalseConstant(); 1830 Node* lead = graph()->NewNode(simplified()->StringCharCodeAt(), string, 1831 index, if_true0); 1832 1833 // branch1: if ((lead & 0xFC00) === 0xD800) 1834 Node* check1 = 1835 graph()->NewNode(simplified()->NumberEqual(), 1836 graph()->NewNode(simplified()->NumberBitwiseAnd(), 1837 lead, jsgraph()->Constant(0xFC00)), 1838 jsgraph()->Constant(0xD800)); 1839 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1840 check1, if_true0); 1841 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1842 Node* vtrue1; 1843 { 1844 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, 1845 jsgraph()->OneConstant()); 1846 // branch2: if ((index + 1) < length) 1847 Node* check2 = graph()->NewNode(simplified()->NumberLessThan(), 1848 next_index, length); 1849 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1850 check2, if_true1); 1851 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 1852 Node* vtrue2; 1853 { 1854 Node* trail = graph()->NewNode(simplified()->StringCharCodeAt(), 1855 string, next_index, if_true2); 1856 // branch3: if ((trail & 0xFC00) === 0xDC00) 1857 Node* check3 = graph()->NewNode( 1858 simplified()->NumberEqual(), 1859 graph()->NewNode(simplified()->NumberBitwiseAnd(), trail, 1860 jsgraph()->Constant(0xFC00)), 1861 jsgraph()->Constant(0xDC00)); 1862 Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1863 check3, if_true2); 1864 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); 1865 Node* vtrue3; 1866 { 1867 vtrue3 = graph()->NewNode( 1868 simplified()->NumberBitwiseOr(), 1869 // Need to swap the order for big-endian platforms 1870 #if V8_TARGET_BIG_ENDIAN 1871 graph()->NewNode(simplified()->NumberShiftLeft(), lead, 1872 jsgraph()->Constant(16)), 1873 trail); 1874 #else 1875 graph()->NewNode(simplified()->NumberShiftLeft(), trail, 1876 jsgraph()->Constant(16)), 1877 lead); 1878 #endif 1879 } 1880 1881 Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3); 1882 Node* vfalse3 = lead; 1883 if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3); 1884 vtrue2 = 1885 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), 1886 vtrue3, vfalse3, if_true2); 1887 } 1888 1889 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); 1890 Node* vfalse2 = lead; 1891 if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); 1892 vtrue1 = 1893 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), 1894 vtrue2, vfalse2, if_true1); 1895 } 1896 1897 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1898 Node* vfalse1 = lead; 1899 if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); 1900 vtrue0 = 1901 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), 1902 vtrue1, vfalse1, if_true0); 1903 vtrue0 = graph()->NewNode( 1904 simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), vtrue0); 1905 1906 // Update iterator.[[NextIndex]] 1907 Node* char_length = etrue0 = graph()->NewNode( 1908 simplified()->LoadField(AccessBuilder::ForStringLength()), vtrue0, 1909 etrue0, if_true0); 1910 index = graph()->NewNode(simplified()->NumberAdd(), index, char_length); 1911 etrue0 = graph()->NewNode( 1912 simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()), 1913 receiver, index, etrue0, if_true0); 1914 } 1915 1916 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1917 Node* done_false; 1918 Node* vfalse0; 1919 { 1920 vfalse0 = jsgraph()->UndefinedConstant(); 1921 done_false = jsgraph()->TrueConstant(); 1922 } 1923 1924 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 1925 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control); 1926 Node* value = 1927 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1928 vtrue0, vfalse0, control); 1929 Node* done = 1930 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1931 done_true, done_false, control); 1932 1933 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), 1934 value, done, context, effect); 1935 1936 ReplaceWithValue(node, value, effect, control); 1937 return Replace(value); 1938 } 1939 return NoChange(); 1940 } 1941 1942 Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor( 1943 Node* node, InstanceType instance_type, FieldAccess const& access) { 1944 Node* receiver = NodeProperties::GetValueInput(node, 1); 1945 Node* effect = NodeProperties::GetEffectInput(node); 1946 Node* control = NodeProperties::GetControlInput(node); 1947 if (HasInstanceTypeWitness(receiver, effect, instance_type)) { 1948 // Load the {receiver}s field. 1949 Node* value = effect = graph()->NewNode(simplified()->LoadField(access), 1950 receiver, effect, control); 1951 1952 // See if we can skip the neutering check. 1953 if (isolate()->IsArrayBufferNeuteringIntact()) { 1954 // Add a code dependency so we are deoptimized in case an ArrayBuffer 1955 // gets neutered. 1956 dependencies()->AssumePropertyCell( 1957 factory()->array_buffer_neutering_protector()); 1958 } else { 1959 // Check if the {receiver}s buffer was neutered. 1960 Node* receiver_buffer = effect = graph()->NewNode( 1961 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 1962 receiver, effect, control); 1963 Node* check = effect = 1964 graph()->NewNode(simplified()->ArrayBufferWasNeutered(), 1965 receiver_buffer, effect, control); 1966 1967 // Default to zero if the {receiver}s buffer was neutered. 1968 value = graph()->NewNode( 1969 common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), 1970 check, jsgraph()->ZeroConstant(), value); 1971 } 1972 1973 ReplaceWithValue(node, value, effect, control); 1974 return Replace(value); 1975 } 1976 return NoChange(); 1977 } 1978 1979 Reduction JSBuiltinReducer::Reduce(Node* node) { 1980 Reduction reduction = NoChange(); 1981 JSCallReduction r(node); 1982 1983 // Dispatch according to the BuiltinFunctionId if present. 1984 if (!r.HasBuiltinFunctionId()) return NoChange(); 1985 switch (r.GetBuiltinFunctionId()) { 1986 case kArrayEntries: 1987 return ReduceArrayIterator(node, IterationKind::kEntries); 1988 case kArrayKeys: 1989 return ReduceArrayIterator(node, IterationKind::kKeys); 1990 case kArrayValues: 1991 return ReduceArrayIterator(node, IterationKind::kValues); 1992 case kArrayIteratorNext: 1993 return ReduceArrayIteratorNext(node); 1994 case kArrayPop: 1995 return ReduceArrayPop(node); 1996 case kArrayPush: 1997 return ReduceArrayPush(node); 1998 case kDateNow: 1999 return ReduceDateNow(node); 2000 case kDateGetTime: 2001 return ReduceDateGetTime(node); 2002 case kGlobalIsFinite: 2003 reduction = ReduceGlobalIsFinite(node); 2004 break; 2005 case kGlobalIsNaN: 2006 reduction = ReduceGlobalIsNaN(node); 2007 break; 2008 case kMathAbs: 2009 reduction = ReduceMathAbs(node); 2010 break; 2011 case kMathAcos: 2012 reduction = ReduceMathAcos(node); 2013 break; 2014 case kMathAcosh: 2015 reduction = ReduceMathAcosh(node); 2016 break; 2017 case kMathAsin: 2018 reduction = ReduceMathAsin(node); 2019 break; 2020 case kMathAsinh: 2021 reduction = ReduceMathAsinh(node); 2022 break; 2023 case kMathAtan: 2024 reduction = ReduceMathAtan(node); 2025 break; 2026 case kMathAtanh: 2027 reduction = ReduceMathAtanh(node); 2028 break; 2029 case kMathAtan2: 2030 reduction = ReduceMathAtan2(node); 2031 break; 2032 case kMathCbrt: 2033 reduction = ReduceMathCbrt(node); 2034 break; 2035 case kMathCeil: 2036 reduction = ReduceMathCeil(node); 2037 break; 2038 case kMathClz32: 2039 reduction = ReduceMathClz32(node); 2040 break; 2041 case kMathCos: 2042 reduction = ReduceMathCos(node); 2043 break; 2044 case kMathCosh: 2045 reduction = ReduceMathCosh(node); 2046 break; 2047 case kMathExp: 2048 reduction = ReduceMathExp(node); 2049 break; 2050 case kMathExpm1: 2051 reduction = ReduceMathExpm1(node); 2052 break; 2053 case kMathFloor: 2054 reduction = ReduceMathFloor(node); 2055 break; 2056 case kMathFround: 2057 reduction = ReduceMathFround(node); 2058 break; 2059 case kMathImul: 2060 reduction = ReduceMathImul(node); 2061 break; 2062 case kMathLog: 2063 reduction = ReduceMathLog(node); 2064 break; 2065 case kMathLog1p: 2066 reduction = ReduceMathLog1p(node); 2067 break; 2068 case kMathLog10: 2069 reduction = ReduceMathLog10(node); 2070 break; 2071 case kMathLog2: 2072 reduction = ReduceMathLog2(node); 2073 break; 2074 case kMathMax: 2075 reduction = ReduceMathMax(node); 2076 break; 2077 case kMathMin: 2078 reduction = ReduceMathMin(node); 2079 break; 2080 case kMathPow: 2081 reduction = ReduceMathPow(node); 2082 break; 2083 case kMathRound: 2084 reduction = ReduceMathRound(node); 2085 break; 2086 case kMathSign: 2087 reduction = ReduceMathSign(node); 2088 break; 2089 case kMathSin: 2090 reduction = ReduceMathSin(node); 2091 break; 2092 case kMathSinh: 2093 reduction = ReduceMathSinh(node); 2094 break; 2095 case kMathSqrt: 2096 reduction = ReduceMathSqrt(node); 2097 break; 2098 case kMathTan: 2099 reduction = ReduceMathTan(node); 2100 break; 2101 case kMathTanh: 2102 reduction = ReduceMathTanh(node); 2103 break; 2104 case kMathTrunc: 2105 reduction = ReduceMathTrunc(node); 2106 break; 2107 case kNumberIsFinite: 2108 reduction = ReduceNumberIsFinite(node); 2109 break; 2110 case kNumberIsInteger: 2111 reduction = ReduceNumberIsInteger(node); 2112 break; 2113 case kNumberIsNaN: 2114 reduction = ReduceNumberIsNaN(node); 2115 break; 2116 case kNumberIsSafeInteger: 2117 reduction = ReduceNumberIsSafeInteger(node); 2118 break; 2119 case kNumberParseInt: 2120 reduction = ReduceNumberParseInt(node); 2121 break; 2122 case kObjectCreate: 2123 reduction = ReduceObjectCreate(node); 2124 break; 2125 case kStringFromCharCode: 2126 reduction = ReduceStringFromCharCode(node); 2127 break; 2128 case kStringCharAt: 2129 return ReduceStringCharAt(node); 2130 case kStringCharCodeAt: 2131 return ReduceStringCharCodeAt(node); 2132 case kStringIndexOf: 2133 return ReduceStringIndexOf(node); 2134 case kStringIterator: 2135 return ReduceStringIterator(node); 2136 case kStringIteratorNext: 2137 return ReduceStringIteratorNext(node); 2138 case kDataViewByteLength: 2139 return ReduceArrayBufferViewAccessor( 2140 node, JS_DATA_VIEW_TYPE, 2141 AccessBuilder::ForJSArrayBufferViewByteLength()); 2142 case kDataViewByteOffset: 2143 return ReduceArrayBufferViewAccessor( 2144 node, JS_DATA_VIEW_TYPE, 2145 AccessBuilder::ForJSArrayBufferViewByteOffset()); 2146 case kTypedArrayByteLength: 2147 return ReduceArrayBufferViewAccessor( 2148 node, JS_TYPED_ARRAY_TYPE, 2149 AccessBuilder::ForJSArrayBufferViewByteLength()); 2150 case kTypedArrayByteOffset: 2151 return ReduceArrayBufferViewAccessor( 2152 node, JS_TYPED_ARRAY_TYPE, 2153 AccessBuilder::ForJSArrayBufferViewByteOffset()); 2154 case kTypedArrayLength: 2155 return ReduceArrayBufferViewAccessor( 2156 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); 2157 case kTypedArrayEntries: 2158 return ReduceTypedArrayIterator(node, IterationKind::kEntries); 2159 case kTypedArrayKeys: 2160 return ReduceTypedArrayIterator(node, IterationKind::kKeys); 2161 case kTypedArrayValues: 2162 return ReduceTypedArrayIterator(node, IterationKind::kValues); 2163 default: 2164 break; 2165 } 2166 2167 // Replace builtin call assuming replacement nodes are pure values that don't 2168 // produce an effect. Replaces {node} with {reduction} and relaxes effects. 2169 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); 2170 2171 return reduction; 2172 } 2173 2174 Node* JSBuiltinReducer::ToNumber(Node* input) { 2175 Type* input_type = NodeProperties::GetType(input); 2176 if (input_type->Is(Type::Number())) return input; 2177 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input); 2178 } 2179 2180 Node* JSBuiltinReducer::ToUint32(Node* input) { 2181 input = ToNumber(input); 2182 Type* input_type = NodeProperties::GetType(input); 2183 if (input_type->Is(Type::Unsigned32())) return input; 2184 return graph()->NewNode(simplified()->NumberToUint32(), input); 2185 } 2186 2187 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } 2188 2189 Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); } 2190 2191 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); } 2192 2193 2194 CommonOperatorBuilder* JSBuiltinReducer::common() const { 2195 return jsgraph()->common(); 2196 } 2197 2198 2199 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { 2200 return jsgraph()->simplified(); 2201 } 2202 2203 JSOperatorBuilder* JSBuiltinReducer::javascript() const { 2204 return jsgraph()->javascript(); 2205 } 2206 2207 } // namespace compiler 2208 } // namespace internal 2209 } // namespace v8 2210