| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |