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:
JSCallReduction(Node * node)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.
HasBuiltinFunctionId()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.
GetBuiltinFunctionId()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
ReceiverMatches(Type * type)48 bool ReceiverMatches(Type* type) {
49 return NodeProperties::GetType(receiver())->Is(type);
50 }
51
52 // Determines whether the call takes zero inputs.
InputsMatchZero()53 bool InputsMatchZero() { return GetJSCallArity() == 0; }
54
55 // Determines whether the call takes one input of the given type.
InputsMatchOne(Type * t1)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.
InputsMatchTwo(Type * t1,Type * t2)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.
InputsMatchAll(Type * t)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
receiver()78 Node* receiver() { return NodeProperties::GetValueInput(node_, 1); }
left()79 Node* left() { return GetJSCallInput(0); }
right()80 Node* right() { return GetJSCallInput(1); }
81
GetJSCallArity()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
GetJSCallInput(int index)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
JSBuiltinReducer(Editor * editor,JSGraph * jsgraph,Flags flags,CompilationDependencies * dependencies,Handle<Context> native_context)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
GetMapWitness(Node * node)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.
IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map)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.
CanInlineArrayResizeOperation(Handle<Map> receiver_map)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
CanInlineJSArrayIteration(Handle<Map> receiver_map)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
ReduceArrayIterator(Node * node,IterationKind kind)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
ReduceTypedArrayIterator(Node * node,IterationKind kind)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
ReduceArrayIterator(Handle<Map> receiver_map,Node * node,IterationKind kind,ArrayIteratorKind iter_kind)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
ReduceFastArrayIteratorNext(Handle<Map> iterator_map,Node * node,IterationKind kind)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
ReduceTypedArrayIteratorNext(Handle<Map> iterator_map,Node * node,IterationKind kind)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
ReduceArrayIteratorNext(Node * node)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 ( )
ReduceArrayPop(Node * node)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 ( )
ReduceArrayPush(Node * node)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
HasInstanceTypeWitness(Node * receiver,Node * effect,InstanceType instance_type)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 ( )
ReduceDateNow(Node * node)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 ( )
ReduceDateGetTime(Node * node)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 )
ReduceGlobalIsFinite(Node * node)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 )
ReduceGlobalIsNaN(Node * node)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 )
ReduceMathAbs(Node * node)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 )
ReduceMathAcos(Node * node)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 )
ReduceMathAcosh(Node * node)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 )
ReduceMathAsin(Node * node)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 )
ReduceMathAsinh(Node * node)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 )
ReduceMathAtan(Node * node)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 )
ReduceMathAtanh(Node * node)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 )
ReduceMathAtan2(Node * node)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 )
ReduceMathCeil(Node * node)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 )
ReduceMathClz32(Node * node)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 )
ReduceMathCos(Node * node)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 )
ReduceMathCosh(Node * node)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 )
ReduceMathExp(Node * node)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 )
ReduceMathExpm1(Node * node)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 )
ReduceMathFloor(Node * node)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 )
ReduceMathFround(Node * node)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 )
ReduceMathImul(Node * node)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 )
ReduceMathLog(Node * node)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 )
ReduceMathLog1p(Node * node)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 )
ReduceMathLog10(Node * node)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 )
ReduceMathLog2(Node * node)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 )
ReduceMathMax(Node * node)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 )
ReduceMathMin(Node * node)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 )
ReduceMathPow(Node * node)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 )
ReduceMathRound(Node * node)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 )
ReduceMathCbrt(Node * node)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 )
ReduceMathSign(Node * node)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 )
ReduceMathSin(Node * node)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 )
ReduceMathSinh(Node * node)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 )
ReduceMathSqrt(Node * node)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 )
ReduceMathTan(Node * node)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 )
ReduceMathTanh(Node * node)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 )
ReduceMathTrunc(Node * node)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 )
ReduceNumberIsFinite(Node * node)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 )
ReduceNumberIsInteger(Node * node)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 )
ReduceNumberIsNaN(Node * node)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 )
ReduceNumberIsSafeInteger(Node * node)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 )
ReduceNumberParseInt(Node * node)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)
ReduceObjectCreate(Node * node)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 )
ReduceStringFromCharCode(Node * node)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
GetStringWitness(Node * node)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 )
ReduceStringCharAt(Node * node)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 )
ReduceStringCharCodeAt(Node * node)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
ReduceStringIndexOf(Node * node)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
ReduceStringIterator(Node * node)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
ReduceStringIteratorNext(Node * node)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
ReduceArrayBufferViewAccessor(Node * node,InstanceType instance_type,FieldAccess const & access)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
Reduce(Node * node)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
ToNumber(Node * input)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
ToUint32(Node * input)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
graph() const2187 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
2188
factory() const2189 Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
2190
isolate() const2191 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
2192
2193
common() const2194 CommonOperatorBuilder* JSBuiltinReducer::common() const {
2195 return jsgraph()->common();
2196 }
2197
2198
simplified() const2199 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
2200 return jsgraph()->simplified();
2201 }
2202
javascript() const2203 JSOperatorBuilder* JSBuiltinReducer::javascript() const {
2204 return jsgraph()->javascript();
2205 }
2206
2207 } // namespace compiler
2208 } // namespace internal
2209 } // namespace v8
2210