OLD | NEW |
---|---|
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-builtin-reducer.h" | 5 #include "src/compiler/js-builtin-reducer.h" |
6 | 6 |
7 #include "src/compilation-dependencies.h" | 7 #include "src/compilation-dependencies.h" |
8 #include "src/compiler/access-builder.h" | 8 #include "src/compiler/access-builder.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 IsFastElementsKind(receiver_map->elements_kind()) && | 170 IsFastElementsKind(receiver_map->elements_kind()) && |
171 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && | 171 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && |
172 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && | 172 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && |
173 isolate->IsFastArrayConstructorPrototypeChainIntact() && | 173 isolate->IsFastArrayConstructorPrototypeChainIntact() && |
174 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && | 174 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && |
175 !IsReadOnlyLengthDescriptor(receiver_map); | 175 !IsReadOnlyLengthDescriptor(receiver_map); |
176 } | 176 } |
177 | 177 |
178 } // namespace | 178 } // namespace |
179 | 179 |
180 Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node, | |
181 IterationKind kind) { | |
182 Handle<Map> receiver_map; | |
183 Node* receiver = NodeProperties::GetValueInput(node, 1); | |
184 Node* effect = NodeProperties::GetEffectInput(node); | |
185 Node* control = NodeProperties::GetControlInput(node); | |
186 | |
187 if (GetMapWitness(node).ToHandle(&receiver_map)) { | |
188 int map_index = -1; | |
189 Node* object_map = jsgraph()->UndefinedConstant(); | |
190 switch (receiver_map->instance_type()) { | |
191 case JS_ARRAY_TYPE: | |
192 if (kind == IterationKind::kKeys) { | |
193 map_index = Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX; | |
194 } else { | |
195 map_index = | |
196 kind == IterationKind::kValues | |
197 ? Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX | |
198 : Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX; | |
199 | |
200 if (IsFastElementsKind(receiver_map->elements_kind()) && | |
Benedikt Meurer
2016/11/08 08:30:00
For holey arrays you first need to check whether a
caitp
2016/11/08 17:53:07
I did some creative stuff to have (I think) exactl
| |
201 (!IsFastHoleyElementsKind(receiver_map->elements_kind()) || | |
202 receiver_map->prototype() == | |
203 native_context()->initial_array_prototype())) { | |
204 // Use `generic` elements for holey arrays if there may be elements | |
205 // on the prototype chain. | |
206 map_index += static_cast<int>(receiver_map->elements_kind()); | |
207 object_map = jsgraph()->Constant(receiver_map); | |
208 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { | |
209 Handle<JSObject> initial_array_prototype( | |
210 native_context()->initial_array_prototype(), isolate()); | |
211 dependencies()->AssumePrototypeMapsStable( | |
212 receiver_map, initial_array_prototype); | |
213 } | |
214 } else { | |
215 map_index += (Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX - | |
216 Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX); | |
217 } | |
218 } | |
219 break; | |
220 case JS_TYPED_ARRAY_TYPE: | |
221 if (kind == IterationKind::kKeys) { | |
222 map_index = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX; | |
223 } else { | |
224 DCHECK_GE(receiver_map->elements_kind(), UINT8_ELEMENTS); | |
225 DCHECK_LE(receiver_map->elements_kind(), UINT8_CLAMPED_ELEMENTS); | |
226 map_index = | |
227 (kind == IterationKind::kValues | |
228 ? Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX | |
229 : Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX) + | |
230 (receiver_map->elements_kind() - UINT8_ELEMENTS); | |
231 } | |
232 break; | |
233 default: | |
234 if (kind == IterationKind::kKeys) { | |
235 map_index = Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX; | |
236 } else if (kind == IterationKind::kValues) { | |
237 map_index = Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX; | |
238 } else { | |
239 map_index = Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX; | |
240 } | |
241 break; | |
242 } | |
243 | |
244 DCHECK_GE(map_index, Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX); | |
245 DCHECK_LE(map_index, Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX); | |
246 | |
247 Handle<Map> map(Map::cast(native_context()->get(map_index)), isolate()); | |
248 | |
249 // allocate new iterator | |
250 effect = graph()->NewNode( | |
251 common()->BeginRegion(RegionObservability::kNotObservable), effect); | |
252 Node* value = effect = graph()->NewNode( | |
253 simplified()->Allocate(NOT_TENURED), | |
254 jsgraph()->Constant(JSArrayIterator::kSize), effect, control); | |
255 effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), | |
256 value, jsgraph()->Constant(map), effect, control); | |
257 effect = graph()->NewNode( | |
258 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, | |
259 jsgraph()->EmptyFixedArrayConstant(), effect, control); | |
260 effect = graph()->NewNode( | |
261 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, | |
262 jsgraph()->EmptyFixedArrayConstant(), effect, control); | |
263 | |
264 // attach the iterator to this object | |
265 effect = graph()->NewNode( | |
266 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()), | |
267 value, receiver, effect, control); | |
268 effect = graph()->NewNode( | |
269 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex()), | |
270 value, jsgraph()->ZeroConstant(), effect, control); | |
271 effect = graph()->NewNode( | |
272 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObjectMap()), | |
273 value, object_map, effect, control); | |
274 | |
275 value = effect = graph()->NewNode(common()->FinishRegion(), value, effect); | |
276 | |
277 // replace it | |
278 ReplaceWithValue(node, value, effect, control); | |
279 return Replace(value); | |
280 } | |
281 return NoChange(); | |
282 } | |
283 | |
284 Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext( | |
285 Handle<Map> iterator_map, Node* node, IterationKind kind) { | |
286 Node* iterator = NodeProperties::GetValueInput(node, 1); | |
287 Node* effect = NodeProperties::GetEffectInput(node); | |
288 Node* control = NodeProperties::GetControlInput(node); | |
289 Node* context = NodeProperties::GetContextInput(node); | |
290 | |
291 if (kind != IterationKind::kKeys && !isolate()->CanInlineArrayIterator()) { | |
292 // Avoid deopt loops for non-key iteration if the array_iterator_protector | |
293 // cell has been invalidated. | |
294 return NoChange(); | |
295 } | |
296 | |
297 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType( | |
298 iterator_map->instance_type()); | |
299 | |
300 if (IsFastHoleyElementsKind(elements_kind)) { | |
301 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | |
302 return NoChange(); | |
303 } else { | |
304 Handle<JSObject> initial_array_prototype( | |
305 native_context()->initial_array_prototype(), isolate()); | |
306 dependencies()->AssumePropertyCell(factory()->array_protector()); | |
307 } | |
308 } | |
309 | |
310 Node* array = effect = graph()->NewNode( | |
311 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()), | |
312 iterator, effect, control); | |
313 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array, | |
314 jsgraph()->UndefinedConstant()); | |
315 Node* branch0 = | |
316 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); | |
317 | |
318 Node* vdone_false0; | |
319 Node* vfalse0; | |
320 Node* efalse0 = effect; | |
321 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); | |
322 { | |
323 // iterator.[[IteratedObject]] !== undefined, continue iterating. | |
324 Node* index = efalse0 = graph()->NewNode( | |
325 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex( | |
326 JS_ARRAY_TYPE, elements_kind)), | |
327 iterator, efalse0, if_false0); | |
328 | |
329 Node* length = efalse0 = graph()->NewNode( | |
330 simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)), | |
331 array, efalse0, if_false0); | |
332 Node* check1 = | |
333 graph()->NewNode(simplified()->NumberLessThan(), index, length); | |
334 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), | |
335 check1, if_false0); | |
336 | |
337 Node* vdone_true1; | |
338 Node* vtrue1; | |
339 Node* etrue1 = efalse0; | |
340 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); | |
341 { | |
342 // iterator.[[NextIndex]] < array.length, continue iterating | |
343 vdone_true1 = jsgraph()->FalseConstant(); | |
344 if (kind == IterationKind::kKeys) { | |
345 vtrue1 = index; | |
346 } else { | |
347 // For value/entry iteration, first step is a mapcheck to ensure | |
348 // inlining is still valid. | |
349 Node* orig_map = etrue1 = | |
350 graph()->NewNode(simplified()->LoadField( | |
351 AccessBuilder::ForJSArrayIteratorObjectMap()), | |
352 iterator, etrue1, if_true1); | |
353 etrue1 = graph()->NewNode(simplified()->CheckMaps(1), array, orig_map, | |
354 etrue1, if_true1); | |
355 } | |
356 | |
357 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, | |
358 jsgraph()->OneConstant()); | |
359 next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index); | |
360 | |
361 etrue1 = graph()->NewNode( | |
362 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex( | |
363 JS_ARRAY_TYPE, elements_kind)), | |
364 iterator, next_index, etrue1, if_true1); | |
365 | |
366 if (kind != IterationKind::kKeys) { | |
367 Node* elements = etrue1 = graph()->NewNode( | |
368 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), | |
369 array, etrue1, if_true1); | |
370 Node* value = etrue1 = graph()->NewNode( | |
371 simplified()->LoadElement( | |
372 AccessBuilder::ForFixedArrayElement(elements_kind)), | |
373 elements, index, etrue1, if_true1); | |
374 | |
375 // Convert hole to undefined if needed. | |
376 if (elements_kind == FAST_HOLEY_ELEMENTS || | |
377 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { | |
378 value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), | |
379 value); | |
380 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { | |
381 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole; | |
382 // Check if we are allowed to return the hole directly. | |
383 value = etrue1 = graph()->NewNode( | |
384 simplified()->CheckFloat64Hole(mode), value, etrue1, if_true1); | |
385 } | |
386 | |
387 if (kind == IterationKind::kEntries) { | |
388 // Allocate elements for key/value pair | |
389 etrue1 = graph()->NewNode( | |
390 common()->BeginRegion(RegionObservability::kNotObservable), | |
391 etrue1); | |
392 Node* elements = etrue1 = graph()->NewNode( | |
393 simplified()->Allocate(NOT_TENURED), | |
394 jsgraph()->Constant(FixedArray::SizeFor(2)), etrue1, if_true1); | |
395 etrue1 = graph()->NewNode( | |
396 simplified()->StoreField(AccessBuilder::ForMap()), elements, | |
397 jsgraph()->Constant(isolate()->factory()->fixed_array_map()), | |
398 etrue1, if_true1); | |
399 etrue1 = graph()->NewNode( | |
400 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), | |
401 elements, jsgraph()->Constant(2)); | |
402 etrue1 = graph()->NewNode( | |
403 simplified()->StoreElement( | |
404 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)), | |
405 elements, jsgraph()->Constant(0), index, etrue1, if_true1); | |
406 etrue1 = graph()->NewNode( | |
407 simplified()->StoreElement( | |
408 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)), | |
409 elements, jsgraph()->Constant(1), value, etrue1, if_true1); | |
410 elements = etrue1 = | |
411 graph()->NewNode(common()->FinishRegion(), elements, etrue1); | |
412 | |
413 // Allocate JSArray for key/value pair | |
414 etrue1 = graph()->NewNode( | |
415 common()->BeginRegion(RegionObservability::kNotObservable), | |
416 etrue1); | |
417 Node* entry = etrue1 = graph()->NewNode( | |
418 simplified()->Allocate(NOT_TENURED), | |
419 jsgraph()->Constant(JSArray::kSize), etrue1, if_true1); | |
420 etrue1 = graph()->NewNode( | |
421 simplified()->StoreField(AccessBuilder::ForMap()), entry, | |
422 jsgraph()->Constant( | |
423 handle(native_context()->js_array_fast_elements_map_index())), | |
424 etrue1, if_true1); | |
425 etrue1 = graph()->NewNode( | |
426 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), | |
427 entry, jsgraph()->EmptyFixedArrayConstant(), etrue1, if_true1); | |
428 etrue1 = graph()->NewNode( | |
429 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), | |
430 entry, elements, etrue1, if_true1); | |
431 etrue1 = graph()->NewNode( | |
432 simplified()->StoreField( | |
433 AccessBuilder::ForJSArrayLength(elements_kind)), | |
434 entry, jsgraph()->Constant(2), etrue1, if_true1); | |
435 entry = etrue1 = | |
436 graph()->NewNode(common()->FinishRegion(), entry, etrue1); | |
437 vtrue1 = entry; | |
438 } else { | |
439 DCHECK(kind == IterationKind::kValues); | |
Benedikt Meurer
2016/11/08 08:30:00
Please use DCHECK_EQ here (and add operator<< over
caitp
2016/11/08 17:53:07
will do that for the next one
| |
440 vtrue1 = value; | |
441 } | |
442 } | |
443 } | |
444 | |
445 Node* vdone_false1; | |
446 Node* vfalse1; | |
447 Node* efalse1 = efalse0; | |
448 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); | |
449 { | |
450 // iterator.[[NextIndex]] >= array.length, stop iterating. | |
451 vdone_false1 = jsgraph()->TrueConstant(); | |
452 vfalse1 = jsgraph()->UndefinedConstant(); | |
453 efalse1 = graph()->NewNode( | |
454 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()), | |
455 iterator, vfalse1, efalse1, if_false1); | |
456 } | |
457 | |
458 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); | |
459 efalse0 = | |
460 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); | |
461 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
462 vtrue1, vfalse1, if_false0); | |
463 vdone_false0 = | |
464 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
465 vdone_true1, vdone_false1, if_false0); | |
466 } | |
467 | |
468 Node* vdone_true0; | |
469 Node* vtrue0; | |
470 Node* etrue0 = effect; | |
471 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); | |
472 { | |
473 // iterator.[[IteratedObject]] === undefined, the iterator is done. | |
474 vdone_true0 = jsgraph()->TrueConstant(); | |
475 vtrue0 = jsgraph()->UndefinedConstant(); | |
476 } | |
477 | |
478 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0); | |
479 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control); | |
480 Node* value = | |
481 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
482 vfalse0, vtrue0, control); | |
483 Node* done = | |
484 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
485 vdone_false0, vdone_true0, control); | |
486 | |
487 // Create IteratorResult object. | |
488 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), | |
489 value, done, context, effect); | |
490 ReplaceWithValue(node, value, effect, control); | |
491 return Replace(value); | |
492 } | |
493 | |
494 Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext( | |
495 Handle<Map> iterator_map, Node* node, IterationKind kind) { | |
496 Node* iterator = NodeProperties::GetValueInput(node, 1); | |
497 Node* effect = NodeProperties::GetEffectInput(node); | |
498 Node* control = NodeProperties::GetControlInput(node); | |
499 Node* context = NodeProperties::GetContextInput(node); | |
500 | |
501 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType( | |
502 iterator_map->instance_type()); | |
503 | |
504 Node* array = effect = graph()->NewNode( | |
505 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()), | |
506 iterator, effect, control); | |
507 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array, | |
508 jsgraph()->UndefinedConstant()); | |
509 Node* branch0 = | |
510 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); | |
511 | |
512 Node* vdone_false0; | |
513 Node* vfalse0; | |
514 Node* efalse0 = effect; | |
515 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); | |
516 { | |
517 // iterator.[[IteratedObject]] !== undefined, continue iterating. | |
518 Node* index = efalse0 = graph()->NewNode( | |
519 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex( | |
520 JS_TYPED_ARRAY_TYPE, elements_kind)), | |
521 iterator, efalse0, if_false0); | |
522 | |
523 // typedarray.[[ViewedArrayBuffer]] | |
524 Node* buffer = efalse0 = graph()->NewNode( | |
525 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), | |
526 array, efalse0, if_false0); | |
527 | |
528 Node* check1 = efalse0 = graph()->NewNode( | |
529 simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0); | |
530 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), | |
531 check1, if_false0); | |
532 | |
533 Node* vfalse1; | |
534 Node* efalse1 = efalse0; | |
535 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); | |
536 { | |
537 vfalse1 = efalse1 = graph()->NewNode( | |
538 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), | |
539 array, efalse1, if_false1); | |
540 } | |
541 | |
542 Node* vtrue1; | |
543 Node* etrue1 = efalse0; | |
544 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); | |
545 { | |
546 // TODO(caitp): If IsDetached(buffer) is true, throw a TypeError, per | |
547 // https://github.com/tc39/ecma262/issues/713 | |
548 vtrue1 = jsgraph()->Constant(0); | |
549 } | |
550 | |
551 if_false0 = graph()->NewNode(common()->Merge(2), if_false1, if_true1); | |
552 efalse0 = | |
553 graph()->NewNode(common()->EffectPhi(2), efalse1, etrue1, if_false0); | |
554 Node* length = | |
555 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
556 vfalse1, vtrue1, if_false0); | |
557 | |
558 Node* check2 = | |
559 graph()->NewNode(simplified()->NumberLessThan(), index, length); | |
560 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue), | |
561 check2, if_false0); | |
562 | |
563 Node* vdone_true2; | |
564 Node* vtrue2; | |
565 Node* etrue2 = efalse0; | |
566 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); | |
567 { | |
568 // iterator.[[NextIndex]] < array.length, continue iterating | |
569 vdone_true2 = jsgraph()->FalseConstant(); | |
570 if (kind == IterationKind::kKeys) { | |
571 vtrue2 = index; | |
572 } | |
573 | |
574 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, | |
575 jsgraph()->OneConstant()); | |
Benedikt Meurer
2016/11/08 08:30:00
Here you also need to do the NumberToUint32 trunca
caitp
2016/11/08 17:53:07
added truncation for both cases
| |
576 etrue2 = graph()->NewNode( | |
577 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex( | |
578 JS_TYPED_ARRAY_TYPE, elements_kind)), | |
579 iterator, next_index, etrue2, if_true2); | |
580 | |
581 if (kind != IterationKind::kKeys) { | |
582 Node* elements = etrue2 = graph()->NewNode( | |
583 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), | |
584 array, etrue2, if_true2); | |
585 Node* base_ptr = etrue2 = graph()->NewNode( | |
586 simplified()->LoadField( | |
587 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), | |
588 elements, etrue2, if_true2); | |
589 Node* external_ptr = etrue2 = graph()->NewNode( | |
590 simplified()->LoadField( | |
591 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), | |
592 elements, etrue2, if_true2); | |
593 | |
594 ExternalArrayType array_type = kExternalInt8Array; | |
595 switch (elements_kind) { | |
596 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
597 case TYPE##_ELEMENTS: \ | |
598 array_type = kExternal##Type##Array; | |
599 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
600 default: | |
601 UNREACHABLE(); | |
602 #undef TYPED_ARRAY_CASE | |
603 } | |
604 | |
605 Node* value = etrue2 = | |
606 graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer, | |
607 base_ptr, external_ptr, index, etrue2, if_true2); | |
608 | |
609 if (kind == IterationKind::kEntries) { | |
610 // Allocate elements for key/value pair | |
611 etrue2 = graph()->NewNode( | |
612 common()->BeginRegion(RegionObservability::kNotObservable), | |
613 etrue2); | |
614 Node* elements = etrue2 = graph()->NewNode( | |
615 simplified()->Allocate(NOT_TENURED), | |
616 jsgraph()->Constant(FixedArray::SizeFor(2)), etrue2, if_true2); | |
617 etrue2 = graph()->NewNode( | |
618 simplified()->StoreField(AccessBuilder::ForMap()), elements, | |
619 jsgraph()->Constant(isolate()->factory()->fixed_array_map()), | |
620 etrue1, if_true2); | |
621 etrue2 = graph()->NewNode( | |
622 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), | |
623 elements, jsgraph()->Constant(2)); | |
624 etrue2 = graph()->NewNode( | |
625 simplified()->StoreElement( | |
626 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)), | |
627 elements, jsgraph()->Constant(0), index, etrue2, if_true2); | |
628 etrue2 = graph()->NewNode( | |
629 simplified()->StoreElement( | |
630 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)), | |
631 elements, jsgraph()->Constant(1), value, etrue2, if_true2); | |
632 elements = etrue2 = | |
633 graph()->NewNode(common()->FinishRegion(), elements, etrue2); | |
634 | |
635 // Allocate JSArray for key/value pair | |
636 etrue2 = graph()->NewNode( | |
637 common()->BeginRegion(RegionObservability::kNotObservable), | |
638 etrue2); | |
639 Node* entry = etrue2 = graph()->NewNode( | |
640 simplified()->Allocate(NOT_TENURED), | |
641 jsgraph()->Constant(JSArray::kSize), etrue2, if_true2); | |
642 etrue2 = graph()->NewNode( | |
643 simplified()->StoreField(AccessBuilder::ForMap()), entry, | |
644 jsgraph()->Constant( | |
645 handle(native_context()->js_array_fast_elements_map_index())), | |
646 etrue2, if_true2); | |
647 etrue2 = graph()->NewNode( | |
648 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), | |
649 entry, jsgraph()->EmptyFixedArrayConstant(), etrue2, if_true2); | |
650 etrue2 = graph()->NewNode( | |
651 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), | |
652 entry, elements, etrue2, if_true2); | |
653 etrue2 = graph()->NewNode( | |
654 simplified()->StoreField( | |
655 AccessBuilder::ForJSArrayLength(elements_kind)), | |
656 entry, jsgraph()->Constant(2), etrue2, if_true2); | |
657 entry = etrue1 = | |
658 graph()->NewNode(common()->FinishRegion(), entry, etrue2); | |
659 vtrue2 = entry; | |
660 } else { | |
661 DCHECK(kind == IterationKind::kValues); | |
662 vtrue2 = value; | |
663 } | |
664 } | |
665 } | |
666 | |
667 Node* vdone_false2; | |
668 Node* vfalse2; | |
669 Node* efalse2 = efalse0; | |
670 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); | |
671 { | |
672 // iterator.[[NextIndex]] >= array.length, stop iterating. | |
673 vdone_false2 = jsgraph()->TrueConstant(); | |
674 vfalse2 = jsgraph()->UndefinedConstant(); | |
675 efalse2 = graph()->NewNode( | |
676 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()), | |
677 iterator, vfalse2, efalse2, if_false2); | |
678 } | |
679 | |
680 if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); | |
681 efalse0 = | |
682 graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0); | |
683 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
684 vtrue2, vfalse2, if_false0); | |
685 vdone_false0 = | |
686 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
687 vdone_true2, vdone_false2, if_false0); | |
688 } | |
689 | |
690 Node* vdone_true0; | |
691 Node* vtrue0; | |
692 Node* etrue0 = effect; | |
693 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); | |
694 { | |
695 // iterator.[[IteratedObject]] === undefined, the iterator is done. | |
696 vdone_true0 = jsgraph()->TrueConstant(); | |
697 vtrue0 = jsgraph()->UndefinedConstant(); | |
698 } | |
699 | |
700 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0); | |
701 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control); | |
702 Node* value = | |
703 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
704 vfalse0, vtrue0, control); | |
705 Node* done = | |
706 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
707 vdone_false0, vdone_true0, control); | |
708 | |
709 // Create IteratorResult object. | |
710 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), | |
711 value, done, context, effect); | |
712 ReplaceWithValue(node, value, effect, control); | |
713 return Replace(value); | |
714 } | |
715 | |
716 Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { | |
717 Handle<Map> receiver_map; | |
718 if (GetMapWitness(node).ToHandle(&receiver_map)) { | |
719 switch (receiver_map->instance_type()) { | |
720 case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE: | |
721 return ReduceTypedArrayIteratorNext(receiver_map, node, | |
722 IterationKind::kKeys); | |
723 | |
724 case JS_FAST_ARRAY_KEY_ITERATOR_TYPE: | |
725 return ReduceFastArrayIteratorNext(receiver_map, node, | |
726 IterationKind::kKeys); | |
727 | |
728 case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
729 case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
730 case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
731 case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
732 case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
733 case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
734 case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
735 case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
736 case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
737 return ReduceTypedArrayIteratorNext(receiver_map, node, | |
738 IterationKind::kEntries); | |
739 | |
740 case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
741 case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
742 case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
743 case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
744 case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
745 case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: | |
746 return ReduceFastArrayIteratorNext(receiver_map, node, | |
747 IterationKind::kEntries); | |
748 | |
749 case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE: | |
750 case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE: | |
751 case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE: | |
752 case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE: | |
753 case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE: | |
754 case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE: | |
755 case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE: | |
756 case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE: | |
757 case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE: | |
758 return ReduceTypedArrayIteratorNext(receiver_map, node, | |
759 IterationKind::kValues); | |
760 | |
761 case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE: | |
762 case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE: | |
763 case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE: | |
764 case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE: | |
765 case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: | |
766 case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: | |
767 return ReduceFastArrayIteratorNext(receiver_map, node, | |
768 IterationKind::kValues); | |
769 | |
770 default: | |
771 // Slow array iterators are not reduced | |
772 return NoChange(); | |
773 } | |
774 } | |
775 return NoChange(); | |
776 } | |
777 | |
180 // ES6 section 22.1.3.17 Array.prototype.pop ( ) | 778 // ES6 section 22.1.3.17 Array.prototype.pop ( ) |
181 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { | 779 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { |
182 Handle<Map> receiver_map; | 780 Handle<Map> receiver_map; |
183 Node* receiver = NodeProperties::GetValueInput(node, 1); | 781 Node* receiver = NodeProperties::GetValueInput(node, 1); |
184 Node* effect = NodeProperties::GetEffectInput(node); | 782 Node* effect = NodeProperties::GetEffectInput(node); |
185 Node* control = NodeProperties::GetControlInput(node); | 783 Node* control = NodeProperties::GetControlInput(node); |
186 // TODO(turbofan): Extend this to also handle fast (holey) double elements | 784 // TODO(turbofan): Extend this to also handle fast (holey) double elements |
187 // once we got the hole NaN mess sorted out in TurboFan/V8. | 785 // once we got the hole NaN mess sorted out in TurboFan/V8. |
188 if (GetMapWitness(node).ToHandle(&receiver_map) && | 786 if (GetMapWitness(node).ToHandle(&receiver_map) && |
189 CanInlineArrayResizeOperation(receiver_map) && | 787 CanInlineArrayResizeOperation(receiver_map) && |
(...skipping 1063 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1253 return NoChange(); | 1851 return NoChange(); |
1254 } | 1852 } |
1255 | 1853 |
1256 Reduction JSBuiltinReducer::Reduce(Node* node) { | 1854 Reduction JSBuiltinReducer::Reduce(Node* node) { |
1257 Reduction reduction = NoChange(); | 1855 Reduction reduction = NoChange(); |
1258 JSCallReduction r(node); | 1856 JSCallReduction r(node); |
1259 | 1857 |
1260 // Dispatch according to the BuiltinFunctionId if present. | 1858 // Dispatch according to the BuiltinFunctionId if present. |
1261 if (!r.HasBuiltinFunctionId()) return NoChange(); | 1859 if (!r.HasBuiltinFunctionId()) return NoChange(); |
1262 switch (r.GetBuiltinFunctionId()) { | 1860 switch (r.GetBuiltinFunctionId()) { |
1861 case kArrayEntries: | |
1862 return ReduceArrayIterator(node, IterationKind::kEntries); | |
1863 case kArrayKeys: | |
1864 return ReduceArrayIterator(node, IterationKind::kKeys); | |
1865 case kArrayValues: | |
1866 return ReduceArrayIterator(node, IterationKind::kValues); | |
1867 case kArrayIteratorNext: | |
1868 return ReduceArrayIteratorNext(node); | |
1263 case kArrayPop: | 1869 case kArrayPop: |
1264 return ReduceArrayPop(node); | 1870 return ReduceArrayPop(node); |
1265 case kArrayPush: | 1871 case kArrayPush: |
1266 return ReduceArrayPush(node); | 1872 return ReduceArrayPush(node); |
1267 case kDateGetTime: | 1873 case kDateGetTime: |
1268 return ReduceDateGetTime(node); | 1874 return ReduceDateGetTime(node); |
1269 case kGlobalIsFinite: | 1875 case kGlobalIsFinite: |
1270 reduction = ReduceGlobalIsFinite(node); | 1876 reduction = ReduceGlobalIsFinite(node); |
1271 break; | 1877 break; |
1272 case kGlobalIsNaN: | 1878 case kGlobalIsNaN: |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1456 return jsgraph()->simplified(); | 2062 return jsgraph()->simplified(); |
1457 } | 2063 } |
1458 | 2064 |
1459 JSOperatorBuilder* JSBuiltinReducer::javascript() const { | 2065 JSOperatorBuilder* JSBuiltinReducer::javascript() const { |
1460 return jsgraph()->javascript(); | 2066 return jsgraph()->javascript(); |
1461 } | 2067 } |
1462 | 2068 |
1463 } // namespace compiler | 2069 } // namespace compiler |
1464 } // namespace internal | 2070 } // namespace internal |
1465 } // namespace v8 | 2071 } // namespace v8 |
OLD | NEW |