Chromium Code Reviews| 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 { | |
|
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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |