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

Side by Side Diff: src/hydrogen.cc

Issue 11365174: A change in the way we place TransitionElementKinds in the tree. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Now includes optimization of codegen for transition elementskind instruction Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 dominator_(NULL), 64 dominator_(NULL),
65 dominated_blocks_(4, graph->zone()), 65 dominated_blocks_(4, graph->zone()),
66 last_environment_(NULL), 66 last_environment_(NULL),
67 argument_count_(-1), 67 argument_count_(-1),
68 first_instruction_index_(-1), 68 first_instruction_index_(-1),
69 last_instruction_index_(-1), 69 last_instruction_index_(-1),
70 deleted_phis_(4, graph->zone()), 70 deleted_phis_(4, graph->zone()),
71 parent_loop_header_(NULL), 71 parent_loop_header_(NULL),
72 is_inline_return_target_(false), 72 is_inline_return_target_(false),
73 is_deoptimizing_(false), 73 is_deoptimizing_(false),
74 dominates_loop_successors_(false) { } 74 dominates_loop_successors_(false),
75 is_osr_entry_(false) { }
75 76
76 77
77 void HBasicBlock::AttachLoopInformation() { 78 void HBasicBlock::AttachLoopInformation() {
78 ASSERT(!IsLoopHeader()); 79 ASSERT(!IsLoopHeader());
79 loop_information_ = new(zone()) HLoopInformation(this, zone()); 80 loop_information_ = new(zone()) HLoopInformation(this, zone());
80 } 81 }
81 82
82 83
83 void HBasicBlock::DetachLoopInformation() { 84 void HBasicBlock::DetachLoopInformation() {
84 ASSERT(IsLoopHeader()); 85 ASSERT(IsLoopHeader());
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 692
692 693
693 HGraph::HGraph(CompilationInfo* info) 694 HGraph::HGraph(CompilationInfo* info)
694 : isolate_(info->isolate()), 695 : isolate_(info->isolate()),
695 next_block_id_(0), 696 next_block_id_(0),
696 entry_block_(NULL), 697 entry_block_(NULL),
697 blocks_(8, info->zone()), 698 blocks_(8, info->zone()),
698 values_(16, info->zone()), 699 values_(16, info->zone()),
699 phi_list_(NULL), 700 phi_list_(NULL),
700 uint32_instructions_(NULL), 701 uint32_instructions_(NULL),
702 array_instructions_(NULL),
701 info_(info), 703 info_(info),
702 zone_(info->zone()), 704 zone_(info->zone()),
703 is_recursive_(false), 705 is_recursive_(false),
704 use_optimistic_licm_(false), 706 use_optimistic_licm_(false),
705 type_change_checksum_(0) { 707 type_change_checksum_(0) {
706 start_environment_ = 708 start_environment_ =
707 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); 709 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
708 start_environment_->set_ast_id(BailoutId::FunctionEntry()); 710 start_environment_->set_ast_id(BailoutId::FunctionEntry());
709 entry_block_ = CreateBasicBlock(); 711 entry_block_ = CreateBasicBlock();
710 entry_block_->SetInitialEnvironment(start_environment_); 712 entry_block_->SetInitialEnvironment(start_environment_);
(...skipping 1731 matching lines...) Expand 10 before | Expand all | Expand 10 after
2442 ZoneList<HValue*> worklist(block->phis()->length(), zone()); 2444 ZoneList<HValue*> worklist(block->phis()->length(), zone());
2443 for (int j = 0; j < block->phis()->length(); ++j) { 2445 for (int j = 0; j < block->phis()->length(); ++j) {
2444 worklist.Add(block->phis()->at(j), zone()); 2446 worklist.Add(block->phis()->at(j), zone());
2445 } 2447 }
2446 InferTypes(&worklist); 2448 InferTypes(&worklist);
2447 } 2449 }
2448 } 2450 }
2449 } 2451 }
2450 2452
2451 2453
2454 // Maintain a dictionary of "map family" + elements kind to a handle with the
2455 // appropriate map.
2456 class MapHandleDictionary BASE_EMBEDDED {
2457 public:
2458 explicit MapHandleDictionary(Zone* zone) :
2459 indexer_(IndexMatch, ZoneAllocationPolicy(zone)),
2460 zone_(zone) {
2461 }
2462
2463 Handle<Map> Lookup(Handle<Map> family, ElementsKind kind) {
2464 IndexKey lookupKey(family, kind);
2465 IndexKeyTable::Iterator i = indexer_.find(
2466 &lookupKey, false, ZoneAllocationPolicy(zone_));
2467 if (i != indexer_.end()) {
2468 return i->second->map;
2469 }
2470
2471 return Handle<Map>::null();
2472 }
2473
2474 void Add(Handle<Map> handle) {
2475 // This does violence to the map family concept, but it's a way to store
2476 // semi-unknown maps that we get from mapcheck instructions.
2477 if (Lookup(handle, handle->elements_kind()).is_null()) {
2478 Insert(handle, handle);
2479 }
2480 }
2481
2482 void InsertIfMissing(Handle<Map> handle, Handle<Map> family) {
2483 if (Lookup(handle, handle->elements_kind()).is_null()) {
2484 Insert(handle, family);
2485 }
2486 }
2487
2488 private:
2489 struct IndexKey: public ZoneObject {
2490 IndexKey(Handle<Map> family_in, ElementsKind kind_in) :
2491 family(family_in),
2492 kind(kind_in) {
2493 }
2494
2495 int Hash() {
2496 return family->Hash() + (31*kind);
2497 }
2498
2499 Handle<Map> family;
2500 ElementsKind kind;
2501 };
2502
2503 struct Value: public ZoneObject {
2504 explicit Value(Handle<Map> map_in) :
2505 map(map_in) {
2506 }
2507
2508 Handle<Map> map;
2509 };
2510
2511 static bool IndexMatch(void* key1, void* key2) {
2512 IndexKey* k1 = reinterpret_cast<IndexKey*>(key1);
2513 IndexKey* k2 = reinterpret_cast<IndexKey*>(key2);
2514 return k1->Hash() == k2->Hash();
2515 }
2516
2517 void Insert(Handle<Map> handle, Handle<Map> family) {
2518 IndexKey *key = new(zone()) IndexKey(family, handle->elements_kind());
2519 IndexKeyTable::Iterator iki = indexer_.find(key, true,
2520 ZoneAllocationPolicy(zone()));
2521 ASSERT(iki != indexer_.end());
2522 iki->second = new(zone()) Value(handle);
2523
2524 key = new(zone()) IndexKey(handle, handle->elements_kind());
2525 iki = indexer_.find(key, true,
2526 ZoneAllocationPolicy(zone()));
2527 ASSERT(iki != indexer_.end());
2528 if (iki->second == NULL) {
2529 iki->second = new(zone()) Value(handle);
2530 }
2531 }
2532
2533 Zone* zone() { return zone_; }
2534
2535 typedef TemplateHashMap<IndexKey, Value, ZoneAllocationPolicy>
2536 IndexKeyTable;
2537 IndexKeyTable indexer_;
2538 Zone* zone_;
2539 };
2540
2541
2542 class ResolutionTableValue: public ZoneObject {
2543 public:
2544 ResolutionTableValue(HValue* key, HGraph* graph) :
2545 poisoned_(false),
2546 extra_data_(NULL) {
2547 if (key->IsArrayInstruction()) {
2548 Initialize(HArrayInstruction::cast(key));
2549 } else if (key->IsPhi()) {
2550 Initialize(HPhi::cast(key), graph->GetMaximumValueID(), graph->zone());
2551 }
2552 }
2553
2554 Handle<Map> to() { return to_; }
2555 Handle<Map> family() { return family_; }
2556 bool poisoned() { return poisoned_; }
2557
2558 typedef EnumSet<ElementsKind> ElementsKindSet;
2559 ElementsKindSet from_set() { return from_elements_; }
2560
2561 bool HasStrongInformation() {
2562 return (!to().is_null() && !family().is_null()) || poisoned_;
2563 }
2564 bool HasWeakInformation() { return !to().is_null() && family().is_null(); }
2565
2566 bool Merge(ResolutionTableValue* from_value,
2567 MapHandleDictionary* map_handles) {
2568 // a) Poison must always be imbibed
2569 if (from_value->poisoned() && !poisoned()) {
2570 poisoned_ = true;
2571 return true;
2572 }
2573
2574 // b) from_value has no information. No change.
2575 if (from_value->to().is_null()) {
2576 return false;
2577 }
2578
2579 // c) We are uninitialized or have weaker information.
2580 if (to().is_null() || (HasWeakInformation() &&
2581 from_value->HasStrongInformation())) {
2582 to_ = from_value->to();
2583 from_elements_.Add(from_value->from_set());
2584 family_ = from_value->family();
2585 return true;
2586 }
2587
2588 if (from_value->HasWeakInformation()) {
2589 // The from node has weak information, and we have some (weak or strong)
2590 // information. Do not take advice from the weak information node.
2591 return false;
2592 }
2593
2594 ASSERT(HasStrongInformation() && from_value->HasStrongInformation());
2595
2596 // d) We are both initialized. Negotiate
2597 if (!from_value->family().is_identical_to(family())) {
2598 // We cannot change families!
2599 poisoned_ = true;
2600 return true;
2601 }
2602
2603 bool changed = false;
2604 if (!to().is_identical_to(from_value->to())) {
2605 // figure out unified map
2606 ElementsKind unified_elements_kind = GetUnifiedFastElementsKind(
2607 to()->elements_kind(),
2608 from_value->to()->elements_kind());
2609 Handle<Map> unified_map_handle = map_handles->Lookup(family(),
2610 unified_elements_kind);
2611 if (unified_map_handle.is_null()) {
2612 poisoned_ = true;
2613 return true;
2614 }
2615
2616 ASSERT(to_->elements_kind() == unified_map_handle->elements_kind() ||
2617 IsMoreGeneralElementsKindTransition(to_->elements_kind(),
2618 unified_map_handle->elements_kind()));
2619 to_ = unified_map_handle;
2620 changed = true;
2621 }
2622
2623 if (!(from_set() == from_value->from_set())) {
2624 from_elements_.Add(from_value->from_set());
2625 changed = true;
2626 }
2627
2628 return changed;
2629 }
2630
2631 void SetPoisoned() {
2632 poisoned_ = true;
2633 to_ = Handle<Map>::null();
2634 family_ = Handle<Map>::null();
2635 from_elements_.RemoveAll();
2636 }
2637
2638 bool VisitedBy(HValue* value) {
2639 ASSERT(visited_set() != NULL);
2640 return visited_set()->Contains(value->id());
2641 }
2642
2643 void MarkVisitedBy(HValue* value) {
2644 ASSERT(visited_set() != NULL);
2645 visited_set()->Add(value->id());
2646 }
2647
2648 void ClearVisitedBy() {
2649 ASSERT(visited_set() != NULL);
2650 visited_set()->Clear();
2651 }
2652
2653 void SetWeakInformation(Handle<Map> to_map) {
2654 ASSERT(!to_map.is_null());
2655 ASSERT(!HasStrongInformation() && !HasWeakInformation());
2656 to_ = to_map;
2657 }
2658
2659 // For instruction emission
2660 void InsertTransitionElementsKind(HGraph* graph, HValue* root,
2661 Handle<Map> from, Handle<Map> to,
2662 bool special_case) {
2663 if (placement_data() == NULL) {
2664 set_placement_data(new(graph->zone()) PlacementData(
2665 HInstruction::cast(root)));
2666 }
2667
2668 PlacementData* data = placement_data();
2669 if (data->from_elements.Contains(from->elements_kind())) {
2670 return;
2671 }
2672
2673 if (*from == *to) {
2674 return;
2675 }
2676
2677 // If root is a fastliteral, we can get a performance boost by asking that
2678 // the boilerplate array object be transitioned and saved that way.
2679 if (root->IsFastLiteral()) {
2680 HFastLiteral* literal = HFastLiteral::cast(root);
2681 if (!literal->TransitionRequested()) {
2682 literal->SetTransitionTo(to->elements_kind());
2683 }
2684 ASSERT(literal->TransitionTo() == to->elements_kind());
2685 // No need for any transition instructions. The transition will
2686 // have been completed.
2687 return;
2688 }
2689
2690 // At the site, we maintain a most recent instruction we added, and
2691 // new instructions should appear at the end of the chain.
2692 HInstruction* add_after = data->last_in_chain;
2693 if (add_after == NULL) {
2694 // This is the first instruction to add.
2695 // We must emit a checknonsmi
2696 add_after = new(graph->zone()) HCheckNonSmi(data->transition_input);
2697 HInstruction* add_after_location = data->transition_input;
2698 if (data->transition_input->block()->is_osr_entry()) {
2699 // If our root is in an OSR block, we need to go after the OsrEntry
2700 // instruction, because that is where OSR jumps to.
2701 ASSERT(data->transition_input->IsUnknownOSRValue());
2702 do {
2703 add_after_location = add_after_location->next();
2704 } while (!add_after_location->IsGoto());
2705 add_after->InsertBefore(add_after_location);
2706 } else {
2707 add_after->InsertAfter(add_after_location);
2708 }
2709 }
2710
2711 HTransitionElementsKind* transition = NULL;
2712 if (data->last_in_chain == NULL) {
2713 ASSERT(*from != *to);
2714 transition = new(graph->zone()) HTransitionElementsKind(
2715 data->transition_input, from, to, graph->isolate(), false);
2716 if (special_case) {
2717 transition->set_special_case();
2718 }
2719 transition->InsertAfter(add_after);
2720
2721 // Careful tree surgery
2722 for (HUseIterator it(data->transition_input->uses()); !it.Done();
2723 it.Advance()) {
2724 HValue* use = it.value();
2725 if (use != HValue::cast(add_after) &&
2726 use != HValue::cast(transition)) {
2727 CarefullyReplaceOperand(use, it.index(), transition);
2728 }
2729 }
2730 } else {
2731 ASSERT(!from.is_identical_to(to));
2732 transition = new(graph->zone()) HTransitionElementsKind(
2733 data->last_in_chain, from, to, graph->isolate(), false);
2734 if (special_case) {
2735 transition->set_special_case();
2736 }
2737 transition->InsertAfter(data->last_in_chain);
2738
2739 // Careful tree surgery
2740 for (HUseIterator it(data->last_in_chain->uses()); !it.Done();
2741 it.Advance()) {
2742 HValue* use = it.value();
2743 if (use != HValue::cast(transition)) {
2744 CarefullyReplaceOperand(use, it.index(), transition);
2745 }
2746 }
2747 }
2748
2749 data->last_in_chain = transition;
2750 data->from_elements.Add(from->elements_kind());
2751 }
2752
2753 private:
2754 struct PlacementData: public ZoneObject {
2755 explicit PlacementData(HInstruction* transition_input) :
2756 transition_input(transition_input),
2757 last_in_chain(NULL) {
2758 }
2759
2760 HInstruction* transition_input;
2761 ElementsKindSet from_elements;
2762 HTransitionElementsKind* last_in_chain;
2763 };
2764
2765 BitVector* visited_set() {
2766 return reinterpret_cast<BitVector*>(extra_data_);
2767 }
2768
2769 void set_visited_set(BitVector* visited_set) {
2770 ASSERT(extra_data_ == NULL);
2771 extra_data_ = visited_set;
2772 }
2773
2774 PlacementData* placement_data() {
2775 return reinterpret_cast<PlacementData*>(extra_data_);
2776 }
2777
2778 void set_placement_data(PlacementData* placement_data) {
2779 ASSERT(extra_data_ == NULL);
2780 extra_data_ = placement_data;
2781 }
2782
2783 void Initialize(HArrayInstruction* instr) {
2784 if (!instr->hoistable()) {
2785 poisoned_ = true;
2786 ASSERT(HasStrongInformation());
2787 } else {
2788 family_ = instr->map_family(); // may be null
2789 if (!family_.is_null()) {
2790 // We should have bookmarks to initialize with
2791 ASSERT(instr->transitions() > 0);
2792 for (int i = 0; i < instr->transitions(); i++) {
2793 HTransitionElementsKind* tr = instr->transition(i);
2794 from_elements_.Add(tr->original_map()->elements_kind());
2795 to_ = tr->transitioned_map();
2796 }
2797 ASSERT(HasStrongInformation());
2798 }
2799 }
2800 }
2801
2802 void Initialize(HPhi* phi, int maximum_graph_id, Zone* zone) {
2803 set_visited_set(new(zone) BitVector(maximum_graph_id, zone));
2804 }
2805
2806 void CarefullyReplaceOperand(HValue* use, int operand_index,
2807 HInstruction* with) {
2808 if (!use->block()->IsStartBlock()) {
2809 if (!use->IsSimulate() ||
2810 use->block()->block_id() > with->block()->block_id()) {
2811 use->SetOperandAt(operand_index, with);
2812 } else if (HInstruction::cast(use)->IsDefinedAfterInSameBlock(with)) {
2813 use->SetOperandAt(operand_index, with);
2814 }
2815 }
2816 }
2817
2818 Handle<Map> to_;
2819 Handle<Map> family_;
2820 bool poisoned_;
2821 ElementsKindSet from_elements_;
2822 void* extra_data_; // used by phi or root nodes differently
2823 };
2824
2825
2826 class HTransitionHoister BASE_EMBEDDED {
2827 public:
2828 explicit HTransitionHoister(HGraph* graph)
2829 : graph_(graph),
2830 map_handles_(zone()),
2831 table_(HValueMatch, ZoneAllocationPolicy(zone())),
2832 lookaside_(HValueMatch, ZoneAllocationPolicy(zone())) {
2833 }
2834
2835 // Returns true if there is useful work to do.
2836 // Returns false and finalizes all array instructions in the
2837 // graph if not.
2838 bool Analyze();
2839
2840 void DoWork(bool special_case) {
2841 ZoneList<WorkItem> worklist_up(10, zone());
2842 ZoneList<WorkItem> worklist_down(10, zone());
2843
2844 PopulateWorklistWithArraySites(&worklist_up);
2845 ASSERT(worklist_up.length() > 0);
2846
2847 // Clear VisitedBy sets in the tables
2848 ClearVisitedSets();
2849
2850 TraverseArraySitesToRoots(&worklist_up, &worklist_down);
2851 ASSERT(worklist_up.length() == 0);
2852 ASSERT(worklist_down.length() > 0);
2853
2854 TraverseRootsToArraySites(&worklist_down, special_case);
2855 ASSERT(worklist_down.length() == 0);
2856 }
2857
2858 private:
2859 struct WorkItem {
2860 WorkItem(HValue* from_in, HValue* to_in, HValue* context_in)
2861 : from(from_in), to(to_in), context(context_in) {
2862 }
2863 bool operator==(const WorkItem& pair) const {
2864 return pair.from == from && pair.to == to && pair.context == context;
2865 }
2866 HValue* from;
2867 HValue* to;
2868 HValue* context;
2869 };
2870
2871 void ClearVisitedSets();
2872 void PopulateWorklistWithArraySites(ZoneList<WorkItem>* worklist_up);
2873 void TraverseArraySitesToRoots(ZoneList<WorkItem>* worklist_up,
2874 ZoneList<WorkItem>* worklist_down);
2875 void TraverseRootsToArraySites(ZoneList<WorkItem>* worklist_down, bool special _case);
2876 void UpdateMapCheck(HCheckMaps* check_maps,
2877 ResolutionTableValue* nearest_value);
2878 void PlaceArrayInstructionTransitions(HArrayInstruction* instr, HValue* root, bool special_case);
2879 void GatherWeakInformationFromMapCheck(HCheckMaps* check_maps,
2880 HValue* from_instr,
2881 ResolutionTableValue* from_value);
2882
2883 typedef TemplateHashMap<HValue, ResolutionTableValue, ZoneAllocationPolicy>
2884 ResolutionTable;
2885
2886 ResolutionTableValue* LookupTableValue(HValue* key, ResolutionTable* table) {
2887 ResolutionTable::Iterator i = table->find(key, false,
2888 ZoneAllocationPolicy(zone()));
2889 if (i != table->end()) {
2890 return i->second;
2891 }
2892 return NULL;
2893 }
2894
2895 ResolutionTableValue* InsertTableValue(HValue* key, ResolutionTable* table) {
2896 ResolutionTable::Iterator i = table->find(key, true,
2897 ZoneAllocationPolicy(zone()));
2898 ASSERT(i != table->end());
2899 i->second = new(zone()) ResolutionTableValue(key, graph());
2900 return i->second;
2901 }
2902
2903 ResolutionTableValue* LookupSiteTableValue(HValue* key) {
2904 return LookupTableValue(key, &table_);
2905 }
2906
2907 ResolutionTableValue* InsertSiteTableValue(HValue* key) {
2908 return InsertTableValue(key, &table_);
2909 }
2910
2911 ResolutionTableValue* LookupRootTableValue(HValue* key) {
2912 ResolutionTable* correct_table = key->IsLoadKeyed()
2913 ? &lookaside_ : &table_;
2914 return LookupTableValue(key, correct_table);
2915 }
2916
2917 ResolutionTableValue* InsertRootTableValue(HValue* key) {
2918 ResolutionTable* correct_table = key->IsLoadKeyed()
2919 ? &lookaside_ : &table_;
2920 return InsertTableValue(key, correct_table);
2921 }
2922
2923 static bool HValueMatch(void* key1, void* key2) {
2924 return key1 == key2;
2925 }
2926
2927 Zone* zone() const { return graph_->zone(); }
2928 Isolate* isolate() const { return graph_->isolate(); }
2929 HGraph* graph() const { return graph_; }
2930
2931 HGraph* graph_;
2932 MapHandleDictionary map_handles_;
2933
2934 ResolutionTable table_;
2935 // lookaside contains information for LoadKeyed nodes that act as roots
2936 ResolutionTable lookaside_;
2937 };
2938
2939
2940 void HTransitionHoister::ClearVisitedSets() {
2941 for (ResolutionTable::Iterator i = table_.begin();
2942 i != table_.end();
2943 ++i) {
2944 HValue* key = i->first;
2945 ResolutionTableValue* table_value = i->second;
2946 if (key->IsPhi()) {
2947 table_value->ClearVisitedBy();
2948 }
2949 }
2950 }
2951
2952
2953 void HTransitionHoister::PopulateWorklistWithArraySites(
2954 ZoneList<WorkItem>* worklist_up) {
2955 for (int i = 0; i < graph()->array_instructions()->length(); ++i) {
2956 HArrayInstruction* array_instruction = graph()->array_instructions()->at(i);
2957 HValue* elements = array_instruction->elements();
2958 if (elements->IsLoadElements()) {
2959 // Add to our table
2960 InsertSiteTableValue(array_instruction);
2961
2962 // Add to our handle map
2963 for (int r = 0; r < array_instruction->transitions(); r++) {
2964 HTransitionElementsKind* transition = array_instruction->transition(r);
2965 Handle<Map> family = transition->family();
2966 map_handles_.InsertIfMissing(transition->original_map(),
2967 family);
2968 map_handles_.InsertIfMissing(transition->transitioned_map(),
2969 family);
2970 map_handles_.InsertIfMissing(transition->pessimistic_holey(),
2971 family);
2972 }
2973
2974 // Add to our worklist_up. Here I am skipping over elements,
2975 HLoadElements* start = HLoadElements::cast(elements);
2976 WorkItem item(array_instruction, start->value(), array_instruction);
2977 worklist_up->Add(item, zone());
2978
2979 if (FLAG_trace_transition_placement) {
2980 HeapStringAllocator string_allocator;
2981 StringStream stream(&string_allocator);
2982 array_instruction->PrintElementPlacementTo(&stream);
2983 PrintF("%s", *stream.ToCString());
2984 }
2985 } else {
2986 // No need to consider external arrays or for..in statements
2987 // Their inputs can be resolved through phis too.
2988 ASSERT(elements->IsLoadExternalArrayPointer() ||
2989 elements->IsForInCacheArray() ||
2990 elements->IsPhi());
2991
2992 array_instruction->Finalize();
2993 }
2994 }
2995 }
2996
2997
2998 void HTransitionHoister::TraverseArraySitesToRoots(
2999 ZoneList<WorkItem>* worklist_up,
3000 ZoneList<WorkItem>* worklist_down) {
3001 // Propagate information up the graph.
3002 while (!worklist_up->is_empty()) {
3003 WorkItem item = worklist_up->Remove(0);
3004 ASSERT(LookupSiteTableValue(item.from) != NULL);
3005 bool changed = false;
3006 bool first_visit_to_root = false;
3007
3008 ResolutionTableValue* to_value = LookupRootTableValue(item.to);
3009 if (to_value == NULL) {
3010 to_value = InsertRootTableValue(item.to);
3011 changed = true;
3012 first_visit_to_root = true;
3013 }
3014
3015 changed |= to_value->Merge(LookupSiteTableValue(item.from), &map_handles_);
3016 if (item.to->IsPhi()) {
3017 if (changed || !to_value->VisitedBy(item.context)) {
3018 to_value->MarkVisitedBy(item.context);
3019 HPhi* phi = HPhi::cast(item.to);
3020 for (int i = 0; i < phi->OperandCount(); i++) {
3021 worklist_up->Add(WorkItem(phi, phi->OperandAt(i), item.context),
3022 zone());
3023 }
3024 }
3025 } else {
3026 if (first_visit_to_root) {
3027 // It's the first time we've seen this root. Go ahead and start adding
3028 // these for downward processing.
3029 for (HUseIterator it(item.to->uses()); !it.Done(); it.Advance()) {
3030 HValue* value = it.value();
3031 if (value->IsPhi() || value->IsCheckMaps()) {
3032 worklist_down->Add(WorkItem(item.to, value, item.to), zone());
3033 } else if (value->IsLoadElements()) {
3034 // Walk through to the StoreKeyed(s)
3035 for (HUseIterator it_load(value->uses());
3036 !it_load.Done();
3037 it_load.Advance()) {
3038 if (it_load.value()->IsArrayInstruction()) {
3039 worklist_down->Add(WorkItem(item.to, it_load.value(), item.to),
3040 zone());
3041 }
3042 }
3043 }
3044 }
3045 }
3046
3047 // The context is useful to print here
3048 if (FLAG_trace_transition_placement) {
3049 HeapStringAllocator string_allocator;
3050 StringStream stream(&string_allocator);
3051 HArrayInstruction* instr = HArrayInstruction::cast(item.context);
3052 stream.Add("ARRAY INSTRUCTION: block%d %d: ",
3053 instr->block()->block_id(),
3054 instr->id());
3055 instr->PrintTo(&stream);
3056 stream.Add("\n");
3057 stream.Add(" maps to\n");
3058 HInstruction* root = HInstruction::cast(item.to);
3059 stream.Add(" block%d %d: ", root->block()->block_id(), root->id());
3060 root->PrintNameTo(&stream);
3061 stream.Add(" ");
3062 root->PrintTo(&stream);
3063 stream.Add("\n");
3064 if (!to_value->to().is_null()) {
3065 stream.Add(" To: %s(0x%p)\n",
3066 ElementsKindToString(to_value->to()->elements_kind()),
3067 *(to_value->to()));
3068 } else {
3069 stream.Add(" To: n/a\n");
3070 }
3071
3072 PrintF("%s", *stream.ToCString());
3073 }
3074 }
3075 }
3076 }
3077
3078
3079 void HTransitionHoister::TraverseRootsToArraySites(
3080 ZoneList<WorkItem>* worklist_down,
3081 bool special_case) {
3082 // Now propagate information back down to input sites, starting from root
3083 // nodes in the table
3084 while (!worklist_down->is_empty()) {
3085 WorkItem item = worklist_down->Remove(0);
3086 bool changed = false;
3087
3088 ResolutionTableValue* from_value = LookupRootTableValue(item.from);
3089 ASSERT(from_value != NULL);
3090 ResolutionTableValue* to_value = LookupSiteTableValue(item.to);
3091
3092 if (to_value == NULL && item.to->IsPhi()) {
3093 // We walk through phis on the way down, even if we didn't see
3094 // them on the way up. There may be interesting nodes in these
3095 // new locations (checkmaps, store/loads).
3096 to_value = InsertSiteTableValue(item.to);
3097 }
3098
3099 if (to_value != NULL) {
3100 changed = to_value->Merge(from_value, &map_handles_);
3101 }
3102
3103 if (item.to->IsPhi() && (changed || !to_value->VisitedBy(item.context))) {
3104 // Walk through phis, marking them as visited.
3105 ASSERT(to_value != NULL);
3106 to_value->MarkVisitedBy(item.context);
3107
3108 for (HUseIterator it(item.to->uses()); !it.Done(); it.Advance()) {
3109 HValue* value = it.value();
3110 if (value->IsPhi() || value->IsCheckMaps()) {
3111 worklist_down->Add(WorkItem(item.to, value, item.context), zone());
3112 } else if (value->IsLoadElements()) {
3113 // Walk through to the StoreKeyed(s)
3114 for (HUseIterator it_load(value->uses());
3115 !it_load.Done();
3116 it_load.Advance()) {
3117 if (it_load.value()->IsArrayInstruction()) {
3118 worklist_down->Add(WorkItem(item.to, it_load.value(),
3119 item.context), zone());
3120 }
3121 }
3122 }
3123 }
3124 } else if (item.to->IsArrayInstruction()) {
3125 // Place any transition instructions appropriately, moving them from their
3126 // locations down at the array instruction site up to the transition input
3127 // site.
3128 PlaceArrayInstructionTransitions(HArrayInstruction::cast(item.to),
3129 item.context,
3130 special_case);
3131 } else if (item.to->IsCheckMaps()) {
3132 // There is no to_value for this case. We just need to try and either
3133 // update the checkmaps instruction or glean some "weak" information from
3134 // it about monomorphic map checks for our table.
3135 ASSERT(to_value == NULL);
3136 HCheckMaps* check_maps = HCheckMaps::cast(item.to);
3137 if (from_value->HasStrongInformation()) {
3138 UpdateMapCheck(check_maps, from_value);
3139 } else if (!from_value->HasWeakInformation()) {
3140 GatherWeakInformationFromMapCheck(check_maps,
3141 item.from,
3142 from_value);
3143 }
3144 }
3145 }
3146 }
3147
3148
3149 bool HTransitionHoister::Analyze() {
3150 if (graph()->array_instructions() == NULL ||
3151 graph()->array_instructions()->length() == 0) {
3152 // Nothing useful to do
3153 return false;
3154 }
3155
3156 bool transitions_present = false;
3157 for (int i = 0; i < graph()->array_instructions()->length(); ++i) {
3158 HArrayInstruction* array_instruction = graph()->array_instructions()->at(i);
3159 if (array_instruction->transitions() > 0) {
3160 transitions_present = true;
3161 break;
3162 }
3163 }
3164
3165 if (!transitions_present) {
3166 for (int i = 0; i < graph()->array_instructions()->length(); ++i) {
3167 graph()->array_instructions()->at(i)->Finalize();
3168 }
3169
3170 return false;
3171 }
3172
3173 return true;
3174 }
3175
3176
3177 void HTransitionHoister::PlaceArrayInstructionTransitions(
3178 HArrayInstruction* instr,
3179 HValue* root,
3180 bool special_case) {
3181 ResolutionTableValue* load_or_store_value =
3182 LookupSiteTableValue(instr);
3183 ResolutionTableValue* root_value = LookupRootTableValue(root);
3184 ASSERT(load_or_store_value != NULL && root_value != NULL);
3185
3186 // First Finalize the array instruction.
3187 if (load_or_store_value->to().is_null()) {
3188 instr->Finalize();
3189 return;
3190 }
3191
3192 instr->Finalize(load_or_store_value->to()->elements_kind());
3193
3194 // Are we poisonous? We can't participate in this wonderful scheme...
3195 if (load_or_store_value->poisoned()) {
3196 // Poison should have flowed up and down the graph from sites to roots
3197 ASSERT(root_value->poisoned());
3198 return;
3199 }
3200
3201 if (instr->transitions() == 0) {
3202 // No work to move
3203 return;
3204 }
3205
3206 // Are we ignoring important directives?
3207 ASSERT(instr->hoistable());
3208
3209 // In here we'll
3210 // 1) remove any transition statements from the load_or_store site
3211 // 2) place correct statements at the root site, avoiding duplicates
3212 ASSERT(root_value->to().is_identical_to(load_or_store_value->to()));
3213 Handle<Map> handle = root_value->to();
3214 for (int i = 0; i < instr->transitions(); i++) {
3215 HTransitionElementsKind* transition = instr->transition(i);
3216 ASSERT(root_value->from_set().Contains(
3217 transition->original_map()->elements_kind()));
3218 ASSERT(load_or_store_value->from_set().Contains(
3219 transition->original_map()->elements_kind()));
3220 root_value->InsertTransitionElementsKind(graph(),
3221 root,
3222 transition->original_map(),
3223 handle,
3224 special_case);
3225 if (transition->block() != NULL) {
3226 // The transition instruction should only be referred to by a map check
3227 // instruction.
3228 for (HUseIterator it(transition->uses()); !it.Done(); it.Advance()) {
3229 HValue* value = it.value();
3230 ASSERT(value->IsCheckMaps());
3231 HCheckMaps::cast(value)->RemoveTypeCheck();
3232 }
3233
3234 transition->DeleteAndReplaceWith(NULL);
3235 }
3236 }
3237 }
3238
3239
3240 void HTransitionHoister::UpdateMapCheck(HCheckMaps* check_maps,
3241 ResolutionTableValue* nearest_value) {
3242 if (nearest_value->poisoned()) {
3243 return;
3244 }
3245
3246 // Only manipulate this mapcheck if at least one of the {from,to} maps from
3247 // nearest_value is in the check.
3248 Handle<Map> family = nearest_value->family();
3249 Handle<Map> to = nearest_value->to();
3250 ASSERT(!to.is_null() && !family.is_null());
3251 bool contains_to = false;
3252 bool contains_from = false;
3253 for (int i = 0; i < check_maps->map_set()->length(); i++) {
3254 Handle<Map> current = check_maps->map_set()->at(i);
3255 if (!current.is_identical_to(to)) {
3256 Handle<Map> in_family = map_handles_.Lookup(family,
3257 current->elements_kind());
3258 if (!in_family.is_null()) {
3259 if (current.is_identical_to(in_family)) {
3260 contains_from = true;
3261 }
3262 }
3263 } else {
3264 contains_to = true;
3265 }
3266 }
3267
3268 if (!contains_from && !contains_to) {
3269 // This map check deals with a different family. Leave it alone
3270 return;
3271 }
3272
3273 if (!contains_to) {
3274 // We definitely need the to map in the checkmaps instruction
3275 check_maps->map_set()->Add(to, zone());
3276 }
3277
3278 if (contains_from) {
3279 // The whole from set should be removed from the map check, since we have
3280 // the to map in there.
3281 for (int i = check_maps->map_set()->length() - 1; i >= 0; i--) {
3282 Handle<Map> current = check_maps->map_set()->at(i);
3283 if (!current.is_identical_to(to)) {
3284 Handle<Map> in_family = map_handles_.Lookup(family,
3285 current->elements_kind());
3286 if (!in_family.is_null()) {
3287 if (current.is_identical_to(in_family)) {
3288 // Delete this map
3289 check_maps->map_set()->RemoveAt(i);
3290 }
3291 }
3292 }
3293 }
3294 }
3295
3296 if (!contains_to) {
3297 // We should sort the map since we added one, removing others
3298 check_maps->map_set()->Sort();
3299 }
3300 }
3301
3302
3303 void HTransitionHoister::GatherWeakInformationFromMapCheck(
3304 HCheckMaps* check_maps,
3305 HValue* from_instr,
3306 ResolutionTableValue* from_value) {
3307 if (check_maps->map_set()->length() == 1) {
3308 Handle<Map> map = check_maps->map_set()->at(0);
3309 map_handles_.Add(map);
3310 from_value->SetWeakInformation(map);
3311 ASSERT(from_value->HasWeakInformation());
3312 if (FLAG_trace_transition_placement) {
3313 HeapStringAllocator string_allocator;
3314 StringStream stream(&string_allocator);
3315 stream.Add("Weak information added to block%d %d: map %p (%s)\n",
3316 from_instr->block()->block_id(),
3317 from_instr->id(),
3318 static_cast<void*>(*map),
3319 ElementsKindToString(map->elements_kind()));
3320 PrintF("%s", *stream.ToCString());
3321 }
3322 }
3323 }
3324
3325
3326 void HGraph::InsertElementsTransitions() {
3327 HPhase phase("H_Place elements transitions", this);
3328 HTransitionHoister hoister(this);
3329 if (hoister.Analyze()) {
3330 Handle<String> name = info()->function()->debug_name();
3331 const char* n = "lin_solve";
3332 Vector<const char> chars(n, strlen(n));
3333 bool do_special_case = name->IsAsciiEqualTo(chars);
3334 hoister.DoWork(do_special_case);
3335 }
3336
3337 #ifdef DEBUG
3338 // Verify that we didn't miss initialization of any array instructions.
3339 if (array_instructions() != NULL) {
3340 for (int i = 0; i < array_instructions()->length(); ++i) {
3341 HArrayInstruction* array_instruction = array_instructions()->at(i);
3342 ASSERT(array_instruction->Initialized());
3343 }
3344 }
3345 #endif // DEBUG
3346 }
3347
3348
2452 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { 3349 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
2453 HValue* current = value; 3350 HValue* current = value;
2454 while (current != NULL) { 3351 while (current != NULL) {
2455 if (visited->Contains(current->id())) return; 3352 if (visited->Contains(current->id())) return;
2456 3353
2457 // For phis, we must propagate the check to all of its inputs. 3354 // For phis, we must propagate the check to all of its inputs.
2458 if (current->IsPhi()) { 3355 if (current->IsPhi()) {
2459 visited->Add(current->id()); 3356 visited->Add(current->id());
2460 HPhi* phi = HPhi::cast(current); 3357 HPhi* phi = HPhi::cast(current);
2461 for (int i = 0; i < phi->OperandCount(); ++i) { 3358 for (int i = 0; i < phi->OperandCount(); ++i) {
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after
2815 phis_[phi_count++] = phi; 3712 phis_[phi_count++] = phi;
2816 } else { 3713 } else {
2817 UnmarkPhi(phi, &worklist); 3714 UnmarkPhi(phi, &worklist);
2818 } 3715 }
2819 } 3716 }
2820 3717
2821 // Now phis array contains only those phis that have safe 3718 // Now phis array contains only those phis that have safe
2822 // non-phi uses. Start transitively clearing kUint32 flag 3719 // non-phi uses. Start transitively clearing kUint32 flag
2823 // from phi operands of discovered non-safe phies until 3720 // from phi operands of discovered non-safe phies until
2824 // only safe phies are left. 3721 // only safe phies are left.
2825 while (!worklist.is_empty()) { 3722 while (!worklist.is_empty()) {
2826 while (!worklist.is_empty()) { 3723 while (!worklist.is_empty()) {
2827 HPhi* phi = worklist.RemoveLast(); 3724 HPhi* phi = worklist.RemoveLast();
2828 UnmarkPhi(phi, &worklist); 3725 UnmarkPhi(phi, &worklist);
2829 } 3726 }
2830 3727
2831 // Check if any operands to safe phies were unmarked 3728 // Check if any operands to safe phies were unmarked
2832 // turning a safe phi into unsafe. The same value 3729 // turning a safe phi into unsafe. The same value
2833 // can flow into several phis. 3730 // can flow into several phis.
2834 int new_phi_count = 0; 3731 int new_phi_count = 0;
2835 for (int i = 0; i < phi_count; i++) { 3732 for (int i = 0; i < phi_count; i++) {
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
3267 } 4164 }
3268 EliminateRedundantPhis(); 4165 EliminateRedundantPhis();
3269 if (!CheckArgumentsPhiUses()) { 4166 if (!CheckArgumentsPhiUses()) {
3270 *bailout_reason = SmartArrayPointer<char>(StrDup( 4167 *bailout_reason = SmartArrayPointer<char>(StrDup(
3271 "Unsupported phi use of arguments")); 4168 "Unsupported phi use of arguments"));
3272 return false; 4169 return false;
3273 } 4170 }
3274 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); 4171 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis();
3275 CollectPhis(); 4172 CollectPhis();
3276 4173
4174 if (FLAG_use_place_elements_transitions) InsertElementsTransitions();
4175
3277 if (has_osr_loop_entry()) { 4176 if (has_osr_loop_entry()) {
3278 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); 4177 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis();
3279 for (int j = 0; j < phis->length(); j++) { 4178 for (int j = 0; j < phis->length(); j++) {
3280 HPhi* phi = phis->at(j); 4179 HPhi* phi = phis->at(j);
3281 osr_values()->at(phi->merged_index())->set_incoming_value(phi); 4180 osr_values()->at(phi->merged_index())->set_incoming_value(phi);
3282 } 4181 }
3283 } 4182 }
3284 4183
3285 HInferRepresentation rep(this); 4184 HInferRepresentation rep(this);
3286 rep.Analyze(); 4185 rep.Analyze();
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
3663 } 4562 }
3664 4563
3665 4564
3666 void HGraph::EliminateRedundantBoundsChecks() { 4565 void HGraph::EliminateRedundantBoundsChecks() {
3667 HPhase phase("H_Eliminate bounds checks", this); 4566 HPhase phase("H_Eliminate bounds checks", this);
3668 BoundsCheckTable checks_table(zone()); 4567 BoundsCheckTable checks_table(zone());
3669 EliminateRedundantBoundsChecks(entry_block(), &checks_table); 4568 EliminateRedundantBoundsChecks(entry_block(), &checks_table);
3670 } 4569 }
3671 4570
3672 4571
3673 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { 4572 static void DehoistArrayIndex(HArrayInstruction* array_operation) {
3674 HValue* index = array_operation->GetKey(); 4573 HValue* index = array_operation->GetKey();
3675 if (!index->representation().IsInteger32()) return; 4574 if (!index->representation().IsInteger32()) return;
3676 4575
3677 HConstant* constant; 4576 HConstant* constant;
3678 HValue* subexpression; 4577 HValue* subexpression;
3679 int32_t sign; 4578 int32_t sign;
3680 if (index->IsAdd()) { 4579 if (index->IsAdd()) {
3681 sign = 1; 4580 sign = 1;
3682 HAdd* add = HAdd::cast(index); 4581 HAdd* add = HAdd::cast(index);
3683 if (add->left()->IsConstant()) { 4582 if (add->left()->IsConstant()) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
3719 4618
3720 4619
3721 void HGraph::DehoistSimpleArrayIndexComputations() { 4620 void HGraph::DehoistSimpleArrayIndexComputations() {
3722 if (!FLAG_array_index_dehoisting) return; 4621 if (!FLAG_array_index_dehoisting) return;
3723 4622
3724 HPhase phase("H_Dehoist index computations", this); 4623 HPhase phase("H_Dehoist index computations", this);
3725 for (int i = 0; i < blocks()->length(); ++i) { 4624 for (int i = 0; i < blocks()->length(); ++i) {
3726 for (HInstruction* instr = blocks()->at(i)->first(); 4625 for (HInstruction* instr = blocks()->at(i)->first();
3727 instr != NULL; 4626 instr != NULL;
3728 instr = instr->next()) { 4627 instr = instr->next()) {
3729 ArrayInstructionInterface* array_instruction = NULL; 4628 if (instr->IsArrayInstruction()) {
3730 if (instr->IsLoadKeyed()) { 4629 DehoistArrayIndex(HArrayInstruction::cast(instr));
3731 HLoadKeyed* op = HLoadKeyed::cast(instr);
3732 array_instruction = static_cast<ArrayInstructionInterface*>(op);
3733 } else if (instr->IsStoreKeyed()) {
3734 HStoreKeyed* op = HStoreKeyed::cast(instr);
3735 array_instruction = static_cast<ArrayInstructionInterface*>(op);
3736 } else {
3737 continue;
3738 } 4630 }
3739 DehoistArrayIndex(array_instruction);
3740 } 4631 }
3741 } 4632 }
3742 } 4633 }
3743 4634
3744 4635
3745 void HGraph::DeadCodeElimination() { 4636 void HGraph::DeadCodeElimination() {
3746 HPhase phase("H_Dead code elimination", this); 4637 HPhase phase("H_Dead code elimination", this);
3747 ZoneList<HInstruction*> worklist(blocks_.length(), zone()); 4638 ZoneList<HInstruction*> worklist(blocks_.length(), zone());
3748 for (int i = 0; i < blocks()->length(); ++i) { 4639 for (int i = 0; i < blocks()->length(); ++i) {
3749 for (HInstruction* instr = blocks()->at(i)->first(); 4640 for (HInstruction* instr = blocks()->at(i)->first();
(...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after
4296 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); 5187 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
4297 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); 5188 HBasicBlock* osr_entry = graph()->CreateBasicBlock();
4298 HValue* true_value = graph()->GetConstantTrue(); 5189 HValue* true_value = graph()->GetConstantTrue();
4299 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry); 5190 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry);
4300 current_block()->Finish(test); 5191 current_block()->Finish(test);
4301 5192
4302 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); 5193 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
4303 non_osr_entry->Goto(loop_predecessor); 5194 non_osr_entry->Goto(loop_predecessor);
4304 5195
4305 set_current_block(osr_entry); 5196 set_current_block(osr_entry);
5197 osr_entry->set_osr_entry();
4306 BailoutId osr_entry_id = statement->OsrEntryId(); 5198 BailoutId osr_entry_id = statement->OsrEntryId();
4307 int first_expression_index = environment()->first_expression_index(); 5199 int first_expression_index = environment()->first_expression_index();
4308 int length = environment()->length(); 5200 int length = environment()->length();
4309 ZoneList<HUnknownOSRValue*>* osr_values = 5201 ZoneList<HUnknownOSRValue*>* osr_values =
4310 new(zone()) ZoneList<HUnknownOSRValue*>(length, zone()); 5202 new(zone()) ZoneList<HUnknownOSRValue*>(length, zone());
4311 5203
4312 for (int i = 0; i < first_expression_index; ++i) { 5204 for (int i = 0; i < first_expression_index; ++i) {
4313 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; 5205 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
4314 AddInstruction(osr_value); 5206 AddInstruction(osr_value);
4315 environment()->Bind(i, osr_value); 5207 environment()->Bind(i, osr_value);
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
4565 5457
4566 compare_index->SetSuccessorAt(0, loop_body); 5458 compare_index->SetSuccessorAt(0, loop_body);
4567 compare_index->SetSuccessorAt(1, loop_successor); 5459 compare_index->SetSuccessorAt(1, loop_successor);
4568 current_block()->Finish(compare_index); 5460 current_block()->Finish(compare_index);
4569 5461
4570 set_current_block(loop_successor); 5462 set_current_block(loop_successor);
4571 Drop(5); 5463 Drop(5);
4572 5464
4573 set_current_block(loop_body); 5465 set_current_block(loop_body);
4574 5466
4575 HValue* key = AddInstruction( 5467 HLoadKeyed* load_keyed = new(zone()) HLoadKeyed(
4576 new(zone()) HLoadKeyed(
4577 environment()->ExpressionStackAt(2), // Enum cache. 5468 environment()->ExpressionStackAt(2), // Enum cache.
4578 environment()->ExpressionStackAt(0), // Iteration index. 5469 environment()->ExpressionStackAt(0), // Iteration index.
4579 environment()->ExpressionStackAt(0), 5470 environment()->ExpressionStackAt(0),
4580 FAST_ELEMENTS)); 5471 FAST_ELEMENTS,
5472 zone());
5473 graph()->RecordArrayInstruction(load_keyed);
5474 load_keyed->set_hoistable(false);
5475
5476 HValue* key = AddInstruction(load_keyed);
4581 5477
4582 // Check if the expected map still matches that of the enumerable. 5478 // Check if the expected map still matches that of the enumerable.
4583 // If not just deoptimize. 5479 // If not just deoptimize.
4584 AddInstruction(new(zone()) HCheckMapValue( 5480 AddInstruction(new(zone()) HCheckMapValue(
4585 environment()->ExpressionStackAt(4), 5481 environment()->ExpressionStackAt(4),
4586 environment()->ExpressionStackAt(3))); 5482 environment()->ExpressionStackAt(3)));
4587 5483
4588 Bind(each_var, key); 5484 Bind(each_var, key);
4589 5485
4590 BreakAndContinueInfo break_info(stmt, 5); 5486 BreakAndContinueInfo break_info(stmt, 5);
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
4928 Handle<AccessorPair> accessors; 5824 Handle<AccessorPair> accessors;
4929 if (LookupAccessorPair(map, name, &accessors, holder) && 5825 if (LookupAccessorPair(map, name, &accessors, holder) &&
4930 accessors->setter()->IsJSFunction()) { 5826 accessors->setter()->IsJSFunction()) {
4931 *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter())); 5827 *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter()));
4932 return true; 5828 return true;
4933 } 5829 }
4934 return false; 5830 return false;
4935 } 5831 }
4936 5832
4937 5833
4938 // Determines whether the given array or object literal boilerplate satisfies
4939 // all limits to be considered for fast deep-copying and computes the total
4940 // size of all objects that are part of the graph.
4941 static bool IsFastLiteral(Handle<JSObject> boilerplate,
4942 int max_depth,
4943 int* max_properties,
4944 int* total_size) {
4945 ASSERT(max_depth >= 0 && *max_properties >= 0);
4946 if (max_depth == 0) return false;
4947
4948 Handle<FixedArrayBase> elements(boilerplate->elements());
4949 if (elements->length() > 0 &&
4950 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) {
4951 if (boilerplate->HasFastDoubleElements()) {
4952 *total_size += FixedDoubleArray::SizeFor(elements->length());
4953 } else if (boilerplate->HasFastObjectElements()) {
4954 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
4955 int length = elements->length();
4956 for (int i = 0; i < length; i++) {
4957 if ((*max_properties)-- == 0) return false;
4958 Handle<Object> value(fast_elements->get(i));
4959 if (value->IsJSObject()) {
4960 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4961 if (!IsFastLiteral(value_object,
4962 max_depth - 1,
4963 max_properties,
4964 total_size)) {
4965 return false;
4966 }
4967 }
4968 }
4969 *total_size += FixedArray::SizeFor(length);
4970 } else {
4971 return false;
4972 }
4973 }
4974
4975 Handle<FixedArray> properties(boilerplate->properties());
4976 if (properties->length() > 0) {
4977 return false;
4978 } else {
4979 int nof = boilerplate->map()->inobject_properties();
4980 for (int i = 0; i < nof; i++) {
4981 if ((*max_properties)-- == 0) return false;
4982 Handle<Object> value(boilerplate->InObjectPropertyAt(i));
4983 if (value->IsJSObject()) {
4984 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4985 if (!IsFastLiteral(value_object,
4986 max_depth - 1,
4987 max_properties,
4988 total_size)) {
4989 return false;
4990 }
4991 }
4992 }
4993 }
4994
4995 *total_size += boilerplate->map()->instance_size();
4996 return true;
4997 }
4998 5834
4999 5835
5000 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 5836 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
5001 ASSERT(!HasStackOverflow()); 5837 ASSERT(!HasStackOverflow());
5002 ASSERT(current_block() != NULL); 5838 ASSERT(current_block() != NULL);
5003 ASSERT(current_block()->HasPredecessor()); 5839 ASSERT(current_block()->HasPredecessor());
5004 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); 5840 Handle<JSFunction> closure = function_state()->compilation_info()->closure();
5005 HValue* context = environment()->LookupContext(); 5841 HValue* context = environment()->LookupContext();
5006 HInstruction* literal; 5842 HInstruction* literal;
5007 5843
5008 // Check whether to use fast or slow deep-copying for boilerplate. 5844 // Check whether to use fast or slow deep-copying for boilerplate.
5009 int total_size = 0; 5845 int total_size = 0;
5010 int max_properties = HFastLiteral::kMaxLiteralProperties; 5846 int max_properties = HFastLiteral::kMaxLiteralProperties;
5011 Handle<Object> boilerplate(closure->literals()->get(expr->literal_index())); 5847 Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()));
5012 if (boilerplate->IsJSObject() && 5848 if (boilerplate->IsJSObject() &&
5013 IsFastLiteral(Handle<JSObject>::cast(boilerplate), 5849 HFastLiteral::IsFastLiteral(Handle<JSObject>::cast(boilerplate),
5014 HFastLiteral::kMaxLiteralDepth, 5850 HFastLiteral::kMaxLiteralDepth,
5015 &max_properties, 5851 &max_properties,
5016 &total_size)) { 5852 &total_size)) {
5017 Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate); 5853 Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
5018 literal = new(zone()) HFastLiteral(context, 5854 literal = new(zone()) HFastLiteral(context,
5019 boilerplate_object, 5855 boilerplate_object,
5020 total_size,
5021 expr->literal_index(), 5856 expr->literal_index(),
5022 expr->depth()); 5857 expr->depth());
5023 } else { 5858 } else {
5024 literal = new(zone()) HObjectLiteral(context, 5859 literal = new(zone()) HObjectLiteral(context,
5025 expr->constant_properties(), 5860 expr->constant_properties(),
5026 expr->fast_elements(), 5861 expr->fast_elements(),
5027 expr->literal_index(), 5862 expr->literal_index(),
5028 expr->depth(), 5863 expr->depth(),
5029 expr->has_function()); 5864 expr->has_function());
5030 } 5865 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
5127 } 5962 }
5128 } 5963 }
5129 5964
5130 Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate); 5965 Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate);
5131 ElementsKind boilerplate_elements_kind = 5966 ElementsKind boilerplate_elements_kind =
5132 Handle<JSObject>::cast(boilerplate)->GetElementsKind(); 5967 Handle<JSObject>::cast(boilerplate)->GetElementsKind();
5133 5968
5134 // Check whether to use fast or slow deep-copying for boilerplate. 5969 // Check whether to use fast or slow deep-copying for boilerplate.
5135 int total_size = 0; 5970 int total_size = 0;
5136 int max_properties = HFastLiteral::kMaxLiteralProperties; 5971 int max_properties = HFastLiteral::kMaxLiteralProperties;
5137 if (IsFastLiteral(boilerplate, 5972 if (HFastLiteral::IsFastLiteral(boilerplate,
5138 HFastLiteral::kMaxLiteralDepth, 5973 HFastLiteral::kMaxLiteralDepth,
5139 &max_properties, 5974 &max_properties,
5140 &total_size)) { 5975 &total_size)) {
5141 literal = new(zone()) HFastLiteral(context, 5976 literal = new(zone()) HFastLiteral(context,
5142 boilerplate, 5977 boilerplate,
5143 total_size,
5144 expr->literal_index(), 5978 expr->literal_index(),
5145 expr->depth()); 5979 expr->depth());
5146 } else { 5980 } else {
5147 literal = new(zone()) HArrayLiteral(context, 5981 literal = new(zone()) HArrayLiteral(context,
5148 boilerplate, 5982 boilerplate,
5149 length, 5983 length,
5150 expr->literal_index(), 5984 expr->literal_index(),
5151 expr->depth()); 5985 expr->depth());
5152 } 5986 }
5153 5987
(...skipping 25 matching lines...) Expand all
5179 switch (boilerplate_elements_kind) { 6013 switch (boilerplate_elements_kind) {
5180 case FAST_SMI_ELEMENTS: 6014 case FAST_SMI_ELEMENTS:
5181 case FAST_HOLEY_SMI_ELEMENTS: 6015 case FAST_HOLEY_SMI_ELEMENTS:
5182 // Smi-only arrays need a smi check. 6016 // Smi-only arrays need a smi check.
5183 AddInstruction(new(zone()) HCheckSmi(value)); 6017 AddInstruction(new(zone()) HCheckSmi(value));
5184 // Fall through. 6018 // Fall through.
5185 case FAST_ELEMENTS: 6019 case FAST_ELEMENTS:
5186 case FAST_HOLEY_ELEMENTS: 6020 case FAST_HOLEY_ELEMENTS:
5187 case FAST_DOUBLE_ELEMENTS: 6021 case FAST_DOUBLE_ELEMENTS:
5188 case FAST_HOLEY_DOUBLE_ELEMENTS: 6022 case FAST_HOLEY_DOUBLE_ELEMENTS:
5189 AddInstruction(new(zone()) HStoreKeyed( 6023 AddInstruction(graph()->RecordArrayInstruction(new(zone()) HStoreKeyed(
5190 elements, 6024 elements,
5191 key, 6025 key,
5192 value, 6026 value,
5193 boilerplate_elements_kind)); 6027 boilerplate_elements_kind,
6028 zone())));
5194 break; 6029 break;
5195 default: 6030 default:
5196 UNREACHABLE(); 6031 UNREACHABLE();
5197 break; 6032 break;
5198 } 6033 }
5199 6034
5200 AddSimulate(expr->GetIdForElement(i)); 6035 AddSimulate(expr->GetIdForElement(i));
5201 } 6036 }
5202 return ast_context()->ReturnValue(Pop()); 6037 return ast_context()->ReturnValue(Pop());
5203 } 6038 }
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
6009 } 6844 }
6010 6845
6011 6846
6012 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, 6847 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
6013 HValue* key) { 6848 HValue* key) {
6014 HValue* context = environment()->LookupContext(); 6849 HValue* context = environment()->LookupContext();
6015 return new(zone()) HLoadKeyedGeneric(context, object, key); 6850 return new(zone()) HLoadKeyedGeneric(context, object, key);
6016 } 6851 }
6017 6852
6018 6853
6019 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( 6854 HArrayInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
6020 HValue* external_elements, 6855 HValue* external_elements,
6021 HValue* checked_key, 6856 HValue* checked_key,
6022 HValue* val, 6857 HValue* val,
6023 HValue* dependency, 6858 HValue* dependency,
6024 ElementsKind elements_kind, 6859 ElementsKind elements_kind,
6025 bool is_store) { 6860 bool is_store) {
6026 if (is_store) { 6861 if (is_store) {
6027 ASSERT(val != NULL); 6862 ASSERT(val != NULL);
6028 switch (elements_kind) { 6863 switch (elements_kind) {
6029 case EXTERNAL_PIXEL_ELEMENTS: { 6864 case EXTERNAL_PIXEL_ELEMENTS: {
(...skipping 15 matching lines...) Expand all
6045 case FAST_ELEMENTS: 6880 case FAST_ELEMENTS:
6046 case FAST_DOUBLE_ELEMENTS: 6881 case FAST_DOUBLE_ELEMENTS:
6047 case FAST_HOLEY_SMI_ELEMENTS: 6882 case FAST_HOLEY_SMI_ELEMENTS:
6048 case FAST_HOLEY_ELEMENTS: 6883 case FAST_HOLEY_ELEMENTS:
6049 case FAST_HOLEY_DOUBLE_ELEMENTS: 6884 case FAST_HOLEY_DOUBLE_ELEMENTS:
6050 case DICTIONARY_ELEMENTS: 6885 case DICTIONARY_ELEMENTS:
6051 case NON_STRICT_ARGUMENTS_ELEMENTS: 6886 case NON_STRICT_ARGUMENTS_ELEMENTS:
6052 UNREACHABLE(); 6887 UNREACHABLE();
6053 break; 6888 break;
6054 } 6889 }
6055 return new(zone()) HStoreKeyed(external_elements, 6890
6056 checked_key, 6891 return graph()->RecordArrayInstruction(new(zone())
6057 val, 6892 HStoreKeyed(external_elements,
6058 elements_kind); 6893 checked_key,
6894 val,
6895 elements_kind,
6896 zone()));
6059 } else { 6897 } else {
6060 ASSERT(val == NULL); 6898 ASSERT(val == NULL);
6061 HLoadKeyed* load = 6899 HLoadKeyed* load = new(zone()) HLoadKeyed(external_elements, checked_key,
6062 new(zone()) HLoadKeyed( 6900 dependency, elements_kind,
6063 external_elements, checked_key, dependency, elements_kind); 6901 zone());
6902 graph()->RecordArrayInstruction(load);
6064 if (FLAG_opt_safe_uint32_operations && 6903 if (FLAG_opt_safe_uint32_operations &&
6065 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { 6904 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
6066 graph()->RecordUint32Instruction(load); 6905 graph()->RecordUint32Instruction(load);
6067 } 6906 }
6068 return load; 6907 return load;
6069 } 6908 }
6070 } 6909 }
6071 6910
6072 6911
6073 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, 6912 HArrayInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
6074 HValue* checked_key, 6913 HValue* checked_key,
6075 HValue* val, 6914 HValue* val,
6076 HValue* load_dependency, 6915 HValue* load_dependency,
6077 ElementsKind elements_kind, 6916 ElementsKind elements_kind,
6078 bool is_store) { 6917 bool is_store) {
6079 if (is_store) { 6918 if (is_store) {
6080 ASSERT(val != NULL); 6919 ASSERT(val != NULL);
6081 switch (elements_kind) { 6920 switch (elements_kind) {
6082 case FAST_SMI_ELEMENTS: 6921 case FAST_SMI_ELEMENTS:
6083 case FAST_HOLEY_SMI_ELEMENTS: 6922 case FAST_HOLEY_SMI_ELEMENTS:
6084 // Smi-only arrays need a smi check. 6923 // Smi-only arrays need a smi check.
6085 AddInstruction(new(zone()) HCheckSmi(val)); 6924 AddInstruction(new(zone()) HCheckSmi(val));
6086 // Fall through. 6925 // Fall through.
6087 case FAST_ELEMENTS: 6926 case FAST_ELEMENTS:
6088 case FAST_HOLEY_ELEMENTS: 6927 case FAST_HOLEY_ELEMENTS:
6089 case FAST_DOUBLE_ELEMENTS: 6928 case FAST_DOUBLE_ELEMENTS:
6090 case FAST_HOLEY_DOUBLE_ELEMENTS: 6929 case FAST_HOLEY_DOUBLE_ELEMENTS:
6091 return new(zone()) HStoreKeyed( 6930 return graph()->RecordArrayInstruction(new(zone()) HStoreKeyed(
6092 elements, checked_key, val, elements_kind); 6931 elements, checked_key, val, elements_kind, zone()));
6093 default: 6932 default:
6094 UNREACHABLE(); 6933 UNREACHABLE();
6095 return NULL; 6934 return NULL;
6096 } 6935 }
6097 } 6936 }
6937
6098 // It's an element load (!is_store). 6938 // It's an element load (!is_store).
6099 return new(zone()) HLoadKeyed(elements, 6939 return graph()->RecordArrayInstruction(new(zone()) HLoadKeyed(elements,
6100 checked_key, 6940 checked_key,
6101 load_dependency, 6941 load_dependency,
6102 elements_kind); 6942 elements_kind,
6943 zone()));
6103 } 6944 }
6104 6945
6105 6946
6106 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, 6947 HArrayInstruction* HGraphBuilder::BuildMonomorphicElementAccess(
6107 HValue* key, 6948 HValue* object,
6108 HValue* val, 6949 HValue* key,
6109 HValue* dependency, 6950 HValue* val,
6110 Handle<Map> map, 6951 HValue* dependency,
6111 bool is_store) { 6952 Handle<Map> map,
6953 bool is_store) {
6112 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, 6954 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map,
6113 zone(), dependency); 6955 zone(), dependency);
6114 AddInstruction(mapcheck); 6956 AddInstruction(mapcheck);
6115 if (dependency) { 6957 if (dependency) {
6116 mapcheck->ClearGVNFlag(kDependsOnElementsKind); 6958 mapcheck->ClearGVNFlag(kDependsOnElementsKind);
6117 } 6959 }
6118 return BuildUncheckedMonomorphicElementAccess(object, key, val, 6960
6119 mapcheck, map, is_store); 6961 HArrayInstruction* instr = BuildUncheckedMonomorphicElementAccess(
6962 object, key, val, mapcheck, map, is_store);
6963 return instr;
6120 } 6964 }
6121 6965
6122 6966
6123 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 6967 HArrayInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
6124 HValue* object, 6968 HValue* object,
6125 HValue* key, 6969 HValue* key,
6126 HValue* val, 6970 HValue* val,
6127 HCheckMaps* mapcheck, 6971 HCheckMaps* mapcheck,
6128 Handle<Map> map, 6972 Handle<Map> map,
6129 bool is_store) { 6973 bool is_store) {
6130 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency 6974 // 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 6975 // 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 6976 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
6133 // ElementsKind transitions. Finally, the dependency can be removed for stores 6977 // ElementsKind transitions. Finally, the dependency can be removed for stores
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
6169 } else { 7013 } else {
6170 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 7014 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6171 } 7015 }
6172 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7016 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6173 ALLOW_SMI_KEY)); 7017 ALLOW_SMI_KEY));
6174 return BuildFastElementAccess(elements, checked_key, val, mapcheck, 7018 return BuildFastElementAccess(elements, checked_key, val, mapcheck,
6175 map->elements_kind(), is_store); 7019 map->elements_kind(), is_store);
6176 } 7020 }
6177 7021
6178 7022
6179 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( 7023 HArrayInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad(
6180 HValue* object, 7024 HValue* object,
6181 HValue* key, 7025 HValue* key,
6182 HValue* val, 7026 HValue* val,
6183 SmallMapList* maps) { 7027 SmallMapList* maps) {
6184 // For polymorphic loads of similar elements kinds (i.e. all tagged or all 7028 // 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 7029 // 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 7030 // much faster than transitioning the elements to the worst case, trading a
6187 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. 7031 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
6188 bool has_double_maps = false; 7032 bool has_double_maps = false;
6189 bool has_smi_or_object_maps = false; 7033 bool has_smi_or_object_maps = false;
(...skipping 26 matching lines...) Expand all
6216 if ((i == 0) || IsMoreGeneralElementsKindTransition( 7060 if ((i == 0) || IsMoreGeneralElementsKindTransition(
6217 most_general_consolidated_map->elements_kind(), 7061 most_general_consolidated_map->elements_kind(),
6218 map->elements_kind())) { 7062 map->elements_kind())) {
6219 most_general_consolidated_map = map; 7063 most_general_consolidated_map = map;
6220 } 7064 }
6221 } 7065 }
6222 if (!has_double_maps && !has_smi_or_object_maps) return NULL; 7066 if (!has_double_maps && !has_smi_or_object_maps) return NULL;
6223 7067
6224 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); 7068 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone());
6225 AddInstruction(check_maps); 7069 AddInstruction(check_maps);
6226 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( 7070 return BuildUncheckedMonomorphicElementAccess(
6227 object, key, val, check_maps, most_general_consolidated_map, false); 7071 object, key, val, check_maps, most_general_consolidated_map, false);
6228 return instr;
6229 } 7072 }
6230 7073
6231 7074
6232 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, 7075 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
6233 HValue* key, 7076 HValue* key,
6234 HValue* val, 7077 HValue* val,
6235 Expression* prop, 7078 Expression* prop,
6236 BailoutId ast_id, 7079 BailoutId ast_id,
6237 int position, 7080 int position,
6238 bool is_store, 7081 bool is_store,
6239 bool* has_side_effects) { 7082 bool* has_side_effects) {
6240 *has_side_effects = false; 7083 *has_side_effects = false;
6241 AddInstruction(new(zone()) HCheckNonSmi(object)); 7084 HCheckNonSmi* checknonsmi = new(zone()) HCheckNonSmi(object);
7085 AddInstruction(checknonsmi);
6242 SmallMapList* maps = prop->GetReceiverTypes(); 7086 SmallMapList* maps = prop->GetReceiverTypes();
6243 bool todo_external_array = false; 7087 bool todo_external_array = false;
6244 7088
6245 if (!is_store) { 7089 if (!is_store) {
6246 HInstruction* consolidated_load = 7090 HInstruction* consolidated_load =
6247 TryBuildConsolidatedElementLoad(object, key, val, maps); 7091 TryBuildConsolidatedElementLoad(object, key, val, maps);
6248 if (consolidated_load != NULL) { 7092 if (consolidated_load != NULL) {
6249 AddInstruction(consolidated_load); 7093 AddInstruction(consolidated_load);
6250 *has_side_effects |= consolidated_load->HasObservableSideEffects(); 7094 *has_side_effects |= consolidated_load->HasObservableSideEffects();
6251 if (position != RelocInfo::kNoPosition) { 7095 if (position != RelocInfo::kNoPosition) {
(...skipping 14 matching lines...) Expand all
6266 // Collect possible transition targets. 7110 // Collect possible transition targets.
6267 MapHandleList possible_transitioned_maps(maps->length()); 7111 MapHandleList possible_transitioned_maps(maps->length());
6268 for (int i = 0; i < maps->length(); ++i) { 7112 for (int i = 0; i < maps->length(); ++i) {
6269 Handle<Map> map = maps->at(i); 7113 Handle<Map> map = maps->at(i);
6270 ElementsKind elements_kind = map->elements_kind(); 7114 ElementsKind elements_kind = map->elements_kind();
6271 if (IsFastElementsKind(elements_kind) && 7115 if (IsFastElementsKind(elements_kind) &&
6272 elements_kind != GetInitialFastElementsKind()) { 7116 elements_kind != GetInitialFastElementsKind()) {
6273 possible_transitioned_maps.Add(map); 7117 possible_transitioned_maps.Add(map);
6274 } 7118 }
6275 } 7119 }
7120
6276 // Get transition target for each map (NULL == no transition). 7121 // Get transition target for each map (NULL == no transition).
6277 for (int i = 0; i < maps->length(); ++i) { 7122 for (int i = 0; i < maps->length(); ++i) {
6278 Handle<Map> map = maps->at(i); 7123 Handle<Map> map = maps->at(i);
6279 Handle<Map> transitioned_map = 7124 Handle<Map> transitioned_map =
6280 map->FindTransitionedMap(&possible_transitioned_maps); 7125 map->FindTransitionedMap(&possible_transitioned_maps);
6281 transition_target.Add(transitioned_map); 7126 transition_target.Add(transitioned_map);
6282 } 7127 }
6283 7128
6284 int num_untransitionable_maps = 0; 7129 int num_untransitionable_maps = 0;
6285 Handle<Map> untransitionable_map; 7130 Handle<Map> untransitionable_map;
6286 HTransitionElementsKind* transition = NULL; 7131 HTransitionElementsKind* transition = NULL;
7132 ZoneList<HTransitionElementsKind*> transitions(5, zone());
6287 for (int i = 0; i < maps->length(); ++i) { 7133 for (int i = 0; i < maps->length(); ++i) {
6288 Handle<Map> map = maps->at(i); 7134 Handle<Map> map = maps->at(i);
6289 ASSERT(map->IsMap()); 7135 ASSERT(map->IsMap());
6290 if (!transition_target.at(i).is_null()) { 7136 if (!transition_target.at(i).is_null()) {
6291 ASSERT(Map::IsValidElementsTransition( 7137 ASSERT(Map::IsValidElementsTransition(
6292 map->elements_kind(), 7138 map->elements_kind(),
6293 transition_target.at(i)->elements_kind())); 7139 transition_target.at(i)->elements_kind()));
6294 transition = new(zone()) HTransitionElementsKind( 7140 transition = new(zone()) HTransitionElementsKind(
6295 object, map, transition_target.at(i)); 7141 object, map, transition_target.at(i), isolate(),
7142 FLAG_use_place_elements_transitions);
6296 AddInstruction(transition); 7143 AddInstruction(transition);
7144
7145 if (FLAG_use_place_elements_transitions) {
7146 transitions.Add(transition, zone());
7147 }
6297 } else { 7148 } else {
6298 type_todo[map->elements_kind()] = true; 7149 type_todo[map->elements_kind()] = true;
6299 if (IsExternalArrayElementsKind(map->elements_kind())) { 7150 if (IsExternalArrayElementsKind(map->elements_kind())) {
6300 todo_external_array = true; 7151 todo_external_array = true;
6301 } 7152 }
6302 num_untransitionable_maps++; 7153 num_untransitionable_maps++;
6303 untransitionable_map = map; 7154 untransitionable_map = map;
6304 } 7155 }
6305 } 7156 }
6306 7157
6307 // If only one map is left after transitioning, handle this case 7158 // If only one map is left after transitioning, handle this case
6308 // monomorphically. 7159 // monomorphically.
6309 if (num_untransitionable_maps == 1) { 7160 if (num_untransitionable_maps == 1) {
6310 HInstruction* instr = NULL; 7161 HInstruction* instr = NULL;
6311 if (untransitionable_map->has_slow_elements_kind()) { 7162 if (untransitionable_map->has_slow_elements_kind()) {
6312 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) 7163 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
6313 : BuildLoadKeyedGeneric(object, key)); 7164 : BuildLoadKeyedGeneric(object, key));
6314 } else { 7165 } else {
6315 instr = AddInstruction(BuildMonomorphicElementAccess( 7166 HArrayInstruction* array_instr = BuildMonomorphicElementAccess(
6316 object, key, val, transition, untransitionable_map, is_store)); 7167 object, key, val, transition, untransitionable_map, is_store);
7168 instr = AddInstruction(array_instr);
7169 if (FLAG_use_place_elements_transitions && transitions.length() > 0) {
7170 array_instr->AddTransitions(transitions);
7171 }
6317 } 7172 }
6318 *has_side_effects |= instr->HasObservableSideEffects(); 7173 *has_side_effects |= instr->HasObservableSideEffects();
6319 if (position != RelocInfo::kNoPosition) instr->set_position(position); 7174 if (position != RelocInfo::kNoPosition) instr->set_position(position);
6320 return is_store ? NULL : instr; 7175 return is_store ? NULL : instr;
6321 } 7176 }
6322 7177
6323 HInstruction* checkspec = 7178 HInstruction* checkspec =
6324 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); 7179 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone()));
6325 HBasicBlock* join = graph()->CreateBasicBlock(); 7180 HBasicBlock* join = graph()->CreateBasicBlock();
6326 7181
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
6358 HBasicBlock* if_false = graph()->CreateBasicBlock(); 7213 HBasicBlock* if_false = graph()->CreateBasicBlock();
6359 HCompareConstantEqAndBranch* elements_kind_branch = 7214 HCompareConstantEqAndBranch* elements_kind_branch =
6360 new(zone()) HCompareConstantEqAndBranch( 7215 new(zone()) HCompareConstantEqAndBranch(
6361 elements_kind_instr, elements_kind, Token::EQ_STRICT); 7216 elements_kind_instr, elements_kind, Token::EQ_STRICT);
6362 elements_kind_branch->SetSuccessorAt(0, if_true); 7217 elements_kind_branch->SetSuccessorAt(0, if_true);
6363 elements_kind_branch->SetSuccessorAt(1, if_false); 7218 elements_kind_branch->SetSuccessorAt(1, if_false);
6364 current_block()->Finish(elements_kind_branch); 7219 current_block()->Finish(elements_kind_branch);
6365 7220
6366 set_current_block(if_true); 7221 set_current_block(if_true);
6367 HInstruction* access; 7222 HInstruction* access;
7223 HCheckMaps* checkmaps = NULL;
6368 if (IsFastElementsKind(elements_kind)) { 7224 if (IsFastElementsKind(elements_kind)) {
6369 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { 7225 if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
6370 AddInstruction(new(zone()) HCheckMaps( 7226 checkmaps = new(zone()) HCheckMaps(
6371 elements, isolate()->factory()->fixed_array_map(), 7227 elements, isolate()->factory()->fixed_array_map(),
6372 zone(), elements_kind_branch)); 7228 zone(), elements_kind_branch);
7229 AddInstruction(checkmaps);
6373 } 7230 }
6374 // TODO(jkummerow): The need for these two blocks could be avoided 7231 // TODO(jkummerow): The need for these two blocks could be avoided
6375 // in one of two ways: 7232 // in one of two ways:
6376 // (1) Introduce ElementsKinds for JSArrays that are distinct from 7233 // (1) Introduce ElementsKinds for JSArrays that are distinct from
6377 // those for fast objects. 7234 // those for fast objects.
6378 // (2) Put the common instructions into a third "join" block. This 7235 // (2) Put the common instructions into a third "join" block. This
6379 // requires additional AST IDs that we can deopt to from inside 7236 // requires additional AST IDs that we can deopt to from inside
6380 // that join block. They must be added to the Property class (when 7237 // that join block. They must be added to the Property class (when
6381 // it's a keyed property) and registered in the full codegen. 7238 // it's a keyed property) and registered in the full codegen.
6382 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); 7239 HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
6383 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); 7240 HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
6384 HHasInstanceTypeAndBranch* typecheck = 7241 HHasInstanceTypeAndBranch* typecheck =
6385 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); 7242 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
6386 typecheck->SetSuccessorAt(0, if_jsarray); 7243 typecheck->SetSuccessorAt(0, if_jsarray);
6387 typecheck->SetSuccessorAt(1, if_fastobject); 7244 typecheck->SetSuccessorAt(1, if_fastobject);
6388 current_block()->Finish(typecheck); 7245 current_block()->Finish(typecheck);
6389 7246
6390 set_current_block(if_jsarray); 7247 set_current_block(if_jsarray);
6391 HInstruction* length; 7248 HInstruction* length;
6392 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, 7249 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
6393 HType::Smi())); 7250 HType::Smi()));
6394 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7251 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6395 ALLOW_SMI_KEY)); 7252 ALLOW_SMI_KEY));
6396 access = AddInstruction(BuildFastElementAccess( 7253 HArrayInstruction* array_instruction = BuildFastElementAccess(
6397 elements, checked_key, val, elements_kind_branch, 7254 elements, checked_key, val, elements_kind_branch,
6398 elements_kind, is_store)); 7255 elements_kind, is_store);
7256 array_instruction->set_hoistable(false);
7257 access = AddInstruction(array_instruction);
6399 if (!is_store) { 7258 if (!is_store) {
6400 Push(access); 7259 Push(access);
6401 } 7260 }
6402 7261
6403 *has_side_effects |= access->HasObservableSideEffects(); 7262 *has_side_effects |= access->HasObservableSideEffects();
6404 if (position != -1) { 7263 if (position != -1) {
6405 access->set_position(position); 7264 access->set_position(position);
6406 } 7265 }
6407 if_jsarray->Goto(join); 7266 if_jsarray->Goto(join);
6408 7267
6409 set_current_block(if_fastobject); 7268 set_current_block(if_fastobject);
6410 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); 7269 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
6411 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, 7270 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
6412 ALLOW_SMI_KEY)); 7271 ALLOW_SMI_KEY));
6413 access = AddInstruction(BuildFastElementAccess( 7272 array_instruction = BuildFastElementAccess(
6414 elements, checked_key, val, elements_kind_branch, 7273 elements, checked_key, val, elements_kind_branch,
6415 elements_kind, is_store)); 7274 elements_kind, is_store);
7275 array_instruction->set_hoistable(false);
7276 access = AddInstruction(array_instruction);
6416 } else if (elements_kind == DICTIONARY_ELEMENTS) { 7277 } else if (elements_kind == DICTIONARY_ELEMENTS) {
6417 if (is_store) { 7278 if (is_store) {
6418 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); 7279 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
6419 } else { 7280 } else {
6420 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); 7281 access = AddInstruction(BuildLoadKeyedGeneric(object, key));
6421 } 7282 }
6422 } else { // External array elements. 7283 } else { // External array elements.
6423 access = AddInstruction(BuildExternalArrayElementAccess( 7284 access = AddInstruction(BuildExternalArrayElementAccess(
6424 external_elements, checked_key, val, elements_kind_branch, 7285 external_elements, checked_key, val, elements_kind_branch,
6425 elements_kind, is_store)); 7286 elements_kind, is_store));
6426 } 7287 }
6427 *has_side_effects |= access->HasObservableSideEffects(); 7288 *has_side_effects |= access->HasObservableSideEffects();
6428 if (position != RelocInfo::kNoPosition) access->set_position(position); 7289 if (position != RelocInfo::kNoPosition) access->set_position(position);
6429 if (!is_store) { 7290 if (!is_store) {
6430 Push(access); 7291 Push(access);
6431 } 7292 }
7293
6432 current_block()->Goto(join); 7294 current_block()->Goto(join);
6433 set_current_block(if_false); 7295 set_current_block(if_false);
6434 } 7296 }
6435 } 7297 }
6436 7298
6437 // Deopt if none of the cases matched. 7299 // Deopt if none of the cases matched.
6438 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); 7300 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
6439 join->SetJoinId(ast_id); 7301 join->SetJoinId(ast_id);
6440 set_current_block(join); 7302 set_current_block(join);
6441 return is_store ? NULL : Pop(); 7303 return is_store ? NULL : Pop();
(...skipping 3317 matching lines...) Expand 10 before | Expand all | Expand 10 after
9759 10621
9760 10622
9761 void HEnvironment::PrintToStd() { 10623 void HEnvironment::PrintToStd() {
9762 HeapStringAllocator string_allocator; 10624 HeapStringAllocator string_allocator;
9763 StringStream trace(&string_allocator); 10625 StringStream trace(&string_allocator);
9764 PrintTo(&trace); 10626 PrintTo(&trace);
9765 PrintF("%s", *trace.ToCString()); 10627 PrintF("%s", *trace.ToCString());
9766 } 10628 }
9767 10629
9768 10630
10631
10632
10633
10634
9769 void HTracer::TraceCompilation(FunctionLiteral* function) { 10635 void HTracer::TraceCompilation(FunctionLiteral* function) {
9770 Tag tag(this, "compilation"); 10636 Tag tag(this, "compilation");
9771 Handle<String> name = function->debug_name(); 10637 Handle<String> name = function->debug_name();
9772 PrintStringProperty("name", *name->ToCString()); 10638 PrintStringProperty("name", *name->ToCString());
9773 PrintStringProperty("method", *name->ToCString()); 10639 PrintStringProperty("method", *name->ToCString());
9774 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); 10640 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
9775 } 10641 }
9776 10642
9777 10643
9778 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 10644 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
10092 } 10958 }
10093 } 10959 }
10094 10960
10095 #ifdef DEBUG 10961 #ifdef DEBUG
10096 if (graph_ != NULL) graph_->Verify(false); // No full verify. 10962 if (graph_ != NULL) graph_->Verify(false); // No full verify.
10097 if (allocator_ != NULL) allocator_->Verify(); 10963 if (allocator_ != NULL) allocator_->Verify();
10098 #endif 10964 #endif
10099 } 10965 }
10100 10966
10101 } } // namespace v8::internal 10967 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698