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 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 | 686 |
| 687 | 687 |
| 688 HGraph::HGraph(CompilationInfo* info) | 688 HGraph::HGraph(CompilationInfo* info) |
| 689 : isolate_(info->isolate()), | 689 : isolate_(info->isolate()), |
| 690 next_block_id_(0), | 690 next_block_id_(0), |
| 691 entry_block_(NULL), | 691 entry_block_(NULL), |
| 692 blocks_(8, info->zone()), | 692 blocks_(8, info->zone()), |
| 693 values_(16, info->zone()), | 693 values_(16, info->zone()), |
| 694 phi_list_(NULL), | 694 phi_list_(NULL), |
| 695 uint32_instructions_(NULL), | 695 uint32_instructions_(NULL), |
| 696 deferred_transitions_(10, info->zone()), | |
| 696 info_(info), | 697 info_(info), |
| 697 zone_(info->zone()), | 698 zone_(info->zone()), |
| 698 is_recursive_(false), | 699 is_recursive_(false), |
| 699 use_optimistic_licm_(false), | 700 use_optimistic_licm_(false), |
| 700 type_change_checksum_(0) { | 701 type_change_checksum_(0) { |
| 701 start_environment_ = | 702 start_environment_ = |
| 702 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 703 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
| 703 start_environment_->set_ast_id(BailoutId::FunctionEntry()); | 704 start_environment_->set_ast_id(BailoutId::FunctionEntry()); |
| 704 entry_block_ = CreateBasicBlock(); | 705 entry_block_ = CreateBasicBlock(); |
| 705 entry_block_->SetInitialEnvironment(start_environment_); | 706 entry_block_->SetInitialEnvironment(start_environment_); |
| (...skipping 1789 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2495 ZoneList<HValue*> worklist(block->phis()->length(), zone()); | 2496 ZoneList<HValue*> worklist(block->phis()->length(), zone()); |
| 2496 for (int j = 0; j < block->phis()->length(); ++j) { | 2497 for (int j = 0; j < block->phis()->length(); ++j) { |
| 2497 worklist.Add(block->phis()->at(j), zone()); | 2498 worklist.Add(block->phis()->at(j), zone()); |
| 2498 } | 2499 } |
| 2499 InferTypes(&worklist); | 2500 InferTypes(&worklist); |
| 2500 } | 2501 } |
| 2501 } | 2502 } |
| 2502 } | 2503 } |
| 2503 | 2504 |
| 2504 | 2505 |
| 2506 static bool TerminalMatch(void* key1, void* key2) { | |
| 2507 return key1 == key2; | |
| 2508 } | |
| 2509 | |
| 2510 typedef ZoneList<DeferredTransitions*> DeferredTransitionsList; | |
| 2511 | |
| 2512 class HighestMapAndFamily { | |
|
danno
2012/11/14 15:28:18
When you say "highest", do you mean most general?
mvstanton
2012/11/16 15:15:06
I needed to update many locations to be consistent
| |
| 2513 public: | |
| 2514 HighestMapAndFamily() : highest_map_(NULL), family_(NULL) { } | |
| 2515 HighestMapAndFamily(HighestMapAndFamily& h) | |
| 2516 : highest_map_(h.highest_map()), | |
| 2517 family_(h.family()) { | |
| 2518 } | |
| 2519 | |
| 2520 Map* highest_map() const { return highest_map_; } | |
| 2521 Map* family() const { return family_; } | |
| 2522 | |
| 2523 void change(Map* new_highest_map, Map* new_family) { | |
|
danno
2012/11/14 15:28:18
Maybe "Update" instead?
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2524 if (is_valid()) { | |
| 2525 ASSERT(new_family == family_); // family shouldn't be changed | |
| 2526 highest_map_ = new_highest_map; | |
| 2527 } else { | |
| 2528 highest_map_ = new_highest_map; | |
| 2529 family_ = new_family; | |
| 2530 } | |
| 2531 } | |
| 2532 | |
| 2533 void invalidate() { | |
| 2534 highest_map_ = NULL; | |
| 2535 family_ = NULL; | |
| 2536 } | |
| 2537 | |
| 2538 bool is_valid() const { return highest_map_ != NULL && family_ != NULL; } | |
| 2539 bool operator==(const HighestMapAndFamily& h) const { | |
|
danno
2012/11/14 15:28:18
We tend to avoid operator== (see http://google-sty
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2540 if (!is_valid() || !h.is_valid()) { | |
| 2541 return is_valid() == h.is_valid(); | |
| 2542 } | |
| 2543 return highest_map_ == h.highest_map() && family_ == h.family(); | |
| 2544 } | |
| 2545 | |
| 2546 bool operator!=(const HighestMapAndFamily& h) const { | |
|
danno
2012/11/14 15:28:18
operator overloading
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2547 return !(*this == h); | |
| 2548 } | |
| 2549 | |
| 2550 HighestMapAndFamily& operator=(const HighestMapAndFamily& h) { | |
|
danno
2012/11/14 15:28:18
operator overloading
mvstanton
2012/11/16 15:15:06
this one I need to keep in order to copy these thi
| |
| 2551 if(this != &h) { | |
| 2552 highest_map_ = h.highest_map(); | |
| 2553 family_ = h.family(); | |
| 2554 } | |
| 2555 return *this; | |
| 2556 } | |
| 2557 | |
| 2558 private: | |
| 2559 Map *highest_map_; | |
|
danno
2012/11/14 15:28:18
Map* highest_map_
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2560 Map *family_; | |
| 2561 }; | |
| 2562 | |
| 2563 typedef EnumSet<ElementsKind> ElementsKindSet; | |
| 2564 | |
| 2565 class TerminalMapValue: public ZoneObject { | |
|
danno
2012/11/14 15:28:18
TransitionElementsInputValueData?
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2566 public: | |
| 2567 TerminalMapValue(HInstruction* terminal_node,Zone* zone) : | |
| 2568 terminal_node_(terminal_node), | |
| 2569 transitions_(new (zone) DeferredTransitionsList(10,zone)), | |
| 2570 zone_(zone), | |
| 2571 last_in_chain_(NULL) { | |
| 2572 | |
| 2573 } | |
| 2574 | |
| 2575 void add_transition(DeferredTransitions* todo) { | |
|
danno
2012/11/14 15:28:18
AddTransition
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2576 if (todo->terminal_nodes() == 1) { | |
| 2577 // put at the front of the list. Processing single element | |
| 2578 // transitions first makes score calculation easier. | |
| 2579 transitions_->InsertAt(0, todo, zone_); | |
| 2580 } else { | |
| 2581 transitions_->Add(todo, zone_); | |
| 2582 } | |
| 2583 } | |
| 2584 | |
| 2585 ElementsKind highest_elementskind() const { | |
|
danno
2012/11/14 15:28:18
GetMostGenerateElementsKind()?
mvstanton
2012/11/16 15:15:06
removed method, no callers
| |
| 2586 ASSERT(highest_.highest_map() != NULL); | |
| 2587 return highest_.highest_map()->elements_kind(); | |
| 2588 } | |
| 2589 | |
| 2590 HighestMapAndFamily& highest() { return highest_; } | |
| 2591 void set_highest(HighestMapAndFamily& h) { highest_ = h; } | |
| 2592 | |
| 2593 int todo_count() const { return transitions_->length(); } | |
| 2594 DeferredTransitions* todo(int i) { return (*transitions_)[i]; } | |
| 2595 Zone* zone() { return zone_; } | |
| 2596 | |
| 2597 // For instruction emission | |
| 2598 | |
| 2599 bool RequiresTransitionElementsKind(ElementsKind from) const { | |
| 2600 return !from_elements_.Contains(from); | |
| 2601 } | |
| 2602 | |
| 2603 void InsertTransitionElementsKind(HTransitionElementsKind* new_instr) { | |
| 2604 ElementsKind from_elements_kind = new_instr->original_map()->elements_kind() ; | |
| 2605 ASSERT(RequiresTransitionElementsKind(from_elements_kind)); | |
| 2606 // At the site, we maintain a most recent instruction we added, and | |
| 2607 // new instructions should appear at the end of the chain. | |
| 2608 HInstruction* addafter = last_in_chain_; | |
| 2609 if (addafter == NULL) { | |
| 2610 // This is the first instruction to add. | |
| 2611 // We must emit a checknonsmi | |
| 2612 addafter = new(zone()) HCheckNonSmi(terminal_node_); | |
| 2613 addafter->InsertAfter(terminal_node_); | |
| 2614 } | |
| 2615 | |
| 2616 new_instr->InsertAfter(addafter); | |
| 2617 last_in_chain_ = new_instr; | |
| 2618 from_elements_.Add(from_elements_kind); | |
| 2619 } | |
| 2620 | |
| 2621 HTransitionElementsKind* last_transitionelementskind() const { | |
| 2622 // Will be NULL if none inserted yet. | |
| 2623 return last_in_chain_; | |
| 2624 } | |
| 2625 | |
| 2626 private: | |
| 2627 HInstruction* terminal_node_; | |
|
danno
2012/11/14 15:28:18
HValue*
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2628 DeferredTransitionsList* transitions_; | |
| 2629 Zone* zone_; | |
| 2630 HighestMapAndFamily highest_; | |
| 2631 ElementsKindSet from_elements_; | |
| 2632 HTransitionElementsKind* last_in_chain_; | |
| 2633 }; | |
| 2634 | |
| 2635 | |
| 2636 // This method walks through the TODOs that mapped to a particular terminal node | |
| 2637 // value. It returns the "TO" map that these nodes unify too. If they return | |
| 2638 // a NULL handle, then that means that the nodes couldn't be unified, and have | |
| 2639 // already been marked as invalid. | |
| 2640 // If they return a non-null value, then all the TODOs have also been updated to | |
| 2641 // recognize the returned map as their "TO" map as well. | |
| 2642 void ComputeHighest(TerminalMapValue* value, HighestMapAndFamily* highest, Defer redTransitions** cannotTransition) { | |
| 2643 *highest = value->highest(); | |
| 2644 | |
| 2645 // At the end of this function all todos in the list need to agree on the high est map. | |
| 2646 // so one time through the loop isn't enough. | |
| 2647 for (int count=0; count<2; count++) { | |
| 2648 for (int i=0; i<value->todo_count(); i++) { | |
| 2649 DeferredTransitions* todo = value->todo(i); | |
| 2650 Map* todo_highest = todo->highest(); | |
| 2651 | |
| 2652 if (!highest->is_valid()) { | |
| 2653 // First todo, first time through the loop | |
| 2654 highest->change(todo_highest, todo->map_family()); | |
| 2655 } else if (highest->highest_map() != todo_highest) { | |
| 2656 | |
| 2657 // Are they in the same family? | |
| 2658 if (highest->family() != todo->map_family()) { | |
| 2659 // Yikes. this won't work. | |
| 2660 *cannotTransition = todo; | |
| 2661 highest->invalidate(); | |
| 2662 return; | |
| 2663 } | |
| 2664 | |
| 2665 // which one is higher? Figure that out and then the other one needs to | |
| 2666 // be able to find a path to it. | |
| 2667 ElementsKind unified_highest_elements_kind = GetUnifiedFastElementsKind( | |
| 2668 highest->highest_map()->elements_kind(), todo_highest->elements_kind ()); | |
| 2669 | |
| 2670 // make sure both maps have a path to success | |
| 2671 Map* unified_highest_map = highest->highest_map()->LookupElementsTransit ionMap(unified_highest_elements_kind); | |
| 2672 Map* unified_todo_highest_map = todo_highest->LookupElementsTransitionMa p(unified_highest_elements_kind); | |
| 2673 if (unified_highest_map == NULL || unified_todo_highest_map == NULL || | |
| 2674 (unified_highest_map != unified_todo_highest_map)) { | |
| 2675 *cannotTransition = todo; | |
| 2676 highest->invalidate(); | |
| 2677 return; | |
| 2678 } | |
| 2679 | |
| 2680 highest->change(unified_highest_map, todo->map_family()); | |
| 2681 todo->set_highest(highest->highest_map()); | |
| 2682 } | |
| 2683 } | |
| 2684 } | |
| 2685 } | |
| 2686 | |
| 2687 | |
| 2688 void ScorchTerminalMap(ZoneAllocationPolicy allocationPolicy, Zone* zone, | |
| 2689 DeferredTransitions* cannotTransition, ZoneHashMap* termi nalMap) { | |
| 2690 ZoneList<DeferredTransitions*> worklist(10, zone); | |
| 2691 cannotTransition->set_invalid(); | |
| 2692 worklist.Add(cannotTransition, zone); | |
| 2693 | |
| 2694 while (!worklist.is_empty()) { | |
| 2695 DeferredTransitions* todo = worklist.RemoveLast(); | |
| 2696 ASSERT(todo->invalid()); | |
| 2697 for (int t=0; t<todo->terminal_nodes(); t++) { | |
| 2698 HInstruction* terminal_node = todo->terminal_node(t); | |
| 2699 ZoneHashMap::Entry* entry = terminalMap->Lookup(terminal_node, | |
| 2700 terminal_node->id(), | |
| 2701 false, | |
| 2702 allocationPolicy); | |
| 2703 if (entry != NULL) { | |
| 2704 TerminalMapValue* value = reinterpret_cast<TerminalMapValue*>(entry->val ue); | |
| 2705 for (int i=0; i<value->todo_count(); i++) { | |
| 2706 DeferredTransitions* todo = value->todo(i); | |
| 2707 if (!todo->invalid()) { | |
| 2708 todo->set_invalid(); | |
| 2709 worklist.Add(todo, zone); | |
| 2710 } | |
| 2711 } | |
| 2712 | |
| 2713 terminalMap->Remove(terminal_node, terminal_node->id()); | |
| 2714 } | |
| 2715 } | |
| 2716 } | |
| 2717 } | |
| 2718 | |
| 2719 | |
| 2720 Handle<Map>& StashedMapHandle(ZoneList<DeferredTransitions>* transitions, | |
| 2721 Map* map) { | |
| 2722 | |
| 2723 // The guarantee is that a handle does exist for the given map, since | |
| 2724 // we saved/created it earlier. | |
| 2725 // TODO(mvstanton): this could be way more efficient. It is brute force. | |
| 2726 for (int i=0; i<transitions->length(); i++) { | |
| 2727 DeferredTransitions& todo = transitions->at(i); | |
| 2728 for (int r=0; r<todo.transitions(); r++) { | |
| 2729 TransitionRecord& record = todo.transition_ref(r); | |
| 2730 if (*(record.map_to().location()) == map) { | |
| 2731 return record.map_to_ref(); | |
| 2732 } else if(*(record.optimistic_holey().location()) == map) { | |
| 2733 return record.optimistic_holey_ref(); | |
| 2734 } | |
| 2735 } | |
| 2736 } | |
| 2737 | |
| 2738 // This code is marked as unreachable because at runtime we can't actually cre ate | |
| 2739 // a handle during compiler optimization. | |
| 2740 UNREACHABLE(); | |
| 2741 return transitions->at(0).transition_ref(0).map_to_ref(); | |
| 2742 } | |
| 2743 | |
| 2744 | |
| 2745 void FinalizeTransitionToDos(ZoneList<DeferredTransitions>& transitions, int max imumGraphID) { | |
|
danno
2012/11/14 15:28:18
How about FinalizeDeferredTransitionElements?
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2746 for (int i=0; i<transitions.length(); i++) { | |
| 2747 DeferredTransitions& todo = transitions[i]; | |
| 2748 todo.ComputeTerminalNodes(maximumGraphID); | |
| 2749 // Also fill in the current highest, which may later be changed externally. | |
|
danno
2012/11/14 15:28:18
most general?
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2750 todo.compute_highest(); | |
| 2751 } | |
| 2752 } | |
| 2753 | |
| 2754 void HGraph::InitializeTerminalMap(ZoneHashMap& terminalMap) { | |
| 2755 ZoneAllocationPolicy allocator(zone()); | |
| 2756 Counters* counters = isolate()->counters(); | |
| 2757 | |
| 2758 for (int i=0; i<deferred_transitions_.length(); i++) { | |
| 2759 DeferredTransitions& todo = deferred_transitions_[i]; | |
| 2760 ASSERT(todo.transitions() > 0); | |
| 2761 int site_nesting_depth = todo.instr()->block()->LoopNestingDepth(); | |
| 2762 | |
| 2763 for (int t=0; t<todo.terminal_nodes(); t++) { | |
| 2764 HInstruction* terminal_node = todo.terminal_node(t); | |
| 2765 | |
| 2766 // Score computation | |
| 2767 int terminal_site_nesting_depth = terminal_node->block()->LoopNestingDepth (); | |
| 2768 int loop_delta = site_nesting_depth - terminal_site_nesting_depth; | |
| 2769 int proposedAdds = todo.transitions(); | |
| 2770 DeferredTransitions::ScoreType scoreType = todo.scoretype_from_loopdelta(l oop_delta); | |
| 2771 int score = (loop_delta==0 ? 1 : loop_delta)*proposedAdds; | |
| 2772 if (score < 0) score *= -1; | |
| 2773 todo.increment_score(scoreType,score); | |
| 2774 | |
| 2775 ZoneHashMap::Entry* entry = terminalMap.Lookup(terminal_node, | |
| 2776 terminal_node->id(), | |
| 2777 true, | |
| 2778 allocator); | |
| 2779 TerminalMapValue* value = NULL; | |
| 2780 if (entry->value == NULL) { | |
| 2781 // It's new, add a value | |
| 2782 value = new (zone()) TerminalMapValue(terminal_node,zone()); | |
| 2783 entry->value = reinterpret_cast<void*>(value); | |
| 2784 } else { | |
| 2785 value = reinterpret_cast<TerminalMapValue*>(entry->value); | |
| 2786 } | |
| 2787 | |
| 2788 value->add_transition(&todo); | |
| 2789 } | |
| 2790 | |
| 2791 // Export the site score in aggregate for reporting | |
| 2792 counters->transition_site_positive_score()->Increment(todo.score(DeferredTra nsitions::SCORE_POSITIVE)); | |
| 2793 counters->transition_site_negative_score()->Increment(todo.score(DeferredTra nsitions::SCORE_NEGATIVE)); | |
| 2794 counters->transition_site_neutral_score()->Increment(todo.score(DeferredTran sitions::SCORE_NEUTRAL)); | |
| 2795 } | |
| 2796 } | |
| 2797 | |
| 2798 void HGraph::InsertElementsTransitions() | |
| 2799 { | |
| 2800 ZoneAllocationPolicy allocator(zone()); | |
| 2801 HPhase phase("H_Place elements transitions", this); | |
| 2802 | |
| 2803 // =========================================================================== | |
| 2804 // Compute the equivalence classes of the LoadKeyed/StoreKeyed sites that need | |
| 2805 // transitions. | |
| 2806 FinalizeTransitionToDos(deferred_transitions_, GetMaximumValueID()); | |
| 2807 | |
| 2808 // | |
| 2809 // IF in a forest of terminal nodes shared among some load/store keyed | |
| 2810 // instructions, there are map transitions TO maps that are not in the same | |
| 2811 // "floor" of the map tree, then all transitions involving those terminal | |
|
danno
2012/11/14 15:28:18
to abuse the metaphor even more, maybe "trunk" ins
danno
2012/11/14 15:28:18
pre-transitioned input value?
| |
| 2812 // nodes must be left down at the load/store site, rather than factored up. | |
| 2813 // | |
| 2814 ZoneHashMap terminalMap(TerminalMatch,32,allocator); | |
|
danno
2012/11/14 15:28:18
spaces after ,s
mvstanton
2012/11/16 15:15:06
Done.
| |
| 2815 InitializeTerminalMap(terminalMap); | |
| 2816 | |
| 2817 // Now that the map is created, run the unification algorithm | |
| 2818 bool done = false; | |
| 2819 while (!done) { | |
| 2820 bool changed = false; | |
| 2821 for (ZoneHashMap::Entry* p = terminalMap.Start(); p != NULL; | |
| 2822 p = terminalMap.Next(p)) { | |
| 2823 TerminalMapValue* value = reinterpret_cast<TerminalMapValue*>(p->value); | |
| 2824 DeferredTransitions* cannotTransitionTodo = NULL; | |
| 2825 HighestMapAndFamily newHighest; | |
| 2826 ComputeHighest(value, &newHighest, &cannotTransitionTodo); | |
| 2827 if (!newHighest.is_valid()) { | |
| 2828 ASSERT(cannotTransitionTodo != NULL); | |
| 2829 ScorchTerminalMap(allocator, zone(), cannotTransitionTodo, &terminalMap) ; | |
| 2830 changed = true; | |
| 2831 break; | |
| 2832 } | |
| 2833 | |
| 2834 if (value->highest() != newHighest) { | |
| 2835 value->set_highest(newHighest); | |
| 2836 changed = true; | |
| 2837 } | |
| 2838 } | |
| 2839 | |
| 2840 done = !changed; | |
| 2841 } | |
| 2842 | |
| 2843 // Now we have the "to" value for each location, and todos have been divided i nto | |
| 2844 // sets, including a set that couldn't be transitioned and is no longer repres ented | |
| 2845 // in the terminalMap | |
| 2846 // Handle each todo again. | |
| 2847 if (FLAG_trace_transition_placement) { | |
| 2848 for (int i=0; i<deferred_transitions_.length(); i++) { | |
| 2849 DeferredTransitions& todo = deferred_transitions_[i]; | |
| 2850 HeapStringAllocator string_allocator; | |
| 2851 StringStream stream(&string_allocator); | |
| 2852 todo.PrintTo(&stream); | |
| 2853 PrintF("%s", *stream.ToCString()); | |
| 2854 } | |
| 2855 } | |
| 2856 | |
| 2857 // Do the work | |
| 2858 for (int i=0; i<deferred_transitions_.length(); i++) { | |
| 2859 DeferredTransitions& todo = deferred_transitions_[i]; | |
| 2860 | |
| 2861 // All todos need to be finalized, even if we don't take action on them. | |
| 2862 todo.Finalize(); | |
| 2863 | |
| 2864 if (todo.invalid()) { | |
| 2865 // We aren't moving this todo, leave it alone and visit the next | |
| 2866 continue; | |
| 2867 } | |
| 2868 | |
| 2869 // 1) Remove the nonsmicheck. | |
| 2870 todo.checknonsmi_instr()->DeleteAndReplaceWith(NULL); | |
| 2871 | |
| 2872 // 2) alter the elementkind of the loadkeyed/storekeyed instruction if requi red. | |
| 2873 // (note that steps a,b,c won't happen if the transition was marked as inval id because | |
| 2874 // it operates on a different map family) | |
| 2875 // 2a) unlink transitions associated with this site from their current locat ion | |
| 2876 // 2b) Create appropriate transition instructions up at the terminal site. | |
| 2877 // 2c) Fix the checkmaps instruction if required. | |
| 2878 | |
| 2879 Handle<Map>& handle = StashedMapHandle(&deferred_transitions_, todo.highest( )); | |
| 2880 | |
| 2881 for (int t=0; t<todo.terminal_nodes(); t++) { | |
| 2882 HInstruction* terminal_node = todo.terminal_node(t); | |
| 2883 ZoneHashMap::Entry* entry = terminalMap.Lookup(terminal_node, | |
| 2884 terminal_node->id(), | |
| 2885 false, | |
| 2886 allocator); | |
| 2887 CHECK(entry->value != NULL); | |
| 2888 TerminalMapValue* value = reinterpret_cast<TerminalMapValue*>(entry->value ); | |
| 2889 for (int r=0; r<todo.transitions(); r++) { | |
| 2890 TransitionRecord& record = todo.transition_ref(r); | |
| 2891 if (value->RequiresTransitionElementsKind(record.from())) { | |
| 2892 | |
| 2893 // We need to emit a transition. | |
| 2894 ASSERT(terminal_node->IsInstruction()); | |
| 2895 HTransitionElementsKind* transition = new(zone()) | |
| 2896 HTransitionElementsKind(terminal_node, record.map_from(), handle); | |
| 2897 value->InsertTransitionElementsKind(transition); | |
| 2898 | |
| 2899 // Remove the transition from it's original location | |
| 2900 if (record.transition_instruction()->block() != NULL) { | |
| 2901 if (record.transition_instruction()->HasNoUses()) { | |
| 2902 record.transition_instruction()->DeleteAndReplaceWith(NULL); | |
| 2903 } else { | |
| 2904 record.transition_instruction()->DeleteAndReplaceWith(transition); | |
| 2905 } | |
| 2906 } | |
| 2907 } | |
| 2908 } | |
| 2909 | |
| 2910 HCheckMaps* checkmaps = todo.checkmaps_instr(); | |
| 2911 if (checkmaps != NULL) { | |
| 2912 // The checkmaps depends on the transition instruction we just unlinked. | |
| 2913 // Conveniently, we can make it depend on the last instruction we just e mitted. | |
| 2914 | |
| 2915 // We may need to update the map | |
| 2916 // TODO(mvstanton) update the map instruction | |
| 2917 // todo.mapcheck_instr()-> | |
| 2918 // one case: | |
| 2919 // HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, | |
| 2920 // zone(), dependency); | |
| 2921 // other case: | |
| 2922 // emitted_checkmaps = new(zone()) HCheckMaps( | |
| 2923 // elements, isolate()->factory()->fixed_array_map(), | |
| 2924 // zone(), elements_kind_branch); | |
| 2925 | |
| 2926 // I'm not sure what to do right now if this is > 1, so | |
| 2927 // TODO(mvstanton): this assert is temporary | |
| 2928 ASSERT(checkmaps->map_set()->length() == 1); | |
| 2929 // Surgically replace the map in there | |
| 2930 checkmaps->map_set()->Clear(); | |
| 2931 checkmaps->map_set()->Add(handle, zone()); | |
| 2932 | |
| 2933 // Remove the dependency, only keeping it if our new transition is in th e same basic | |
| 2934 // block as the checkmaps. | |
| 2935 HTransitionElementsKind* lasttransition = value->last_transitionelements kind(); | |
| 2936 if (checkmaps->has_typecheck()) { | |
| 2937 if (lasttransition->block() == checkmaps->block()) { | |
| 2938 checkmaps->SetOperandAt(1, lasttransition); | |
| 2939 } else { | |
| 2940 checkmaps->SetOperandAt(1, checkmaps->OperandAt(0)); | |
| 2941 } | |
| 2942 } | |
| 2943 } | |
| 2944 } | |
| 2945 } | |
| 2946 } | |
| 2947 | |
| 2948 | |
| 2949 template<class T> | |
| 2950 void FinishFastKeyedInitialization(T* instruction, ElementsKind elements_kind) { | |
| 2951 instruction->PerformDeferredInitialization(elements_kind); | |
| 2952 } | |
| 2953 | |
| 2954 | |
| 2955 | |
| 2505 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { | 2956 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { |
| 2506 HValue* current = value; | 2957 HValue* current = value; |
| 2507 while (current != NULL) { | 2958 while (current != NULL) { |
| 2508 if (visited->Contains(current->id())) return; | 2959 if (visited->Contains(current->id())) return; |
| 2509 | 2960 |
| 2510 // For phis, we must propagate the check to all of its inputs. | 2961 // For phis, we must propagate the check to all of its inputs. |
| 2511 if (current->IsPhi()) { | 2962 if (current->IsPhi()) { |
| 2512 visited->Add(current->id()); | 2963 visited->Add(current->id()); |
| 2513 HPhi* phi = HPhi::cast(current); | 2964 HPhi* phi = HPhi::cast(current); |
| 2514 for (int i = 0; i < phi->OperandCount(); ++i) { | 2965 for (int i = 0; i < phi->OperandCount(); ++i) { |
| (...skipping 788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3303 } | 3754 } |
| 3304 EliminateRedundantPhis(); | 3755 EliminateRedundantPhis(); |
| 3305 if (!CheckArgumentsPhiUses()) { | 3756 if (!CheckArgumentsPhiUses()) { |
| 3306 *bailout_reason = SmartArrayPointer<char>(StrDup( | 3757 *bailout_reason = SmartArrayPointer<char>(StrDup( |
| 3307 "Unsupported phi use of arguments")); | 3758 "Unsupported phi use of arguments")); |
| 3308 return false; | 3759 return false; |
| 3309 } | 3760 } |
| 3310 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); | 3761 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); |
| 3311 CollectPhis(); | 3762 CollectPhis(); |
| 3312 | 3763 |
| 3764 InsertElementsTransitions(); | |
| 3765 | |
| 3313 if (has_osr_loop_entry()) { | 3766 if (has_osr_loop_entry()) { |
| 3314 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); | 3767 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); |
| 3315 for (int j = 0; j < phis->length(); j++) { | 3768 for (int j = 0; j < phis->length(); j++) { |
| 3316 HPhi* phi = phis->at(j); | 3769 HPhi* phi = phis->at(j); |
| 3317 osr_values()->at(phi->merged_index())->set_incoming_value(phi); | 3770 osr_values()->at(phi->merged_index())->set_incoming_value(phi); |
| 3318 } | 3771 } |
| 3319 } | 3772 } |
| 3320 | 3773 |
| 3321 HInferRepresentation rep(this); | 3774 HInferRepresentation rep(this); |
| 3322 rep.Analyze(); | 3775 rep.Analyze(); |
| (...skipping 2767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6090 return load; | 6543 return load; |
| 6091 } | 6544 } |
| 6092 } | 6545 } |
| 6093 | 6546 |
| 6094 | 6547 |
| 6095 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, | 6548 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
| 6096 HValue* checked_key, | 6549 HValue* checked_key, |
| 6097 HValue* val, | 6550 HValue* val, |
| 6098 HValue* load_dependency, | 6551 HValue* load_dependency, |
| 6099 ElementsKind elements_kind, | 6552 ElementsKind elements_kind, |
| 6100 bool is_store) { | 6553 bool is_store, |
| 6554 bool defer_initialization) { | |
| 6101 if (is_store) { | 6555 if (is_store) { |
| 6102 ASSERT(val != NULL); | 6556 ASSERT(val != NULL); |
| 6103 switch (elements_kind) { | 6557 switch (elements_kind) { |
| 6104 case FAST_SMI_ELEMENTS: | 6558 case FAST_SMI_ELEMENTS: |
| 6105 case FAST_HOLEY_SMI_ELEMENTS: | 6559 case FAST_HOLEY_SMI_ELEMENTS: |
| 6106 // Smi-only arrays need a smi check. | 6560 // Smi-only arrays need a smi check. |
| 6107 AddInstruction(new(zone()) HCheckSmi(val)); | 6561 AddInstruction(new(zone()) HCheckSmi(val)); |
| 6108 // Fall through. | 6562 // Fall through. |
| 6109 case FAST_ELEMENTS: | 6563 case FAST_ELEMENTS: |
| 6110 case FAST_HOLEY_ELEMENTS: | 6564 case FAST_HOLEY_ELEMENTS: |
| 6111 case FAST_DOUBLE_ELEMENTS: | 6565 case FAST_DOUBLE_ELEMENTS: |
| 6112 case FAST_HOLEY_DOUBLE_ELEMENTS: | 6566 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 6113 return new(zone()) HStoreKeyed( | 6567 return new(zone()) HStoreKeyed( |
| 6114 elements, checked_key, val, elements_kind); | 6568 elements, checked_key, val, elements_kind, defer_initialization); |
| 6115 default: | 6569 default: |
| 6116 UNREACHABLE(); | 6570 UNREACHABLE(); |
| 6117 return NULL; | 6571 return NULL; |
| 6118 } | 6572 } |
| 6119 } | 6573 } |
| 6120 // It's an element load (!is_store). | 6574 // It's an element load (!is_store). |
| 6121 return new(zone()) HLoadKeyed(elements, | 6575 return new(zone()) HLoadKeyed(elements, |
| 6122 checked_key, | 6576 checked_key, |
| 6123 load_dependency, | 6577 load_dependency, |
| 6124 elements_kind); | 6578 elements_kind, defer_initialization); |
| 6125 } | 6579 } |
| 6126 | 6580 |
| 6127 | 6581 |
| 6128 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 6582 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 6129 HValue* key, | 6583 HValue* key, |
| 6130 HValue* val, | 6584 HValue* val, |
| 6131 HValue* dependency, | 6585 HValue* dependency, |
| 6132 Handle<Map> map, | 6586 Handle<Map> map, |
| 6133 bool is_store) { | 6587 bool is_store, |
| 6588 HCheckMaps** checkmap _instr) { | |
| 6134 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, | 6589 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, |
| 6135 zone(), dependency); | 6590 zone(), dependency); |
| 6136 AddInstruction(mapcheck); | 6591 AddInstruction(mapcheck); |
| 6137 if (dependency) { | 6592 if (dependency) { |
| 6138 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 6593 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 6139 } | 6594 } |
| 6595 | |
| 6596 if (checkmap_instr != NULL) { | |
| 6597 *checkmap_instr = mapcheck; | |
| 6598 } | |
| 6599 | |
| 6140 return BuildUncheckedMonomorphicElementAccess(object, key, val, | 6600 return BuildUncheckedMonomorphicElementAccess(object, key, val, |
| 6141 mapcheck, map, is_store); | 6601 mapcheck, map, is_store, depende ncy != NULL); |
| 6142 } | 6602 } |
| 6143 | 6603 |
| 6144 | 6604 |
| 6145 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 6605 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 6146 HValue* object, | 6606 HValue* object, |
| 6147 HValue* key, | 6607 HValue* key, |
| 6148 HValue* val, | 6608 HValue* val, |
| 6149 HCheckMaps* mapcheck, | 6609 HCheckMaps* mapcheck, |
| 6150 Handle<Map> map, | 6610 Handle<Map> map, |
| 6151 bool is_store) { | 6611 bool is_store, |
| 6612 bool defer_initialization) { | |
| 6152 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 6613 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
| 6153 // on a HElementsTransition instruction. The flag can also be removed if the | 6614 // on a HElementsTransition instruction. The flag can also be removed if the |
| 6154 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 6615 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
| 6155 // ElementsKind transitions. Finally, the dependency can be removed for stores | 6616 // ElementsKind transitions. Finally, the dependency can be removed for stores |
| 6156 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 6617 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 6157 // generated store code. | 6618 // generated store code. |
| 6158 if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) || | 6619 if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) || |
| 6159 (map->elements_kind() == FAST_ELEMENTS && is_store)) { | 6620 (map->elements_kind() == FAST_ELEMENTS && is_store)) { |
| 6160 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 6621 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 6161 } | 6622 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 6187 map->has_fast_double_elements()); | 6648 map->has_fast_double_elements()); |
| 6188 if (map->instance_type() == JS_ARRAY_TYPE) { | 6649 if (map->instance_type() == JS_ARRAY_TYPE) { |
| 6189 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck, | 6650 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck, |
| 6190 HType::Smi())); | 6651 HType::Smi())); |
| 6191 } else { | 6652 } else { |
| 6192 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 6653 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 6193 } | 6654 } |
| 6194 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 6655 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6195 ALLOW_SMI_KEY)); | 6656 ALLOW_SMI_KEY)); |
| 6196 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 6657 return BuildFastElementAccess(elements, checked_key, val, mapcheck, |
| 6197 map->elements_kind(), is_store); | 6658 map->elements_kind(), is_store, defer_initializa tion); |
| 6198 } | 6659 } |
| 6199 | 6660 |
| 6200 | 6661 |
| 6201 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( | 6662 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( |
| 6202 HValue* object, | 6663 HValue* object, |
| 6203 HValue* key, | 6664 HValue* key, |
| 6204 HValue* val, | 6665 HValue* val, |
| 6205 SmallMapList* maps) { | 6666 SmallMapList* maps) { |
| 6206 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 6667 // For polymorphic loads of similar elements kinds (i.e. all tagged or all |
| 6207 // double), always use the "worst case" code without a transition. This is | 6668 // double), always use the "worst case" code without a transition. This is |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6239 most_general_consolidated_map->elements_kind(), | 6700 most_general_consolidated_map->elements_kind(), |
| 6240 map->elements_kind())) { | 6701 map->elements_kind())) { |
| 6241 most_general_consolidated_map = map; | 6702 most_general_consolidated_map = map; |
| 6242 } | 6703 } |
| 6243 } | 6704 } |
| 6244 if (!has_double_maps && !has_smi_or_object_maps) return NULL; | 6705 if (!has_double_maps && !has_smi_or_object_maps) return NULL; |
| 6245 | 6706 |
| 6246 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); | 6707 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); |
| 6247 AddInstruction(check_maps); | 6708 AddInstruction(check_maps); |
| 6248 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( | 6709 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( |
| 6249 object, key, val, check_maps, most_general_consolidated_map, false); | 6710 object, key, val, check_maps, most_general_consolidated_map, false, false) ; |
| 6250 return instr; | 6711 return instr; |
| 6251 } | 6712 } |
| 6252 | 6713 |
| 6253 | 6714 |
| 6254 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, | 6715 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
| 6255 HValue* key, | 6716 HValue* key, |
| 6256 HValue* val, | 6717 HValue* val, |
| 6257 Expression* prop, | 6718 Expression* prop, |
| 6258 BailoutId ast_id, | 6719 BailoutId ast_id, |
| 6259 int position, | 6720 int position, |
| 6260 bool is_store, | 6721 bool is_store, |
| 6261 bool* has_side_effects) { | 6722 bool* has_side_effects) { |
| 6262 *has_side_effects = false; | 6723 *has_side_effects = false; |
| 6263 AddInstruction(new(zone()) HCheckNonSmi(object)); | 6724 HCheckNonSmi* checknonsmi = new(zone()) HCheckNonSmi(object); |
| 6725 AddInstruction(checknonsmi); | |
| 6264 SmallMapList* maps = prop->GetReceiverTypes(); | 6726 SmallMapList* maps = prop->GetReceiverTypes(); |
| 6265 bool todo_external_array = false; | 6727 bool todo_external_array = false; |
| 6266 | 6728 |
| 6267 if (!is_store) { | 6729 if (!is_store) { |
| 6730 // TODO(mvstanton): Should I reference this as a TODO for worst case transit ion? | |
| 6268 HInstruction* consolidated_load = | 6731 HInstruction* consolidated_load = |
| 6269 TryBuildConsolidatedElementLoad(object, key, val, maps); | 6732 TryBuildConsolidatedElementLoad(object, key, val, maps); |
| 6270 if (consolidated_load != NULL) { | 6733 if (consolidated_load != NULL) { |
| 6271 AddInstruction(consolidated_load); | 6734 AddInstruction(consolidated_load); |
| 6272 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 6735 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
| 6273 if (position != RelocInfo::kNoPosition) { | 6736 if (position != RelocInfo::kNoPosition) { |
| 6274 consolidated_load->set_position(position); | 6737 consolidated_load->set_position(position); |
| 6275 } | 6738 } |
| 6276 return consolidated_load; | 6739 return consolidated_load; |
| 6277 } | 6740 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 6299 for (int i = 0; i < maps->length(); ++i) { | 6762 for (int i = 0; i < maps->length(); ++i) { |
| 6300 Handle<Map> map = maps->at(i); | 6763 Handle<Map> map = maps->at(i); |
| 6301 Handle<Map> transitioned_map = | 6764 Handle<Map> transitioned_map = |
| 6302 map->FindTransitionedMap(&possible_transitioned_maps); | 6765 map->FindTransitionedMap(&possible_transitioned_maps); |
| 6303 transition_target.Add(transitioned_map); | 6766 transition_target.Add(transitioned_map); |
| 6304 } | 6767 } |
| 6305 | 6768 |
| 6306 int num_untransitionable_maps = 0; | 6769 int num_untransitionable_maps = 0; |
| 6307 Handle<Map> untransitionable_map; | 6770 Handle<Map> untransitionable_map; |
| 6308 HTransitionElementsKind* transition = NULL; | 6771 HTransitionElementsKind* transition = NULL; |
| 6772 ZoneList<TransitionRecord> records(10, zone()); | |
| 6309 for (int i = 0; i < maps->length(); ++i) { | 6773 for (int i = 0; i < maps->length(); ++i) { |
| 6310 Handle<Map> map = maps->at(i); | 6774 Handle<Map> map = maps->at(i); |
| 6311 ASSERT(map->IsMap()); | 6775 ASSERT(map->IsMap()); |
| 6312 if (!transition_target.at(i).is_null()) { | 6776 if (!transition_target.at(i).is_null()) { |
| 6313 ASSERT(Map::IsValidElementsTransition( | 6777 ASSERT(Map::IsValidElementsTransition( |
| 6314 map->elements_kind(), | 6778 map->elements_kind(), |
| 6315 transition_target.at(i)->elements_kind())); | 6779 transition_target.at(i)->elements_kind())); |
| 6316 transition = new(zone()) HTransitionElementsKind( | 6780 transition = new(zone()) HTransitionElementsKind( |
| 6317 object, map, transition_target.at(i)); | 6781 object, map, transition_target.at(i)); |
| 6318 AddInstruction(transition); | 6782 AddInstruction(transition); |
| 6783 | |
| 6784 TransitionRecord tr(transition, map, transition_target.at(i)); | |
| 6785 records.Add(tr,zone()); | |
| 6319 } else { | 6786 } else { |
| 6320 type_todo[map->elements_kind()] = true; | 6787 type_todo[map->elements_kind()] = true; |
| 6321 if (IsExternalArrayElementsKind(map->elements_kind())) { | 6788 if (IsExternalArrayElementsKind(map->elements_kind())) { |
| 6322 todo_external_array = true; | 6789 todo_external_array = true; |
| 6323 } | 6790 } |
| 6324 num_untransitionable_maps++; | 6791 num_untransitionable_maps++; |
| 6325 untransitionable_map = map; | 6792 untransitionable_map = map; |
| 6326 } | 6793 } |
| 6327 } | 6794 } |
| 6328 | 6795 |
| 6329 // If only one map is left after transitioning, handle this case | 6796 // If only one map is left after transitioning, handle this case |
| 6330 // monomorphically. | 6797 // monomorphically. |
| 6331 if (num_untransitionable_maps == 1) { | 6798 if (num_untransitionable_maps == 1) { |
| 6332 HInstruction* instr = NULL; | 6799 HInstruction* instr = NULL; |
| 6333 if (untransitionable_map->has_slow_elements_kind()) { | 6800 if (untransitionable_map->has_slow_elements_kind()) { |
| 6334 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 6801 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 6335 : BuildLoadKeyedGeneric(object, key)); | 6802 : BuildLoadKeyedGeneric(object, key)); |
| 6336 } else { | 6803 } else { |
| 6804 // TODO(mvstanton): when we remove the transition what do we do about the | |
| 6805 // parameter in the call to BuildMonomorphicElementAccess? | |
| 6806 HCheckMaps *checkmaps = NULL; | |
| 6337 instr = AddInstruction(BuildMonomorphicElementAccess( | 6807 instr = AddInstruction(BuildMonomorphicElementAccess( |
| 6338 object, key, val, transition, untransitionable_map, is_store)); | 6808 object, key, val, transition, untransitionable_map, is_store, |
| 6809 &checkmaps)); | |
| 6810 | |
| 6811 if (records.length() > 0) { | |
| 6812 DeferredTransitions todo(instr,checknonsmi,checkmaps,zone()); | |
| 6813 todo.add_transitions(records); | |
| 6814 graph()->AddDeferredTransitions(todo); | |
| 6815 } | |
| 6339 } | 6816 } |
| 6340 *has_side_effects |= instr->HasObservableSideEffects(); | 6817 *has_side_effects |= instr->HasObservableSideEffects(); |
| 6341 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 6818 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
| 6342 return is_store ? NULL : instr; | 6819 return is_store ? NULL : instr; |
| 6343 } | 6820 } |
| 6344 | 6821 |
| 6345 HInstruction* checkspec = | 6822 HInstruction* checkspec = |
| 6346 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); | 6823 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); |
| 6347 HBasicBlock* join = graph()->CreateBasicBlock(); | 6824 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 6348 | 6825 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6380 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 6857 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6381 HCompareConstantEqAndBranch* elements_kind_branch = | 6858 HCompareConstantEqAndBranch* elements_kind_branch = |
| 6382 new(zone()) HCompareConstantEqAndBranch( | 6859 new(zone()) HCompareConstantEqAndBranch( |
| 6383 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 6860 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
| 6384 elements_kind_branch->SetSuccessorAt(0, if_true); | 6861 elements_kind_branch->SetSuccessorAt(0, if_true); |
| 6385 elements_kind_branch->SetSuccessorAt(1, if_false); | 6862 elements_kind_branch->SetSuccessorAt(1, if_false); |
| 6386 current_block()->Finish(elements_kind_branch); | 6863 current_block()->Finish(elements_kind_branch); |
| 6387 | 6864 |
| 6388 set_current_block(if_true); | 6865 set_current_block(if_true); |
| 6389 HInstruction* access; | 6866 HInstruction* access; |
| 6867 HCheckMaps* checkmaps = NULL; | |
| 6390 if (IsFastElementsKind(elements_kind)) { | 6868 if (IsFastElementsKind(elements_kind)) { |
| 6391 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { | 6869 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
| 6392 AddInstruction(new(zone()) HCheckMaps( | 6870 checkmaps = new(zone()) HCheckMaps( |
| 6393 elements, isolate()->factory()->fixed_array_map(), | 6871 elements, isolate()->factory()->fixed_array_map(), |
| 6394 zone(), elements_kind_branch)); | 6872 zone(), elements_kind_branch); |
| 6873 AddInstruction(checkmaps); | |
| 6395 } | 6874 } |
| 6396 // TODO(jkummerow): The need for these two blocks could be avoided | 6875 // TODO(jkummerow): The need for these two blocks could be avoided |
| 6397 // in one of two ways: | 6876 // in one of two ways: |
| 6398 // (1) Introduce ElementsKinds for JSArrays that are distinct from | 6877 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
| 6399 // those for fast objects. | 6878 // those for fast objects. |
| 6400 // (2) Put the common instructions into a third "join" block. This | 6879 // (2) Put the common instructions into a third "join" block. This |
| 6401 // requires additional AST IDs that we can deopt to from inside | 6880 // requires additional AST IDs that we can deopt to from inside |
| 6402 // that join block. They must be added to the Property class (when | 6881 // that join block. They must be added to the Property class (when |
| 6403 // it's a keyed property) and registered in the full codegen. | 6882 // it's a keyed property) and registered in the full codegen. |
| 6404 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | 6883 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
| 6405 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | 6884 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
| 6406 HHasInstanceTypeAndBranch* typecheck = | 6885 HHasInstanceTypeAndBranch* typecheck = |
| 6407 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | 6886 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
| 6408 typecheck->SetSuccessorAt(0, if_jsarray); | 6887 typecheck->SetSuccessorAt(0, if_jsarray); |
| 6409 typecheck->SetSuccessorAt(1, if_fastobject); | 6888 typecheck->SetSuccessorAt(1, if_fastobject); |
| 6410 current_block()->Finish(typecheck); | 6889 current_block()->Finish(typecheck); |
| 6411 | 6890 |
| 6412 set_current_block(if_jsarray); | 6891 set_current_block(if_jsarray); |
| 6413 HInstruction* length; | 6892 HInstruction* length; |
| 6414 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, | 6893 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, |
| 6415 HType::Smi())); | 6894 HType::Smi())); |
| 6416 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 6895 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6417 ALLOW_SMI_KEY)); | 6896 ALLOW_SMI_KEY)); |
| 6418 access = AddInstruction(BuildFastElementAccess( | 6897 access = AddInstruction(BuildFastElementAccess( |
| 6419 elements, checked_key, val, elements_kind_branch, | 6898 elements, checked_key, val, elements_kind_branch, |
| 6420 elements_kind, is_store)); | 6899 elements_kind, is_store, true)); |
| 6421 if (!is_store) { | 6900 if (!is_store) { |
| 6422 Push(access); | 6901 Push(access); |
| 6423 } | 6902 } |
| 6424 | 6903 |
| 6425 *has_side_effects |= access->HasObservableSideEffects(); | 6904 *has_side_effects |= access->HasObservableSideEffects(); |
| 6426 if (position != -1) { | 6905 if (position != -1) { |
| 6427 access->set_position(position); | 6906 access->set_position(position); |
| 6428 } | 6907 } |
| 6429 if_jsarray->Goto(join); | 6908 if_jsarray->Goto(join); |
| 6430 | 6909 |
| 6431 set_current_block(if_fastobject); | 6910 set_current_block(if_fastobject); |
| 6432 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 6911 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 6433 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 6912 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6434 ALLOW_SMI_KEY)); | 6913 ALLOW_SMI_KEY)); |
| 6435 access = AddInstruction(BuildFastElementAccess( | 6914 access = AddInstruction(BuildFastElementAccess( |
| 6436 elements, checked_key, val, elements_kind_branch, | 6915 elements, checked_key, val, elements_kind_branch, |
| 6437 elements_kind, is_store)); | 6916 elements_kind, is_store, true)); |
| 6438 } else if (elements_kind == DICTIONARY_ELEMENTS) { | 6917 } else if (elements_kind == DICTIONARY_ELEMENTS) { |
| 6439 if (is_store) { | 6918 if (is_store) { |
| 6440 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | 6919 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
| 6441 } else { | 6920 } else { |
| 6442 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | 6921 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 6443 } | 6922 } |
| 6444 } else { // External array elements. | 6923 } else { // External array elements. |
| 6445 access = AddInstruction(BuildExternalArrayElementAccess( | 6924 access = AddInstruction(BuildExternalArrayElementAccess( |
| 6446 external_elements, checked_key, val, elements_kind_branch, | 6925 external_elements, checked_key, val, elements_kind_branch, |
| 6447 elements_kind, is_store)); | 6926 elements_kind, is_store)); |
| 6448 } | 6927 } |
| 6449 *has_side_effects |= access->HasObservableSideEffects(); | 6928 *has_side_effects |= access->HasObservableSideEffects(); |
| 6450 if (position != RelocInfo::kNoPosition) access->set_position(position); | 6929 if (position != RelocInfo::kNoPosition) access->set_position(position); |
| 6451 if (!is_store) { | 6930 if (!is_store) { |
| 6452 Push(access); | 6931 Push(access); |
| 6453 } | 6932 } |
| 6933 | |
| 6934 if (records.length() > 0) { | |
| 6935 // Only move transitions for fast element types | |
| 6936 if (IsFastElementsKind(elements_kind)) { | |
| 6937 ASSERT(access->IsLoadKeyed() || access->IsStoreKeyed()); | |
| 6938 DeferredTransitions todo(access,checknonsmi,checkmaps,zone()); | |
| 6939 todo.add_transitions(records); | |
| 6940 graph()->AddDeferredTransitions(todo); | |
| 6941 } | |
| 6942 } | |
| 6943 | |
| 6454 current_block()->Goto(join); | 6944 current_block()->Goto(join); |
| 6455 set_current_block(if_false); | 6945 set_current_block(if_false); |
| 6456 } | 6946 } |
| 6457 } | 6947 } |
| 6458 | 6948 |
| 6459 // Deopt if none of the cases matched. | 6949 // Deopt if none of the cases matched. |
| 6460 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 6950 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
| 6461 join->SetJoinId(ast_id); | 6951 join->SetJoinId(ast_id); |
| 6462 set_current_block(join); | 6952 set_current_block(join); |
| 6463 return is_store ? NULL : Pop(); | 6953 return is_store ? NULL : Pop(); |
| (...skipping 3227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9691 | 10181 |
| 9692 | 10182 |
| 9693 void HEnvironment::PrintToStd() { | 10183 void HEnvironment::PrintToStd() { |
| 9694 HeapStringAllocator string_allocator; | 10184 HeapStringAllocator string_allocator; |
| 9695 StringStream trace(&string_allocator); | 10185 StringStream trace(&string_allocator); |
| 9696 PrintTo(&trace); | 10186 PrintTo(&trace); |
| 9697 PrintF("%s", *trace.ToCString()); | 10187 PrintF("%s", *trace.ToCString()); |
| 9698 } | 10188 } |
| 9699 | 10189 |
| 9700 | 10190 |
| 10191 TransitionRecord::TransitionRecord(HTransitionElementsKind* transition_instr, | |
| 10192 Handle<Map> map_from, Handle<Map> map_to) | |
| 10193 : transition_instr_(transition_instr), | |
| 10194 map_from_(map_from), | |
| 10195 map_to_(map_to), | |
| 10196 optimistic_holey_() { | |
| 10197 | |
| 10198 // When transition records are created, we have the chance to create map trans itions we | |
| 10199 // might need later. Transitions are unified during optimization, and we may n eed | |
| 10200 // to transition from a packed fastmap to a holey version of same. But we can' t create | |
| 10201 // those transitions during optimization. Do it now, recognizing that when the handle | |
| 10202 // disappears these maps may be collected if they didn't make it into usage in the | |
| 10203 // optimized graph. | |
| 10204 | |
| 10205 // TODO(mvstanton): generalize this service into "MakeWorstCaseMapForElementsK indTransition" | |
| 10206 // (ie, not "holey") | |
| 10207 if (IsFastPackedElementsKind(map_to->elements_kind())) { | |
| 10208 ElementsKind holey_kind = GetHoleyElementsKind(map_to->elements_kind()); | |
| 10209 // The transition might already exist | |
| 10210 Handle<Map> holey_map_handle(FindClosestElementsTransition(*map_to, holey_ki nd)); | |
| 10211 ASSERT(!holey_map_handle.is_null()); | |
| 10212 if (holey_map_handle->elements_kind() != holey_kind) { | |
| 10213 MaybeObject* holey_map = AddMissingElementsTransitions(*map_to, holey_kind ); | |
| 10214 holey_map->ToHandle<Map>(&optimistic_holey_); | |
| 10215 } else { | |
| 10216 optimistic_holey_ = holey_map_handle; | |
| 10217 } | |
| 10218 } else { | |
| 10219 optimistic_holey_ = map_to; | |
| 10220 } | |
| 10221 | |
| 10222 ASSERT(!optimistic_holey_.is_null()); | |
| 10223 | |
| 10224 // fill in map_family_ | |
| 10225 // Walk up to the base map from the map_to(); | |
| 10226 Handle<Map> end_map(FindClosestElementsTransition(*map_to, TERMINAL_FAST_ELEME NTS_KIND)); | |
| 10227 ASSERT(!end_map.is_null()); | |
| 10228 map_family_ = end_map; | |
| 10229 } | |
| 10230 | |
| 10231 | |
| 10232 void DeferredTransitions::compute_highest() { | |
| 10233 // Walk the transition records and find the "highest to" value, setting it. | |
| 10234 Map* newHighest = *(transition(0).map_to().location()); | |
| 10235 set_highest(newHighest); | |
| 10236 } | |
| 10237 | |
| 10238 | |
| 10239 void DeferredTransitions::ComputeTerminalNodes(int maximumGraphValueID) { | |
| 10240 HValue* elements = NULL; | |
| 10241 | |
| 10242 if(instr()->IsStoreKeyed()) { | |
| 10243 elements = HStoreKeyed::cast(instr())->elements(); | |
| 10244 } else { | |
| 10245 CHECK(instr()->IsLoadKeyed()); | |
| 10246 elements = HLoadKeyed::cast(instr())->elements(); | |
| 10247 } | |
| 10248 | |
| 10249 ASSERT(elements != NULL); | |
| 10250 // Now get the item from the elements | |
| 10251 ASSERT(elements->IsLoadElements()); | |
| 10252 HLoadElements *start = HLoadElements::cast(elements); | |
| 10253 | |
| 10254 ASSERT(terminal_nodes_->length() == 0); | |
| 10255 BitVector visited(maximumGraphValueID, zone()); | |
| 10256 | |
| 10257 ZoneList<HValue*> worklist(10, zone()); | |
| 10258 worklist.Add(start->value(), zone()); | |
| 10259 | |
| 10260 while (!worklist.is_empty()) { | |
| 10261 HValue* value = worklist.RemoveLast(); | |
| 10262 // Have we visited this node? | |
| 10263 if (!visited.Contains(value->id())) { | |
| 10264 visited.Add(value->id()); | |
| 10265 if (value->IsPhi()) { | |
| 10266 HPhi *phi = HPhi::cast(value); | |
| 10267 for (int i=0; i<phi->OperandCount(); i++) { | |
| 10268 worklist.Add(phi->OperandAt(i), zone()); | |
| 10269 } | |
| 10270 } else { | |
| 10271 // It must be a terminal node. | |
| 10272 ASSERT(value->IsInstruction()); | |
| 10273 terminal_nodes_->Add(HInstruction::cast(value), zone()); | |
| 10274 } | |
| 10275 } | |
| 10276 } | |
| 10277 | |
| 10278 // We must have found something. | |
| 10279 ASSERT(terminal_nodes_->length() > 0); | |
| 10280 } | |
| 10281 | |
| 10282 | |
| 10283 void DeferredTransitions::PrintTo(StringStream* stream) const { | |
| 10284 stream->Add("SITE: block%d %d: ", instr()->block()->block_id(), instr()->id()) ; | |
| 10285 instr()->PrintTo(stream); | |
| 10286 stream->Add("\n"); | |
| 10287 | |
| 10288 // Print validness | |
| 10289 stream->Add(" VALIDITY: %s\n", invalid() ? "invalid" : "valid"); | |
| 10290 | |
| 10291 // Print score | |
| 10292 stream->Add(" SCORE: (+%d,%d,-%d)\n", score_[0], score_[1], score_[2]); | |
| 10293 | |
| 10294 // Find the def point for the instruction | |
| 10295 HValue *elementsptr = NULL; | |
| 10296 if(instr()->IsStoreKeyed()) { | |
| 10297 elementsptr = HStoreKeyed::cast(instr())->elements(); | |
| 10298 } else { | |
| 10299 ASSERT(instr()->IsLoadKeyed()); | |
| 10300 elementsptr = HLoadKeyed::cast(instr())->elements(); | |
| 10301 } | |
| 10302 | |
| 10303 ASSERT(elementsptr != NULL); | |
| 10304 // Now get the item from the elements | |
| 10305 ASSERT(elementsptr->IsLoadElements()); | |
| 10306 HLoadElements *elements = HLoadElements::cast(elementsptr); | |
| 10307 HValue *elementValue = elements->value(); | |
| 10308 stream->Add(" OBJECT: "); | |
| 10309 elementValue->PrintNameTo(stream); | |
| 10310 stream->Add(" "); | |
| 10311 elementValue->PrintTo(stream); | |
| 10312 stream->Add(" %s\n",elementValue->IsPhi() ? "PHI" : ""); | |
| 10313 stream->Add(" TRANSITIONS:\n"); | |
| 10314 ElementsKind transitionElementsKind = FAST_SMI_ELEMENTS; | |
| 10315 for (int i = 0; i < transitions(); i++) { | |
| 10316 stream->Add(" %s", ElementsKindToString(transition(i).from())); | |
| 10317 stream->Add("(0x%p)-> ", *(transition(i).map_from())); | |
| 10318 stream->Add("%s", ElementsKindToString(transition(i).to())); | |
| 10319 stream->Add("(0x%p)\n", *(transition(i).map_to())); | |
| 10320 transitionElementsKind = transition(i).to(); | |
| 10321 } | |
| 10322 | |
| 10323 // Print possibly externally computed map | |
| 10324 const char *signifier = (transitionElementsKind != highest()->elements_kind()) | |
| 10325 ? "*" : ""; | |
| 10326 stream->Add(" COMPUTED HIGHEST: %s%s(0x%p)\n", signifier, | |
| 10327 ElementsKindToString(highest()->elements_kind()), | |
| 10328 highest()); | |
| 10329 | |
| 10330 // Print terminal nodes if available | |
| 10331 stream->Add(" TERMINAL NODES:\n"); | |
| 10332 for (int j=0; j < terminal_nodes(); j++) { | |
| 10333 HValue* node = terminal_node(j); | |
| 10334 stream->Add(" block%d %d: ", node->block()->block_id(), node->id()); | |
| 10335 node->PrintNameTo(stream); | |
| 10336 stream->Add(" "); | |
| 10337 node->PrintTo(stream); | |
| 10338 stream->Add("\n"); | |
| 10339 } | |
| 10340 | |
| 10341 } | |
| 10342 | |
| 10343 | |
| 10344 void DeferredTransitions::PrintToStd() const { | |
| 10345 HeapStringAllocator string_allocator; | |
| 10346 StringStream trace(&string_allocator); | |
| 10347 PrintTo(&trace); | |
| 10348 PrintF("%s", *trace.ToCString()); | |
| 10349 } | |
| 10350 | |
| 10351 | |
| 9701 void HTracer::TraceCompilation(FunctionLiteral* function) { | 10352 void HTracer::TraceCompilation(FunctionLiteral* function) { |
| 9702 Tag tag(this, "compilation"); | 10353 Tag tag(this, "compilation"); |
| 9703 Handle<String> name = function->debug_name(); | 10354 Handle<String> name = function->debug_name(); |
| 9704 PrintStringProperty("name", *name->ToCString()); | 10355 PrintStringProperty("name", *name->ToCString()); |
| 9705 PrintStringProperty("method", *name->ToCString()); | 10356 PrintStringProperty("method", *name->ToCString()); |
| 9706 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); | 10357 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); |
| 9707 } | 10358 } |
| 9708 | 10359 |
| 9709 | 10360 |
| 9710 void HTracer::TraceLithium(const char* name, LChunk* chunk) { | 10361 void HTracer::TraceLithium(const char* name, LChunk* chunk) { |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10011 } | 10662 } |
| 10012 } | 10663 } |
| 10013 | 10664 |
| 10014 #ifdef DEBUG | 10665 #ifdef DEBUG |
| 10015 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10666 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 10016 if (allocator_ != NULL) allocator_->Verify(); | 10667 if (allocator_ != NULL) allocator_->Verify(); |
| 10017 #endif | 10668 #endif |
| 10018 } | 10669 } |
| 10019 | 10670 |
| 10020 } } // namespace v8::internal | 10671 } } // namespace v8::internal |
| OLD | NEW |