| 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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |