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

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: Visited set needs to consider edges, not vertexes on down propagation through the network. Created 8 years 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 2431 matching lines...) Expand 10 before | Expand all | Expand 10 after
2442 ZoneList<HValue*> worklist(block->phis()->length(), zone()); 2442 ZoneList<HValue*> worklist(block->phis()->length(), zone());
2443 for (int j = 0; j < block->phis()->length(); ++j) { 2443 for (int j = 0; j < block->phis()->length(); ++j) {
2444 worklist.Add(block->phis()->at(j), zone()); 2444 worklist.Add(block->phis()->at(j), zone());
2445 } 2445 }
2446 InferTypes(&worklist); 2446 InferTypes(&worklist);
2447 } 2447 }
2448 } 2448 }
2449 } 2449 }
2450 2450
2451 2451
2452 typedef ZoneList<HInstruction*> TransitionInputList;
2453 typedef ZoneList<ArrayInstruction*> ArrayInstructionList;
2454 typedef EnumSet<ElementsKind> ElementsKindSet;
2455
2456
2457 class MapHandleMap BASE_EMBEDDED {
2458 public:
2459 explicit MapHandleMap(Zone* zone) :
2460 map_(MapPointerMatch, ZoneAllocationPolicy(zone)),
2461 indexer_(IndexMatch, ZoneAllocationPolicy(zone)),
2462 zone_(zone),
2463 null_handle_(Handle<Map>::null()) {
2464 }
2465
2466 Handle<Map>& Lookup(Map* map) {
2467 MapHandleTable::Iterator i = map_.find(map, false,
2468 ZoneAllocationPolicy(zone_));
2469 if (i != map_.end()) {
2470 return *(i->second);
2471 }
2472
2473 return null_handle_;
2474 }
2475
2476 Map* Lookup(Map* family, ElementsKind kind) {
2477 IndexKey lookupKey(family, kind);
2478 IndexKeyTable::Iterator i = indexer_.find(
2479 &lookupKey, false, ZoneAllocationPolicy(zone_));
2480 if (i != indexer_.end()) {
2481 return i->second;
2482 }
2483
2484 return NULL;
2485 }
2486
2487 void Populate(ArrayInstruction* instruction) {
2488 for (int r = 0; r < instruction->bookmarks(); r++) {
2489 Add(instruction->bookmark(r));
2490 }
2491 }
2492
2493 private:
2494 struct IndexKey: public ZoneObject {
2495 IndexKey(Map* family_in, ElementsKind kind_in) :
2496 family(family_in),
2497 kind(kind_in) {
2498 }
2499
2500 int Hash() {
2501 return family->Hash() + (31*kind);
2502 }
2503
2504 Map* family;
2505 ElementsKind kind;
2506 };
2507
2508 static bool MapPointerMatch(void* key1, void* key2) {
2509 return key1 == key2;
2510 }
2511
2512 static bool IndexMatch(void* key1, void* key2) {
2513 IndexKey* k1 = reinterpret_cast<IndexKey*>(key1);
2514 IndexKey* k2 = reinterpret_cast<IndexKey*>(key2);
2515 return k1->Hash() == k2->Hash();
2516 }
2517
2518 void Add(TransitionElementsBookmark* record) {
2519 Handle<Map>* family = record->family_pointer();
2520 InsertIfMissing(record->from_pointer(), family);
2521 InsertIfMissing(record->to_pointer(), family);
2522 InsertIfMissing(record->pessimistic_holey_pointer(), family);
2523 }
2524
2525 void Insert(Handle<Map>* handle, Handle<Map>* family) {
2526 Map* map = *(handle->location());
2527 Map* family_map = *(family->location());
2528
2529 MapHandleTable::Iterator i = map_.find(map, true,
2530 ZoneAllocationPolicy(zone_));
2531 ASSERT(i != map_.end());
2532 i->second = handle;
2533
2534 IndexKey *key = new(zone()) IndexKey(family_map, map->elements_kind());
2535 IndexKeyTable::Iterator iki = indexer_.find(
2536 key, true,
2537 ZoneAllocationPolicy(zone_));
2538 ASSERT(iki != indexer_.end());
2539 iki->second = map;
2540 }
2541
2542 void InsertIfMissing(Handle<Map>* handle, Handle<Map>* family) {
2543 if (Lookup(*(handle->location())).is_null()) {
2544 Insert(handle, family);
2545 }
2546 }
2547
2548 Zone* zone() { return zone_; }
2549
2550 typedef TemplateHashMap<Map, Handle<Map>, ZoneAllocationPolicy>
2551 MapHandleTable;
2552 MapHandleTable map_;
2553 typedef TemplateHashMap<IndexKey, Map, ZoneAllocationPolicy>
2554 IndexKeyTable;
2555 IndexKeyTable indexer_;
2556 Zone* zone_;
2557 Handle<Map> null_handle_;
2558 };
2559
2560
2561 class InstructionPlacer: public ZoneObject {
2562 public:
2563 InstructionPlacer(HInstruction* transition_input, Zone* zone) :
2564 zone_(zone),
2565 transition_input_(transition_input),
2566 last_in_chain_(NULL) {
2567
2568 }
2569
2570 // For instruction emission
2571 bool RequiresTransitionElementsKind(ElementsKind from) const {
2572 return !from_elements_.Contains(from);
2573 }
2574
2575 void InsertTransitionElementsKind(Handle<Map> from, Handle<Map> to) {
2576 ASSERT(RequiresTransitionElementsKind(from->elements_kind()));
2577 // At the site, we maintain a most recent instruction we added, and
2578 // new instructions should appear at the end of the chain.
2579 HInstruction* addafter = last_in_chain_;
2580 if (addafter == NULL) {
2581 // This is the first instruction to add.
2582 // We must emit a checknonsmi
2583 addafter = new(zone()) HCheckNonSmi(transition_input_);
2584 addafter->InsertAfter(transition_input_);
2585 }
2586
2587 HTransitionElementsKind* transition = NULL;
2588 if (last_in_chain_ == NULL) {
2589 transition = new(zone()) HTransitionElementsKind(transition_input_, from,
2590 to);
2591 transition->InsertAfter(addafter);
2592
2593 // Careful tree surgery
2594 for (HUseIterator it(transition_input_->uses()); !it.Done();
2595 it.Advance()) {
2596 HValue* use = it.value();
2597 if (use != HValue::cast(addafter) &&
2598 use != HValue::cast(transition)) {
2599 CarefullyReplaceOperand(&it, transition);
2600 }
2601 }
2602 } else {
2603 transition = new(zone()) HTransitionElementsKind(last_in_chain_, from,
2604 to);
2605 transition->InsertAfter(last_in_chain_);
2606
2607 // Careful tree surgery
2608 for (HUseIterator it(last_in_chain_->uses()); !it.Done();
2609 it.Advance()) {
2610 HValue* use = it.value();
2611 if (use != HValue::cast(transition)) {
2612 CarefullyReplaceOperand(&it, transition);
2613 }
2614 }
2615 }
2616
2617 last_in_chain_ = transition;
2618 from_elements_.Add(from->elements_kind());
2619 }
2620
2621 HInstruction* transition_input() const { return transition_input_; }
2622
2623 private:
2624 void CarefullyReplaceOperand(HUseIterator* it, HInstruction* with) {
2625 HValue* use = it->value();
2626 if (!use->block()->IsStartBlock()) {
2627 if (!use->IsSimulate() || use->block() != with->block()) {
2628 use->SetOperandAt(it->index(), with);
2629 } else {
2630 // Because of the way our new transition elements can be placed at the
2631 // start of a block, but ONLY AFTER any simulate instruction, we can
2632 // only replace usages of the with instruction if we are sure our new
2633 // instruction is defined in the block somewhere before the simulate.
2634 HInstruction* cur = HInstruction::cast(use)->previous();
2635 while (cur != NULL) {
2636 if (cur == with) break;
2637 cur = cur->previous();
2638 }
2639 if (cur == with) {
2640 // We can safely do the replacement
2641 use->SetOperandAt(it->index(), with);
2642 }
2643 }
2644 }
2645 }
2646
2647 Zone* zone() { return zone_; }
2648 Zone* zone_;
2649 HInstruction* transition_input_;
2650 ElementsKindSet from_elements_;
2651 HTransitionElementsKind* last_in_chain_;
2652 };
2653
2654
2655 class ResolutionTableValue: public ZoneObject {
2656 public:
2657 ResolutionTableValue() :
2658 to_(NULL),
2659 family_(NULL),
2660 poisoned_(false),
2661 placer_(NULL) {
2662
2663 }
2664
2665 Map* to() { return to_; }
2666 Map* family() { return family_; }
2667 bool poisoned() { return poisoned_; }
2668 ElementsKindSet from_set() { return from_elements_; }
2669
2670 void Initialize(ArrayInstruction* instr) {
2671 if (!instr->hoistable()) {
2672 poisoned_ = true;
2673 return;
2674 }
2675
2676 family_ = instr->map_family(); // may be null
2677 if (family_ != NULL) {
2678 // We should have bookmarks to initialize with
2679 ASSERT(instr->bookmarks() > 0);
2680 for (int i=0;i<instr->bookmarks();i++) {
2681 TransitionElementsBookmark* tr = instr->bookmark(i);
2682 from_elements_.Add(tr->elementskind_from());
2683 to_ = *(tr->to_pointer()->location());
2684 }
2685 }
2686 }
2687
2688 void Initialize(HPhi* phi, int maximum_graph_id, Zone* zone) {
2689 visited_set_ = new(zone) BitVector(maximum_graph_id, zone);
2690 }
2691
2692 bool Merge(ResolutionTableValue* from_value) {
2693
2694 // a) Poison must always be imbibed
2695 if (from_value->poisoned() && !poisoned()) {
2696 poisoned_ = true;
2697 return true;
2698 }
2699
2700 // b) from_value has no information. No change.
2701 if (from_value->to() == NULL) {
2702 return false;
2703 }
2704
2705 // c) We are uninitialized. Copy from_value.
2706 ASSERT(from_value->family() != NULL);
2707 if (to() == NULL) {
2708 to_ = from_value->to();
2709 from_elements_.Add(from_value->from_set());
2710 family_ = from_value->family();
2711 return true;
2712 }
2713
2714 // d) We are both initialized. Negotiate
2715 if (from_value->family() != family()) {
2716 // We cannot change families!
2717 poisoned_ = true;
2718 return true;
2719 }
2720
2721 bool changed = false;
2722 if (to() != from_value->to()) {
2723 // figure out unified map
2724 ElementsKind unified_elements_kind = GetUnifiedFastElementsKind(
2725 to()->elements_kind(),
2726 from_value->to()->elements_kind());
2727 // make sure both maps have a path to success
2728 Map* unified_map = to()->LookupElementsTransitionMap(unified_elements_kind );
2729 Map* unified_from_value_map = from_value->to()->LookupElementsTransitionMa p(unified_elements_kind);
2730 if (unified_map == NULL || unified_from_value_map == NULL ||
2731 (unified_map != unified_from_value_map)) {
2732 // impossible
2733 poisoned_ = true;
2734 return true;
2735 }
2736
2737 // TODO(mvstanton): on merges "down" the tree from roots back to load/stor e sites,
2738 // we know we already did the unification step above, and that the current ResolutionTableValue
2739 // should just accept the from.to_ map. Is it worth adding something like "mergemode"
2740 // to save the trouble of the calls above?
2741 to_ = unified_map;
2742 changed = true;
2743 }
2744
2745 if (!(from_set() == from_value->from_set())) {
2746 from_elements_.Add(from_value->from_set());
2747 changed = true;
2748 }
2749
2750 return changed;
2751 }
2752
2753 bool VisitedBy(HValue* value) {
2754 return visited_set_->Contains(value->id());
2755 }
2756
2757 void MarkVisitedBy(HValue* value) {
2758 visited_set_->Add(value->id());
2759 }
2760
2761 InstructionPlacer* placer() { return placer_; }
2762 void set_placer(InstructionPlacer* placer) { placer_ = placer; }
2763 private:
2764 Map* to_;
2765 Map* family_;
2766 bool poisoned_;
2767 ElementsKindSet from_elements_;
2768 InstructionPlacer* placer_; // Field only used for root nodes
2769 BitVector* visited_set_; // only used by phi nodes
2770 };
2771
2772
2773 class ResolutionTable BASE_EMBEDDED {
2774 public:
2775 explicit ResolutionTable(Isolate* isolate, Zone* zone) :
2776 dictionary_(NodeMatch, 32, ZoneAllocationPolicy(zone)),
2777 zone_(zone) {
2778 }
2779
2780 void Insert(HValue* node, ResolutionTableValue* value) {
2781 ZoneHashMap::Entry* entry = dictionary_.Lookup(node,
2782 node->id(),
2783 true,
2784 ZoneAllocationPolicy(zone_));
2785 ASSERT(entry->value == NULL);
2786 entry->value = value;
2787 }
2788
2789 ResolutionTableValue* Lookup(HValue* node) {
2790 ZoneHashMap::Entry* entry = dictionary_.Lookup(node,
2791 node->id(),
2792 false,
2793 ZoneAllocationPolicy(zone_));
2794
2795 if (entry == NULL) {
2796 return NULL;
2797 }
2798
2799 ResolutionTableValue* value =
2800 reinterpret_cast<ResolutionTableValue*>(entry->value);
2801 return value;
2802 }
2803
2804 ZoneHashMap::Entry* Start() {
2805 return dictionary_.Start();
2806 }
2807
2808 inline HValue* KeyFromEntry(ZoneHashMap::Entry* entry) {
2809 return reinterpret_cast<HValue*>(entry->key);
2810 }
2811
2812 inline ResolutionTableValue* ValueFromEntry(ZoneHashMap::Entry* entry) {
2813 return reinterpret_cast<ResolutionTableValue*>(entry->value);
2814 }
2815
2816 ZoneHashMap::Entry* Next(ZoneHashMap::Entry* previous_entry) {
2817 return dictionary_.Next(previous_entry);
2818 }
2819
2820 private:
2821 Zone* zone() { return zone_; }
2822 static bool NodeMatch(void* key1, void* key2) {
2823 return key1 == key2;
2824 }
2825
2826 ZoneHashMap dictionary_;
2827 Zone* zone_;
2828 };
2829
2830
2831 struct WorkItem {
2832 WorkItem(HValue* from_in, HValue* to_in, HValue* context_in)
2833 : from(from_in), to(to_in), context(context_in) {
2834 }
2835 bool operator==(const WorkItem& pair) const {
2836 return pair.from == from && pair.to == to && pair.context == context;
2837 }
2838 HValue* from;
2839 HValue* to;
2840 HValue* context;
2841 };
2842
2843
2844 void HoistTransitionsFromArrayInstructionSites(ArrayInstruction* load_or_store,
2845 ResolutionTableValue* load_or_store_value,
2846 HValue* root,
2847 ResolutionTableValue* root_value,
2848 MapHandleMap* map_handles,
2849 Zone* zone) {
2850
2851 // Are we poisonous? We can't participate in this wonderful scheme...
2852 if (load_or_store_value->poisoned()) {
2853 // Poison should have flowed up and down the graph from sites to roots
2854 ASSERT(root_value->poisoned());
2855 return;
2856 }
2857
2858 // In here we'll
2859 // 1) remove any transition statements from the load_or_store site
2860 // 2) place correct statements at the root site, avoiding duplicates
2861 if (load_or_store->bookmarks() > 0 && root_value->placer() == NULL) {
2862 ASSERT(root->IsInstruction());
2863 root_value->set_placer(new(zone) InstructionPlacer(HInstruction::cast(root),
2864 zone));
2865 }
2866
2867 ASSERT(root_value->to() == load_or_store_value->to());
2868 Handle<Map>& handle = map_handles->Lookup(root_value->to());
2869 InstructionPlacer* placer = root_value->placer();
2870 for (int i = 0; i < load_or_store->bookmarks(); i++) {
2871 TransitionElementsBookmark* bookmark = load_or_store->bookmark(i);
2872
2873 // TODO(mvstanton): lots of asserts in this method that the information
2874 // at the instruction site and the root site are the same or subsets.
2875 // Unnecessary redundancy?
2876 ASSERT(root_value->from_set().Contains(bookmark->elementskind_from()));
2877 ASSERT(load_or_store_value->from_set().Contains(
2878 bookmark->elementskind_from()));
2879
2880 if (placer->RequiresTransitionElementsKind(bookmark->elementskind_from())) {
2881 placer->InsertTransitionElementsKind(bookmark->from(), handle);
2882
2883 if (bookmark->transition_instruction()->block() != NULL) {
2884 // The transition instruction should only be referred to by a map check instruction.
2885 for (HUseIterator it(bookmark->transition_instruction()->uses()); !it.Do ne(); it.Advance()) {
2886 HValue* value = it.value();
2887 ASSERT(value->IsCheckMaps());
2888 HCheckMaps::cast(value)->RemoveTypeCheck();
2889 }
2890
2891 bookmark->transition_instruction()->DeleteAndReplaceWith(NULL);
2892 }
2893 }
2894 }
2895 }
2896
2897
2898 void UpdateMapCheck(HCheckMaps* check_maps,
2899 ResolutionTableValue* nearest_value,
2900 MapHandleMap* map_handles,
2901 Zone* zone) {
2902 // Only manipulate this mapcheck if at least one of the {from,to} maps from
2903 // nearest_value is in the check.
2904 Map* family = nearest_value->family();
2905 Map* to = nearest_value->to();
2906 ASSERT(to != NULL && family != NULL);
2907 bool contains_to = false;
2908 bool contains_from = false;
2909 for (int i = 0; i < check_maps->map_set()->length(); i++) {
2910 Map* current = *(check_maps->map_set()->at(i).location());
2911 if (current != to) {
2912 Map* in_family = map_handles->Lookup(family,
2913 current->elements_kind());
2914 if (current == in_family) {
2915 contains_from = true;
2916 }
2917 } else {
2918 contains_to = true;
2919 }
2920 }
2921
2922 if (!contains_from && !contains_to) {
2923 // This map check deals with a different family. Leave it alone
2924 return;
2925 }
2926
2927 if (!contains_to) {
2928 // We definitely need the to map in the checkmaps instruction
2929 Handle<Map>& handle = map_handles->Lookup(to);
2930 ASSERT(!handle.is_null());
2931 check_maps->map_set()->Add(handle, zone);
2932 }
2933
2934 if (contains_from) {
2935 // The whole from set should be removed from the map check, since we have
2936 // the to map in there.
2937 for (int i = check_maps->map_set()->length() - 1; i >= 0; i--) {
2938 Map* current = *(check_maps->map_set()->at(i).location());
2939 if (current != to) {
2940 Map* in_family = map_handles->Lookup(family,
2941 current->elements_kind());
2942 if (current == in_family) {
2943 // Delete this map
2944 check_maps->map_set()->RemoveAt(i);
2945 }
2946 }
2947 }
2948 }
2949
2950 if (!contains_to) {
2951 // We should sort the map since we added one, removing others
2952 check_maps->map_set()->Sort();
2953 }
2954 }
2955
2956
2957 void HGraph::InsertElementsTransitions() {
2958 ZoneAllocationPolicy allocator(zone());
2959 HPhase phase("H_Place elements transitions", this);
2960
2961 MapHandleMap mapHandleMap(zone());
2962 ResolutionTable table(isolate(),zone());
2963
2964 ZoneList<WorkItem> worklist(10, zone());
2965
2966 // Walk the graph looking for store and load keyed instructions.
2967 for (int i = 0; i < blocks()->length(); ++i) {
2968 for (HInstruction* instr = blocks()->at(i)->first();
2969 instr != NULL;
2970 instr = instr->next()) {
2971 ArrayInstruction* array_instruction = NULL;
2972 if (instr->IsLoadKeyed()) {
2973 HLoadKeyed* op = HLoadKeyed::cast(instr);
2974 array_instruction = static_cast<ArrayInstruction*>(op);
2975 } else if (instr->IsStoreKeyed()) {
2976 HStoreKeyed* op = HStoreKeyed::cast(instr);
2977 array_instruction = static_cast<ArrayInstruction*>(op);
2978 } else {
2979 continue;
2980 }
2981
2982 HValue* elements = array_instruction->elements();
2983 if (elements->IsLoadElements()) {
2984 // Add to our table
2985 ResolutionTableValue* value = new(zone()) ResolutionTableValue();
2986 value->Initialize(array_instruction);
2987 table.Insert(array_instruction, value);
2988
2989 // Add to our handle map
2990 mapHandleMap.Populate(array_instruction);
2991
2992 // Add to our worklist. Here I am skipping over elements,
2993 HLoadElements* start = HLoadElements::cast(elements);
2994 WorkItem item(array_instruction, start->value(), array_instruction);
2995 worklist.Add(item, zone());
2996
2997 if (FLAG_trace_transition_placement) {
2998 HeapStringAllocator string_allocator;
2999 StringStream stream(&string_allocator);
3000 array_instruction->PrintElementPlacementTo(&stream);
3001 PrintF("%s", *stream.ToCString());
3002 }
3003 } else {
3004 // No need to consider external arrays in our case.
3005 ASSERT(IsExternalArrayElementsKind(array_instruction->GetElementsKind()) );
3006 array_instruction->Finalize();
3007 }
3008 }
3009 }
3010
3011 // Propagate information up the graph.
3012 while (!worklist.is_empty()) {
3013 WorkItem item = worklist.RemoveLast();
3014 ASSERT(table.Lookup(item.from) != NULL);
3015 bool changed = false;
3016 ResolutionTableValue* to_value = table.Lookup(item.to);
3017 if (to_value == NULL) {
3018 to_value = new(zone()) ResolutionTableValue();
3019 table.Insert(item.to, to_value);
3020 if (item.to->IsPhi()) {
3021 to_value->Initialize(HPhi::cast(item.to),GetMaximumValueID(), zone());
3022 }
3023 changed = true;
3024 }
3025
3026 changed |= to_value->Merge(table.Lookup(item.from));
3027 if (item.to->IsPhi()) {
3028 if (changed) {
3029 HPhi* phi = HPhi::cast(item.to);
3030 for (int i = 0; i < phi->OperandCount(); i++) {
3031 worklist.Add(WorkItem(phi, phi->OperandAt(i), item.context), zone());
3032 }
3033 }
3034 } else {
3035 // Item.to is a root node. The context is useful to print
3036 if (FLAG_trace_transition_placement) {
3037 HeapStringAllocator string_allocator;
3038 StringStream stream(&string_allocator);
3039 ArrayInstruction* instr = reinterpret_cast<ArrayInstruction*>(item.conte xt);
3040 stream.Add("ARRAY INSTRUCTION: block%d %d: ", instr->block()->block_id() ,
3041 instr->id());
3042 instr->PrintTo(&stream);
3043 stream.Add("\n");
3044 stream.Add(" maps to\n");
3045 HInstruction* root = HInstruction::cast(item.to);
3046 stream.Add(" block%d %d: ", root->block()->block_id(), root->id());
3047 root->PrintNameTo(&stream);
3048 stream.Add(" ");
3049 root->PrintTo(&stream);
3050 stream.Add("\n");
3051 if (to_value->to() != NULL) {
3052 stream.Add(" To: %s(0x%p)\n",
3053 ElementsKindToString(to_value->to()->elements_kind()),
3054 to_value->to());
3055 } else {
3056 stream.Add(" To: n/a\n");
3057 }
3058
3059 PrintF("%s", *stream.ToCString());
3060 }
3061 }
3062 }
3063
3064 // Now propagate information back down to input sites, starting from root
3065 // nodes in the table
3066 // Table contains phi nodes, arrayinstructions, and roots.
3067 ZoneHashMap::Entry* current = table.Start();
3068 while (current != NULL) {
3069 HValue* current_value = table.KeyFromEntry(current);
3070 if (!current_value->IsPhi() && !current_value->IsLoadKeyed() &&
3071 !current_value->IsStoreKeyed()) {
3072 HInstruction* current_instr = HInstruction::cast(current_value);
3073
3074 for (HUseIterator it(current_instr->uses()); !it.Done(); it.Advance()) {
3075 HValue* value = it.value();
3076 if (value->IsPhi()) {
3077 worklist.Add(WorkItem(current_value, value, current_value), zone());
3078 } else if (value->IsLoadElements()) {
3079 // Walk through to the StoreKeyed(s)
3080 for (HUseIterator it_load(value->uses()); !it_load.Done(); it_load.Adv ance()) {
3081 HValue* value_load = it_load.value();
3082 if (value_load->IsStoreKeyed() || value_load->IsLoadKeyed()) {
3083 worklist.Add(WorkItem(current_value, value_load, current_value), z one());
3084 }
3085 }
3086 } else if (value->IsCheckMaps()) {
3087 // CheckMaps don't have rows in the table, as they are periphery instr uctions
3088 // we might need to update.
3089 worklist.Add(WorkItem(current_value, value, current_value), zone());
3090 }
3091 }
3092 }
3093
3094 current = table.Next(current);
3095 }
3096
3097 while (!worklist.is_empty()) {
3098 WorkItem item = worklist.RemoveLast();
3099 /*
3100 PrintF("Downpropagation: (%d,%d,%d)\n",
3101 item.from->id(),
3102 item.to->id(),
3103 item.context->id());
3104 */
3105 bool changed = false;
3106
3107 ResolutionTableValue* from_value = table.Lookup(item.from);
3108 ASSERT(from_value != NULL);
3109 ResolutionTableValue* to_value = table.Lookup(item.to);
3110
3111 if (to_value == NULL && item.to->IsPhi()) {
3112 // We walk through phis on the way down, even if we didn't see
3113 // them on the way up. There may be interesting nodes in these
3114 // new locations (checkmaps, store/loads).
3115 to_value = new(zone()) ResolutionTableValue();
3116 to_value->Initialize(HPhi::cast(item.to), GetMaximumValueID(), zone());
3117 table.Insert(item.to, to_value);
3118 }
3119
3120 if (to_value != NULL) {
3121 changed = to_value->Merge(from_value);
3122 }
3123
3124 if (item.to->IsPhi() && (changed || !to_value->VisitedBy(item.context))) {
3125 to_value->MarkVisitedBy(item.context);
3126
3127 ASSERT(to_value != NULL);
3128 for (HUseIterator it(item.to->uses()); !it.Done(); it.Advance()) {
3129 HValue* value = it.value();
3130 if (value->IsPhi()) {
3131 worklist.Add(WorkItem(item.to, value, item.context), zone());
3132 } else if (value->IsLoadElements()) {
3133 // Walk through to the StoreKeyed(s)
3134 for (HUseIterator it_load(value->uses()); !it_load.Done(); it_load.Adv ance()) {
3135 HValue* value_load = it_load.value();
3136 if (value_load->IsStoreKeyed() || value_load->IsLoadKeyed()) {
3137 worklist.Add(WorkItem(item.to, value_load, item.context), zone());
3138 }
3139 }
3140 } else if (value->IsCheckMaps()) {
3141 worklist.Add(WorkItem(item.to, value, item.context), zone());
3142 }
3143 }
3144 } else if (item.to->IsLoadKeyed() || item.to->IsStoreKeyed()) {
3145 // Either it's the first time we are coming here OR the change is effectiv ely no change
3146 // This is because we begin the graph traversal at ROOT nodes, which have comprehensive
3147 // information. Any edge in the worklist which leads to the array instruct ion will have
3148 // that full information already, so there aren't really any changes at th is point.
3149
3150 ASSERT(to_value != NULL);
3151 ArrayInstruction* array_instruction = reinterpret_cast<ArrayInstruction*>( item.to);
3152 // It can now be finalized
3153 ResolutionTableValue* context_value = table.Lookup(item.context);
3154 ASSERT(context_value != NULL);
3155 if (to_value->to() != NULL) {
3156 array_instruction->Finalize(to_value->to()->elements_kind());
3157 if (array_instruction->bookmarks() > 0) {
3158 // We have work to do here with the context variable.
3159 // It is the root node where we'll move transitions to.
3160 HoistTransitionsFromArrayInstructionSites(array_instruction,
3161 to_value,
3162 item.context,
3163 context_value,
3164 &mapHandleMap,
3165 zone());
3166 }
3167 } else {
3168 // It's possible there is no exchange of typing information for a site.
3169 array_instruction->Finalize();
3170 }
3171 } else if (item.to->IsCheckMaps()) {
3172 // There is no to_value for this case. We just need to try and update the
3173 // checkmaps
3174 ASSERT(to_value == NULL);
3175 if (from_value->to() != NULL) {
3176 UpdateMapCheck(HCheckMaps::cast(item.to), from_value, &mapHandleMap, zon e());
3177 }
3178 }
3179 }
3180
3181 #ifdef DEBUG
3182 // Verify that we didn't miss initialization of any array instructions.
3183 current = table.Start();
3184 while (current != NULL) {
3185 HValue* current_value = table.KeyFromEntry(current);
3186 if (current_value->IsLoadKeyed() || current_value->IsStoreKeyed()) {
3187 ArrayInstruction* array_instr = reinterpret_cast<ArrayInstruction*>(curren t_value);
3188 ASSERT(array_instr->Initialized());
3189 }
3190
3191 current = table.Next(current);
3192 }
3193 #endif // DEBUG
3194 }
3195
3196
2452 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { 3197 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
2453 HValue* current = value; 3198 HValue* current = value;
2454 while (current != NULL) { 3199 while (current != NULL) {
2455 if (visited->Contains(current->id())) return; 3200 if (visited->Contains(current->id())) return;
2456 3201
2457 // For phis, we must propagate the check to all of its inputs. 3202 // For phis, we must propagate the check to all of its inputs.
2458 if (current->IsPhi()) { 3203 if (current->IsPhi()) {
2459 visited->Add(current->id()); 3204 visited->Add(current->id());
2460 HPhi* phi = HPhi::cast(current); 3205 HPhi* phi = HPhi::cast(current);
2461 for (int i = 0; i < phi->OperandCount(); ++i) { 3206 for (int i = 0; i < phi->OperandCount(); ++i) {
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
3267 } 4012 }
3268 EliminateRedundantPhis(); 4013 EliminateRedundantPhis();
3269 if (!CheckArgumentsPhiUses()) { 4014 if (!CheckArgumentsPhiUses()) {
3270 *bailout_reason = SmartArrayPointer<char>(StrDup( 4015 *bailout_reason = SmartArrayPointer<char>(StrDup(
3271 "Unsupported phi use of arguments")); 4016 "Unsupported phi use of arguments"));
3272 return false; 4017 return false;
3273 } 4018 }
3274 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); 4019 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis();
3275 CollectPhis(); 4020 CollectPhis();
3276 4021
4022 if (FLAG_use_place_elements_transitions) InsertElementsTransitions();
4023
3277 if (has_osr_loop_entry()) { 4024 if (has_osr_loop_entry()) {
3278 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); 4025 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
3279 for (int j = 0; j < phis->length(); j++) { 4026 for (int j = 0; j < phis->length(); j++) {
3280 HPhi* phi = phis->at(j); 4027 HPhi* phi = phis->at(j);
3281 osr_values()->at(phi->merged_index())->set_incoming_value(phi); 4028 osr_values()->at(phi->merged_index())->set_incoming_value(phi);
3282 } 4029 }
3283 } 4030 }
3284 4031
3285 HInferRepresentation rep(this); 4032 HInferRepresentation rep(this);
3286 rep.Analyze(); 4033 rep.Analyze();
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
3663 } 4410 }
3664 4411
3665 4412
3666 void HGraph::EliminateRedundantBoundsChecks() { 4413 void HGraph::EliminateRedundantBoundsChecks() {
3667 HPhase phase("H_Eliminate bounds checks", this); 4414 HPhase phase("H_Eliminate bounds checks", this);
3668 BoundsCheckTable checks_table(zone()); 4415 BoundsCheckTable checks_table(zone());
3669 EliminateRedundantBoundsChecks(entry_block(), &checks_table); 4416 EliminateRedundantBoundsChecks(entry_block(), &checks_table);
3670 } 4417 }
3671 4418
3672 4419
3673 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { 4420 static void DehoistArrayIndex(ArrayInstruction* array_operation) {
3674 HValue* index = array_operation->GetKey(); 4421 HValue* index = array_operation->GetKey();
3675 if (!index->representation().IsInteger32()) return; 4422 if (!index->representation().IsInteger32()) return;
3676 4423
3677 HConstant* constant; 4424 HConstant* constant;
3678 HValue* subexpression; 4425 HValue* subexpression;
3679 int32_t sign; 4426 int32_t sign;
3680 if (index->IsAdd()) { 4427 if (index->IsAdd()) {
3681 sign = 1; 4428 sign = 1;
3682 HAdd* add = HAdd::cast(index); 4429 HAdd* add = HAdd::cast(index);
3683 if (add->left()->IsConstant()) { 4430 if (add->left()->IsConstant()) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
3719 4466
3720 4467
3721 void HGraph::DehoistSimpleArrayIndexComputations() { 4468 void HGraph::DehoistSimpleArrayIndexComputations() {
3722 if (!FLAG_array_index_dehoisting) return; 4469 if (!FLAG_array_index_dehoisting) return;
3723 4470
3724 HPhase phase("H_Dehoist index computations", this); 4471 HPhase phase("H_Dehoist index computations", this);
3725 for (int i = 0; i < blocks()->length(); ++i) { 4472 for (int i = 0; i < blocks()->length(); ++i) {
3726 for (HInstruction* instr = blocks()->at(i)->first(); 4473 for (HInstruction* instr = blocks()->at(i)->first();
3727 instr != NULL; 4474 instr != NULL;
3728 instr = instr->next()) { 4475 instr = instr->next()) {
3729 ArrayInstructionInterface* array_instruction = NULL; 4476 ArrayInstruction* array_instruction = NULL;
3730 if (instr->IsLoadKeyed()) { 4477 if (instr->IsLoadKeyed()) {
3731 HLoadKeyed* op = HLoadKeyed::cast(instr); 4478 HLoadKeyed* op = HLoadKeyed::cast(instr);
3732 array_instruction = static_cast<ArrayInstructionInterface*>(op); 4479 array_instruction = static_cast<ArrayInstruction*>(op);
3733 } else if (instr->IsStoreKeyed()) { 4480 } else if (instr->IsStoreKeyed()) {
3734 HStoreKeyed* op = HStoreKeyed::cast(instr); 4481 HStoreKeyed* op = HStoreKeyed::cast(instr);
3735 array_instruction = static_cast<ArrayInstructionInterface*>(op); 4482 array_instruction = static_cast<ArrayInstruction*>(op);
3736 } else { 4483 } else {
3737 continue; 4484 continue;
3738 } 4485 }
3739 DehoistArrayIndex(array_instruction); 4486 DehoistArrayIndex(array_instruction);
3740 } 4487 }
3741 } 4488 }
3742 } 4489 }
3743 4490
3744 4491
3745 void HGraph::DeadCodeElimination() { 4492 void HGraph::DeadCodeElimination() {
(...skipping 824 matching lines...) Expand 10 before | Expand all | Expand 10 after
4570 set_current_block(loop_successor); 5317 set_current_block(loop_successor);
4571 Drop(5); 5318 Drop(5);
4572 5319
4573 set_current_block(loop_body); 5320 set_current_block(loop_body);
4574 5321
4575 HValue* key = AddInstruction( 5322 HValue* key = AddInstruction(
4576 new(zone()) HLoadKeyed( 5323 new(zone()) HLoadKeyed(
4577 environment()->ExpressionStackAt(2), // Enum cache. 5324 environment()->ExpressionStackAt(2), // Enum cache.
4578 environment()->ExpressionStackAt(0), // Iteration index. 5325 environment()->ExpressionStackAt(0), // Iteration index.
4579 environment()->ExpressionStackAt(0), 5326 environment()->ExpressionStackAt(0),
4580 FAST_ELEMENTS)); 5327 FAST_ELEMENTS,
5328 zone()));
4581 5329
4582 // Check if the expected map still matches that of the enumerable. 5330 // Check if the expected map still matches that of the enumerable.
4583 // If not just deoptimize. 5331 // If not just deoptimize.
4584 AddInstruction(new(zone()) HCheckMapValue( 5332 AddInstruction(new(zone()) HCheckMapValue(
4585 environment()->ExpressionStackAt(4), 5333 environment()->ExpressionStackAt(4),
4586 environment()->ExpressionStackAt(3))); 5334 environment()->ExpressionStackAt(3)));
4587 5335
4588 Bind(each_var, key); 5336 Bind(each_var, key);
4589 5337
4590 BreakAndContinueInfo break_info(stmt, 5); 5338 BreakAndContinueInfo break_info(stmt, 5);
(...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after
5183 AddInstruction(new(zone()) HCheckSmi(value)); 5931 AddInstruction(new(zone()) HCheckSmi(value));
5184 // Fall through. 5932 // Fall through.
5185 case FAST_ELEMENTS: 5933 case FAST_ELEMENTS:
5186 case FAST_HOLEY_ELEMENTS: 5934 case FAST_HOLEY_ELEMENTS:
5187 case FAST_DOUBLE_ELEMENTS: 5935 case FAST_DOUBLE_ELEMENTS:
5188 case FAST_HOLEY_DOUBLE_ELEMENTS: 5936 case FAST_HOLEY_DOUBLE_ELEMENTS:
5189 AddInstruction(new(zone()) HStoreKeyed( 5937 AddInstruction(new(zone()) HStoreKeyed(
5190 elements, 5938 elements,
5191 key, 5939 key,
5192 value, 5940 value,
5193 boilerplate_elements_kind)); 5941 boilerplate_elements_kind,
5942 zone()));
5194 break; 5943 break;
5195 default: 5944 default:
5196 UNREACHABLE(); 5945 UNREACHABLE();
5197 break; 5946 break;
5198 } 5947 }
5199 5948
5200 AddSimulate(expr->GetIdForElement(i)); 5949 AddSimulate(expr->GetIdForElement(i));
5201 } 5950 }
5202 return ast_context()->ReturnValue(Pop()); 5951 return ast_context()->ReturnValue(Pop());
5203 } 5952 }
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
6009 } 6758 }
6010 6759
6011 6760
6012 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, 6761 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
6013 HValue* key) { 6762 HValue* key) {
6014 HValue* context = environment()->LookupContext(); 6763 HValue* context = environment()->LookupContext();
6015 return new(zone()) HLoadKeyedGeneric(context, object, key); 6764 return new(zone()) HLoadKeyedGeneric(context, object, key);
6016 } 6765 }
6017 6766
6018 6767
6019 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( 6768 ArrayInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
6020 HValue* external_elements, 6769 HValue* external_elements,
6021 HValue* checked_key, 6770 HValue* checked_key,
6022 HValue* val, 6771 HValue* val,
6023 HValue* dependency, 6772 HValue* dependency,
6024 ElementsKind elements_kind, 6773 ElementsKind elements_kind,
6025 bool is_store) { 6774 bool is_store) {
6026 if (is_store) { 6775 if (is_store) {
6027 ASSERT(val != NULL); 6776 ASSERT(val != NULL);
6028 switch (elements_kind) { 6777 switch (elements_kind) {
6029 case EXTERNAL_PIXEL_ELEMENTS: { 6778 case EXTERNAL_PIXEL_ELEMENTS: {
(...skipping 18 matching lines...) Expand all
6048 case FAST_HOLEY_ELEMENTS: 6797 case FAST_HOLEY_ELEMENTS:
6049 case FAST_HOLEY_DOUBLE_ELEMENTS: 6798 case FAST_HOLEY_DOUBLE_ELEMENTS:
6050 case DICTIONARY_ELEMENTS: 6799 case DICTIONARY_ELEMENTS:
6051 case NON_STRICT_ARGUMENTS_ELEMENTS: 6800 case NON_STRICT_ARGUMENTS_ELEMENTS:
6052 UNREACHABLE(); 6801 UNREACHABLE();
6053 break; 6802 break;
6054 } 6803 }
6055 return new(zone()) HStoreKeyed(external_elements, 6804 return new(zone()) HStoreKeyed(external_elements,
6056 checked_key, 6805 checked_key,
6057 val, 6806 val,
6058 elements_kind); 6807 elements_kind,
6808 zone());
6059 } else { 6809 } else {
6060 ASSERT(val == NULL); 6810 ASSERT(val == NULL);
6061 HLoadKeyed* load = 6811 HLoadKeyed* load =
6062 new(zone()) HLoadKeyed( 6812 new(zone()) HLoadKeyed(
6063 external_elements, checked_key, dependency, elements_kind); 6813 external_elements, checked_key, dependency, elements_kind, zone());
6064 if (FLAG_opt_safe_uint32_operations && 6814 if (FLAG_opt_safe_uint32_operations &&
6065 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { 6815 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
6066 graph()->RecordUint32Instruction(load); 6816 graph()->RecordUint32Instruction(load);
6067 } 6817 }
6068 return load; 6818 return load;
6069 } 6819 }
6070 } 6820 }
6071 6821
6072 6822
6073 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, 6823 ArrayInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
6074 HValue* checked_key, 6824 HValue* checked_key,
6075 HValue* val, 6825 HValue* val,
6076 HValue* load_dependency, 6826 HValue* load_dependency,
6077 ElementsKind elements_kind, 6827 ElementsKind elements_ki nd,
6078 bool is_store) { 6828 bool is_store) {
6079 if (is_store) { 6829 if (is_store) {
6080 ASSERT(val != NULL); 6830 ASSERT(val != NULL);
6081 switch (elements_kind) { 6831 switch (elements_kind) {
6082 case FAST_SMI_ELEMENTS: 6832 case FAST_SMI_ELEMENTS:
6083 case FAST_HOLEY_SMI_ELEMENTS: 6833 case FAST_HOLEY_SMI_ELEMENTS:
6084 // Smi-only arrays need a smi check. 6834 // Smi-only arrays need a smi check.
6085 AddInstruction(new(zone()) HCheckSmi(val)); 6835 AddInstruction(new(zone()) HCheckSmi(val));
6086 // Fall through. 6836 // Fall through.
6087 case FAST_ELEMENTS: 6837 case FAST_ELEMENTS:
6088 case FAST_HOLEY_ELEMENTS: 6838 case FAST_HOLEY_ELEMENTS:
6089 case FAST_DOUBLE_ELEMENTS: 6839 case FAST_DOUBLE_ELEMENTS:
6090 case FAST_HOLEY_DOUBLE_ELEMENTS: 6840 case FAST_HOLEY_DOUBLE_ELEMENTS:
6091 return new(zone()) HStoreKeyed( 6841 return new(zone()) HStoreKeyed(
6092 elements, checked_key, val, elements_kind); 6842 elements, checked_key, val, elements_kind, zone());
6093 default: 6843 default:
6094 UNREACHABLE(); 6844 UNREACHABLE();
6095 return NULL; 6845 return NULL;
6096 } 6846 }
6097 } 6847 }
6098 // It's an element load (!is_store). 6848 // It's an element load (!is_store).
6099 return new(zone()) HLoadKeyed(elements, 6849 return new(zone()) HLoadKeyed(elements,
6100 checked_key, 6850 checked_key,
6101 load_dependency, 6851 load_dependency,
6102 elements_kind); 6852 elements_kind,
6853 zone());
6103 } 6854 }
6104 6855
6105 6856
6106 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, 6857 ArrayInstruction* HGraphBuilder::BuildMonomorphicElementAccess(
6107 HValue* key, 6858 HValue* object,
6108 HValue* val, 6859 HValue* key,
6109 HValue* dependency, 6860 HValue* val,
6110 Handle<Map> map, 6861 HValue* dependency,
6111 bool is_store) { 6862 Handle<Map> map,
6863 bool is_store) {
6112 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, 6864 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map,
6113 zone(), dependency); 6865 zone(), dependency);
6114 AddInstruction(mapcheck); 6866 AddInstruction(mapcheck);
6115 if (dependency) { 6867 if (dependency) {
6116 mapcheck->ClearGVNFlag(kDependsOnElementsKind); 6868 mapcheck->ClearGVNFlag(kDependsOnElementsKind);
6117 } 6869 }
6118 return BuildUncheckedMonomorphicElementAccess(object, key, val, 6870
6119 mapcheck, map, is_store); 6871 ArrayInstruction* instr = BuildUncheckedMonomorphicElementAccess(
6872 object, key, val, mapcheck, map, is_store);
6873 return instr;
6120 } 6874 }
6121 6875
6122 6876
6123 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 6877 ArrayInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
6124 HValue* object, 6878 HValue* object,
6125 HValue* key, 6879 HValue* key,
6126 HValue* val, 6880 HValue* val,
6127 HCheckMaps* mapcheck, 6881 HCheckMaps* mapcheck,
6128 Handle<Map> map, 6882 Handle<Map> map,
6129 bool is_store) { 6883 bool is_store) {
6130 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency 6884 // 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 6885 // 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 6886 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
6133 // ElementsKind transitions. Finally, the dependency can be removed for stores 6887 // ElementsKind transitions. Finally, the dependency can be removed for stores
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
6169 } else { 6923 } else {
6170 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 6924 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6171 } 6925 }
6172 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 6926 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6173 ALLOW_SMI_KEY)); 6927 ALLOW_SMI_KEY));
6174 return BuildFastElementAccess(elements, checked_key, val, mapcheck, 6928 return BuildFastElementAccess(elements, checked_key, val, mapcheck,
6175 map->elements_kind(), is_store); 6929 map->elements_kind(), is_store);
6176 } 6930 }
6177 6931
6178 6932
6179 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( 6933 ArrayInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad(
6180 HValue* object, 6934 HValue* object,
6181 HValue* key, 6935 HValue* key,
6182 HValue* val, 6936 HValue* val,
6183 SmallMapList* maps) { 6937 SmallMapList* maps) {
6184 // For polymorphic loads of similar elements kinds (i.e. all tagged or all 6938 // 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 6939 // double), always use the "worst case" code without a transition. This is
6186 // much faster than transitioning the elements to the worst case, trading a 6940 // much faster than transitioning the elements to the worst case, trading a
6187 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. 6941 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
6188 bool has_double_maps = false; 6942 bool has_double_maps = false;
6189 bool has_smi_or_object_maps = false; 6943 bool has_smi_or_object_maps = false;
(...skipping 26 matching lines...) Expand all
6216 if ((i == 0) || IsMoreGeneralElementsKindTransition( 6970 if ((i == 0) || IsMoreGeneralElementsKindTransition(
6217 most_general_consolidated_map->elements_kind(), 6971 most_general_consolidated_map->elements_kind(),
6218 map->elements_kind())) { 6972 map->elements_kind())) {
6219 most_general_consolidated_map = map; 6973 most_general_consolidated_map = map;
6220 } 6974 }
6221 } 6975 }
6222 if (!has_double_maps && !has_smi_or_object_maps) return NULL; 6976 if (!has_double_maps && !has_smi_or_object_maps) return NULL;
6223 6977
6224 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); 6978 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone());
6225 AddInstruction(check_maps); 6979 AddInstruction(check_maps);
6226 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( 6980 return BuildUncheckedMonomorphicElementAccess(
6227 object, key, val, check_maps, most_general_consolidated_map, false); 6981 object, key, val, check_maps, most_general_consolidated_map, false);
6228 return instr;
6229 } 6982 }
6230 6983
6231 6984
6232 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, 6985 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
6233 HValue* key, 6986 HValue* key,
6234 HValue* val, 6987 HValue* val,
6235 Expression* prop, 6988 Expression* prop,
6236 BailoutId ast_id, 6989 BailoutId ast_id,
6237 int position, 6990 int position,
6238 bool is_store, 6991 bool is_store,
6239 bool* has_side_effects) { 6992 bool* has_side_effects) {
6240 *has_side_effects = false; 6993 *has_side_effects = false;
6241 AddInstruction(new(zone()) HCheckNonSmi(object)); 6994 bool use_groups = FLAG_use_place_elements_transitions;
6995 HCheckNonSmi* checknonsmi = new(zone()) HCheckNonSmi(object);
6996 AddInstruction(checknonsmi);
6242 SmallMapList* maps = prop->GetReceiverTypes(); 6997 SmallMapList* maps = prop->GetReceiverTypes();
6243 bool todo_external_array = false; 6998 bool todo_external_array = false;
6244 6999
6245 if (!is_store) { 7000 if (!is_store) {
6246 HInstruction* consolidated_load = 7001 HInstruction* consolidated_load =
6247 TryBuildConsolidatedElementLoad(object, key, val, maps); 7002 TryBuildConsolidatedElementLoad(object, key, val, maps);
6248 if (consolidated_load != NULL) { 7003 if (consolidated_load != NULL) {
6249 AddInstruction(consolidated_load); 7004 AddInstruction(consolidated_load);
6250 *has_side_effects |= consolidated_load->HasObservableSideEffects(); 7005 *has_side_effects |= consolidated_load->HasObservableSideEffects();
6251 if (position != RelocInfo::kNoPosition) { 7006 if (position != RelocInfo::kNoPosition) {
(...skipping 25 matching lines...) Expand all
6277 for (int i = 0; i < maps->length(); ++i) { 7032 for (int i = 0; i < maps->length(); ++i) {
6278 Handle<Map> map = maps->at(i); 7033 Handle<Map> map = maps->at(i);
6279 Handle<Map> transitioned_map = 7034 Handle<Map> transitioned_map =
6280 map->FindTransitionedMap(&possible_transitioned_maps); 7035 map->FindTransitionedMap(&possible_transitioned_maps);
6281 transition_target.Add(transitioned_map); 7036 transition_target.Add(transitioned_map);
6282 } 7037 }
6283 7038
6284 int num_untransitionable_maps = 0; 7039 int num_untransitionable_maps = 0;
6285 Handle<Map> untransitionable_map; 7040 Handle<Map> untransitionable_map;
6286 HTransitionElementsKind* transition = NULL; 7041 HTransitionElementsKind* transition = NULL;
7042 ZoneList<TransitionElementsBookmark> bookmarks(10, zone());
6287 for (int i = 0; i < maps->length(); ++i) { 7043 for (int i = 0; i < maps->length(); ++i) {
6288 Handle<Map> map = maps->at(i); 7044 Handle<Map> map = maps->at(i);
6289 ASSERT(map->IsMap()); 7045 ASSERT(map->IsMap());
6290 if (!transition_target.at(i).is_null()) { 7046 if (!transition_target.at(i).is_null()) {
6291 ASSERT(Map::IsValidElementsTransition( 7047 ASSERT(Map::IsValidElementsTransition(
6292 map->elements_kind(), 7048 map->elements_kind(),
6293 transition_target.at(i)->elements_kind())); 7049 transition_target.at(i)->elements_kind()));
6294 transition = new(zone()) HTransitionElementsKind( 7050 transition = new(zone()) HTransitionElementsKind(
6295 object, map, transition_target.at(i)); 7051 object, map, transition_target.at(i));
6296 AddInstruction(transition); 7052 AddInstruction(transition);
7053
7054 if (use_groups) {
7055 TransitionElementsBookmark tr(transition,
7056 map,
7057 transition_target.at(i),
7058 isolate());
7059 bookmarks.Add(tr, zone());
7060 }
6297 } else { 7061 } else {
6298 type_todo[map->elements_kind()] = true; 7062 type_todo[map->elements_kind()] = true;
6299 if (IsExternalArrayElementsKind(map->elements_kind())) { 7063 if (IsExternalArrayElementsKind(map->elements_kind())) {
6300 todo_external_array = true; 7064 todo_external_array = true;
6301 } 7065 }
6302 num_untransitionable_maps++; 7066 num_untransitionable_maps++;
6303 untransitionable_map = map; 7067 untransitionable_map = map;
6304 } 7068 }
6305 } 7069 }
6306 7070
6307 // If only one map is left after transitioning, handle this case 7071 // If only one map is left after transitioning, handle this case
6308 // monomorphically. 7072 // monomorphically.
6309 if (num_untransitionable_maps == 1) { 7073 if (num_untransitionable_maps == 1) {
6310 HInstruction* instr = NULL; 7074 HInstruction* instr = NULL;
6311 if (untransitionable_map->has_slow_elements_kind()) { 7075 if (untransitionable_map->has_slow_elements_kind()) {
6312 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) 7076 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
6313 : BuildLoadKeyedGeneric(object, key)); 7077 : BuildLoadKeyedGeneric(object, key));
6314 } else { 7078 } else {
6315 instr = AddInstruction(BuildMonomorphicElementAccess( 7079 ArrayInstruction* array_instr = BuildMonomorphicElementAccess(
6316 object, key, val, transition, untransitionable_map, is_store)); 7080 object, key, val, transition, untransitionable_map, is_store);
7081 instr = AddInstruction(array_instr);
7082 if (use_groups && bookmarks.length() > 0) {
7083 array_instr->AddBookmarks(bookmarks);
7084 }
6317 } 7085 }
6318 *has_side_effects |= instr->HasObservableSideEffects(); 7086 *has_side_effects |= instr->HasObservableSideEffects();
6319 if (position != RelocInfo::kNoPosition) instr->set_position(position); 7087 if (position != RelocInfo::kNoPosition) instr->set_position(position);
6320 return is_store ? NULL : instr; 7088 return is_store ? NULL : instr;
6321 } 7089 }
6322 7090
6323 HInstruction* checkspec = 7091 HInstruction* checkspec =
6324 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); 7092 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone()));
6325 HBasicBlock* join = graph()->CreateBasicBlock(); 7093 HBasicBlock* join = graph()->CreateBasicBlock();
6326 7094
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
6358 HBasicBlock* if_false = graph()->CreateBasicBlock(); 7126 HBasicBlock* if_false = graph()->CreateBasicBlock();
6359 HCompareConstantEqAndBranch* elements_kind_branch = 7127 HCompareConstantEqAndBranch* elements_kind_branch =
6360 new(zone()) HCompareConstantEqAndBranch( 7128 new(zone()) HCompareConstantEqAndBranch(
6361 elements_kind_instr, elements_kind, Token::EQ_STRICT); 7129 elements_kind_instr, elements_kind, Token::EQ_STRICT);
6362 elements_kind_branch->SetSuccessorAt(0, if_true); 7130 elements_kind_branch->SetSuccessorAt(0, if_true);
6363 elements_kind_branch->SetSuccessorAt(1, if_false); 7131 elements_kind_branch->SetSuccessorAt(1, if_false);
6364 current_block()->Finish(elements_kind_branch); 7132 current_block()->Finish(elements_kind_branch);
6365 7133
6366 set_current_block(if_true); 7134 set_current_block(if_true);
6367 HInstruction* access; 7135 HInstruction* access;
7136 HCheckMaps* checkmaps = NULL;
6368 if (IsFastElementsKind(elements_kind)) { 7137 if (IsFastElementsKind(elements_kind)) {
6369 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { 7138 if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
6370 AddInstruction(new(zone()) HCheckMaps( 7139 checkmaps = new(zone()) HCheckMaps(
6371 elements, isolate()->factory()->fixed_array_map(), 7140 elements, isolate()->factory()->fixed_array_map(),
6372 zone(), elements_kind_branch)); 7141 zone(), elements_kind_branch);
7142 AddInstruction(checkmaps);
6373 } 7143 }
6374 // TODO(jkummerow): The need for these two blocks could be avoided 7144 // TODO(jkummerow): The need for these two blocks could be avoided
6375 // in one of two ways: 7145 // in one of two ways:
6376 // (1) Introduce ElementsKinds for JSArrays that are distinct from 7146 // (1) Introduce ElementsKinds for JSArrays that are distinct from
6377 // those for fast objects. 7147 // those for fast objects.
6378 // (2) Put the common instructions into a third "join" block. This 7148 // (2) Put the common instructions into a third "join" block. This
6379 // requires additional AST IDs that we can deopt to from inside 7149 // requires additional AST IDs that we can deopt to from inside
6380 // that join block. They must be added to the Property class (when 7150 // that join block. They must be added to the Property class (when
6381 // it's a keyed property) and registered in the full codegen. 7151 // it's a keyed property) and registered in the full codegen.
6382 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); 7152 HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
6383 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); 7153 HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
6384 HHasInstanceTypeAndBranch* typecheck = 7154 HHasInstanceTypeAndBranch* typecheck =
6385 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); 7155 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
6386 typecheck->SetSuccessorAt(0, if_jsarray); 7156 typecheck->SetSuccessorAt(0, if_jsarray);
6387 typecheck->SetSuccessorAt(1, if_fastobject); 7157 typecheck->SetSuccessorAt(1, if_fastobject);
6388 current_block()->Finish(typecheck); 7158 current_block()->Finish(typecheck);
6389 7159
6390 set_current_block(if_jsarray); 7160 set_current_block(if_jsarray);
6391 HInstruction* length; 7161 HInstruction* length;
6392 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, 7162 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
6393 HType::Smi())); 7163 HType::Smi()));
6394 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7164 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6395 ALLOW_SMI_KEY)); 7165 ALLOW_SMI_KEY));
6396 access = AddInstruction(BuildFastElementAccess( 7166 ArrayInstruction* array_instruction = BuildFastElementAccess(
6397 elements, checked_key, val, elements_kind_branch, 7167 elements, checked_key, val, elements_kind_branch,
6398 elements_kind, is_store)); 7168 elements_kind, is_store);
7169 array_instruction->set_hoistable(false);
7170
7171 access = AddInstruction(array_instruction);
6399 if (!is_store) { 7172 if (!is_store) {
6400 Push(access); 7173 Push(access);
6401 } 7174 }
6402 7175
6403 *has_side_effects |= access->HasObservableSideEffects(); 7176 *has_side_effects |= access->HasObservableSideEffects();
6404 if (position != -1) { 7177 if (position != -1) {
6405 access->set_position(position); 7178 access->set_position(position);
6406 } 7179 }
6407 if_jsarray->Goto(join); 7180 if_jsarray->Goto(join);
6408 7181
6409 set_current_block(if_fastobject); 7182 set_current_block(if_fastobject);
6410 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 7183 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6411 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7184 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6412 ALLOW_SMI_KEY)); 7185 ALLOW_SMI_KEY));
6413 access = AddInstruction(BuildFastElementAccess( 7186 array_instruction = BuildFastElementAccess(
6414 elements, checked_key, val, elements_kind_branch, 7187 elements, checked_key, val, elements_kind_branch,
6415 elements_kind, is_store)); 7188 elements_kind, is_store);
7189 array_instruction->set_hoistable(false);
7190 access = AddInstruction(array_instruction);
6416 } else if (elements_kind == DICTIONARY_ELEMENTS) { 7191 } else if (elements_kind == DICTIONARY_ELEMENTS) {
6417 if (is_store) { 7192 if (is_store) {
6418 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); 7193 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
6419 } else { 7194 } else {
6420 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); 7195 access = AddInstruction(BuildLoadKeyedGeneric(object, key));
6421 } 7196 }
6422 } else { // External array elements. 7197 } else { // External array elements.
6423 access = AddInstruction(BuildExternalArrayElementAccess( 7198 access = AddInstruction(BuildExternalArrayElementAccess(
6424 external_elements, checked_key, val, elements_kind_branch, 7199 external_elements, checked_key, val, elements_kind_branch,
6425 elements_kind, is_store)); 7200 elements_kind, is_store));
6426 } 7201 }
6427 *has_side_effects |= access->HasObservableSideEffects(); 7202 *has_side_effects |= access->HasObservableSideEffects();
6428 if (position != RelocInfo::kNoPosition) access->set_position(position); 7203 if (position != RelocInfo::kNoPosition) access->set_position(position);
6429 if (!is_store) { 7204 if (!is_store) {
6430 Push(access); 7205 Push(access);
6431 } 7206 }
7207
6432 current_block()->Goto(join); 7208 current_block()->Goto(join);
6433 set_current_block(if_false); 7209 set_current_block(if_false);
6434 } 7210 }
6435 } 7211 }
6436 7212
6437 // Deopt if none of the cases matched. 7213 // Deopt if none of the cases matched.
6438 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); 7214 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
6439 join->SetJoinId(ast_id); 7215 join->SetJoinId(ast_id);
6440 set_current_block(join); 7216 set_current_block(join);
6441 return is_store ? NULL : Pop(); 7217 return is_store ? NULL : Pop();
(...skipping 1097 matching lines...) Expand 10 before | Expand all | Expand 10 after
7539 ast_context()->ReturnInstruction(call, expr->id()); 8315 ast_context()->ReturnInstruction(call, expr->id());
7540 return true; 8316 return true;
7541 } 8317 }
7542 } 8318 }
7543 8319
7544 8320
7545 // Checks if all maps in |types| are from the same family, i.e., are elements 8321 // Checks if all maps in |types| are from the same family, i.e., are elements
7546 // transitions of each other. Returns either NULL if they are not from the same 8322 // transitions of each other. Returns either NULL if they are not from the same
7547 // family, or a Map* indicating the map with the first elements kind of the 8323 // family, or a Map* indicating the map with the first elements kind of the
7548 // family that is in the list. 8324 // family that is in the list.
8325
8326 //
8327 // TODO(mvstanton) - can I use this function?
8328 //
7549 static Map* CheckSameElementsFamily(SmallMapList* types) { 8329 static Map* CheckSameElementsFamily(SmallMapList* types) {
7550 if (types->length() <= 1) return NULL; 8330 if (types->length() <= 1) return NULL;
7551 // Check if all maps belong to the same transition family. 8331 // Check if all maps belong to the same transition family.
7552 Map* kinds[kFastElementsKindCount]; 8332 Map* kinds[kFastElementsKindCount];
7553 Map* first_map = *types->first(); 8333 Map* first_map = *types->first();
7554 ElementsKind first_kind = first_map->elements_kind(); 8334 ElementsKind first_kind = first_map->elements_kind();
7555 if (!IsFastElementsKind(first_kind)) return NULL; 8335 if (!IsFastElementsKind(first_kind)) return NULL;
7556 int first_index = GetSequenceIndexFromFastElementsKind(first_kind); 8336 int first_index = GetSequenceIndexFromFastElementsKind(first_kind);
7557 int last_index = first_index; 8337 int last_index = first_index;
7558 8338
(...skipping 2209 matching lines...) Expand 10 before | Expand all | Expand 10 after
9768 10548
9769 10549
9770 void HEnvironment::PrintToStd() { 10550 void HEnvironment::PrintToStd() {
9771 HeapStringAllocator string_allocator; 10551 HeapStringAllocator string_allocator;
9772 StringStream trace(&string_allocator); 10552 StringStream trace(&string_allocator);
9773 PrintTo(&trace); 10553 PrintTo(&trace);
9774 PrintF("%s", *trace.ToCString()); 10554 PrintF("%s", *trace.ToCString());
9775 } 10555 }
9776 10556
9777 10557
10558
10559
10560
10561
9778 void HTracer::TraceCompilation(FunctionLiteral* function) { 10562 void HTracer::TraceCompilation(FunctionLiteral* function) {
9779 Tag tag(this, "compilation"); 10563 Tag tag(this, "compilation");
9780 Handle<String> name = function->debug_name(); 10564 Handle<String> name = function->debug_name();
9781 PrintStringProperty("name", *name->ToCString()); 10565 PrintStringProperty("name", *name->ToCString());
9782 PrintStringProperty("method", *name->ToCString()); 10566 PrintStringProperty("method", *name->ToCString());
9783 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); 10567 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
9784 } 10568 }
9785 10569
9786 10570
9787 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 10571 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
10101 } 10885 }
10102 } 10886 }
10103 10887
10104 #ifdef DEBUG 10888 #ifdef DEBUG
10105 if (graph_ != NULL) graph_->Verify(false); // No full verify. 10889 if (graph_ != NULL) graph_->Verify(false); // No full verify.
10106 if (allocator_ != NULL) allocator_->Verify(); 10890 if (allocator_ != NULL) allocator_->Verify();
10107 #endif 10891 #endif
10108 } 10892 }
10109 10893
10110 } } // namespace v8::internal 10894 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | src/hydrogen-instructions.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698