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

Side by Side Diff: src/hydrogen.cc

Issue 11365174: A change in the way we place TransitionElementKinds in the tree. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Finally addressed all comments from first review. Created 8 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 691
692 692
693 HGraph::HGraph(CompilationInfo* info) 693 HGraph::HGraph(CompilationInfo* info)
694 : isolate_(info->isolate()), 694 : isolate_(info->isolate()),
695 next_block_id_(0), 695 next_block_id_(0),
696 entry_block_(NULL), 696 entry_block_(NULL),
697 blocks_(8, info->zone()), 697 blocks_(8, info->zone()),
698 values_(16, info->zone()), 698 values_(16, info->zone()),
699 phi_list_(NULL), 699 phi_list_(NULL),
700 uint32_instructions_(NULL), 700 uint32_instructions_(NULL),
701 marked_transitions_(10, info->zone()),
701 info_(info), 702 info_(info),
702 zone_(info->zone()), 703 zone_(info->zone()),
703 is_recursive_(false), 704 is_recursive_(false),
704 use_optimistic_licm_(false), 705 use_optimistic_licm_(false),
705 type_change_checksum_(0) { 706 type_change_checksum_(0) {
706 start_environment_ = 707 start_environment_ =
707 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); 708 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
708 start_environment_->set_ast_id(BailoutId::FunctionEntry()); 709 start_environment_->set_ast_id(BailoutId::FunctionEntry());
709 entry_block_ = CreateBasicBlock(); 710 entry_block_ = CreateBasicBlock();
710 entry_block_->SetInitialEnvironment(start_environment_); 711 entry_block_->SetInitialEnvironment(start_environment_);
(...skipping 1731 matching lines...) Expand 10 before | Expand all | Expand 10 after
2442 ZoneList<HValue*> worklist(block->phis()->length(), zone()); 2443 ZoneList<HValue*> worklist(block->phis()->length(), zone());
2443 for (int j = 0; j < block->phis()->length(); ++j) { 2444 for (int j = 0; j < block->phis()->length(); ++j) {
2444 worklist.Add(block->phis()->at(j), zone()); 2445 worklist.Add(block->phis()->at(j), zone());
2445 } 2446 }
2446 InferTypes(&worklist); 2447 InferTypes(&worklist);
2447 } 2448 }
2448 } 2449 }
2449 } 2450 }
2450 2451
2451 2452
2453 class TransitionElementsBookmark BASE_EMBEDDED {
2454 public:
2455 TransitionElementsBookmark(HTransitionElementsKind* transition,
2456 Handle<Map> map_from,
2457 Handle<Map> map_to,
2458 Isolate* isolate);
2459 ElementsKind elementskind_from() const { return from_->elements_kind(); }
2460 ElementsKind elementskind_to() const { return to_->elements_kind(); }
2461 Handle<Map> from() const { return from_; }
2462 Handle<Map>* from_pointer() { return &from_; }
2463 Handle<Map> to() const { return to_; }
2464 Handle<Map>* to_pointer() { return &to_; }
2465 Handle<Map> family() const { return family_; }
2466 Handle<Map>* family_pointer() { return &family_; }
2467 Handle<Map> pessimistic_holey() const { return pessimistic_holey_; }
2468 Handle<Map>* pessimistic_holey_pointer() { return &pessimistic_holey_; }
2469 HTransitionElementsKind* transition_instruction() const {
2470 return transition_; }
2471
2472 bool Equals(const TransitionElementsBookmark& other) const {
2473 return *from() == *(other.from()) &&
2474 *to() == *(other.to()) &&
2475 *family() == *(other.family());
2476 }
2477
2478 private:
2479 HTransitionElementsKind* transition_;
2480 Handle<Map> from_;
2481 Handle<Map> to_;
2482 Handle<Map> family_;
2483 Handle<Map> pessimistic_holey_;
2484 };
2485
2486
2487 typedef ZoneList<HInstruction*> TransitionInputList;
2488
2489 class MarkedTransitionElementsGroup: public ZoneObject {
2490 public:
2491 MarkedTransitionElementsGroup(HInstruction* load_or_store,
2492 HCheckNonSmi* check_non_smi,
2493 HCheckMaps* check_maps, Zone* zone)
2494 : zone_(zone),
2495 load_or_store_(load_or_store),
2496 smi_check_(check_non_smi),
2497 map_check_(check_maps),
2498 hoistable_(true),
2499 bookmarks_(new(zone) ZoneList<TransitionElementsBookmark>(10, zone)),
2500 transition_inputs_(new(zone) TransitionInputList(10, zone)) {
2501 ASSERT((load_or_store->IsLoadKeyed() &&
2502 !HLoadKeyed::cast(load_or_store)->Initialized()) ||
2503 (load_or_store->IsStoreKeyed() &&
2504 !HStoreKeyed::cast(load_or_store)->Initialized()));
2505 score_[0] = score_[1] = score_[2] = 0;
2506 }
2507
2508 HInstruction* load_or_store() const { return load_or_store_; }
2509 HCheckMaps* map_check() { return map_check_; }
2510 HCheckNonSmi* smi_check() { return smi_check_; }
2511
2512 void AddBookmarks(const ZoneList<TransitionElementsBookmark>& records);
2513
2514 int bookmarks() const { return bookmarks_->length(); }
2515 const TransitionElementsBookmark& bookmark(int index) const {
2516 return (*bookmarks_)[index];
2517 }
2518
2519 TransitionElementsBookmark* bookmark_pointer(int index) {
2520 return &(bookmarks_->at(index));
2521 }
2522
2523 void PrintTo(StringStream* stream) const;
2524 void PrintToStd() const;
2525
2526 // This must be called before querying transition input values
2527 void ComputeTransitionInputValues(int maximumGraphValueID);
2528
2529 int transition_inputs() const { return transition_inputs_->length(); }
2530 HInstruction* transition_input(int index) const {
2531 return (*transition_inputs_)[index]; }
2532
2533 enum ScoreType {
2534 SCORE_POSITIVE,
2535 SCORE_NEGATIVE,
2536 SCORE_NEUTRAL,
2537 SCORE_TYPE_COUNT
2538 };
2539
2540 ScoreType scoretype_from_loopdelta(int loopDelta) const {
2541 if (loopDelta > 0) return SCORE_POSITIVE;
2542 else if (loopDelta < 0) return SCORE_NEGATIVE;
2543 return SCORE_NEUTRAL;
2544 }
2545
2546 int score(ScoreType type) const { return score_[type]; }
2547 void increment_score(ScoreType type, int score) { score_[type] += score; }
2548
2549 bool hoistable() const { return hoistable_; }
2550 void set_hoistable(bool value) { hoistable_ = value; }
2551
2552 void set_most_general_map(Map* new_most_general_map) {
2553 computed_most_general_map_ = new_most_general_map; }
2554 Map* most_general_map() const { return computed_most_general_map_; }
2555
2556 void Finalize() {
2557 ASSERT(most_general_map() != NULL);
2558 ElementsKind elements_kind = most_general_map()->elements_kind();
2559 // We have to cast to array instruction very carefully here.
2560 // A simple reinterpret cast will produce errors at runtime.
2561 ArrayInstructionInterface* array_instruction = NULL;
2562 if (load_or_store()->IsLoadKeyed()) {
2563 array_instruction = static_cast<ArrayInstructionInterface*>(
2564 HLoadKeyed::cast(load_or_store()));
2565 } else if (load_or_store()->IsStoreKeyed()) {
2566 array_instruction = static_cast<ArrayInstructionInterface*>(
2567 HStoreKeyed::cast(load_or_store()));
2568 }
2569 ASSERT(array_instruction != NULL);
2570 array_instruction->PerformDeferredInitialization(elements_kind);
2571 }
2572
2573 Zone* zone() const { return zone_; }
2574
2575 Map* map_family() const {
2576 Map* family = NULL;
2577 if (bookmarks()) {
2578 family = *(bookmark(0).family().location());
2579 }
2580
2581 #ifdef DEBUG
2582 for (int i = 1; i < bookmarks(); i++) {
2583 const TransitionElementsBookmark& tr = bookmark(i);
2584 ASSERT(*(tr.family().location()) == family);
2585 }
2586 #endif
2587 return family;
2588 }
2589
2590 private:
2591 Zone* zone_;
2592 HInstruction* load_or_store_;
2593 HCheckNonSmi* smi_check_;
2594 HCheckMaps* map_check_;
2595 Map* computed_most_general_map_;
2596 int score_[SCORE_TYPE_COUNT];
2597 bool hoistable_;
2598 ZoneList<TransitionElementsBookmark>* bookmarks_;
2599 TransitionInputList* transition_inputs_;
2600 };
2601
2602
2603 typedef ZoneList<MarkedTransitionElementsGroup*>
2604 MarkedTransitionElementsGroupList;
2605 typedef EnumSet<ElementsKind> ElementsKindSet;
2606
2607
2608 class MostGeneralMapAndFamily {
2609 public:
2610 MostGeneralMapAndFamily() : most_general_map_(NULL), family_(NULL) { }
2611 MostGeneralMapAndFamily(const MostGeneralMapAndFamily& h)
2612 : most_general_map_(h.most_general_map()),
2613 family_(h.family()) {
2614 }
2615
2616 Map* most_general_map() const { return most_general_map_; }
2617 Map* family() const { return family_; }
2618
2619 void Update(Map* new_most_general_map, Map* new_family) {
2620 if (is_valid()) {
2621 // family shouldn't be changed
2622 ASSERT(new_family == family_);
2623 most_general_map_ = new_most_general_map;
2624 } else {
2625 most_general_map_ = new_most_general_map;
2626 family_ = new_family;
2627 }
2628 }
2629
2630 void invalidate() {
2631 most_general_map_ = NULL;
2632 family_ = NULL;
2633 }
2634
2635 bool is_valid() const {
2636 return most_general_map_ != NULL && family_ != NULL; }
2637 bool Equals(const MostGeneralMapAndFamily& h) const {
2638 if (!is_valid() || !h.is_valid()) {
2639 return is_valid() == h.is_valid();
2640 }
2641 return most_general_map_ == h.most_general_map() && family_ == h.family();
2642 }
2643
2644 MostGeneralMapAndFamily& operator=(const MostGeneralMapAndFamily& h) {
2645 if (this != &h) {
2646 most_general_map_ = h.most_general_map();
2647 family_ = h.family();
2648 }
2649 return *this;
2650 }
2651
2652 private:
2653 Map* most_general_map_;
2654 Map* family_;
2655 };
2656
2657
2658 class TransitionInputDictionaryValue: public ZoneObject {
2659 public:
2660 TransitionInputDictionaryValue(HInstruction* transition_input, Zone* zone) :
2661 transition_input_(transition_input),
2662 groups_(new(zone) MarkedTransitionElementsGroupList(10, zone)),
2663 zone_(zone),
2664 last_in_chain_(NULL) {
2665 }
2666
2667 void AddGroup(MarkedTransitionElementsGroup* group) {
2668 if (group->transition_inputs() == 1) {
2669 // put at the front of the list. Processing single element
2670 // transitions first makes score calculation easier.
2671 groups_->InsertAt(0, group, zone_);
2672 } else {
2673 groups_->Add(group, zone_);
2674 }
2675 }
2676
2677 const MostGeneralMapAndFamily& most_general() { return most_general_; }
2678 void set_most_general(const MostGeneralMapAndFamily& m) { most_general_ = m; }
2679
2680 int groups() const { return groups_->length(); }
2681 MarkedTransitionElementsGroup* group(int i) { return (*groups_)[i]; }
2682 Zone* zone() { return zone_; }
2683
2684 void ComputeMostGeneralMapAndFamily(MostGeneralMapAndFamily* most_general,
2685 MarkedTransitionElementsGroup** other_family_group);
2686
2687 // For instruction emission
2688 bool RequiresTransitionElementsKind(ElementsKind from) const {
2689 return !from_elements_.Contains(from);
2690 }
2691
2692 void InsertTransitionElementsKind(Handle<Map> from, Handle<Map> to) {
2693 ASSERT(RequiresTransitionElementsKind(from->elements_kind()));
2694 // At the site, we maintain a most recent instruction we added, and
2695 // new instructions should appear at the end of the chain.
2696 HInstruction* addafter = last_in_chain_;
2697 if (addafter == NULL) {
2698 // This is the first instruction to add.
2699 // We must emit a checknonsmi
2700 addafter = new(zone()) HCheckNonSmi(transition_input_);
2701 addafter->InsertAfter(transition_input_);
2702 }
2703
2704 HTransitionElementsKind* transition = NULL;
2705 if (last_in_chain_ == NULL) {
2706 transition = new(zone()) HTransitionElementsKind(transition_input_, from,
2707 to);
2708 transition->InsertAfter(addafter);
2709
2710 // Careful tree surgery
2711 for (HUseIterator it(transition_input_->uses()); !it.Done();
2712 it.Advance()) {
2713 HValue* use = it.value();
2714 if (use != HValue::cast(addafter) &&
2715 use != HValue::cast(transition)) {
2716 CarefullyReplaceOperand(&it, transition);
2717 }
2718 }
2719 } else {
2720 transition = new(zone()) HTransitionElementsKind(last_in_chain_, from,
2721 to);
2722 transition->InsertAfter(last_in_chain_);
2723
2724 // Careful tree surgery
2725 for (HUseIterator it(last_in_chain_->uses()); !it.Done();
2726 it.Advance()) {
2727 HValue* use = it.value();
2728 if (use != HValue::cast(transition)) {
2729 CarefullyReplaceOperand(&it, transition);
2730 }
2731 }
2732 }
2733
2734 last_in_chain_ = transition;
2735 from_elements_.Add(from->elements_kind());
2736 }
2737
2738 HInstruction* transition_input() const { return transition_input_; }
2739
2740 private:
2741 void CarefullyReplaceOperand(HUseIterator* it, HInstruction* with) {
2742 HValue* use = it->value();
2743 if (!use->block()->IsStartBlock()) {
danno 2012/11/28 14:42:10 More comments?
2744 if (!use->IsSimulate() || use->block() != with->block()) {
2745 use->SetOperandAt(it->index(), with);
2746 } else {
2747 // Because of the way our new transition elements can be placed at the
2748 // start of a block, but ONLY AFTER any simulate instruction, we can
2749 // only replace usages of the with instruction if we are sure our new
2750 // instruction is defined in the block somewhere before the simulate.
2751 HInstruction* cur = HInstruction::cast(use)->previous();
2752 while (cur != NULL) {
2753 if (cur == with) break;
2754 cur = cur->previous();
2755 }
2756 if (cur == with) {
2757 // We can safely do the replacement
2758 use->SetOperandAt(it->index(), with);
2759 }
2760 }
2761 }
2762 }
2763
2764 HInstruction* transition_input_;
2765 MarkedTransitionElementsGroupList* groups_;
2766 Zone* zone_;
2767 MostGeneralMapAndFamily most_general_;
2768 ElementsKindSet from_elements_;
2769 HTransitionElementsKind* last_in_chain_;
2770 };
2771
2772
2773
2774 class MapHandleMap BASE_EMBEDDED {
2775 public:
2776 explicit MapHandleMap(Zone* zone) :
2777 map_(MapPointerMatch, ZoneAllocationPolicy(zone)),
2778 zone_(zone),
2779 null_handle_(Handle<Map>::null()) {
2780 }
2781
2782 Handle<Map>& Lookup(Map* map) {
2783 MapHandleTable::Iterator i = map_.find(map, false,
2784 ZoneAllocationPolicy(zone_));
2785 if (i != map_.end()) {
2786 return *(i->second);
2787 }
2788
2789 return null_handle_;
2790 }
2791
2792 void Populate(ZoneList<MarkedTransitionElementsGroup*>* groups) {
2793 for (int i = 0; i < groups->length(); i++) {
2794 MarkedTransitionElementsGroup* group = groups->at(i);
2795 for (int r = 0; r < group->bookmarks(); r++) {
2796 Add(group->bookmark_pointer(r));
2797 }
2798 }
2799 }
2800
2801 private:
2802 static bool MapPointerMatch(void* key1, void* key2) {
2803 return key1 == key2;
2804 }
2805
2806 void Add(TransitionElementsBookmark* record) {
2807 InsertIfMissing(record->from_pointer());
2808 InsertIfMissing(record->to_pointer());
2809 InsertIfMissing(record->family_pointer());
2810 InsertIfMissing(record->pessimistic_holey_pointer());
2811 }
2812
2813 void Insert(Handle<Map>* handle) {
2814 MapHandleTable::Iterator i = map_.find(*(handle->location()), true,
2815 ZoneAllocationPolicy(zone_));
2816 ASSERT(i != map_.end());
2817 i->second = handle;
2818 }
2819
2820 void InsertIfMissing(Handle<Map>* handle) {
2821 if (Lookup(*(handle->location())).is_null()) {
2822 Insert(handle);
2823 }
2824 }
2825
2826 typedef TemplateHashMap<Map, Handle<Map>, ZoneAllocationPolicy>
2827 MapHandleTable;
2828 MapHandleTable map_;
2829 Zone* zone_;
2830 Handle<Map> null_handle_;
2831 };
2832
2833
2834 class TransitionInputDictionary BASE_EMBEDDED {
2835 public:
2836 explicit TransitionInputDictionary(Zone* zone) :
2837 dictionary_(TransitionInputMatch, 32, ZoneAllocationPolicy(zone)),
2838 zone_(zone),
2839 iterator_(NULL) {
2840 }
2841
2842 void Initialize(Isolate* isolate,
2843 ZoneList<MarkedTransitionElementsGroup*>* groups);
2844
2845 TransitionInputDictionaryValue* Lookup(HInstruction* transition_input) {
2846 ZoneHashMap::Entry* entry = dictionary_.Lookup(transition_input,
2847 transition_input->id(),
2848 false,
2849 ZoneAllocationPolicy(zone_));
2850
2851 if (entry == NULL) {
2852 return NULL;
2853 }
2854
2855 TransitionInputDictionaryValue* value =
2856 reinterpret_cast<TransitionInputDictionaryValue*>(entry->value);
2857 return value;
2858 }
2859
2860 void Scorch(MarkedTransitionElementsGroup* other_family_group);
2861
2862 TransitionInputDictionaryValue* Start() {
2863 iterator_ = dictionary_.Start();
2864 if (iterator_ != NULL) {
2865 return reinterpret_cast<TransitionInputDictionaryValue*>(
2866 iterator_->value);
2867 }
2868
2869 return NULL;
2870 }
2871
2872 TransitionInputDictionaryValue* Next() {
2873 iterator_ = dictionary_.Next(iterator_);
2874 if (iterator_ != NULL) {
2875 return reinterpret_cast<TransitionInputDictionaryValue*>(
2876 iterator_->value);
2877 }
2878
2879 return NULL;
2880 }
2881
2882 private:
2883 Zone* zone() { return zone_; }
2884 static bool TransitionInputMatch(void* key1, void* key2) {
2885 return key1 == key2;
2886 }
2887
2888 void Insert(TransitionInputDictionaryValue* value) {
2889 ZoneHashMap::Entry* entry = dictionary_.Lookup(value->transition_input(),
2890 value->transition_input()->id(),
2891 true,
2892 ZoneAllocationPolicy(zone_));
2893 ASSERT(entry->value == NULL);
2894 entry->value = value;
2895 iterator_ = NULL;
2896 }
2897
2898 void Remove(HInstruction* transition_input) {
2899 dictionary_.Remove(transition_input, transition_input->id());
2900 iterator_ = NULL;
2901 }
2902
2903 ZoneHashMap dictionary_;
2904 Zone* zone_;
2905 ZoneHashMap::Entry* iterator_;
2906 };
2907
2908
2909 void TransitionInputDictionaryValue::ComputeMostGeneralMapAndFamily(
2910 MostGeneralMapAndFamily* most_general_map_and_family,
2911 MarkedTransitionElementsGroup** other_family_group) {
2912 *most_general_map_and_family = most_general();
2913
2914 // At the end of this function all groups in the list need to agree on the
2915 // highest map. so one time through the loop isn't enough.
2916 for (int count = 0; count < 2; count++) {
2917 for (int i = 0; i < groups(); i++) {
2918 Map* todo_most_general_map = group(i)->most_general_map();
2919
2920 if (!most_general_map_and_family->is_valid()) {
2921 // First todo, first time through the loop
2922 most_general_map_and_family->Update(todo_most_general_map,
2923 group(i)->map_family());
2924 } else if (most_general_map_and_family->most_general_map() !=
2925 todo_most_general_map) {
2926 // Are they in the same family?
2927 if (most_general_map_and_family->family() != group(i)->map_family()) {
2928 // Yikes. this won't work.
2929 *other_family_group = group(i);
2930 most_general_map_and_family->invalidate();
2931 return;
2932 }
2933
2934 // which one is higher? Figure that out and then the other one needs to
2935 // be able to find a path to it.
2936 ElementsKind unified_elements_kind = GetUnifiedFastElementsKind(
2937 most_general_map_and_family->most_general_map()->elements_kind(),
2938 todo_most_general_map->elements_kind());
2939
2940 // make sure both maps have a path to success
2941 Map* unified_map = most_general_map_and_family->most_general_map()->
2942 LookupElementsTransitionMap(unified_elements_kind);
2943 Map* unified_todo_map = todo_most_general_map->
2944 LookupElementsTransitionMap(unified_elements_kind);
2945 if (unified_map == NULL || unified_todo_map == NULL ||
2946 (unified_map != unified_todo_map)) {
2947 *other_family_group = group(i);
2948 most_general_map_and_family->invalidate();
2949 return;
2950 }
2951
2952 most_general_map_and_family->Update(unified_map,
2953 group(i)->map_family());
2954 group(i)->set_most_general_map(
2955 most_general_map_and_family->most_general_map());
2956 }
2957 }
2958 }
2959 }
2960
2961
2962 void TransitionInputDictionary::Scorch(MarkedTransitionElementsGroup*
2963 other_family_group) {
2964 MarkedTransitionElementsGroupList worklist(10, zone());
2965 other_family_group->set_hoistable(false);
2966 worklist.Add(other_family_group, zone());
2967
2968 while (!worklist.is_empty()) {
2969 MarkedTransitionElementsGroup* group = worklist.RemoveLast();
2970 ASSERT(!group->hoistable());
2971 for (int t = 0; t < group->transition_inputs(); t++) {
2972 HInstruction* transition_input = group->transition_input(t);
2973 TransitionInputDictionaryValue* value = Lookup(transition_input);
2974 if (value != NULL) {
2975 for (int i = 0; i < value->groups(); i++) {
2976 MarkedTransitionElementsGroup* other_group = value->group(i);
2977 if (other_group->hoistable()) {
2978 other_group->set_hoistable(false);
2979 worklist.Add(other_group, zone());
2980 }
2981 }
2982
2983 Remove(transition_input);
2984 }
2985 }
2986 }
2987 }
2988
2989
2990 void TransitionInputDictionary::Initialize(Isolate* isolate,
2991 ZoneList<MarkedTransitionElementsGroup*>* groups) {
2992 ZoneAllocationPolicy allocator(zone());
2993 Counters* counters = isolate->counters();
2994
2995 for (int i = 0; i < groups->length(); i++) {
2996 MarkedTransitionElementsGroup* group = groups->at(i);
2997 int site_nesting_depth = group->load_or_store()->block()->
2998 LoopNestingDepth();
2999
3000 for (int t = 0; t < group->transition_inputs(); t++) {
3001 HInstruction* transition_input = group->transition_input(t);
3002
3003 // Score computation
3004 int input_site_nesting_depth = transition_input->block()->
3005 LoopNestingDepth();
3006 int loop_delta = site_nesting_depth - input_site_nesting_depth;
3007 int proposedAdds = group->bookmarks();
3008 MarkedTransitionElementsGroup::ScoreType scoreType =
3009 group->scoretype_from_loopdelta(loop_delta);
3010 int score = (loop_delta == 0 ? 1 : loop_delta)*proposedAdds;
3011 if (score < 0) score *= -1;
3012 group->increment_score(scoreType, score);
3013 TransitionInputDictionaryValue* value = Lookup(transition_input);
3014 if (value == NULL) {
3015 // It's new, add a value
3016 value = new(zone())
3017 TransitionInputDictionaryValue(transition_input, zone());
3018 Insert(value);
3019 }
3020
3021 value->AddGroup(group);
3022 }
3023
3024 // Export the site score in aggregate for reporting
3025 counters->transition_site_positive_score()->
3026 Increment(group->score(MarkedTransitionElementsGroup::SCORE_POSITIVE));
3027 counters->transition_site_negative_score()->
3028 Increment(group->score(MarkedTransitionElementsGroup::SCORE_NEGATIVE));
3029 counters->transition_site_neutral_score()->
3030 Increment(group->score(MarkedTransitionElementsGroup::SCORE_NEUTRAL));
3031 }
3032 }
3033
3034
3035 void HGraph::InsertElementsTransitions() {
3036 ZoneAllocationPolicy allocator(zone());
3037 HPhase phase("H_Place elements transitions", this);
3038
3039 // Initialize the groups, the map handle map, the transition input dictionary
3040 for (int i = 0; i < marked_transitions_.length(); i++) {
3041 MarkedTransitionElementsGroup* group = marked_transitions_[i];
3042 ASSERT(group->bookmarks() > 0);
3043 group->ComputeTransitionInputValues(GetMaximumValueID());
danno 2012/11/28 14:42:10 As discussed, this algorithm costs O(n x m), where
3044 }
3045
3046 MapHandleMap mapHandleMap(zone());
3047 mapHandleMap.Populate(&marked_transitions_);
3048
3049 TransitionInputDictionary transitionInputDictionary(zone());
3050 transitionInputDictionary.Initialize(isolate(), &marked_transitions_);
3051
3052 // Now that the map is created, run the unification algorithm
3053 bool done = false;
3054 while (!done) {
3055 bool changed = false;
3056 for (TransitionInputDictionaryValue* value =
3057 transitionInputDictionary.Start();
3058 value != NULL;
3059 value = transitionInputDictionary.Next()) {
3060 MarkedTransitionElementsGroup* wrong_family_group = NULL;
3061 MostGeneralMapAndFamily new_most_general;
3062 value->ComputeMostGeneralMapAndFamily(&new_most_general,
3063 &wrong_family_group);
3064 if (!new_most_general.is_valid()) {
3065 ASSERT(wrong_family_group != NULL);
3066 transitionInputDictionary.Scorch(wrong_family_group);
3067 changed = true;
3068 break;
3069 }
3070
3071 if (!value->most_general().Equals(new_most_general)) {
3072 value->set_most_general(new_most_general);
3073 changed = true;
3074 }
3075 }
3076
3077 done = !changed;
3078 }
3079
3080 // Now we have the "to" value for each location, and groups have been divided
3081 // into sets, including a set that couldn't be transitioned and is no longer
3082 // represented in the transitionInputDictionary Handle each todo again.
3083 if (FLAG_trace_transition_placement) {
3084 for (int i = 0; i < marked_transitions_.length(); i++) {
3085 MarkedTransitionElementsGroup* group = marked_transitions_.at(i);
3086 HeapStringAllocator string_allocator;
3087 StringStream stream(&string_allocator);
3088 group->PrintTo(&stream);
3089 PrintF("%s", *stream.ToCString());
3090 }
3091 }
3092
3093 // Do the work
3094 for (int i = 0; i < marked_transitions_.length(); i++) {
3095 MarkedTransitionElementsGroup* group = marked_transitions_.at(i);
danno 2012/11/28 14:42:10 Is this just an ArrayInterface?
3096
3097 // All groups need to be finalized, even if we don't take action on them.
3098 group->Finalize();
3099
3100 if (!group->hoistable()) {
3101 // We aren't moving this todo, leave it alone and visit the next
3102 continue;
3103 }
3104
3105 // 1) Remove the nonsmicheck.
3106 if (group->smi_check()->IsLinked()) {
3107 group->smi_check()->DeleteAndReplaceWith(NULL);
3108 }
3109
3110 // 2) alter the elementkind of the loadkeyed/storekeyed instruction if
3111 // required. (note that steps a,b,c won't happen if the transition was
3112 // marked as invalid because it operates on a different map family) 2a)
3113 // unlink transitions associated with this site from their current location
3114 // 2b) Create appropriate transition instructions up at the transition input
3115 // site. 2c) Fix the checkmaps instruction if required.
3116
3117 Handle<Map>& handle = mapHandleMap.Lookup(group->most_general_map());
3118 ASSERT(!handle.is_null());
3119
3120 HCheckMaps* map_check = group->map_check();
3121 if (map_check != NULL) {
3122 ASSERT(map_check->map_set()->length() == 1);
3123 // Surgically replace the map in there if necessary
3124 if (*(map_check->map_set()->at(0).location()) != *handle.location()) {
3125 map_check->map_set()->Clear();
3126 map_check->map_set()->Add(handle, zone());
3127 }
3128
3129 // The map check had a dependency on the transition elements statement
3130 // that was in place before. This is unnecessary now, just remove it.
3131 // After the operations above, the tree expresses dependency through
3132 // ordinary output values
3133 map_check->RemoveTypeCheck();
3134 }
3135
3136 for (int t = 0; t < group->transition_inputs(); t++) {
3137 TransitionInputDictionaryValue* value =
3138 transitionInputDictionary.Lookup(group->transition_input(t));
3139 for (int r = 0; r < group->bookmarks(); r++) {
3140 TransitionElementsBookmark* record = group->bookmark_pointer(r);
3141 if (value->RequiresTransitionElementsKind(
3142 record->elementskind_from())) {
3143 // We need to emit a transition.
3144 value->InsertTransitionElementsKind(record->from(), handle);
3145
3146 // Remove the transition from it's original location
3147 if (record->transition_instruction()->block() != NULL) {
3148 ASSERT(record->transition_instruction()->HasNoUses());
3149 record->transition_instruction()->DeleteAndReplaceWith(NULL);
3150 }
3151 }
3152 }
3153 }
3154 }
3155 }
3156
3157
2452 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { 3158 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
2453 HValue* current = value; 3159 HValue* current = value;
2454 while (current != NULL) { 3160 while (current != NULL) {
2455 if (visited->Contains(current->id())) return; 3161 if (visited->Contains(current->id())) return;
2456 3162
2457 // For phis, we must propagate the check to all of its inputs. 3163 // For phis, we must propagate the check to all of its inputs.
2458 if (current->IsPhi()) { 3164 if (current->IsPhi()) {
2459 visited->Add(current->id()); 3165 visited->Add(current->id());
2460 HPhi* phi = HPhi::cast(current); 3166 HPhi* phi = HPhi::cast(current);
2461 for (int i = 0; i < phi->OperandCount(); ++i) { 3167 for (int i = 0; i < phi->OperandCount(); ++i) {
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
3267 } 3973 }
3268 EliminateRedundantPhis(); 3974 EliminateRedundantPhis();
3269 if (!CheckArgumentsPhiUses()) { 3975 if (!CheckArgumentsPhiUses()) {
3270 *bailout_reason = SmartArrayPointer<char>(StrDup( 3976 *bailout_reason = SmartArrayPointer<char>(StrDup(
3271 "Unsupported phi use of arguments")); 3977 "Unsupported phi use of arguments"));
3272 return false; 3978 return false;
3273 } 3979 }
3274 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); 3980 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis();
3275 CollectPhis(); 3981 CollectPhis();
3276 3982
3983 if (FLAG_use_place_elements_transitions) InsertElementsTransitions();
3984
3277 if (has_osr_loop_entry()) { 3985 if (has_osr_loop_entry()) {
3278 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); 3986 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
3279 for (int j = 0; j < phis->length(); j++) { 3987 for (int j = 0; j < phis->length(); j++) {
3280 HPhi* phi = phis->at(j); 3988 HPhi* phi = phis->at(j);
3281 osr_values()->at(phi->merged_index())->set_incoming_value(phi); 3989 osr_values()->at(phi->merged_index())->set_incoming_value(phi);
3282 } 3990 }
3283 } 3991 }
3284 3992
3285 HInferRepresentation rep(this); 3993 HInferRepresentation rep(this);
3286 rep.Analyze(); 3994 rep.Analyze();
(...skipping 2781 matching lines...) Expand 10 before | Expand all | Expand 10 after
6068 return load; 6776 return load;
6069 } 6777 }
6070 } 6778 }
6071 6779
6072 6780
6073 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, 6781 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
6074 HValue* checked_key, 6782 HValue* checked_key,
6075 HValue* val, 6783 HValue* val,
6076 HValue* load_dependency, 6784 HValue* load_dependency,
6077 ElementsKind elements_kind, 6785 ElementsKind elements_kind,
6078 bool is_store) { 6786 bool is_store,
6787 bool defer_initialization) {
6079 if (is_store) { 6788 if (is_store) {
6080 ASSERT(val != NULL); 6789 ASSERT(val != NULL);
6081 switch (elements_kind) { 6790 switch (elements_kind) {
6082 case FAST_SMI_ELEMENTS: 6791 case FAST_SMI_ELEMENTS:
6083 case FAST_HOLEY_SMI_ELEMENTS: 6792 case FAST_HOLEY_SMI_ELEMENTS:
6084 // Smi-only arrays need a smi check. 6793 // Smi-only arrays need a smi check.
6085 AddInstruction(new(zone()) HCheckSmi(val)); 6794 AddInstruction(new(zone()) HCheckSmi(val));
6086 // Fall through. 6795 // Fall through.
6087 case FAST_ELEMENTS: 6796 case FAST_ELEMENTS:
6088 case FAST_HOLEY_ELEMENTS: 6797 case FAST_HOLEY_ELEMENTS:
6089 case FAST_DOUBLE_ELEMENTS: 6798 case FAST_DOUBLE_ELEMENTS:
6090 case FAST_HOLEY_DOUBLE_ELEMENTS: 6799 case FAST_HOLEY_DOUBLE_ELEMENTS:
6091 return new(zone()) HStoreKeyed( 6800 return new(zone()) HStoreKeyed(
6092 elements, checked_key, val, elements_kind); 6801 elements, checked_key, val, elements_kind, defer_initialization);
6093 default: 6802 default:
6094 UNREACHABLE(); 6803 UNREACHABLE();
6095 return NULL; 6804 return NULL;
6096 } 6805 }
6097 } 6806 }
6098 // It's an element load (!is_store). 6807 // It's an element load (!is_store).
6099 return new(zone()) HLoadKeyed(elements, 6808 return new(zone()) HLoadKeyed(elements,
6100 checked_key, 6809 checked_key,
6101 load_dependency, 6810 load_dependency,
6102 elements_kind); 6811 elements_kind, defer_initialization);
6103 } 6812 }
6104 6813
6105 6814
6106 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, 6815 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
6107 HValue* key, 6816 HValue* key,
6108 HValue* val, 6817 HValue* val,
6109 HValue* dependency, 6818 HValue* dependency,
6110 Handle<Map> map, 6819 Handle<Map> map,
6111 bool is_store) { 6820 bool is_store,
6821 HCheckMaps** checkmap_instr) {
6112 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, 6822 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map,
6113 zone(), dependency); 6823 zone(), dependency);
6114 AddInstruction(mapcheck); 6824 AddInstruction(mapcheck);
6115 if (dependency) { 6825 if (dependency) {
6116 mapcheck->ClearGVNFlag(kDependsOnElementsKind); 6826 mapcheck->ClearGVNFlag(kDependsOnElementsKind);
6117 } 6827 }
6828
6829 if (checkmap_instr != NULL) {
6830 *checkmap_instr = mapcheck;
6831 }
6832
6833 // TODO(mvstanton): this is a bit opaque, maybe just pass in a
6834 // defer_initialization param
6835 bool defer_initialization = FLAG_use_place_elements_transitions &&
6836 (dependency != NULL);
6118 return BuildUncheckedMonomorphicElementAccess(object, key, val, 6837 return BuildUncheckedMonomorphicElementAccess(object, key, val,
6119 mapcheck, map, is_store); 6838 mapcheck, map, is_store,
6839 defer_initialization);
6120 } 6840 }
6121 6841
6122 6842
6123 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 6843 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
6124 HValue* object, 6844 HValue* object,
6125 HValue* key, 6845 HValue* key,
6126 HValue* val, 6846 HValue* val,
6127 HCheckMaps* mapcheck, 6847 HCheckMaps* mapcheck,
6128 Handle<Map> map, 6848 Handle<Map> map,
6129 bool is_store) { 6849 bool is_store,
6850 bool defer_initialization) {
6130 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency 6851 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
6131 // on a HElementsTransition instruction. The flag can also be removed if the 6852 // on a HElementsTransition instruction. The flag can also be removed if the
6132 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further 6853 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
6133 // ElementsKind transitions. Finally, the dependency can be removed for stores 6854 // ElementsKind transitions. Finally, the dependency can be removed for stores
6134 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the 6855 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
6135 // generated store code. 6856 // generated store code.
6136 if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) || 6857 if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) ||
6137 (map->elements_kind() == FAST_ELEMENTS && is_store)) { 6858 (map->elements_kind() == FAST_ELEMENTS && is_store)) {
6138 mapcheck->ClearGVNFlag(kDependsOnElementsKind); 6859 mapcheck->ClearGVNFlag(kDependsOnElementsKind);
6139 } 6860 }
(...skipping 25 matching lines...) Expand all
6165 map->has_fast_double_elements()); 6886 map->has_fast_double_elements());
6166 if (map->instance_type() == JS_ARRAY_TYPE) { 6887 if (map->instance_type() == JS_ARRAY_TYPE) {
6167 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck, 6888 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck,
6168 HType::Smi())); 6889 HType::Smi()));
6169 } else { 6890 } else {
6170 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 6891 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6171 } 6892 }
6172 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 6893 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6173 ALLOW_SMI_KEY)); 6894 ALLOW_SMI_KEY));
6174 return BuildFastElementAccess(elements, checked_key, val, mapcheck, 6895 return BuildFastElementAccess(elements, checked_key, val, mapcheck,
6175 map->elements_kind(), is_store); 6896 map->elements_kind(), is_store,
6897 defer_initialization);
6176 } 6898 }
6177 6899
6178 6900
6179 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( 6901 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad(
6180 HValue* object, 6902 HValue* object,
6181 HValue* key, 6903 HValue* key,
6182 HValue* val, 6904 HValue* val,
6183 SmallMapList* maps) { 6905 SmallMapList* maps) {
6184 // For polymorphic loads of similar elements kinds (i.e. all tagged or all 6906 // For polymorphic loads of similar elements kinds (i.e. all tagged or all
6185 // double), always use the "worst case" code without a transition. This is 6907 // double), always use the "worst case" code without a transition. This is
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
6217 most_general_consolidated_map->elements_kind(), 6939 most_general_consolidated_map->elements_kind(),
6218 map->elements_kind())) { 6940 map->elements_kind())) {
6219 most_general_consolidated_map = map; 6941 most_general_consolidated_map = map;
6220 } 6942 }
6221 } 6943 }
6222 if (!has_double_maps && !has_smi_or_object_maps) return NULL; 6944 if (!has_double_maps && !has_smi_or_object_maps) return NULL;
6223 6945
6224 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); 6946 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone());
6225 AddInstruction(check_maps); 6947 AddInstruction(check_maps);
6226 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( 6948 HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
6227 object, key, val, check_maps, most_general_consolidated_map, false); 6949 object, key, val, check_maps, most_general_consolidated_map, false,
6950 false);
6228 return instr; 6951 return instr;
6229 } 6952 }
6230 6953
6231 6954
6232 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, 6955 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
6233 HValue* key, 6956 HValue* key,
6234 HValue* val, 6957 HValue* val,
6235 Expression* prop, 6958 Expression* prop,
6236 BailoutId ast_id, 6959 BailoutId ast_id,
6237 int position, 6960 int position,
6238 bool is_store, 6961 bool is_store,
6239 bool* has_side_effects) { 6962 bool* has_side_effects) {
6240 *has_side_effects = false; 6963 *has_side_effects = false;
6241 AddInstruction(new(zone()) HCheckNonSmi(object)); 6964 bool use_groups = FLAG_use_place_elements_transitions;
6965 HCheckNonSmi* checknonsmi = new(zone()) HCheckNonSmi(object);
6966 AddInstruction(checknonsmi);
6242 SmallMapList* maps = prop->GetReceiverTypes(); 6967 SmallMapList* maps = prop->GetReceiverTypes();
6243 bool todo_external_array = false; 6968 bool todo_external_array = false;
6244 6969
6245 if (!is_store) { 6970 if (!is_store) {
6246 HInstruction* consolidated_load = 6971 HInstruction* consolidated_load =
6247 TryBuildConsolidatedElementLoad(object, key, val, maps); 6972 TryBuildConsolidatedElementLoad(object, key, val, maps);
6248 if (consolidated_load != NULL) { 6973 if (consolidated_load != NULL) {
6249 AddInstruction(consolidated_load); 6974 AddInstruction(consolidated_load);
6250 *has_side_effects |= consolidated_load->HasObservableSideEffects(); 6975 *has_side_effects |= consolidated_load->HasObservableSideEffects();
6251 if (position != RelocInfo::kNoPosition) { 6976 if (position != RelocInfo::kNoPosition) {
(...skipping 25 matching lines...) Expand all
6277 for (int i = 0; i < maps->length(); ++i) { 7002 for (int i = 0; i < maps->length(); ++i) {
6278 Handle<Map> map = maps->at(i); 7003 Handle<Map> map = maps->at(i);
6279 Handle<Map> transitioned_map = 7004 Handle<Map> transitioned_map =
6280 map->FindTransitionedMap(&possible_transitioned_maps); 7005 map->FindTransitionedMap(&possible_transitioned_maps);
6281 transition_target.Add(transitioned_map); 7006 transition_target.Add(transitioned_map);
6282 } 7007 }
6283 7008
6284 int num_untransitionable_maps = 0; 7009 int num_untransitionable_maps = 0;
6285 Handle<Map> untransitionable_map; 7010 Handle<Map> untransitionable_map;
6286 HTransitionElementsKind* transition = NULL; 7011 HTransitionElementsKind* transition = NULL;
7012 ZoneList<TransitionElementsBookmark> bookmarks(10, zone());
6287 for (int i = 0; i < maps->length(); ++i) { 7013 for (int i = 0; i < maps->length(); ++i) {
6288 Handle<Map> map = maps->at(i); 7014 Handle<Map> map = maps->at(i);
6289 ASSERT(map->IsMap()); 7015 ASSERT(map->IsMap());
6290 if (!transition_target.at(i).is_null()) { 7016 if (!transition_target.at(i).is_null()) {
6291 ASSERT(Map::IsValidElementsTransition( 7017 ASSERT(Map::IsValidElementsTransition(
6292 map->elements_kind(), 7018 map->elements_kind(),
6293 transition_target.at(i)->elements_kind())); 7019 transition_target.at(i)->elements_kind()));
6294 transition = new(zone()) HTransitionElementsKind( 7020 transition = new(zone()) HTransitionElementsKind(
6295 object, map, transition_target.at(i)); 7021 object, map, transition_target.at(i));
6296 AddInstruction(transition); 7022 AddInstruction(transition);
7023
7024 if (use_groups) {
7025 TransitionElementsBookmark tr(transition,
7026 map,
7027 transition_target.at(i),
7028 isolate());
7029 bookmarks.Add(tr, zone());
7030 }
6297 } else { 7031 } else {
6298 type_todo[map->elements_kind()] = true; 7032 type_todo[map->elements_kind()] = true;
6299 if (IsExternalArrayElementsKind(map->elements_kind())) { 7033 if (IsExternalArrayElementsKind(map->elements_kind())) {
6300 todo_external_array = true; 7034 todo_external_array = true;
6301 } 7035 }
6302 num_untransitionable_maps++; 7036 num_untransitionable_maps++;
6303 untransitionable_map = map; 7037 untransitionable_map = map;
6304 } 7038 }
6305 } 7039 }
6306 7040
6307 // If only one map is left after transitioning, handle this case 7041 // If only one map is left after transitioning, handle this case
6308 // monomorphically. 7042 // monomorphically.
6309 if (num_untransitionable_maps == 1) { 7043 if (num_untransitionable_maps == 1) {
6310 HInstruction* instr = NULL; 7044 HInstruction* instr = NULL;
6311 if (untransitionable_map->has_slow_elements_kind()) { 7045 if (untransitionable_map->has_slow_elements_kind()) {
6312 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) 7046 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
6313 : BuildLoadKeyedGeneric(object, key)); 7047 : BuildLoadKeyedGeneric(object, key));
6314 } else { 7048 } else {
7049 HCheckMaps *checkmaps = NULL;
6315 instr = AddInstruction(BuildMonomorphicElementAccess( 7050 instr = AddInstruction(BuildMonomorphicElementAccess(
6316 object, key, val, transition, untransitionable_map, is_store)); 7051 object, key, val, transition, untransitionable_map, is_store,
7052 &checkmaps));
7053
7054 if (use_groups && bookmarks.length() > 0) {
7055 MarkedTransitionElementsGroup* group = new(zone())
7056 MarkedTransitionElementsGroup(instr, checknonsmi,
7057 checkmaps, zone());
7058 group->AddBookmarks(bookmarks);
7059 graph()->AddMarkedTransitionElementsGroup(group);
7060 }
6317 } 7061 }
6318 *has_side_effects |= instr->HasObservableSideEffects(); 7062 *has_side_effects |= instr->HasObservableSideEffects();
6319 if (position != RelocInfo::kNoPosition) instr->set_position(position); 7063 if (position != RelocInfo::kNoPosition) instr->set_position(position);
6320 return is_store ? NULL : instr; 7064 return is_store ? NULL : instr;
6321 } 7065 }
6322 7066
6323 HInstruction* checkspec = 7067 HInstruction* checkspec =
6324 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); 7068 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone()));
6325 HBasicBlock* join = graph()->CreateBasicBlock(); 7069 HBasicBlock* join = graph()->CreateBasicBlock();
6326 7070
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
6358 HBasicBlock* if_false = graph()->CreateBasicBlock(); 7102 HBasicBlock* if_false = graph()->CreateBasicBlock();
6359 HCompareConstantEqAndBranch* elements_kind_branch = 7103 HCompareConstantEqAndBranch* elements_kind_branch =
6360 new(zone()) HCompareConstantEqAndBranch( 7104 new(zone()) HCompareConstantEqAndBranch(
6361 elements_kind_instr, elements_kind, Token::EQ_STRICT); 7105 elements_kind_instr, elements_kind, Token::EQ_STRICT);
6362 elements_kind_branch->SetSuccessorAt(0, if_true); 7106 elements_kind_branch->SetSuccessorAt(0, if_true);
6363 elements_kind_branch->SetSuccessorAt(1, if_false); 7107 elements_kind_branch->SetSuccessorAt(1, if_false);
6364 current_block()->Finish(elements_kind_branch); 7108 current_block()->Finish(elements_kind_branch);
6365 7109
6366 set_current_block(if_true); 7110 set_current_block(if_true);
6367 HInstruction* access; 7111 HInstruction* access;
7112 HCheckMaps* checkmaps = NULL;
6368 if (IsFastElementsKind(elements_kind)) { 7113 if (IsFastElementsKind(elements_kind)) {
6369 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { 7114 if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
6370 AddInstruction(new(zone()) HCheckMaps( 7115 checkmaps = new(zone()) HCheckMaps(
6371 elements, isolate()->factory()->fixed_array_map(), 7116 elements, isolate()->factory()->fixed_array_map(),
6372 zone(), elements_kind_branch)); 7117 zone(), elements_kind_branch);
7118 AddInstruction(checkmaps);
6373 } 7119 }
6374 // TODO(jkummerow): The need for these two blocks could be avoided 7120 // TODO(jkummerow): The need for these two blocks could be avoided
6375 // in one of two ways: 7121 // in one of two ways:
6376 // (1) Introduce ElementsKinds for JSArrays that are distinct from 7122 // (1) Introduce ElementsKinds for JSArrays that are distinct from
6377 // those for fast objects. 7123 // those for fast objects.
6378 // (2) Put the common instructions into a third "join" block. This 7124 // (2) Put the common instructions into a third "join" block. This
6379 // requires additional AST IDs that we can deopt to from inside 7125 // requires additional AST IDs that we can deopt to from inside
6380 // that join block. They must be added to the Property class (when 7126 // that join block. They must be added to the Property class (when
6381 // it's a keyed property) and registered in the full codegen. 7127 // it's a keyed property) and registered in the full codegen.
6382 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); 7128 HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
6383 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); 7129 HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
6384 HHasInstanceTypeAndBranch* typecheck = 7130 HHasInstanceTypeAndBranch* typecheck =
6385 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); 7131 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
6386 typecheck->SetSuccessorAt(0, if_jsarray); 7132 typecheck->SetSuccessorAt(0, if_jsarray);
6387 typecheck->SetSuccessorAt(1, if_fastobject); 7133 typecheck->SetSuccessorAt(1, if_fastobject);
6388 current_block()->Finish(typecheck); 7134 current_block()->Finish(typecheck);
6389 7135
6390 set_current_block(if_jsarray); 7136 set_current_block(if_jsarray);
6391 HInstruction* length; 7137 HInstruction* length;
6392 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, 7138 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
6393 HType::Smi())); 7139 HType::Smi()));
6394 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7140 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6395 ALLOW_SMI_KEY)); 7141 ALLOW_SMI_KEY));
6396 access = AddInstruction(BuildFastElementAccess( 7142 access = AddInstruction(BuildFastElementAccess(
6397 elements, checked_key, val, elements_kind_branch, 7143 elements, checked_key, val, elements_kind_branch,
6398 elements_kind, is_store)); 7144 elements_kind, is_store, use_groups && bookmarks.length() > 0));
6399 if (!is_store) { 7145 if (!is_store) {
6400 Push(access); 7146 Push(access);
6401 } 7147 }
6402 7148
7149 if (use_groups && bookmarks.length() > 0) {
7150 ASSERT(access->IsLoadKeyed() || access->IsStoreKeyed());
7151 MarkedTransitionElementsGroup* group = new(zone())
7152 MarkedTransitionElementsGroup(access, checknonsmi,
7153 checkmaps, zone());
7154 group->AddBookmarks(bookmarks);
7155 graph()->AddMarkedTransitionElementsGroup(group);
7156 }
7157
6403 *has_side_effects |= access->HasObservableSideEffects(); 7158 *has_side_effects |= access->HasObservableSideEffects();
6404 if (position != -1) { 7159 if (position != -1) {
6405 access->set_position(position); 7160 access->set_position(position);
6406 } 7161 }
6407 if_jsarray->Goto(join); 7162 if_jsarray->Goto(join);
6408 7163
6409 set_current_block(if_fastobject); 7164 set_current_block(if_fastobject);
6410 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 7165 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6411 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7166 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6412 ALLOW_SMI_KEY)); 7167 ALLOW_SMI_KEY));
6413 access = AddInstruction(BuildFastElementAccess( 7168 access = AddInstruction(BuildFastElementAccess(
6414 elements, checked_key, val, elements_kind_branch, 7169 elements, checked_key, val, elements_kind_branch,
6415 elements_kind, is_store)); 7170 elements_kind, is_store, use_groups && bookmarks.length() > 0));
7171
7172 if (use_groups && bookmarks.length() > 0) {
7173 ASSERT(access->IsLoadKeyed() || access->IsStoreKeyed());
7174 MarkedTransitionElementsGroup* group = new(zone())
7175 MarkedTransitionElementsGroup(access, checknonsmi,
7176 checkmaps, zone());
7177 group->AddBookmarks(bookmarks);
7178 graph()->AddMarkedTransitionElementsGroup(group);
7179 }
6416 } else if (elements_kind == DICTIONARY_ELEMENTS) { 7180 } else if (elements_kind == DICTIONARY_ELEMENTS) {
6417 if (is_store) { 7181 if (is_store) {
6418 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); 7182 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
6419 } else { 7183 } else {
6420 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); 7184 access = AddInstruction(BuildLoadKeyedGeneric(object, key));
6421 } 7185 }
6422 } else { // External array elements. 7186 } else { // External array elements.
6423 access = AddInstruction(BuildExternalArrayElementAccess( 7187 access = AddInstruction(BuildExternalArrayElementAccess(
6424 external_elements, checked_key, val, elements_kind_branch, 7188 external_elements, checked_key, val, elements_kind_branch,
6425 elements_kind, is_store)); 7189 elements_kind, is_store));
6426 } 7190 }
6427 *has_side_effects |= access->HasObservableSideEffects(); 7191 *has_side_effects |= access->HasObservableSideEffects();
6428 if (position != RelocInfo::kNoPosition) access->set_position(position); 7192 if (position != RelocInfo::kNoPosition) access->set_position(position);
6429 if (!is_store) { 7193 if (!is_store) {
6430 Push(access); 7194 Push(access);
6431 } 7195 }
7196
6432 current_block()->Goto(join); 7197 current_block()->Goto(join);
6433 set_current_block(if_false); 7198 set_current_block(if_false);
6434 } 7199 }
6435 } 7200 }
6436 7201
6437 // Deopt if none of the cases matched. 7202 // Deopt if none of the cases matched.
6438 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); 7203 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
6439 join->SetJoinId(ast_id); 7204 join->SetJoinId(ast_id);
6440 set_current_block(join); 7205 set_current_block(join);
6441 return is_store ? NULL : Pop(); 7206 return is_store ? NULL : Pop();
(...skipping 3273 matching lines...) Expand 10 before | Expand all | Expand 10 after
9715 10480
9716 10481
9717 void HEnvironment::PrintToStd() { 10482 void HEnvironment::PrintToStd() {
9718 HeapStringAllocator string_allocator; 10483 HeapStringAllocator string_allocator;
9719 StringStream trace(&string_allocator); 10484 StringStream trace(&string_allocator);
9720 PrintTo(&trace); 10485 PrintTo(&trace);
9721 PrintF("%s", *trace.ToCString()); 10486 PrintF("%s", *trace.ToCString());
9722 } 10487 }
9723 10488
9724 10489
10490 TransitionElementsBookmark::TransitionElementsBookmark(
10491 HTransitionElementsKind* transition,
10492 Handle<Map> map_from, Handle<Map> map_to, Isolate* isolate)
10493 : transition_(transition),
10494 from_(map_from),
10495 to_(map_to),
10496 pessimistic_holey_() {
10497
10498 // When transition records are created, we have the chance to create map
10499 // transitions we might need later. Transitions are unified during
10500 // optimization, and we may need to transition from a packed fastmap to a
10501 // holey version of same. But we can't create those transitions during
10502 // optimization. Do it now, recognizing that when the handle disappears these
10503 // maps may be collected if they didn't make it into usage in the optimized
10504 // graph.
10505
10506 // TODO(mvstanton): generalize this service into
10507 // "MakeWorstCaseMapForElementsKindTransition" (ie, not "holey")
10508 if (IsFastPackedElementsKind(map_to->elements_kind())) {
10509 ElementsKind holey_kind = GetHoleyElementsKind(map_to->elements_kind());
10510 // The transition might already exist
10511 Handle<Map> holey_map_handle(FindClosestElementsTransition(*map_to,
10512 holey_kind));
10513 ASSERT(!holey_map_handle.is_null());
10514 if (holey_map_handle->elements_kind() != holey_kind) {
10515 MaybeObject* holey_map = map_to->AddMissingElementsTransitions(
10516 holey_kind);
10517 holey_map->ToHandle<Map>(&pessimistic_holey_, isolate);
10518 } else {
10519 pessimistic_holey_ = holey_map_handle;
10520 }
10521 } else {
10522 pessimistic_holey_ = map_to;
10523 }
10524
10525 ASSERT(!pessimistic_holey_.is_null());
10526
10527 // fill in map_family_
10528 // Walk up to the base map from the map_to();
10529 Handle<Map> end_map(FindClosestElementsTransition(*map_to,
10530 TERMINAL_FAST_ELEMENTS_KIND));
10531 ASSERT(!end_map.is_null());
10532 family_ = end_map;
10533 }
10534
10535
10536 void MarkedTransitionElementsGroup::AddBookmarks(
10537 const ZoneList<TransitionElementsBookmark>& records) {
10538 ASSERT(records.length() > 0);
10539 Map* first_to_map = *(records[0].to().location());
10540
10541 // Doesn't check for duplicates.
10542 // The "to" map values should be the same for the whole group
10543 for (int i = 0; i < records.length(); i++) {
10544 bookmarks_->Add(records[i], zone_);
10545 ASSERT(first_to_map == *(records[i].to().location()));
10546 }
10547
10548 set_most_general_map(first_to_map);
10549 }
10550
10551
10552 void MarkedTransitionElementsGroup::ComputeTransitionInputValues(
10553 int maximumGraphValueID) {
10554 HValue* elements = NULL;
10555
10556 HInstruction* instruction = load_or_store();
10557 if (instruction->IsStoreKeyed()) {
10558 elements = HStoreKeyed::cast(instruction)->elements();
danno 2012/11/28 14:42:10 Can you add elements to ArrayInterface?
10559 } else {
10560 CHECK(instruction->IsLoadKeyed());
10561 elements = HLoadKeyed::cast(instruction)->elements();
10562 }
10563
10564 ASSERT(elements != NULL);
10565 // Now get the item from the elements
10566 ASSERT(elements->IsLoadElements());
10567 HLoadElements *start = HLoadElements::cast(elements);
10568
10569 ASSERT(transition_inputs_->length() == 0);
10570 BitVector visited(maximumGraphValueID, zone());
danno 2012/11/28 14:42:10 maximum_graph_value_id
10571
10572 ZoneList<HValue*> worklist(10, zone());
10573 worklist.Add(start->value(), zone());
10574
10575 while (!worklist.is_empty()) {
10576 HValue* value = worklist.RemoveLast();
10577 // Have we visited this node?
10578 if (!visited.Contains(value->id())) {
10579 visited.Add(value->id());
10580 if (value->IsPhi()) {
10581 HPhi *phi = HPhi::cast(value);
10582 for (int i = 0; i < phi->OperandCount(); i++) {
10583 worklist.Add(phi->OperandAt(i), zone());
10584 }
10585 } else {
10586 // It must be a transition input value.
10587 ASSERT(value->IsInstruction());
10588 transition_inputs_->Add(HInstruction::cast(value), zone());
10589 }
10590 }
10591 }
10592
10593 // We must have found something.
10594 ASSERT(transition_inputs_->length() > 0);
10595 }
10596
10597
10598 void MarkedTransitionElementsGroup::PrintTo(StringStream* stream) const {
10599 HInstruction* instruction = load_or_store();
10600 stream->Add("SITE: block%d %d: ", instruction->block()->block_id(),
10601 instruction->id());
10602 instruction->PrintTo(stream);
10603 stream->Add("\n");
10604
10605 // Print validness
10606 stream->Add(" HOISTABLE: %s\n", hoistable() ? "true" : "false");
10607
10608 // Print score
10609 stream->Add(" SCORE: (+%d,%d,-%d)\n", score_[0], score_[1], score_[2]);
10610
10611 // Find the def point for the instruction
10612 HValue *elements = NULL;
10613 if (instruction->IsStoreKeyed()) {
10614 elements = HStoreKeyed::cast(instruction)->elements();
10615 } else {
10616 ASSERT(instruction->IsLoadKeyed());
10617 elements = HLoadKeyed::cast(instruction)->elements();
10618 }
10619
10620 ASSERT(elements != NULL);
10621 // Now get the item from the elements
10622 ASSERT(elements->IsLoadElements());
10623 HValue *elements_value = HLoadElements::cast(elements)->value();
10624 stream->Add(" OBJECT: ");
10625 elements_value->PrintNameTo(stream);
10626 stream->Add(" ");
10627 elements_value->PrintTo(stream);
10628 stream->Add(" %s\n", elements_value->IsPhi() ? "PHI" : "");
10629 stream->Add(" TRANSITIONS:\n");
10630 ElementsKind transitionElementsKind = FAST_SMI_ELEMENTS;
10631 for (int i = 0; i < bookmarks(); i++) {
10632 const TransitionElementsBookmark& b = bookmark(i);
10633 stream->Add(" %s", ElementsKindToString(b.elementskind_from()));
10634 stream->Add("(0x%p)-> ", *(b.from()));
10635 transitionElementsKind = b.elementskind_to();
10636 stream->Add("%s", ElementsKindToString(transitionElementsKind));
10637 stream->Add("(0x%p)\n", *(b.to()));
10638 }
10639
10640 // Print possibly externally computed map
10641 const char *signifier = (transitionElementsKind !=
10642 most_general_map()->elements_kind())
10643 ? "*" : "";
10644 stream->Add(" COMPUTED MOST GENERAL MAP: %s%s(0x%p)\n", signifier,
10645 ElementsKindToString(most_general_map()->elements_kind()),
10646 most_general_map());
10647
10648 // Print terminal nodes if available
10649 stream->Add(" TRANSITION INPUT VALUES:\n");
10650 for (int j = 0; j < transition_inputs(); j++) {
10651 HValue* node = transition_input(j);
10652 stream->Add(" block%d %d: ", node->block()->block_id(), node->id());
10653 node->PrintNameTo(stream);
10654 stream->Add(" ");
10655 node->PrintTo(stream);
10656 stream->Add("\n");
10657 }
10658 }
10659
10660
10661 void MarkedTransitionElementsGroup::PrintToStd() const {
10662 HeapStringAllocator string_allocator;
10663 StringStream trace(&string_allocator);
10664 PrintTo(&trace);
10665 PrintF("%s", *trace.ToCString());
10666 }
10667
10668
9725 void HTracer::TraceCompilation(FunctionLiteral* function) { 10669 void HTracer::TraceCompilation(FunctionLiteral* function) {
9726 Tag tag(this, "compilation"); 10670 Tag tag(this, "compilation");
9727 Handle<String> name = function->debug_name(); 10671 Handle<String> name = function->debug_name();
9728 PrintStringProperty("name", *name->ToCString()); 10672 PrintStringProperty("name", *name->ToCString());
9729 PrintStringProperty("method", *name->ToCString()); 10673 PrintStringProperty("method", *name->ToCString());
9730 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); 10674 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
9731 } 10675 }
9732 10676
9733 10677
9734 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 10678 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
10035 } 10979 }
10036 } 10980 }
10037 10981
10038 #ifdef DEBUG 10982 #ifdef DEBUG
10039 if (graph_ != NULL) graph_->Verify(false); // No full verify. 10983 if (graph_ != NULL) graph_->Verify(false); // No full verify.
10040 if (allocator_ != NULL) allocator_->Verify(); 10984 if (allocator_ != NULL) allocator_->Verify();
10041 #endif 10985 #endif
10042 } 10986 }
10043 10987
10044 } } // namespace v8::internal 10988 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698