Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(641)

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 2232483002: [turbofan] Add support for keyed access to strings. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 27 matching lines...) Expand all
38 return true; 38 return true;
39 } 39 }
40 40
41 bool HasOnlyNumberMaps(MapList const& maps) { 41 bool HasOnlyNumberMaps(MapList const& maps) {
42 for (auto map : maps) { 42 for (auto map : maps) {
43 if (map->instance_type() != HEAP_NUMBER_TYPE) return false; 43 if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
44 } 44 }
45 return true; 45 return true;
46 } 46 }
47 47
48 bool HasOnlyStringMaps(MapList const& maps) { 48 template <typename T>
49 bool HasOnlyStringMaps(T const& maps) {
49 for (auto map : maps) { 50 for (auto map : maps) {
50 if (!map->IsStringMap()) return false; 51 if (!map->IsStringMap()) return false;
51 } 52 }
52 return true; 53 return true;
53 } 54 }
54 55
55 } // namespace 56 } // namespace
56 57
57 JSNativeContextSpecialization::JSNativeContextSpecialization( 58 JSNativeContextSpecialization::JSNativeContextSpecialization(
58 Editor* editor, JSGraph* jsgraph, Flags flags, 59 Editor* editor, JSGraph* jsgraph, Flags flags,
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || 420 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
420 node->opcode() == IrOpcode::kJSStoreProperty); 421 node->opcode() == IrOpcode::kJSStoreProperty);
421 Node* receiver = NodeProperties::GetValueInput(node, 0); 422 Node* receiver = NodeProperties::GetValueInput(node, 0);
422 Node* effect = NodeProperties::GetEffectInput(node); 423 Node* effect = NodeProperties::GetEffectInput(node);
423 Node* control = NodeProperties::GetControlInput(node); 424 Node* control = NodeProperties::GetControlInput(node);
424 Node* frame_state = NodeProperties::FindFrameStateBefore(node); 425 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
425 426
426 // Not much we can do if deoptimization support is disabled. 427 // Not much we can do if deoptimization support is disabled.
427 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 428 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
428 429
429 // Retrieve the native context from the given {node}. 430 // Check for keyed access to strings.
430 Handle<Context> native_context; 431 if (HasOnlyStringMaps(receiver_maps)) {
431 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); 432 // Strings are immutable in JavaScript.
432 433 if (access_mode == AccessMode::kStore) return NoChange();
433 // Compute element access infos for the receiver maps. 434
434 AccessInfoFactory access_info_factory(dependencies(), native_context, 435 // Ensure that the {receiver} is actually a String.
435 graph()->zone()); 436 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver,
436 ZoneVector<ElementAccessInfo> access_infos(zone()); 437 effect, control);
437 if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode, 438
438 &access_infos)) { 439 // Determine the {receiver} length.
439 return NoChange(); 440 Node* length = effect = graph()->NewNode(
440 } 441 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
441 442 effect, control);
442 // Nothing to do if we have no non-deprecated maps. 443
443 if (access_infos.empty()) { 444 // Ensure that {index} is less than {receiver} length.
444 return ReduceSoftDeoptimize( 445 index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
445 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); 446 length, effect, control);
446 } 447
447 448 // Load the character from the {receiver}.
448 // Ensure that {receiver} is a heap object. 449 value = graph()->NewNode(simplified()->StringCharCodeAt(), receiver, index,
449 effect = BuildCheckTaggedPointer(receiver, effect, control); 450 control);
450 451
451 // Check for the monomorphic case. 452 // Return it as a single character string.
452 if (access_infos.size() == 1) { 453 value = graph()->NewNode(simplified()->StringFromCharCode(), value);
453 ElementAccessInfo access_info = access_infos.front(); 454 } else {
454 455 // Retrieve the native context from the given {node}.
455 // Perform possible elements kind transitions. 456 Handle<Context> native_context;
456 for (auto transition : access_info.transitions()) { 457 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange();
457 Handle<Map> const transition_source = transition.first; 458
458 Handle<Map> const transition_target = transition.second; 459 // Compute element access infos for the receiver maps.
459 effect = graph()->NewNode( 460 AccessInfoFactory access_info_factory(dependencies(), native_context,
460 simplified()->TransitionElementsKind( 461 graph()->zone());
461 IsSimpleMapChangeTransition(transition_source->elements_kind(), 462 ZoneVector<ElementAccessInfo> access_infos(zone());
462 transition_target->elements_kind()) 463 if (!access_info_factory.ComputeElementAccessInfos(
463 ? ElementsTransition::kFastTransition 464 receiver_maps, access_mode, &access_infos)) {
464 : ElementsTransition::kSlowTransition), 465 return NoChange();
465 receiver, jsgraph()->HeapConstant(transition_source),
466 jsgraph()->HeapConstant(transition_target), effect, control);
467 } 466 }
468 467
469 // TODO(turbofan): The effect/control linearization will not find a 468 // Nothing to do if we have no non-deprecated maps.
470 // FrameState after the StoreField or Call that is generated for the 469 if (access_infos.empty()) {
471 // elements kind transition above. This is because those operators 470 return ReduceSoftDeoptimize(
472 // don't have the kNoWrite flag on it, even though they are not 471 node,
473 // observable by JavaScript. 472 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
474 effect = 473 }
475 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); 474
476 475 // Ensure that {receiver} is a heap object.
477 // Perform map check on the {receiver}. 476 effect = BuildCheckTaggedPointer(receiver, effect, control);
478 effect = 477
479 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); 478 // Check for the monomorphic case.
480 479 if (access_infos.size() == 1) {
481 // Access the actual element. 480 ElementAccessInfo access_info = access_infos.front();
482 ValueEffectControl continuation = BuildElementAccess(
483 receiver, index, value, effect, control, native_context, access_info,
484 access_mode, store_mode);
485 value = continuation.value();
486 effect = continuation.effect();
487 control = continuation.control();
488 } else {
489 // The final states for every polymorphic branch. We join them with
490 // Merge+Phi+EffectPhi at the bottom.
491 ZoneVector<Node*> values(zone());
492 ZoneVector<Node*> effects(zone());
493 ZoneVector<Node*> controls(zone());
494
495 // Generate code for the various different element access patterns.
496 Node* fallthrough_control = control;
497 for (size_t j = 0; j < access_infos.size(); ++j) {
498 ElementAccessInfo const& access_info = access_infos[j];
499 Node* this_receiver = receiver;
500 Node* this_value = value;
501 Node* this_index = index;
502 Node* this_effect = effect;
503 Node* this_control = fallthrough_control;
504 481
505 // Perform possible elements kind transitions. 482 // Perform possible elements kind transitions.
506 for (auto transition : access_info.transitions()) { 483 for (auto transition : access_info.transitions()) {
507 Handle<Map> const transition_source = transition.first; 484 Handle<Map> const transition_source = transition.first;
508 Handle<Map> const transition_target = transition.second; 485 Handle<Map> const transition_target = transition.second;
509 this_effect = graph()->NewNode( 486 effect = graph()->NewNode(
510 simplified()->TransitionElementsKind( 487 simplified()->TransitionElementsKind(
511 IsSimpleMapChangeTransition(transition_source->elements_kind(), 488 IsSimpleMapChangeTransition(transition_source->elements_kind(),
512 transition_target->elements_kind()) 489 transition_target->elements_kind())
513 ? ElementsTransition::kFastTransition 490 ? ElementsTransition::kFastTransition
514 : ElementsTransition::kSlowTransition), 491 : ElementsTransition::kSlowTransition),
515 receiver, jsgraph()->HeapConstant(transition_source), 492 receiver, jsgraph()->HeapConstant(transition_source),
516 jsgraph()->HeapConstant(transition_target), this_effect, 493 jsgraph()->HeapConstant(transition_target), effect, control);
517 this_control);
518 } 494 }
519 495
520 // Load the {receiver} map. 496 // TODO(turbofan): The effect/control linearization will not find a
521 Node* receiver_map = this_effect = 497 // FrameState after the StoreField or Call that is generated for the
522 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 498 // elements kind transition above. This is because those operators
523 receiver, this_effect, this_control); 499 // don't have the kNoWrite flag on it, even though they are not
524 500 // observable by JavaScript.
525 // Perform map check(s) on {receiver}. 501 effect = graph()->NewNode(common()->Checkpoint(), frame_state, effect,
526 MapList const& receiver_maps = access_info.receiver_maps(); 502 control);
527 { 503
528 ZoneVector<Node*> this_controls(zone()); 504 // Perform map check on the {receiver}.
529 ZoneVector<Node*> this_effects(zone()); 505 effect = BuildCheckMaps(receiver, effect, control,
530 size_t num_classes = receiver_maps.size(); 506 access_info.receiver_maps());
531 for (Handle<Map> map : receiver_maps) { 507
532 DCHECK_LT(0u, num_classes); 508 // Access the actual element.
533 Node* check = 509 ValueEffectControl continuation = BuildElementAccess(
534 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map, 510 receiver, index, value, effect, control, native_context, access_info,
535 jsgraph()->Constant(map)); 511 access_mode, store_mode);
536 if (--num_classes == 0 && j == access_infos.size() - 1) { 512 value = continuation.value();
537 // Last map check on the fallthrough control path, do a conditional 513 effect = continuation.effect();
538 // eager deoptimization exit here. 514 control = continuation.control();
539 // TODO(turbofan): This is ugly as hell! We should probably 515 } else {
540 // introduce macro-ish operators for property access that 516 // The final states for every polymorphic branch. We join them with
541 // encapsulate this whole mess. 517 // Merge+Phi+EffectPhi at the bottom.
542 check = graph()->NewNode(simplified()->CheckIf(), check, 518 ZoneVector<Node*> values(zone());
543 this_effect, this_control); 519 ZoneVector<Node*> effects(zone());
544 this_controls.push_back(this_control); 520 ZoneVector<Node*> controls(zone());
545 this_effects.push_back(check); 521
546 fallthrough_control = nullptr; 522 // Generate code for the various different element access patterns.
523 Node* fallthrough_control = control;
524 for (size_t j = 0; j < access_infos.size(); ++j) {
525 ElementAccessInfo const& access_info = access_infos[j];
526 Node* this_receiver = receiver;
527 Node* this_value = value;
528 Node* this_index = index;
529 Node* this_effect = effect;
530 Node* this_control = fallthrough_control;
531
532 // Perform possible elements kind transitions.
533 for (auto transition : access_info.transitions()) {
534 Handle<Map> const transition_source = transition.first;
535 Handle<Map> const transition_target = transition.second;
536 this_effect = graph()->NewNode(
537 simplified()->TransitionElementsKind(
538 IsSimpleMapChangeTransition(
539 transition_source->elements_kind(),
540 transition_target->elements_kind())
541 ? ElementsTransition::kFastTransition
542 : ElementsTransition::kSlowTransition),
543 receiver, jsgraph()->HeapConstant(transition_source),
544 jsgraph()->HeapConstant(transition_target), this_effect,
545 this_control);
546 }
547
548 // Load the {receiver} map.
549 Node* receiver_map = this_effect =
550 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
551 receiver, this_effect, this_control);
552
553 // Perform map check(s) on {receiver}.
554 MapList const& receiver_maps = access_info.receiver_maps();
555 {
556 ZoneVector<Node*> this_controls(zone());
557 ZoneVector<Node*> this_effects(zone());
558 size_t num_classes = receiver_maps.size();
559 for (Handle<Map> map : receiver_maps) {
560 DCHECK_LT(0u, num_classes);
561 Node* check =
562 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
563 jsgraph()->Constant(map));
564 if (--num_classes == 0 && j == access_infos.size() - 1) {
565 // Last map check on the fallthrough control path, do a
566 // conditional eager deoptimization exit here.
567 // TODO(turbofan): This is ugly as hell! We should probably
568 // introduce macro-ish operators for property access that
569 // encapsulate this whole mess.
570 check = graph()->NewNode(simplified()->CheckIf(), check,
571 this_effect, this_control);
572 this_controls.push_back(this_control);
573 this_effects.push_back(check);
574 fallthrough_control = nullptr;
575 } else {
576 Node* branch = graph()->NewNode(common()->Branch(), check,
577 fallthrough_control);
578 this_controls.push_back(
579 graph()->NewNode(common()->IfTrue(), branch));
580 this_effects.push_back(effect);
581 fallthrough_control =
582 graph()->NewNode(common()->IfFalse(), branch);
583 }
584 }
585
586 // Create single chokepoint for the control.
587 int const this_control_count = static_cast<int>(this_controls.size());
588 if (this_control_count == 1) {
589 this_control = this_controls.front();
590 this_effect = this_effects.front();
547 } else { 591 } else {
548 Node* branch = graph()->NewNode(common()->Branch(), check, 592 this_control =
549 fallthrough_control); 593 graph()->NewNode(common()->Merge(this_control_count),
550 this_controls.push_back( 594 this_control_count, &this_controls.front());
551 graph()->NewNode(common()->IfTrue(), branch)); 595 this_effects.push_back(this_control);
552 this_effects.push_back(effect); 596 this_effect =
553 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 597 graph()->NewNode(common()->EffectPhi(this_control_count),
598 this_control_count + 1, &this_effects.front());
599
600 // TODO(turbofan): The effect/control linearization will not find a
601 // FrameState after the EffectPhi that is generated above.
602 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
603 this_effect, this_control);
554 } 604 }
555 } 605 }
556 606
557 // Create single chokepoint for the control. 607 // Access the actual element.
558 int const this_control_count = static_cast<int>(this_controls.size()); 608 ValueEffectControl continuation = BuildElementAccess(
559 if (this_control_count == 1) { 609 this_receiver, this_index, this_value, this_effect, this_control,
560 this_control = this_controls.front(); 610 native_context, access_info, access_mode, store_mode);
561 this_effect = this_effects.front(); 611 values.push_back(continuation.value());
562 } else { 612 effects.push_back(continuation.effect());
563 this_control = 613 controls.push_back(continuation.control());
564 graph()->NewNode(common()->Merge(this_control_count),
565 this_control_count, &this_controls.front());
566 this_effects.push_back(this_control);
567 this_effect =
568 graph()->NewNode(common()->EffectPhi(this_control_count),
569 this_control_count + 1, &this_effects.front());
570
571 // TODO(turbofan): The effect/control linearization will not find a
572 // FrameState after the EffectPhi that is generated above.
573 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
574 this_effect, this_control);
575 }
576 } 614 }
577 615
578 // Access the actual element. 616 DCHECK_NULL(fallthrough_control);
579 ValueEffectControl continuation = BuildElementAccess( 617
580 this_receiver, this_index, this_value, this_effect, this_control, 618 // Generate the final merge point for all (polymorphic) branches.
581 native_context, access_info, access_mode, store_mode); 619 int const control_count = static_cast<int>(controls.size());
582 values.push_back(continuation.value()); 620 if (control_count == 0) {
583 effects.push_back(continuation.effect()); 621 value = effect = control = jsgraph()->Dead();
584 controls.push_back(continuation.control()); 622 } else if (control_count == 1) {
585 } 623 value = values.front();
586 624 effect = effects.front();
587 DCHECK_NULL(fallthrough_control); 625 control = controls.front();
588 626 } else {
589 // Generate the final merge point for all (polymorphic) branches. 627 control = graph()->NewNode(common()->Merge(control_count),
590 int const control_count = static_cast<int>(controls.size()); 628 control_count, &controls.front());
591 if (control_count == 0) { 629 values.push_back(control);
592 value = effect = control = jsgraph()->Dead(); 630 value = graph()->NewNode(
593 } else if (control_count == 1) { 631 common()->Phi(MachineRepresentation::kTagged, control_count),
594 value = values.front(); 632 control_count + 1, &values.front());
595 effect = effects.front(); 633 effects.push_back(control);
596 control = controls.front(); 634 effect = graph()->NewNode(common()->EffectPhi(control_count),
597 } else { 635 control_count + 1, &effects.front());
598 control = graph()->NewNode(common()->Merge(control_count), control_count, 636 }
599 &controls.front());
600 values.push_back(control);
601 value = graph()->NewNode(
602 common()->Phi(MachineRepresentation::kTagged, control_count),
603 control_count + 1, &values.front());
604 effects.push_back(control);
605 effect = graph()->NewNode(common()->EffectPhi(control_count),
606 control_count + 1, &effects.front());
607 } 637 }
608 } 638 }
609 639
610 ReplaceWithValue(node, value, effect, control); 640 ReplaceWithValue(node, value, effect, control);
611 return Replace(value); 641 return Replace(value);
612 } 642 }
613 643
614 template <typename KeyedICNexus> 644 template <typename KeyedICNexus>
615 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( 645 Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
616 Node* node, Node* index, Node* value, KeyedICNexus const& nexus, 646 Node* node, Node* index, Node* value, KeyedICNexus const& nexus,
(...skipping 800 matching lines...) Expand 10 before | Expand all | Expand 10 after
1417 } 1447 }
1418 1448
1419 1449
1420 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1450 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1421 return jsgraph()->simplified(); 1451 return jsgraph()->simplified();
1422 } 1452 }
1423 1453
1424 } // namespace compiler 1454 } // namespace compiler
1425 } // namespace internal 1455 } // namespace internal
1426 } // namespace v8 1456 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698