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

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: Now have instruction writing, map check updating. 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
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 {
danno 2012/11/28 14:42:10 How about this idea. Just have a single table that
mvstanton 2012/12/04 11:39:58 Done.
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) {
danno 2012/11/28 14:42:10 I kind of think that the methods to handle ArrayIn
mvstanton 2012/12/04 11:39:58 Done.
2488 for (int r = 0; r < instruction->bookmarks(); r++) {
2489 Add(instruction->bookmark(r));
2490 }
2491 }
2492
2493 private:
2494 struct IndexKey {
2495 IndexKey(Map* family_in, ElementsKind kind_in) :
2496 family(family_in),
2497 kind(kind_in) {
2498 }
2499
2500 bool operator==(const IndexKey& pair) const {
2501 return pair.family == family && pair.kind == kind;
2502 }
2503
2504 int Hash() {
2505 return family->Hash() ^ (17*static_cast<int>(kind));
2506 }
2507
2508 Map* family;
2509 ElementsKind kind;
2510 };
2511
2512 static bool MapPointerMatch(void* key1, void* key2) {
2513 return key1 == key2;
2514 }
2515
2516 static bool IndexMatch(void* key1, void* key2) {
2517 IndexKey* k1 = reinterpret_cast<IndexKey*>(key1);
2518 IndexKey* k2 = reinterpret_cast<IndexKey*>(key2);
2519 return *k1 == *k2;
2520 }
2521
2522 void Add(TransitionElementsBookmark* record) {
2523 Handle<Map>* family = record->family_pointer();
2524 InsertIfMissing(record->from_pointer(), family);
2525 InsertIfMissing(record->to_pointer(), family);
2526 InsertIfMissing(record->pessimistic_holey_pointer(), family);
2527 }
2528
2529 void Insert(Handle<Map>* handle, Handle<Map>* family) {
2530 MapHandleTable::Iterator i = map_.find(*(handle->location()), true,
danno 2012/11/28 14:42:10 here and below: doesn't *handle return a Map°, you
mvstanton 2012/12/04 11:39:58 Done.
2531 ZoneAllocationPolicy(zone_));
2532 ASSERT(i != map_.end());
2533 i->second = handle;
2534
2535 IndexKeyTable::Iterator iki = indexer_.find(
2536 new(zone()) IndexKey(*(family->location()),(*handle)->elements_kind()), true,
2537 ZoneAllocationPolicy(zone_));
2538 ASSERT(iki != indexer_.end());
2539 iki->second = *(family->location());
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) {
danno 2012/11/28 14:42:10 add_after
mvstanton 2012/12/04 11:39:58 Done.
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)) {
danno 2012/11/28 14:42:10 Wow. How can this happen? Don't you just visit eac
mvstanton 2012/12/04 11:39:58 Note that the iterator starts at last_in_chain_->u
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()) {
danno 2012/11/28 14:42:10 You mentioned that you copied this magic from some
mvstanton 2012/12/04 11:39:58 Done.
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 bool Merge(ResolutionTableValue* from_value) {
2689 if (from_value->poisoned() && !poisoned()) {
2690 poisoned_ = true;
2691 return true;
2692 }
2693
2694 if (family() != NULL && from_value->family() != family()) {
2695 poisoned_ = true;
2696 return true;
2697 }
2698
2699 bool changed = false;
2700 family_ = from_value->family();
2701 if (to() == NULL) {
2702 to_ = from_value->to();
2703 changed = true;
2704 } else if (to() != from_value->to()) {
2705 // figure out unified map
2706 ElementsKind unified_elements_kind = GetUnifiedFastElementsKind(
2707 to()->elements_kind(),
2708 from_value->to()->elements_kind());
2709 // make sure both maps have a path to success
2710 Map* unified_map = to()->LookupElementsTransitionMap(unified_elements_kind );
danno 2012/11/28 14:42:10 This won't be GC-safe if we're running concurrent
mvstanton 2012/12/04 11:39:58 Done.
2711 Map* unified_from_value_map = from_value->to()->LookupElementsTransitionMa p(unified_elements_kind);
danno 2012/11/28 14:42:10 Same here.
mvstanton 2012/12/04 11:39:58 Done.
2712 if (unified_map == NULL || unified_from_value_map == NULL ||
2713 (unified_map != unified_from_value_map)) {
2714 // impossible
2715 poisoned_ = true;
2716 return false;
2717 }
2718
2719 changed = true;
2720 }
2721
2722 if (!(from_set() == from_value->from_set())) {
2723 from_elements_.Add(from_value->from_set());
2724 changed = true;
2725 }
2726
2727 return changed;
2728 }
2729
2730 InstructionPlacer* placer() { return placer_; }
2731 void set_placer(InstructionPlacer* placer) { placer_ = placer; }
2732 private:
2733 Map* to_;
danno 2012/11/28 14:42:10 Can these be Handles?
2734 Map* family_;
2735 bool poisoned_;
2736 ElementsKindSet from_elements_;
2737 InstructionPlacer* placer_; // Field only used for root nodes
2738 };
2739
2740
2741 class ResolutionTable BASE_EMBEDDED {
2742 public:
2743 explicit ResolutionTable(Isolate* isolate, Zone* zone) :
2744 dictionary_(NodeMatch, 32, ZoneAllocationPolicy(zone)),
2745 zone_(zone) {
2746 }
2747
2748 void Insert(HValue* node, ResolutionTableValue* value) {
2749 ZoneHashMap::Entry* entry = dictionary_.Lookup(node,
2750 node->id(),
2751 true,
2752 ZoneAllocationPolicy(zone_));
2753 ASSERT(entry->value == NULL);
2754 entry->value = value;
2755 }
2756
2757 ResolutionTableValue* Lookup(HValue* node) {
2758 ZoneHashMap::Entry* entry = dictionary_.Lookup(node,
2759 node->id(),
2760 false,
2761 ZoneAllocationPolicy(zone_));
2762
2763 if (entry == NULL) {
2764 return NULL;
2765 }
2766
2767 ResolutionTableValue* value =
2768 reinterpret_cast<ResolutionTableValue*>(entry->value);
2769 return value;
2770 }
2771
2772 ZoneHashMap::Entry* Start() {
2773 return dictionary_.Start();
2774 }
2775
2776 inline HValue* KeyFromEntry(ZoneHashMap::Entry* entry) {
2777 return reinterpret_cast<HValue*>(entry->key);
2778 }
2779
2780 inline ResolutionTableValue* ValueFromEntry(ZoneHashMap::Entry* entry) {
2781 return reinterpret_cast<ResolutionTableValue*>(entry->value);
2782 }
2783
2784 ZoneHashMap::Entry* Next(ZoneHashMap::Entry* previous_entry) {
2785 return dictionary_.Next(previous_entry);
2786 }
2787
2788 private:
2789 Zone* zone() { return zone_; }
2790 static bool NodeMatch(void* key1, void* key2) {
2791 return key1 == key2;
2792 }
2793
2794 ZoneHashMap dictionary_;
2795 Zone* zone_;
2796 };
2797
2798
2799 struct WorkItem {
2800 WorkItem(HValue* from_in, HValue* to_in, HValue* context_in)
2801 : from(from_in), to(to_in), context(context_in) {
2802 }
2803 bool operator==(const WorkItem& pair) const {
2804 return pair.from == from && pair.to == to && pair.context == context;
2805 }
2806 HValue* from;
2807 HValue* to;
2808 HValue* context;
2809 };
2810
2811
2812 void HoistTransitionsFromArrayInstructionSites(ArrayInstruction* load_or_store,
danno 2012/11/28 14:42:10 If you make all of these methods inside of a HInse
mvstanton 2012/12/04 11:39:58 I solved it a little differently, moving the metho
2813 ResolutionTableValue* load_or_store_value,
2814 HValue* root,
2815 ResolutionTableValue* root_value,
2816 MapHandleMap* map_handles,
2817 Zone* zone) {
2818
2819 // Are we poisonous? We can't participate in this wonderful scheme...
2820 if (load_or_store_value->poisoned()) {
2821 // Poison should have flowed up and down the graph from sites to roots
2822 ASSERT(root_value->poisoned());
2823 return;
2824 }
danno 2012/11/28 14:42:10 if (load_or_store->bookmarks() == 0) return; avoi
mvstanton 2012/12/04 11:39:58 Done.
2825
2826 // In here we'll
2827 // 1) remove any transition statements from the load_or_store site
2828 // 2) place correct statements at the root site, avoiding duplicates
2829 if (load_or_store->bookmarks() > 0 && root_value->placer() == NULL) {
2830 ASSERT(root->IsInstruction());
2831 root_value->set_placer(new(zone) InstructionPlacer(HInstruction::cast(root),
2832 zone));
2833 }
2834
2835 ASSERT(root_value->to() == load_or_store_value->to());
2836 Handle<Map>& handle = map_handles->Lookup(root_value->to());
2837 InstructionPlacer* placer = root_value->placer();
2838 for (int i = 0; i < load_or_store->bookmarks(); i++) {
2839 TransitionElementsBookmark* bookmark = load_or_store->bookmark(i);
2840
2841 // TODO(mvstanton): lots of asserts in this method that the information
2842 // at the instruction site and the root site are the same or subsets.
2843 // Unnecessary redundancy?
2844 ASSERT(root_value->from_set().Contains(bookmark->elementskind_from()));
2845 ASSERT(load_or_store_value->from_set().Contains(
2846 bookmark->elementskind_from()));
2847
2848 if (placer->RequiresTransitionElementsKind(bookmark->elementskind_from())) {
2849 placer->InsertTransitionElementsKind(bookmark->from(), handle);
2850
2851 if (bookmark->transition_instruction()->block() != NULL) {
2852 ASSERT(bookmark->transition_instruction()->HasNoUses());
2853 bookmark->transition_instruction()->DeleteAndReplaceWith(NULL);
2854 }
2855 }
2856 }
2857 }
2858
2859
2860 void UpdateMapCheck(HCheckMaps* check_maps,
2861 ResolutionTableValue* nearest_value,
2862 MapHandleMap* map_handles,
2863 Zone* zone) {
2864 // Only manipulate this mapcheck if at least one of the {from,to} maps from
2865 // nearest_value is in the check.
2866 Map* family = nearest_value->family();
2867 Map* to = nearest_value->to();
2868 bool contains_to = false;
2869 bool contains_from = false;
2870 for (int i = 0; i < check_maps->map_set()->length(); i++) {
2871 Map* current = *(check_maps->map_set()->at(i).location());
2872 if (current != to) {
2873 Map* in_family = map_handles->Lookup(family,
2874 current->elements_kind());
2875 if (current == in_family) {
2876 contains_from = true;
2877 }
2878 } else {
2879 contains_to = true;
2880 }
2881 }
2882
2883 if (!contains_from && !contains_to) {
2884 // This map check deals with a different family. Leave it alone
2885 return;
2886 }
2887
2888 if (!contains_to) {
2889 // We definitely need the to map in the checkmaps instruction
2890 Handle<Map>& handle = map_handles->Lookup(to);
2891 ASSERT(!handle.is_null());
2892 check_maps->map_set()->Add(handle, zone);
2893 }
2894
2895 if (contains_from) {
2896 // The whole from set should be removed from the map check, since we have
2897 // the to map in there.
2898 for (int i = check_maps->map_set()->length() - 1; i >= 0; i--) {
2899 Map* current = *(check_maps->map_set()->at(i).location());
2900 if (current != to) {
2901 Map* in_family = map_handles->Lookup(family,
2902 current->elements_kind());
2903 if (current == in_family) {
2904 // Delete this map
2905 Handle<Map>& handle = map_handles->Lookup(current);
2906 ASSERT(!handle.is_null());
2907 check_maps->map_set()->Remove(handle);
2908 }
2909 }
2910 }
2911 }
2912
2913 if (!contains_to) {
2914 // We should sort the map since we added one, removing others
2915 check_maps->map_set()->Sort();
2916 }
2917 }
2918
2919
2920 void HGraph::InsertElementsTransitions() {
2921 ZoneAllocationPolicy allocator(zone());
2922 HPhase phase("H_Place elements transitions", this);
2923
2924 MapHandleMap mapHandleMap(zone());
2925 ResolutionTable table(isolate(),zone());
2926
2927 ZoneList<WorkItem> worklist(10, zone());
2928
2929 // Walk the graph looking for store and load keyed instructions.
danno 2012/11/28 14:42:10 I think it would be better if you build the list o
mvstanton 2012/12/04 11:39:58 Done.
2930 for (int i = 0; i < blocks()->length(); ++i) {
2931 for (HInstruction* instr = blocks()->at(i)->first();
2932 instr != NULL;
2933 instr = instr->next()) {
2934 ArrayInstruction* array_instruction = NULL;
2935 if (instr->IsLoadKeyed()) {
2936 HLoadKeyed* op = HLoadKeyed::cast(instr);
2937 array_instruction = static_cast<ArrayInstruction*>(op);
2938 } else if (instr->IsStoreKeyed()) {
2939 HStoreKeyed* op = HStoreKeyed::cast(instr);
2940 array_instruction = static_cast<ArrayInstruction*>(op);
2941 } else {
2942 continue;
2943 }
2944
2945 // Add to our table
2946 ResolutionTableValue* value = new(zone()) ResolutionTableValue();
2947 value->Initialize(array_instruction);
2948 table.Insert(array_instruction, value);
2949
2950 // Add to our handle map
2951 mapHandleMap.Populate(array_instruction);
2952
2953 // Add to our worklist. Here I am skipping over elements,
2954 HValue* elements = array_instruction->elements();
2955 ASSERT(elements->IsLoadElements());
2956 HLoadElements* start = HLoadElements::cast(elements);
2957 WorkItem item(array_instruction, start->value(), NULL);
2958 worklist.Add(item, zone());
2959 }
2960 }
2961
2962 // Propagate information up the graph.
2963 while (!worklist.is_empty()) {
2964 WorkItem item = worklist.RemoveLast();
2965 ASSERT(table.Lookup(item.from) != NULL);
2966 bool changed = false;
2967 ResolutionTableValue* to_value = table.Lookup(item.to);
2968 if (to_value == NULL) {
2969 to_value = new(zone()) ResolutionTableValue();
2970 table.Insert(item.to, to_value);
2971 changed = true;
2972 }
2973
2974 changed |= to_value->Merge(table.Lookup(item.from));
2975 if (item.to->IsPhi() && changed) {
2976 HPhi* phi = HPhi::cast(item.to);
2977 for (int i = 0; i < phi->OperandCount(); i++) {
2978 worklist.Add(WorkItem(phi, phi->OperandAt(i), NULL), zone());
2979 }
2980 }
2981 }
2982
2983 // Now propagate information back down to input sites, starting from root
danno 2012/11/28 14:42:10 root... do you mean transition input candidates?
2984 // nodes in the table
2985 // Table contains phi nodes, arrayinstructions, and roots.
2986 ZoneHashMap::Entry* current = table.Start();
2987 while (current != NULL) {
2988 HValue* current_value = table.KeyFromEntry(current);
2989 if (!current_value->IsPhi() && !current_value->IsLoadKeyed() &&
danno 2012/11/28 14:42:10 Would things get easier if you had a up_worklist a
mvstanton 2012/12/04 11:39:58 Done.
2990 !current_value->IsStoreKeyed()) {
2991 HInstruction* current_instr = HInstruction::cast(current_value);
2992
2993 for (HUseIterator it(current_instr->uses()); !it.Done(); it.Advance()) {
2994 HValue* value = it.value();
2995 if (value->IsPhi()) {
2996 worklist.Add(WorkItem(current_value, value, current_value), zone());
2997 } else if (value->IsLoadElements()) {
2998 // Walk through to the StoreKeyed(s)
2999 for (HUseIterator it_load(value->uses()); !it_load.Done(); it_load.Adv ance()) {
3000 HValue* value_load = it_load.value();
3001 if (value_load->IsStoreKeyed() || value_load->IsLoadKeyed()) {
3002 worklist.Add(WorkItem(current_value, value_load, current_value), z one());
3003 }
3004 }
3005 } else if (value->IsCheckMaps()) {
3006 // CheckMaps don't have rows in the table, as they are periphery instr uctions
3007 // we might need to update.
3008 worklist.Add(WorkItem(current_value, value, current_value), zone());
danno 2012/11/28 14:42:10 Is it wrong to call UpdateMapCheck here directly?
mvstanton 2012/12/04 11:39:58 We could get away with that. I was thinking though
3009 }
3010 }
3011 }
3012
3013 current = table.Next(current);
3014 }
3015
3016 BitVector visited(GetMaximumValueID(), zone());
3017 while (!worklist.is_empty()) {
3018 WorkItem item = worklist.RemoveLast();
3019 ASSERT(table.Lookup(item.from) != NULL);
3020 bool changed = false;
3021 ResolutionTableValue* from_value = table.Lookup(item.from);
3022 ResolutionTableValue* to_value = table.Lookup(item.to);
3023 if (to_value != NULL) {
3024 changed = to_value->Merge(from_value);
3025 }
3026
3027 if (item.to->IsPhi() &&
3028 (changed || !visited.Contains(item.to->id()))) {
3029 visited.Add(item.to->id());
3030
3031 ASSERT(to_value != NULL);
3032 for (HUseIterator it(item.to->uses()); !it.Done(); it.Advance()) {
3033 HValue* value = it.value();
3034 if (value->IsPhi()) {
3035 worklist.Add(WorkItem(item.to, value, item.context), zone());
3036 } else if (value->IsLoadElements()) {
3037 // Walk through to the StoreKeyed(s)
3038 for (HUseIterator it_load(value->uses()); !it_load.Done(); it_load.Adv ance()) {
3039 HValue* value_load = it_load.value();
3040 if (value_load->IsStoreKeyed() || value_load->IsLoadKeyed()) {
3041 worklist.Add(WorkItem(item.to, value_load, item.context), zone());
3042 }
3043 }
3044 }
3045 }
3046 } else if (item.to->IsLoadKeyed() || item.to->IsStoreKeyed()) {
3047 ASSERT(to_value != NULL);
3048 // It can now be finalized
3049 ArrayInstruction* array_instruction = reinterpret_cast<ArrayInstruction*>( item.to);
3050 if (to_value->to() != NULL) {
danno 2012/11/28 14:42:10 Can you move this and the Finalize in the NULL cas
mvstanton 2012/12/04 11:39:58 Done.
3051 array_instruction->Finalize(to_value->to()->elements_kind());
3052 if (array_instruction->bookmarks() > 0) {
3053 // We have work to do here with the context variable.
3054 // It is the root node where we'll move transitions to.
3055 ResolutionTableValue* context_value = table.Lookup(item.context);
3056 ASSERT(context_value != NULL);
3057 HoistTransitionsFromArrayInstructionSites(array_instruction,
3058 to_value,
3059 item.context,
3060 context_value,
3061 &mapHandleMap,
3062 zone());
3063 }
3064 } else {
3065 // It's possible there is no exchange of typing information for a site.
3066 array_instruction->Finalize();
3067 }
3068 } else if (item.to->IsCheckMaps()) {
3069 // There is no to_value for this case. We just need to try and update the
3070 // checkmaps
3071 ASSERT(to_value == NULL);
3072 UpdateMapCheck(HCheckMaps::cast(item.to), from_value, &mapHandleMap, zone( ));
3073 }
3074 }
3075
3076 #ifdef DEBUG
3077 // Verify that we didn't miss initialization of any array instructions.
3078 current = table.Start();
3079 while (current != NULL) {
3080 HValue* current_value = table.KeyFromEntry(current);
3081 if (current_value->IsLoadKeyed() || current_value->IsStoreKeyed()) {
3082 ArrayInstruction* array_instr = reinterpret_cast<ArrayInstruction*>(curren t_value);
3083 ASSERT(array_instr->Initialized());
3084 }
3085
3086 current = table.Next(current);
3087 }
3088 #endif // DEBUG
3089
3090 // Now the table actually has enough information to make decisions.
3091 if (FLAG_trace_transition_placement) {
3092 HeapStringAllocator string_allocator;
3093 StringStream stream(&string_allocator);
3094
3095 // print the table
3096 ZoneHashMap::Entry* current = table.Start();
3097 while (current != NULL) {
3098 HValue* current_value = table.KeyFromEntry(current);
3099 ResolutionTableValue* value = table.ValueFromEntry(current);
3100
3101 if (current_value->IsLoadKeyed() || current_value->IsStoreKeyed()) {
3102 ArrayInstruction* array_instruction = reinterpret_cast<ArrayInstruction* >(current_value);
3103 array_instruction->PrintElementPlacementTo(&stream);
3104 stream.Add(" Here is what we need to do\n");
3105 if (value->to() != NULL) {
3106 stream.Add(" To: %s\n", ElementsKindToString(value->to()->elements_ki nd()));
3107 } else {
3108 stream.Add(" No instructions\n");
3109 }
3110 }
3111 current = table.Next(current);
3112 }
3113
3114 PrintF("%s", *stream.ToCString());
3115 }
3116 }
3117
3118
2452 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { 3119 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
2453 HValue* current = value; 3120 HValue* current = value;
2454 while (current != NULL) { 3121 while (current != NULL) {
2455 if (visited->Contains(current->id())) return; 3122 if (visited->Contains(current->id())) return;
2456 3123
2457 // For phis, we must propagate the check to all of its inputs. 3124 // For phis, we must propagate the check to all of its inputs.
2458 if (current->IsPhi()) { 3125 if (current->IsPhi()) {
2459 visited->Add(current->id()); 3126 visited->Add(current->id());
2460 HPhi* phi = HPhi::cast(current); 3127 HPhi* phi = HPhi::cast(current);
2461 for (int i = 0; i < phi->OperandCount(); ++i) { 3128 for (int i = 0; i < phi->OperandCount(); ++i) {
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
3267 } 3934 }
3268 EliminateRedundantPhis(); 3935 EliminateRedundantPhis();
3269 if (!CheckArgumentsPhiUses()) { 3936 if (!CheckArgumentsPhiUses()) {
3270 *bailout_reason = SmartArrayPointer<char>(StrDup( 3937 *bailout_reason = SmartArrayPointer<char>(StrDup(
3271 "Unsupported phi use of arguments")); 3938 "Unsupported phi use of arguments"));
3272 return false; 3939 return false;
3273 } 3940 }
3274 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); 3941 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis();
3275 CollectPhis(); 3942 CollectPhis();
3276 3943
3944 if (FLAG_use_place_elements_transitions) InsertElementsTransitions();
3945
3277 if (has_osr_loop_entry()) { 3946 if (has_osr_loop_entry()) {
3278 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); 3947 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
3279 for (int j = 0; j < phis->length(); j++) { 3948 for (int j = 0; j < phis->length(); j++) {
3280 HPhi* phi = phis->at(j); 3949 HPhi* phi = phis->at(j);
3281 osr_values()->at(phi->merged_index())->set_incoming_value(phi); 3950 osr_values()->at(phi->merged_index())->set_incoming_value(phi);
3282 } 3951 }
3283 } 3952 }
3284 3953
3285 HInferRepresentation rep(this); 3954 HInferRepresentation rep(this);
3286 rep.Analyze(); 3955 rep.Analyze();
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
3663 } 4332 }
3664 4333
3665 4334
3666 void HGraph::EliminateRedundantBoundsChecks() { 4335 void HGraph::EliminateRedundantBoundsChecks() {
3667 HPhase phase("H_Eliminate bounds checks", this); 4336 HPhase phase("H_Eliminate bounds checks", this);
3668 BoundsCheckTable checks_table(zone()); 4337 BoundsCheckTable checks_table(zone());
3669 EliminateRedundantBoundsChecks(entry_block(), &checks_table); 4338 EliminateRedundantBoundsChecks(entry_block(), &checks_table);
3670 } 4339 }
3671 4340
3672 4341
3673 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { 4342 static void DehoistArrayIndex(ArrayInstruction* array_operation) {
3674 HValue* index = array_operation->GetKey(); 4343 HValue* index = array_operation->GetKey();
3675 if (!index->representation().IsInteger32()) return; 4344 if (!index->representation().IsInteger32()) return;
3676 4345
3677 HConstant* constant; 4346 HConstant* constant;
3678 HValue* subexpression; 4347 HValue* subexpression;
3679 int32_t sign; 4348 int32_t sign;
3680 if (index->IsAdd()) { 4349 if (index->IsAdd()) {
3681 sign = 1; 4350 sign = 1;
3682 HAdd* add = HAdd::cast(index); 4351 HAdd* add = HAdd::cast(index);
3683 if (add->left()->IsConstant()) { 4352 if (add->left()->IsConstant()) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
3719 4388
3720 4389
3721 void HGraph::DehoistSimpleArrayIndexComputations() { 4390 void HGraph::DehoistSimpleArrayIndexComputations() {
3722 if (!FLAG_array_index_dehoisting) return; 4391 if (!FLAG_array_index_dehoisting) return;
3723 4392
3724 HPhase phase("H_Dehoist index computations", this); 4393 HPhase phase("H_Dehoist index computations", this);
3725 for (int i = 0; i < blocks()->length(); ++i) { 4394 for (int i = 0; i < blocks()->length(); ++i) {
3726 for (HInstruction* instr = blocks()->at(i)->first(); 4395 for (HInstruction* instr = blocks()->at(i)->first();
3727 instr != NULL; 4396 instr != NULL;
3728 instr = instr->next()) { 4397 instr = instr->next()) {
3729 ArrayInstructionInterface* array_instruction = NULL; 4398 ArrayInstruction* array_instruction = NULL;
3730 if (instr->IsLoadKeyed()) { 4399 if (instr->IsLoadKeyed()) {
3731 HLoadKeyed* op = HLoadKeyed::cast(instr); 4400 HLoadKeyed* op = HLoadKeyed::cast(instr);
3732 array_instruction = static_cast<ArrayInstructionInterface*>(op); 4401 array_instruction = static_cast<ArrayInstruction*>(op);
3733 } else if (instr->IsStoreKeyed()) { 4402 } else if (instr->IsStoreKeyed()) {
3734 HStoreKeyed* op = HStoreKeyed::cast(instr); 4403 HStoreKeyed* op = HStoreKeyed::cast(instr);
3735 array_instruction = static_cast<ArrayInstructionInterface*>(op); 4404 array_instruction = static_cast<ArrayInstruction*>(op);
3736 } else { 4405 } else {
3737 continue; 4406 continue;
3738 } 4407 }
3739 DehoistArrayIndex(array_instruction); 4408 DehoistArrayIndex(array_instruction);
3740 } 4409 }
3741 } 4410 }
3742 } 4411 }
3743 4412
3744 4413
3745 void HGraph::DeadCodeElimination() { 4414 void HGraph::DeadCodeElimination() {
(...skipping 824 matching lines...) Expand 10 before | Expand all | Expand 10 after
4570 set_current_block(loop_successor); 5239 set_current_block(loop_successor);
4571 Drop(5); 5240 Drop(5);
4572 5241
4573 set_current_block(loop_body); 5242 set_current_block(loop_body);
4574 5243
4575 HValue* key = AddInstruction( 5244 HValue* key = AddInstruction(
4576 new(zone()) HLoadKeyed( 5245 new(zone()) HLoadKeyed(
4577 environment()->ExpressionStackAt(2), // Enum cache. 5246 environment()->ExpressionStackAt(2), // Enum cache.
4578 environment()->ExpressionStackAt(0), // Iteration index. 5247 environment()->ExpressionStackAt(0), // Iteration index.
4579 environment()->ExpressionStackAt(0), 5248 environment()->ExpressionStackAt(0),
4580 FAST_ELEMENTS)); 5249 FAST_ELEMENTS,
5250 zone()));
4581 5251
4582 // Check if the expected map still matches that of the enumerable. 5252 // Check if the expected map still matches that of the enumerable.
4583 // If not just deoptimize. 5253 // If not just deoptimize.
4584 AddInstruction(new(zone()) HCheckMapValue( 5254 AddInstruction(new(zone()) HCheckMapValue(
4585 environment()->ExpressionStackAt(4), 5255 environment()->ExpressionStackAt(4),
4586 environment()->ExpressionStackAt(3))); 5256 environment()->ExpressionStackAt(3)));
4587 5257
4588 Bind(each_var, key); 5258 Bind(each_var, key);
4589 5259
4590 BreakAndContinueInfo break_info(stmt, 5); 5260 BreakAndContinueInfo break_info(stmt, 5);
(...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after
5183 AddInstruction(new(zone()) HCheckSmi(value)); 5853 AddInstruction(new(zone()) HCheckSmi(value));
5184 // Fall through. 5854 // Fall through.
5185 case FAST_ELEMENTS: 5855 case FAST_ELEMENTS:
5186 case FAST_HOLEY_ELEMENTS: 5856 case FAST_HOLEY_ELEMENTS:
5187 case FAST_DOUBLE_ELEMENTS: 5857 case FAST_DOUBLE_ELEMENTS:
5188 case FAST_HOLEY_DOUBLE_ELEMENTS: 5858 case FAST_HOLEY_DOUBLE_ELEMENTS:
5189 AddInstruction(new(zone()) HStoreKeyed( 5859 AddInstruction(new(zone()) HStoreKeyed(
5190 elements, 5860 elements,
5191 key, 5861 key,
5192 value, 5862 value,
5193 boilerplate_elements_kind)); 5863 boilerplate_elements_kind,
5864 zone()));
5194 break; 5865 break;
5195 default: 5866 default:
5196 UNREACHABLE(); 5867 UNREACHABLE();
5197 break; 5868 break;
5198 } 5869 }
5199 5870
5200 AddSimulate(expr->GetIdForElement(i)); 5871 AddSimulate(expr->GetIdForElement(i));
5201 } 5872 }
5202 return ast_context()->ReturnValue(Pop()); 5873 return ast_context()->ReturnValue(Pop());
5203 } 5874 }
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
6009 } 6680 }
6010 6681
6011 6682
6012 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, 6683 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
6013 HValue* key) { 6684 HValue* key) {
6014 HValue* context = environment()->LookupContext(); 6685 HValue* context = environment()->LookupContext();
6015 return new(zone()) HLoadKeyedGeneric(context, object, key); 6686 return new(zone()) HLoadKeyedGeneric(context, object, key);
6016 } 6687 }
6017 6688
6018 6689
6019 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( 6690 ArrayInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
6020 HValue* external_elements, 6691 HValue* external_elements,
6021 HValue* checked_key, 6692 HValue* checked_key,
6022 HValue* val, 6693 HValue* val,
6023 HValue* dependency, 6694 HValue* dependency,
6024 ElementsKind elements_kind, 6695 ElementsKind elements_kind,
6025 bool is_store) { 6696 bool is_store) {
6026 if (is_store) { 6697 if (is_store) {
6027 ASSERT(val != NULL); 6698 ASSERT(val != NULL);
6028 switch (elements_kind) { 6699 switch (elements_kind) {
6029 case EXTERNAL_PIXEL_ELEMENTS: { 6700 case EXTERNAL_PIXEL_ELEMENTS: {
(...skipping 18 matching lines...) Expand all
6048 case FAST_HOLEY_ELEMENTS: 6719 case FAST_HOLEY_ELEMENTS:
6049 case FAST_HOLEY_DOUBLE_ELEMENTS: 6720 case FAST_HOLEY_DOUBLE_ELEMENTS:
6050 case DICTIONARY_ELEMENTS: 6721 case DICTIONARY_ELEMENTS:
6051 case NON_STRICT_ARGUMENTS_ELEMENTS: 6722 case NON_STRICT_ARGUMENTS_ELEMENTS:
6052 UNREACHABLE(); 6723 UNREACHABLE();
6053 break; 6724 break;
6054 } 6725 }
6055 return new(zone()) HStoreKeyed(external_elements, 6726 return new(zone()) HStoreKeyed(external_elements,
6056 checked_key, 6727 checked_key,
6057 val, 6728 val,
6058 elements_kind); 6729 elements_kind,
6730 zone());
6059 } else { 6731 } else {
6060 ASSERT(val == NULL); 6732 ASSERT(val == NULL);
6061 HLoadKeyed* load = 6733 HLoadKeyed* load =
6062 new(zone()) HLoadKeyed( 6734 new(zone()) HLoadKeyed(
6063 external_elements, checked_key, dependency, elements_kind); 6735 external_elements, checked_key, dependency, elements_kind, zone());
6064 if (FLAG_opt_safe_uint32_operations && 6736 if (FLAG_opt_safe_uint32_operations &&
6065 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { 6737 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
6066 graph()->RecordUint32Instruction(load); 6738 graph()->RecordUint32Instruction(load);
6067 } 6739 }
6068 return load; 6740 return load;
6069 } 6741 }
6070 } 6742 }
6071 6743
6072 6744
6073 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, 6745 ArrayInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
6074 HValue* checked_key, 6746 HValue* checked_key,
6075 HValue* val, 6747 HValue* val,
6076 HValue* load_dependency, 6748 HValue* load_dependency,
6077 ElementsKind elements_kind, 6749 ElementsKind elements_ki nd,
6078 bool is_store) { 6750 bool is_store) {
6079 if (is_store) { 6751 if (is_store) {
6080 ASSERT(val != NULL); 6752 ASSERT(val != NULL);
6081 switch (elements_kind) { 6753 switch (elements_kind) {
6082 case FAST_SMI_ELEMENTS: 6754 case FAST_SMI_ELEMENTS:
6083 case FAST_HOLEY_SMI_ELEMENTS: 6755 case FAST_HOLEY_SMI_ELEMENTS:
6084 // Smi-only arrays need a smi check. 6756 // Smi-only arrays need a smi check.
6085 AddInstruction(new(zone()) HCheckSmi(val)); 6757 AddInstruction(new(zone()) HCheckSmi(val));
6086 // Fall through. 6758 // Fall through.
6087 case FAST_ELEMENTS: 6759 case FAST_ELEMENTS:
6088 case FAST_HOLEY_ELEMENTS: 6760 case FAST_HOLEY_ELEMENTS:
6089 case FAST_DOUBLE_ELEMENTS: 6761 case FAST_DOUBLE_ELEMENTS:
6090 case FAST_HOLEY_DOUBLE_ELEMENTS: 6762 case FAST_HOLEY_DOUBLE_ELEMENTS:
6091 return new(zone()) HStoreKeyed( 6763 return new(zone()) HStoreKeyed(
6092 elements, checked_key, val, elements_kind); 6764 elements, checked_key, val, elements_kind, zone());
6093 default: 6765 default:
6094 UNREACHABLE(); 6766 UNREACHABLE();
6095 return NULL; 6767 return NULL;
6096 } 6768 }
6097 } 6769 }
6098 // It's an element load (!is_store). 6770 // It's an element load (!is_store).
6099 return new(zone()) HLoadKeyed(elements, 6771 return new(zone()) HLoadKeyed(elements,
6100 checked_key, 6772 checked_key,
6101 load_dependency, 6773 load_dependency,
6102 elements_kind); 6774 elements_kind,
6775 zone());
6103 } 6776 }
6104 6777
6105 6778
6106 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, 6779 ArrayInstruction* HGraphBuilder::BuildMonomorphicElementAccess(
6107 HValue* key, 6780 HValue* object,
6108 HValue* val, 6781 HValue* key,
6109 HValue* dependency, 6782 HValue* val,
6110 Handle<Map> map, 6783 HValue* dependency,
6111 bool is_store) { 6784 Handle<Map> map,
6785 bool is_store) {
6112 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, 6786 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map,
6113 zone(), dependency); 6787 zone(), dependency);
6114 AddInstruction(mapcheck); 6788 AddInstruction(mapcheck);
6115 if (dependency) { 6789 if (dependency) {
6116 mapcheck->ClearGVNFlag(kDependsOnElementsKind); 6790 mapcheck->ClearGVNFlag(kDependsOnElementsKind);
6117 } 6791 }
6118 return BuildUncheckedMonomorphicElementAccess(object, key, val, 6792
6119 mapcheck, map, is_store); 6793 ArrayInstruction* instr = BuildUncheckedMonomorphicElementAccess(
6794 object, key, val, mapcheck, map, is_store);
6795 return instr;
6120 } 6796 }
6121 6797
6122 6798
6123 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 6799 ArrayInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
6124 HValue* object, 6800 HValue* object,
6125 HValue* key, 6801 HValue* key,
6126 HValue* val, 6802 HValue* val,
6127 HCheckMaps* mapcheck, 6803 HCheckMaps* mapcheck,
6128 Handle<Map> map, 6804 Handle<Map> map,
6129 bool is_store) { 6805 bool is_store) {
6130 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency 6806 // 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 6807 // 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 6808 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
6133 // ElementsKind transitions. Finally, the dependency can be removed for stores 6809 // ElementsKind transitions. Finally, the dependency can be removed for stores
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
6169 } else { 6845 } else {
6170 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 6846 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6171 } 6847 }
6172 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 6848 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6173 ALLOW_SMI_KEY)); 6849 ALLOW_SMI_KEY));
6174 return BuildFastElementAccess(elements, checked_key, val, mapcheck, 6850 return BuildFastElementAccess(elements, checked_key, val, mapcheck,
6175 map->elements_kind(), is_store); 6851 map->elements_kind(), is_store);
6176 } 6852 }
6177 6853
6178 6854
6179 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( 6855 ArrayInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad(
6180 HValue* object, 6856 HValue* object,
6181 HValue* key, 6857 HValue* key,
6182 HValue* val, 6858 HValue* val,
6183 SmallMapList* maps) { 6859 SmallMapList* maps) {
6184 // For polymorphic loads of similar elements kinds (i.e. all tagged or all 6860 // 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 6861 // 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 6862 // much faster than transitioning the elements to the worst case, trading a
6187 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. 6863 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
6188 bool has_double_maps = false; 6864 bool has_double_maps = false;
6189 bool has_smi_or_object_maps = false; 6865 bool has_smi_or_object_maps = false;
(...skipping 26 matching lines...) Expand all
6216 if ((i == 0) || IsMoreGeneralElementsKindTransition( 6892 if ((i == 0) || IsMoreGeneralElementsKindTransition(
6217 most_general_consolidated_map->elements_kind(), 6893 most_general_consolidated_map->elements_kind(),
6218 map->elements_kind())) { 6894 map->elements_kind())) {
6219 most_general_consolidated_map = map; 6895 most_general_consolidated_map = map;
6220 } 6896 }
6221 } 6897 }
6222 if (!has_double_maps && !has_smi_or_object_maps) return NULL; 6898 if (!has_double_maps && !has_smi_or_object_maps) return NULL;
6223 6899
6224 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); 6900 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone());
6225 AddInstruction(check_maps); 6901 AddInstruction(check_maps);
6226 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( 6902 return BuildUncheckedMonomorphicElementAccess(
6227 object, key, val, check_maps, most_general_consolidated_map, false); 6903 object, key, val, check_maps, most_general_consolidated_map, false);
6228 return instr;
6229 } 6904 }
6230 6905
6231 6906
6232 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, 6907 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
6233 HValue* key, 6908 HValue* key,
6234 HValue* val, 6909 HValue* val,
6235 Expression* prop, 6910 Expression* prop,
6236 BailoutId ast_id, 6911 BailoutId ast_id,
6237 int position, 6912 int position,
6238 bool is_store, 6913 bool is_store,
6239 bool* has_side_effects) { 6914 bool* has_side_effects) {
6240 *has_side_effects = false; 6915 *has_side_effects = false;
6241 AddInstruction(new(zone()) HCheckNonSmi(object)); 6916 bool use_groups = FLAG_use_place_elements_transitions;
6917 HCheckNonSmi* checknonsmi = new(zone()) HCheckNonSmi(object);
6918 AddInstruction(checknonsmi);
6242 SmallMapList* maps = prop->GetReceiverTypes(); 6919 SmallMapList* maps = prop->GetReceiverTypes();
6243 bool todo_external_array = false; 6920 bool todo_external_array = false;
6244 6921
6245 if (!is_store) { 6922 if (!is_store) {
6246 HInstruction* consolidated_load = 6923 HInstruction* consolidated_load =
6247 TryBuildConsolidatedElementLoad(object, key, val, maps); 6924 TryBuildConsolidatedElementLoad(object, key, val, maps);
6248 if (consolidated_load != NULL) { 6925 if (consolidated_load != NULL) {
6249 AddInstruction(consolidated_load); 6926 AddInstruction(consolidated_load);
6250 *has_side_effects |= consolidated_load->HasObservableSideEffects(); 6927 *has_side_effects |= consolidated_load->HasObservableSideEffects();
6251 if (position != RelocInfo::kNoPosition) { 6928 if (position != RelocInfo::kNoPosition) {
(...skipping 25 matching lines...) Expand all
6277 for (int i = 0; i < maps->length(); ++i) { 6954 for (int i = 0; i < maps->length(); ++i) {
6278 Handle<Map> map = maps->at(i); 6955 Handle<Map> map = maps->at(i);
6279 Handle<Map> transitioned_map = 6956 Handle<Map> transitioned_map =
6280 map->FindTransitionedMap(&possible_transitioned_maps); 6957 map->FindTransitionedMap(&possible_transitioned_maps);
6281 transition_target.Add(transitioned_map); 6958 transition_target.Add(transitioned_map);
6282 } 6959 }
6283 6960
6284 int num_untransitionable_maps = 0; 6961 int num_untransitionable_maps = 0;
6285 Handle<Map> untransitionable_map; 6962 Handle<Map> untransitionable_map;
6286 HTransitionElementsKind* transition = NULL; 6963 HTransitionElementsKind* transition = NULL;
6964 ZoneList<TransitionElementsBookmark> bookmarks(10, zone());
6287 for (int i = 0; i < maps->length(); ++i) { 6965 for (int i = 0; i < maps->length(); ++i) {
6288 Handle<Map> map = maps->at(i); 6966 Handle<Map> map = maps->at(i);
6289 ASSERT(map->IsMap()); 6967 ASSERT(map->IsMap());
6290 if (!transition_target.at(i).is_null()) { 6968 if (!transition_target.at(i).is_null()) {
6291 ASSERT(Map::IsValidElementsTransition( 6969 ASSERT(Map::IsValidElementsTransition(
6292 map->elements_kind(), 6970 map->elements_kind(),
6293 transition_target.at(i)->elements_kind())); 6971 transition_target.at(i)->elements_kind()));
6294 transition = new(zone()) HTransitionElementsKind( 6972 transition = new(zone()) HTransitionElementsKind(
6295 object, map, transition_target.at(i)); 6973 object, map, transition_target.at(i));
6296 AddInstruction(transition); 6974 AddInstruction(transition);
6975
6976 if (use_groups) {
6977 TransitionElementsBookmark tr(transition,
6978 map,
6979 transition_target.at(i),
6980 isolate());
6981 bookmarks.Add(tr, zone());
6982 }
6297 } else { 6983 } else {
6298 type_todo[map->elements_kind()] = true; 6984 type_todo[map->elements_kind()] = true;
6299 if (IsExternalArrayElementsKind(map->elements_kind())) { 6985 if (IsExternalArrayElementsKind(map->elements_kind())) {
6300 todo_external_array = true; 6986 todo_external_array = true;
6301 } 6987 }
6302 num_untransitionable_maps++; 6988 num_untransitionable_maps++;
6303 untransitionable_map = map; 6989 untransitionable_map = map;
6304 } 6990 }
6305 } 6991 }
6306 6992
6307 // If only one map is left after transitioning, handle this case 6993 // If only one map is left after transitioning, handle this case
6308 // monomorphically. 6994 // monomorphically.
6309 if (num_untransitionable_maps == 1) { 6995 if (num_untransitionable_maps == 1) {
6310 HInstruction* instr = NULL; 6996 HInstruction* instr = NULL;
6311 if (untransitionable_map->has_slow_elements_kind()) { 6997 if (untransitionable_map->has_slow_elements_kind()) {
6312 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) 6998 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
6313 : BuildLoadKeyedGeneric(object, key)); 6999 : BuildLoadKeyedGeneric(object, key));
6314 } else { 7000 } else {
6315 instr = AddInstruction(BuildMonomorphicElementAccess( 7001 ArrayInstruction* array_instr = BuildMonomorphicElementAccess(
6316 object, key, val, transition, untransitionable_map, is_store)); 7002 object, key, val, transition, untransitionable_map, is_store);
7003 instr = AddInstruction(array_instr);
7004 if (use_groups && bookmarks.length() > 0) {
7005 array_instr->AddBookmarks(bookmarks);
7006 }
6317 } 7007 }
6318 *has_side_effects |= instr->HasObservableSideEffects(); 7008 *has_side_effects |= instr->HasObservableSideEffects();
6319 if (position != RelocInfo::kNoPosition) instr->set_position(position); 7009 if (position != RelocInfo::kNoPosition) instr->set_position(position);
6320 return is_store ? NULL : instr; 7010 return is_store ? NULL : instr;
6321 } 7011 }
6322 7012
6323 HInstruction* checkspec = 7013 HInstruction* checkspec =
6324 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); 7014 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone()));
6325 HBasicBlock* join = graph()->CreateBasicBlock(); 7015 HBasicBlock* join = graph()->CreateBasicBlock();
6326 7016
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
6358 HBasicBlock* if_false = graph()->CreateBasicBlock(); 7048 HBasicBlock* if_false = graph()->CreateBasicBlock();
6359 HCompareConstantEqAndBranch* elements_kind_branch = 7049 HCompareConstantEqAndBranch* elements_kind_branch =
6360 new(zone()) HCompareConstantEqAndBranch( 7050 new(zone()) HCompareConstantEqAndBranch(
6361 elements_kind_instr, elements_kind, Token::EQ_STRICT); 7051 elements_kind_instr, elements_kind, Token::EQ_STRICT);
6362 elements_kind_branch->SetSuccessorAt(0, if_true); 7052 elements_kind_branch->SetSuccessorAt(0, if_true);
6363 elements_kind_branch->SetSuccessorAt(1, if_false); 7053 elements_kind_branch->SetSuccessorAt(1, if_false);
6364 current_block()->Finish(elements_kind_branch); 7054 current_block()->Finish(elements_kind_branch);
6365 7055
6366 set_current_block(if_true); 7056 set_current_block(if_true);
6367 HInstruction* access; 7057 HInstruction* access;
7058 HCheckMaps* checkmaps = NULL;
6368 if (IsFastElementsKind(elements_kind)) { 7059 if (IsFastElementsKind(elements_kind)) {
6369 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { 7060 if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
6370 AddInstruction(new(zone()) HCheckMaps( 7061 checkmaps = new(zone()) HCheckMaps(
6371 elements, isolate()->factory()->fixed_array_map(), 7062 elements, isolate()->factory()->fixed_array_map(),
6372 zone(), elements_kind_branch)); 7063 zone(), elements_kind_branch);
7064 AddInstruction(checkmaps);
6373 } 7065 }
6374 // TODO(jkummerow): The need for these two blocks could be avoided 7066 // TODO(jkummerow): The need for these two blocks could be avoided
6375 // in one of two ways: 7067 // in one of two ways:
6376 // (1) Introduce ElementsKinds for JSArrays that are distinct from 7068 // (1) Introduce ElementsKinds for JSArrays that are distinct from
6377 // those for fast objects. 7069 // those for fast objects.
6378 // (2) Put the common instructions into a third "join" block. This 7070 // (2) Put the common instructions into a third "join" block. This
6379 // requires additional AST IDs that we can deopt to from inside 7071 // requires additional AST IDs that we can deopt to from inside
6380 // that join block. They must be added to the Property class (when 7072 // that join block. They must be added to the Property class (when
6381 // it's a keyed property) and registered in the full codegen. 7073 // it's a keyed property) and registered in the full codegen.
6382 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); 7074 HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
6383 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); 7075 HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
6384 HHasInstanceTypeAndBranch* typecheck = 7076 HHasInstanceTypeAndBranch* typecheck =
6385 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); 7077 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
6386 typecheck->SetSuccessorAt(0, if_jsarray); 7078 typecheck->SetSuccessorAt(0, if_jsarray);
6387 typecheck->SetSuccessorAt(1, if_fastobject); 7079 typecheck->SetSuccessorAt(1, if_fastobject);
6388 current_block()->Finish(typecheck); 7080 current_block()->Finish(typecheck);
6389 7081
6390 set_current_block(if_jsarray); 7082 set_current_block(if_jsarray);
6391 HInstruction* length; 7083 HInstruction* length;
6392 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, 7084 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
6393 HType::Smi())); 7085 HType::Smi()));
6394 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7086 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6395 ALLOW_SMI_KEY)); 7087 ALLOW_SMI_KEY));
6396 access = AddInstruction(BuildFastElementAccess( 7088 ArrayInstruction* array_instruction = BuildFastElementAccess(
6397 elements, checked_key, val, elements_kind_branch, 7089 elements, checked_key, val, elements_kind_branch,
6398 elements_kind, is_store)); 7090 elements_kind, is_store);
7091 array_instruction->set_hoistable(false);
7092
7093 access = AddInstruction(array_instruction);
6399 if (!is_store) { 7094 if (!is_store) {
6400 Push(access); 7095 Push(access);
6401 } 7096 }
6402 7097
6403 *has_side_effects |= access->HasObservableSideEffects(); 7098 *has_side_effects |= access->HasObservableSideEffects();
6404 if (position != -1) { 7099 if (position != -1) {
6405 access->set_position(position); 7100 access->set_position(position);
6406 } 7101 }
6407 if_jsarray->Goto(join); 7102 if_jsarray->Goto(join);
6408 7103
6409 set_current_block(if_fastobject); 7104 set_current_block(if_fastobject);
6410 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 7105 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6411 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7106 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6412 ALLOW_SMI_KEY)); 7107 ALLOW_SMI_KEY));
6413 access = AddInstruction(BuildFastElementAccess( 7108 array_instruction = BuildFastElementAccess(
6414 elements, checked_key, val, elements_kind_branch, 7109 elements, checked_key, val, elements_kind_branch,
6415 elements_kind, is_store)); 7110 elements_kind, is_store);
7111 array_instruction->set_hoistable(false);
7112 access = AddInstruction(array_instruction);
6416 } else if (elements_kind == DICTIONARY_ELEMENTS) { 7113 } else if (elements_kind == DICTIONARY_ELEMENTS) {
6417 if (is_store) { 7114 if (is_store) {
6418 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); 7115 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
6419 } else { 7116 } else {
6420 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); 7117 access = AddInstruction(BuildLoadKeyedGeneric(object, key));
6421 } 7118 }
6422 } else { // External array elements. 7119 } else { // External array elements.
6423 access = AddInstruction(BuildExternalArrayElementAccess( 7120 access = AddInstruction(BuildExternalArrayElementAccess(
6424 external_elements, checked_key, val, elements_kind_branch, 7121 external_elements, checked_key, val, elements_kind_branch,
6425 elements_kind, is_store)); 7122 elements_kind, is_store));
6426 } 7123 }
6427 *has_side_effects |= access->HasObservableSideEffects(); 7124 *has_side_effects |= access->HasObservableSideEffects();
6428 if (position != RelocInfo::kNoPosition) access->set_position(position); 7125 if (position != RelocInfo::kNoPosition) access->set_position(position);
6429 if (!is_store) { 7126 if (!is_store) {
6430 Push(access); 7127 Push(access);
6431 } 7128 }
7129
6432 current_block()->Goto(join); 7130 current_block()->Goto(join);
6433 set_current_block(if_false); 7131 set_current_block(if_false);
6434 } 7132 }
6435 } 7133 }
6436 7134
6437 // Deopt if none of the cases matched. 7135 // Deopt if none of the cases matched.
6438 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); 7136 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
6439 join->SetJoinId(ast_id); 7137 join->SetJoinId(ast_id);
6440 set_current_block(join); 7138 set_current_block(join);
6441 return is_store ? NULL : Pop(); 7139 return is_store ? NULL : Pop();
(...skipping 1097 matching lines...) Expand 10 before | Expand all | Expand 10 after
7539 ast_context()->ReturnInstruction(call, expr->id()); 8237 ast_context()->ReturnInstruction(call, expr->id());
7540 return true; 8238 return true;
7541 } 8239 }
7542 } 8240 }
7543 8241
7544 8242
7545 // Checks if all maps in |types| are from the same family, i.e., are elements 8243 // 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 8244 // 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 8245 // family, or a Map* indicating the map with the first elements kind of the
7548 // family that is in the list. 8246 // family that is in the list.
8247
8248 //
8249 // TODO(mvstanton) - can I use this function?
8250 //
7549 static Map* CheckSameElementsFamily(SmallMapList* types) { 8251 static Map* CheckSameElementsFamily(SmallMapList* types) {
7550 if (types->length() <= 1) return NULL; 8252 if (types->length() <= 1) return NULL;
7551 // Check if all maps belong to the same transition family. 8253 // Check if all maps belong to the same transition family.
7552 Map* kinds[kFastElementsKindCount]; 8254 Map* kinds[kFastElementsKindCount];
7553 Map* first_map = *types->first(); 8255 Map* first_map = *types->first();
7554 ElementsKind first_kind = first_map->elements_kind(); 8256 ElementsKind first_kind = first_map->elements_kind();
7555 if (!IsFastElementsKind(first_kind)) return NULL; 8257 if (!IsFastElementsKind(first_kind)) return NULL;
7556 int first_index = GetSequenceIndexFromFastElementsKind(first_kind); 8258 int first_index = GetSequenceIndexFromFastElementsKind(first_kind);
7557 int last_index = first_index; 8259 int last_index = first_index;
7558 8260
(...skipping 2209 matching lines...) Expand 10 before | Expand all | Expand 10 after
9768 10470
9769 10471
9770 void HEnvironment::PrintToStd() { 10472 void HEnvironment::PrintToStd() {
9771 HeapStringAllocator string_allocator; 10473 HeapStringAllocator string_allocator;
9772 StringStream trace(&string_allocator); 10474 StringStream trace(&string_allocator);
9773 PrintTo(&trace); 10475 PrintTo(&trace);
9774 PrintF("%s", *trace.ToCString()); 10476 PrintF("%s", *trace.ToCString());
9775 } 10477 }
9776 10478
9777 10479
10480
10481
10482
10483
9778 void HTracer::TraceCompilation(FunctionLiteral* function) { 10484 void HTracer::TraceCompilation(FunctionLiteral* function) {
9779 Tag tag(this, "compilation"); 10485 Tag tag(this, "compilation");
9780 Handle<String> name = function->debug_name(); 10486 Handle<String> name = function->debug_name();
9781 PrintStringProperty("name", *name->ToCString()); 10487 PrintStringProperty("name", *name->ToCString());
9782 PrintStringProperty("method", *name->ToCString()); 10488 PrintStringProperty("method", *name->ToCString());
9783 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); 10489 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
9784 } 10490 }
9785 10491
9786 10492
9787 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 10493 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
10101 } 10807 }
10102 } 10808 }
10103 10809
10104 #ifdef DEBUG 10810 #ifdef DEBUG
10105 if (graph_ != NULL) graph_->Verify(false); // No full verify. 10811 if (graph_ != NULL) graph_->Verify(false); // No full verify.
10106 if (allocator_ != NULL) allocator_->Verify(); 10812 if (allocator_ != NULL) allocator_->Verify();
10107 #endif 10813 #endif
10108 } 10814 }
10109 10815
10110 } } // namespace v8::internal 10816 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698