Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 691 | 691 |
| 692 | 692 |
| 693 HGraph::HGraph(CompilationInfo* info) | 693 HGraph::HGraph(CompilationInfo* info) |
| 694 : isolate_(info->isolate()), | 694 : isolate_(info->isolate()), |
| 695 next_block_id_(0), | 695 next_block_id_(0), |
| 696 entry_block_(NULL), | 696 entry_block_(NULL), |
| 697 blocks_(8, info->zone()), | 697 blocks_(8, info->zone()), |
| 698 values_(16, info->zone()), | 698 values_(16, info->zone()), |
| 699 phi_list_(NULL), | 699 phi_list_(NULL), |
| 700 uint32_instructions_(NULL), | 700 uint32_instructions_(NULL), |
| 701 marked_transitions_(10, info->zone()), | |
| 701 info_(info), | 702 info_(info), |
| 702 zone_(info->zone()), | 703 zone_(info->zone()), |
| 703 is_recursive_(false), | 704 is_recursive_(false), |
| 704 use_optimistic_licm_(false), | 705 use_optimistic_licm_(false), |
| 705 type_change_checksum_(0) { | 706 type_change_checksum_(0) { |
| 706 start_environment_ = | 707 start_environment_ = |
| 707 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 708 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
| 708 start_environment_->set_ast_id(BailoutId::FunctionEntry()); | 709 start_environment_->set_ast_id(BailoutId::FunctionEntry()); |
| 709 entry_block_ = CreateBasicBlock(); | 710 entry_block_ = CreateBasicBlock(); |
| 710 entry_block_->SetInitialEnvironment(start_environment_); | 711 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()); | 2443 ZoneList<HValue*> worklist(block->phis()->length(), zone()); |
| 2443 for (int j = 0; j < block->phis()->length(); ++j) { | 2444 for (int j = 0; j < block->phis()->length(); ++j) { |
| 2444 worklist.Add(block->phis()->at(j), zone()); | 2445 worklist.Add(block->phis()->at(j), zone()); |
| 2445 } | 2446 } |
| 2446 InferTypes(&worklist); | 2447 InferTypes(&worklist); |
| 2447 } | 2448 } |
| 2448 } | 2449 } |
| 2449 } | 2450 } |
| 2450 | 2451 |
| 2451 | 2452 |
| 2453 class TransitionElementsBookmark BASE_EMBEDDED { | |
| 2454 public: | |
| 2455 TransitionElementsBookmark(HTransitionElementsKind* transition, | |
| 2456 Handle<Map> map_from, | |
| 2457 Handle<Map> map_to, | |
| 2458 Isolate* isolate); | |
| 2459 ElementsKind elementskind_from() const { return from_->elements_kind(); } | |
| 2460 ElementsKind elementskind_to() const { return to_->elements_kind(); } | |
| 2461 Handle<Map> from() const { return from_; } | |
| 2462 Handle<Map>* from_pointer() { return &from_; } | |
| 2463 Handle<Map> to() const { return to_; } | |
| 2464 Handle<Map>* to_pointer() { return &to_; } | |
| 2465 Handle<Map> family() const { return family_; } | |
| 2466 Handle<Map>* family_pointer() { return &family_; } | |
| 2467 Handle<Map> pessimistic_holey() const { return pessimistic_holey_; } | |
| 2468 Handle<Map>* pessimistic_holey_pointer() { return &pessimistic_holey_; } | |
| 2469 HTransitionElementsKind* transition_instruction() const { | |
| 2470 return transition_; } | |
| 2471 | |
| 2472 bool Equals(const TransitionElementsBookmark& other) const { | |
| 2473 return *from() == *(other.from()) && | |
| 2474 *to() == *(other.to()) && | |
| 2475 *family() == *(other.family()); | |
| 2476 } | |
| 2477 | |
| 2478 private: | |
| 2479 HTransitionElementsKind* transition_; | |
| 2480 Handle<Map> from_; | |
| 2481 Handle<Map> to_; | |
| 2482 Handle<Map> family_; | |
| 2483 Handle<Map> pessimistic_holey_; | |
| 2484 }; | |
| 2485 | |
| 2486 | |
| 2487 typedef ZoneList<HInstruction*> TransitionInputList; | |
| 2488 | |
| 2489 class MarkedTransitionElementsGroup: public ZoneObject { | |
| 2490 public: | |
| 2491 MarkedTransitionElementsGroup(HInstruction* load_or_store, | |
| 2492 HCheckNonSmi* check_non_smi, | |
| 2493 HCheckMaps* check_maps, Zone* zone) | |
| 2494 : zone_(zone), | |
| 2495 load_or_store_(load_or_store), | |
| 2496 smi_check_(check_non_smi), | |
| 2497 map_check_(check_maps), | |
| 2498 hoistable_(true), | |
| 2499 bookmarks_(new(zone) ZoneList<TransitionElementsBookmark>(10, zone)), | |
| 2500 transition_inputs_(new(zone) TransitionInputList(10, zone)) { | |
| 2501 ASSERT((load_or_store->IsLoadKeyed() && | |
| 2502 !HLoadKeyed::cast(load_or_store)->Initialized()) || | |
| 2503 (load_or_store->IsStoreKeyed() && | |
| 2504 !HStoreKeyed::cast(load_or_store)->Initialized())); | |
| 2505 score_[0] = score_[1] = score_[2] = 0; | |
| 2506 } | |
| 2507 | |
| 2508 HInstruction* load_or_store() const { return load_or_store_; } | |
| 2509 HCheckMaps* map_check() { return map_check_; } | |
| 2510 HCheckNonSmi* smi_check() { return smi_check_; } | |
| 2511 | |
| 2512 void AddBookmarks(const ZoneList<TransitionElementsBookmark>& records); | |
| 2513 | |
| 2514 int bookmarks() const { return bookmarks_->length(); } | |
| 2515 const TransitionElementsBookmark& bookmark(int index) const { | |
| 2516 return (*bookmarks_)[index]; | |
| 2517 } | |
| 2518 | |
| 2519 TransitionElementsBookmark* bookmark_pointer(int index) { | |
| 2520 return &(bookmarks_->at(index)); | |
| 2521 } | |
| 2522 | |
| 2523 void PrintTo(StringStream* stream) const; | |
| 2524 void PrintToStd() const; | |
| 2525 | |
| 2526 // This must be called before querying transition input values | |
| 2527 void ComputeTransitionInputValues(int maximumGraphValueID); | |
| 2528 | |
| 2529 int transition_inputs() const { return transition_inputs_->length(); } | |
| 2530 HInstruction* transition_input(int index) const { | |
| 2531 return (*transition_inputs_)[index]; } | |
| 2532 | |
| 2533 enum ScoreType { | |
| 2534 SCORE_POSITIVE, | |
| 2535 SCORE_NEGATIVE, | |
| 2536 SCORE_NEUTRAL, | |
| 2537 SCORE_TYPE_COUNT | |
| 2538 }; | |
| 2539 | |
| 2540 ScoreType scoretype_from_loopdelta(int loopDelta) const { | |
| 2541 if (loopDelta > 0) return SCORE_POSITIVE; | |
| 2542 else if (loopDelta < 0) return SCORE_NEGATIVE; | |
| 2543 return SCORE_NEUTRAL; | |
| 2544 } | |
| 2545 | |
| 2546 int score(ScoreType type) const { return score_[type]; } | |
| 2547 void increment_score(ScoreType type, int score) { score_[type] += score; } | |
| 2548 | |
| 2549 bool hoistable() const { return hoistable_; } | |
| 2550 void set_hoistable(bool value) { hoistable_ = value; } | |
| 2551 | |
| 2552 void set_most_general_map(Map* new_most_general_map) { | |
| 2553 computed_most_general_map_ = new_most_general_map; } | |
| 2554 Map* most_general_map() const { return computed_most_general_map_; } | |
| 2555 | |
| 2556 void Finalize() { | |
| 2557 ASSERT(most_general_map() != NULL); | |
| 2558 ElementsKind elements_kind = most_general_map()->elements_kind(); | |
| 2559 // We have to cast to array instruction very carefully here. | |
| 2560 // A simple reinterpret cast will produce errors at runtime. | |
| 2561 ArrayInstructionInterface* array_instruction = NULL; | |
| 2562 if (load_or_store()->IsLoadKeyed()) { | |
| 2563 array_instruction = static_cast<ArrayInstructionInterface*>( | |
| 2564 HLoadKeyed::cast(load_or_store())); | |
| 2565 } else if (load_or_store()->IsStoreKeyed()) { | |
| 2566 array_instruction = static_cast<ArrayInstructionInterface*>( | |
| 2567 HStoreKeyed::cast(load_or_store())); | |
| 2568 } | |
| 2569 ASSERT(array_instruction != NULL); | |
| 2570 array_instruction->PerformDeferredInitialization(elements_kind); | |
| 2571 } | |
| 2572 | |
| 2573 Zone* zone() const { return zone_; } | |
| 2574 | |
| 2575 Map* map_family() const { | |
| 2576 Map* family = NULL; | |
| 2577 if (bookmarks()) { | |
| 2578 family = *(bookmark(0).family().location()); | |
| 2579 } | |
| 2580 | |
| 2581 #ifdef DEBUG | |
| 2582 for (int i = 1; i < bookmarks(); i++) { | |
| 2583 const TransitionElementsBookmark& tr = bookmark(i); | |
| 2584 ASSERT(*(tr.family().location()) == family); | |
| 2585 } | |
| 2586 #endif | |
| 2587 return family; | |
| 2588 } | |
| 2589 | |
| 2590 private: | |
| 2591 Zone* zone_; | |
| 2592 HInstruction* load_or_store_; | |
| 2593 HCheckNonSmi* smi_check_; | |
| 2594 HCheckMaps* map_check_; | |
| 2595 Map* computed_most_general_map_; | |
| 2596 int score_[SCORE_TYPE_COUNT]; | |
| 2597 bool hoistable_; | |
| 2598 ZoneList<TransitionElementsBookmark>* bookmarks_; | |
| 2599 TransitionInputList* transition_inputs_; | |
| 2600 }; | |
| 2601 | |
| 2602 | |
| 2603 typedef ZoneList<MarkedTransitionElementsGroup*> | |
| 2604 MarkedTransitionElementsGroupList; | |
| 2605 typedef EnumSet<ElementsKind> ElementsKindSet; | |
| 2606 | |
| 2607 | |
| 2608 class MostGeneralMapAndFamily { | |
| 2609 public: | |
| 2610 MostGeneralMapAndFamily() : most_general_map_(NULL), family_(NULL) { } | |
| 2611 MostGeneralMapAndFamily(const MostGeneralMapAndFamily& h) | |
| 2612 : most_general_map_(h.most_general_map()), | |
| 2613 family_(h.family()) { | |
| 2614 } | |
| 2615 | |
| 2616 Map* most_general_map() const { return most_general_map_; } | |
| 2617 Map* family() const { return family_; } | |
| 2618 | |
| 2619 void Update(Map* new_most_general_map, Map* new_family) { | |
| 2620 if (is_valid()) { | |
| 2621 // family shouldn't be changed | |
| 2622 ASSERT(new_family == family_); | |
| 2623 most_general_map_ = new_most_general_map; | |
| 2624 } else { | |
| 2625 most_general_map_ = new_most_general_map; | |
| 2626 family_ = new_family; | |
| 2627 } | |
| 2628 } | |
| 2629 | |
| 2630 void invalidate() { | |
| 2631 most_general_map_ = NULL; | |
| 2632 family_ = NULL; | |
| 2633 } | |
| 2634 | |
| 2635 bool is_valid() const { | |
| 2636 return most_general_map_ != NULL && family_ != NULL; } | |
| 2637 bool Equals(const MostGeneralMapAndFamily& h) const { | |
| 2638 if (!is_valid() || !h.is_valid()) { | |
| 2639 return is_valid() == h.is_valid(); | |
| 2640 } | |
| 2641 return most_general_map_ == h.most_general_map() && family_ == h.family(); | |
| 2642 } | |
| 2643 | |
| 2644 MostGeneralMapAndFamily& operator=(const MostGeneralMapAndFamily& h) { | |
| 2645 if (this != &h) { | |
| 2646 most_general_map_ = h.most_general_map(); | |
| 2647 family_ = h.family(); | |
| 2648 } | |
| 2649 return *this; | |
| 2650 } | |
| 2651 | |
| 2652 private: | |
| 2653 Map* most_general_map_; | |
| 2654 Map* family_; | |
| 2655 }; | |
| 2656 | |
| 2657 | |
| 2658 class TransitionInputDictionaryValue: public ZoneObject { | |
| 2659 public: | |
| 2660 TransitionInputDictionaryValue(HInstruction* transition_input, Zone* zone) : | |
| 2661 transition_input_(transition_input), | |
| 2662 groups_(new(zone) MarkedTransitionElementsGroupList(10, zone)), | |
| 2663 zone_(zone), | |
| 2664 last_in_chain_(NULL) { | |
| 2665 } | |
| 2666 | |
| 2667 void AddGroup(MarkedTransitionElementsGroup* group) { | |
| 2668 if (group->transition_inputs() == 1) { | |
| 2669 // put at the front of the list. Processing single element | |
| 2670 // transitions first makes score calculation easier. | |
| 2671 groups_->InsertAt(0, group, zone_); | |
| 2672 } else { | |
| 2673 groups_->Add(group, zone_); | |
| 2674 } | |
| 2675 } | |
| 2676 | |
| 2677 const MostGeneralMapAndFamily& most_general() { return most_general_; } | |
| 2678 void set_most_general(const MostGeneralMapAndFamily& m) { most_general_ = m; } | |
| 2679 | |
| 2680 int groups() const { return groups_->length(); } | |
| 2681 MarkedTransitionElementsGroup* group(int i) { return (*groups_)[i]; } | |
| 2682 Zone* zone() { return zone_; } | |
| 2683 | |
| 2684 void ComputeMostGeneralMapAndFamily(MostGeneralMapAndFamily* most_general, | |
| 2685 MarkedTransitionElementsGroup** other_family_group); | |
| 2686 | |
| 2687 // For instruction emission | |
| 2688 bool RequiresTransitionElementsKind(ElementsKind from) const { | |
| 2689 return !from_elements_.Contains(from); | |
| 2690 } | |
| 2691 | |
| 2692 void InsertTransitionElementsKind(Handle<Map> from, Handle<Map> to) { | |
| 2693 ASSERT(RequiresTransitionElementsKind(from->elements_kind())); | |
| 2694 // At the site, we maintain a most recent instruction we added, and | |
| 2695 // new instructions should appear at the end of the chain. | |
| 2696 HInstruction* addafter = last_in_chain_; | |
| 2697 if (addafter == NULL) { | |
| 2698 // This is the first instruction to add. | |
| 2699 // We must emit a checknonsmi | |
| 2700 addafter = new(zone()) HCheckNonSmi(transition_input_); | |
| 2701 addafter->InsertAfter(transition_input_); | |
| 2702 } | |
| 2703 | |
| 2704 HTransitionElementsKind* transition = NULL; | |
| 2705 if (last_in_chain_ == NULL) { | |
| 2706 transition = new(zone()) HTransitionElementsKind(transition_input_, from, | |
| 2707 to); | |
| 2708 transition->InsertAfter(addafter); | |
| 2709 | |
| 2710 // Careful tree surgery | |
| 2711 for (HUseIterator it(transition_input_->uses()); !it.Done(); | |
| 2712 it.Advance()) { | |
| 2713 HValue* use = it.value(); | |
| 2714 if (use != HValue::cast(addafter) && | |
| 2715 use != HValue::cast(transition)) { | |
| 2716 CarefullyReplaceOperand(&it, transition); | |
| 2717 } | |
| 2718 } | |
| 2719 } else { | |
| 2720 transition = new(zone()) HTransitionElementsKind(last_in_chain_, from, | |
| 2721 to); | |
| 2722 transition->InsertAfter(last_in_chain_); | |
| 2723 | |
| 2724 // Careful tree surgery | |
| 2725 for (HUseIterator it(last_in_chain_->uses()); !it.Done(); | |
| 2726 it.Advance()) { | |
| 2727 HValue* use = it.value(); | |
| 2728 if (use != HValue::cast(transition)) { | |
| 2729 CarefullyReplaceOperand(&it, transition); | |
| 2730 } | |
| 2731 } | |
| 2732 } | |
| 2733 | |
| 2734 last_in_chain_ = transition; | |
| 2735 from_elements_.Add(from->elements_kind()); | |
| 2736 } | |
| 2737 | |
| 2738 HInstruction* transition_input() const { return transition_input_; } | |
| 2739 | |
| 2740 private: | |
| 2741 void CarefullyReplaceOperand(HUseIterator* it, HInstruction* with) { | |
| 2742 HValue* use = it->value(); | |
| 2743 if (!use->block()->IsStartBlock()) { | |
|
danno
2012/11/28 14:42:10
More comments?
| |
| 2744 if (!use->IsSimulate() || use->block() != with->block()) { | |
| 2745 use->SetOperandAt(it->index(), with); | |
| 2746 } else { | |
| 2747 // Because of the way our new transition elements can be placed at the | |
| 2748 // start of a block, but ONLY AFTER any simulate instruction, we can | |
| 2749 // only replace usages of the with instruction if we are sure our new | |
| 2750 // instruction is defined in the block somewhere before the simulate. | |
| 2751 HInstruction* cur = HInstruction::cast(use)->previous(); | |
| 2752 while (cur != NULL) { | |
| 2753 if (cur == with) break; | |
| 2754 cur = cur->previous(); | |
| 2755 } | |
| 2756 if (cur == with) { | |
| 2757 // We can safely do the replacement | |
| 2758 use->SetOperandAt(it->index(), with); | |
| 2759 } | |
| 2760 } | |
| 2761 } | |
| 2762 } | |
| 2763 | |
| 2764 HInstruction* transition_input_; | |
| 2765 MarkedTransitionElementsGroupList* groups_; | |
| 2766 Zone* zone_; | |
| 2767 MostGeneralMapAndFamily most_general_; | |
| 2768 ElementsKindSet from_elements_; | |
| 2769 HTransitionElementsKind* last_in_chain_; | |
| 2770 }; | |
| 2771 | |
| 2772 | |
| 2773 | |
| 2774 class MapHandleMap BASE_EMBEDDED { | |
| 2775 public: | |
| 2776 explicit MapHandleMap(Zone* zone) : | |
| 2777 map_(MapPointerMatch, ZoneAllocationPolicy(zone)), | |
| 2778 zone_(zone), | |
| 2779 null_handle_(Handle<Map>::null()) { | |
| 2780 } | |
| 2781 | |
| 2782 Handle<Map>& Lookup(Map* map) { | |
| 2783 MapHandleTable::Iterator i = map_.find(map, false, | |
| 2784 ZoneAllocationPolicy(zone_)); | |
| 2785 if (i != map_.end()) { | |
| 2786 return *(i->second); | |
| 2787 } | |
| 2788 | |
| 2789 return null_handle_; | |
| 2790 } | |
| 2791 | |
| 2792 void Populate(ZoneList<MarkedTransitionElementsGroup*>* groups) { | |
| 2793 for (int i = 0; i < groups->length(); i++) { | |
| 2794 MarkedTransitionElementsGroup* group = groups->at(i); | |
| 2795 for (int r = 0; r < group->bookmarks(); r++) { | |
| 2796 Add(group->bookmark_pointer(r)); | |
| 2797 } | |
| 2798 } | |
| 2799 } | |
| 2800 | |
| 2801 private: | |
| 2802 static bool MapPointerMatch(void* key1, void* key2) { | |
| 2803 return key1 == key2; | |
| 2804 } | |
| 2805 | |
| 2806 void Add(TransitionElementsBookmark* record) { | |
| 2807 InsertIfMissing(record->from_pointer()); | |
| 2808 InsertIfMissing(record->to_pointer()); | |
| 2809 InsertIfMissing(record->family_pointer()); | |
| 2810 InsertIfMissing(record->pessimistic_holey_pointer()); | |
| 2811 } | |
| 2812 | |
| 2813 void Insert(Handle<Map>* handle) { | |
| 2814 MapHandleTable::Iterator i = map_.find(*(handle->location()), true, | |
| 2815 ZoneAllocationPolicy(zone_)); | |
| 2816 ASSERT(i != map_.end()); | |
| 2817 i->second = handle; | |
| 2818 } | |
| 2819 | |
| 2820 void InsertIfMissing(Handle<Map>* handle) { | |
| 2821 if (Lookup(*(handle->location())).is_null()) { | |
| 2822 Insert(handle); | |
| 2823 } | |
| 2824 } | |
| 2825 | |
| 2826 typedef TemplateHashMap<Map, Handle<Map>, ZoneAllocationPolicy> | |
| 2827 MapHandleTable; | |
| 2828 MapHandleTable map_; | |
| 2829 Zone* zone_; | |
| 2830 Handle<Map> null_handle_; | |
| 2831 }; | |
| 2832 | |
| 2833 | |
| 2834 class TransitionInputDictionary BASE_EMBEDDED { | |
| 2835 public: | |
| 2836 explicit TransitionInputDictionary(Zone* zone) : | |
| 2837 dictionary_(TransitionInputMatch, 32, ZoneAllocationPolicy(zone)), | |
| 2838 zone_(zone), | |
| 2839 iterator_(NULL) { | |
| 2840 } | |
| 2841 | |
| 2842 void Initialize(Isolate* isolate, | |
| 2843 ZoneList<MarkedTransitionElementsGroup*>* groups); | |
| 2844 | |
| 2845 TransitionInputDictionaryValue* Lookup(HInstruction* transition_input) { | |
| 2846 ZoneHashMap::Entry* entry = dictionary_.Lookup(transition_input, | |
| 2847 transition_input->id(), | |
| 2848 false, | |
| 2849 ZoneAllocationPolicy(zone_)); | |
| 2850 | |
| 2851 if (entry == NULL) { | |
| 2852 return NULL; | |
| 2853 } | |
| 2854 | |
| 2855 TransitionInputDictionaryValue* value = | |
| 2856 reinterpret_cast<TransitionInputDictionaryValue*>(entry->value); | |
| 2857 return value; | |
| 2858 } | |
| 2859 | |
| 2860 void Scorch(MarkedTransitionElementsGroup* other_family_group); | |
| 2861 | |
| 2862 TransitionInputDictionaryValue* Start() { | |
| 2863 iterator_ = dictionary_.Start(); | |
| 2864 if (iterator_ != NULL) { | |
| 2865 return reinterpret_cast<TransitionInputDictionaryValue*>( | |
| 2866 iterator_->value); | |
| 2867 } | |
| 2868 | |
| 2869 return NULL; | |
| 2870 } | |
| 2871 | |
| 2872 TransitionInputDictionaryValue* Next() { | |
| 2873 iterator_ = dictionary_.Next(iterator_); | |
| 2874 if (iterator_ != NULL) { | |
| 2875 return reinterpret_cast<TransitionInputDictionaryValue*>( | |
| 2876 iterator_->value); | |
| 2877 } | |
| 2878 | |
| 2879 return NULL; | |
| 2880 } | |
| 2881 | |
| 2882 private: | |
| 2883 Zone* zone() { return zone_; } | |
| 2884 static bool TransitionInputMatch(void* key1, void* key2) { | |
| 2885 return key1 == key2; | |
| 2886 } | |
| 2887 | |
| 2888 void Insert(TransitionInputDictionaryValue* value) { | |
| 2889 ZoneHashMap::Entry* entry = dictionary_.Lookup(value->transition_input(), | |
| 2890 value->transition_input()->id(), | |
| 2891 true, | |
| 2892 ZoneAllocationPolicy(zone_)); | |
| 2893 ASSERT(entry->value == NULL); | |
| 2894 entry->value = value; | |
| 2895 iterator_ = NULL; | |
| 2896 } | |
| 2897 | |
| 2898 void Remove(HInstruction* transition_input) { | |
| 2899 dictionary_.Remove(transition_input, transition_input->id()); | |
| 2900 iterator_ = NULL; | |
| 2901 } | |
| 2902 | |
| 2903 ZoneHashMap dictionary_; | |
| 2904 Zone* zone_; | |
| 2905 ZoneHashMap::Entry* iterator_; | |
| 2906 }; | |
| 2907 | |
| 2908 | |
| 2909 void TransitionInputDictionaryValue::ComputeMostGeneralMapAndFamily( | |
| 2910 MostGeneralMapAndFamily* most_general_map_and_family, | |
| 2911 MarkedTransitionElementsGroup** other_family_group) { | |
| 2912 *most_general_map_and_family = most_general(); | |
| 2913 | |
| 2914 // At the end of this function all groups in the list need to agree on the | |
| 2915 // highest map. so one time through the loop isn't enough. | |
| 2916 for (int count = 0; count < 2; count++) { | |
| 2917 for (int i = 0; i < groups(); i++) { | |
| 2918 Map* todo_most_general_map = group(i)->most_general_map(); | |
| 2919 | |
| 2920 if (!most_general_map_and_family->is_valid()) { | |
| 2921 // First todo, first time through the loop | |
| 2922 most_general_map_and_family->Update(todo_most_general_map, | |
| 2923 group(i)->map_family()); | |
| 2924 } else if (most_general_map_and_family->most_general_map() != | |
| 2925 todo_most_general_map) { | |
| 2926 // Are they in the same family? | |
| 2927 if (most_general_map_and_family->family() != group(i)->map_family()) { | |
| 2928 // Yikes. this won't work. | |
| 2929 *other_family_group = group(i); | |
| 2930 most_general_map_and_family->invalidate(); | |
| 2931 return; | |
| 2932 } | |
| 2933 | |
| 2934 // which one is higher? Figure that out and then the other one needs to | |
| 2935 // be able to find a path to it. | |
| 2936 ElementsKind unified_elements_kind = GetUnifiedFastElementsKind( | |
| 2937 most_general_map_and_family->most_general_map()->elements_kind(), | |
| 2938 todo_most_general_map->elements_kind()); | |
| 2939 | |
| 2940 // make sure both maps have a path to success | |
| 2941 Map* unified_map = most_general_map_and_family->most_general_map()-> | |
| 2942 LookupElementsTransitionMap(unified_elements_kind); | |
| 2943 Map* unified_todo_map = todo_most_general_map-> | |
| 2944 LookupElementsTransitionMap(unified_elements_kind); | |
| 2945 if (unified_map == NULL || unified_todo_map == NULL || | |
| 2946 (unified_map != unified_todo_map)) { | |
| 2947 *other_family_group = group(i); | |
| 2948 most_general_map_and_family->invalidate(); | |
| 2949 return; | |
| 2950 } | |
| 2951 | |
| 2952 most_general_map_and_family->Update(unified_map, | |
| 2953 group(i)->map_family()); | |
| 2954 group(i)->set_most_general_map( | |
| 2955 most_general_map_and_family->most_general_map()); | |
| 2956 } | |
| 2957 } | |
| 2958 } | |
| 2959 } | |
| 2960 | |
| 2961 | |
| 2962 void TransitionInputDictionary::Scorch(MarkedTransitionElementsGroup* | |
| 2963 other_family_group) { | |
| 2964 MarkedTransitionElementsGroupList worklist(10, zone()); | |
| 2965 other_family_group->set_hoistable(false); | |
| 2966 worklist.Add(other_family_group, zone()); | |
| 2967 | |
| 2968 while (!worklist.is_empty()) { | |
| 2969 MarkedTransitionElementsGroup* group = worklist.RemoveLast(); | |
| 2970 ASSERT(!group->hoistable()); | |
| 2971 for (int t = 0; t < group->transition_inputs(); t++) { | |
| 2972 HInstruction* transition_input = group->transition_input(t); | |
| 2973 TransitionInputDictionaryValue* value = Lookup(transition_input); | |
| 2974 if (value != NULL) { | |
| 2975 for (int i = 0; i < value->groups(); i++) { | |
| 2976 MarkedTransitionElementsGroup* other_group = value->group(i); | |
| 2977 if (other_group->hoistable()) { | |
| 2978 other_group->set_hoistable(false); | |
| 2979 worklist.Add(other_group, zone()); | |
| 2980 } | |
| 2981 } | |
| 2982 | |
| 2983 Remove(transition_input); | |
| 2984 } | |
| 2985 } | |
| 2986 } | |
| 2987 } | |
| 2988 | |
| 2989 | |
| 2990 void TransitionInputDictionary::Initialize(Isolate* isolate, | |
| 2991 ZoneList<MarkedTransitionElementsGroup*>* groups) { | |
| 2992 ZoneAllocationPolicy allocator(zone()); | |
| 2993 Counters* counters = isolate->counters(); | |
| 2994 | |
| 2995 for (int i = 0; i < groups->length(); i++) { | |
| 2996 MarkedTransitionElementsGroup* group = groups->at(i); | |
| 2997 int site_nesting_depth = group->load_or_store()->block()-> | |
| 2998 LoopNestingDepth(); | |
| 2999 | |
| 3000 for (int t = 0; t < group->transition_inputs(); t++) { | |
| 3001 HInstruction* transition_input = group->transition_input(t); | |
| 3002 | |
| 3003 // Score computation | |
| 3004 int input_site_nesting_depth = transition_input->block()-> | |
| 3005 LoopNestingDepth(); | |
| 3006 int loop_delta = site_nesting_depth - input_site_nesting_depth; | |
| 3007 int proposedAdds = group->bookmarks(); | |
| 3008 MarkedTransitionElementsGroup::ScoreType scoreType = | |
| 3009 group->scoretype_from_loopdelta(loop_delta); | |
| 3010 int score = (loop_delta == 0 ? 1 : loop_delta)*proposedAdds; | |
| 3011 if (score < 0) score *= -1; | |
| 3012 group->increment_score(scoreType, score); | |
| 3013 TransitionInputDictionaryValue* value = Lookup(transition_input); | |
| 3014 if (value == NULL) { | |
| 3015 // It's new, add a value | |
| 3016 value = new(zone()) | |
| 3017 TransitionInputDictionaryValue(transition_input, zone()); | |
| 3018 Insert(value); | |
| 3019 } | |
| 3020 | |
| 3021 value->AddGroup(group); | |
| 3022 } | |
| 3023 | |
| 3024 // Export the site score in aggregate for reporting | |
| 3025 counters->transition_site_positive_score()-> | |
| 3026 Increment(group->score(MarkedTransitionElementsGroup::SCORE_POSITIVE)); | |
| 3027 counters->transition_site_negative_score()-> | |
| 3028 Increment(group->score(MarkedTransitionElementsGroup::SCORE_NEGATIVE)); | |
| 3029 counters->transition_site_neutral_score()-> | |
| 3030 Increment(group->score(MarkedTransitionElementsGroup::SCORE_NEUTRAL)); | |
| 3031 } | |
| 3032 } | |
| 3033 | |
| 3034 | |
| 3035 void HGraph::InsertElementsTransitions() { | |
| 3036 ZoneAllocationPolicy allocator(zone()); | |
| 3037 HPhase phase("H_Place elements transitions", this); | |
| 3038 | |
| 3039 // Initialize the groups, the map handle map, the transition input dictionary | |
| 3040 for (int i = 0; i < marked_transitions_.length(); i++) { | |
| 3041 MarkedTransitionElementsGroup* group = marked_transitions_[i]; | |
| 3042 ASSERT(group->bookmarks() > 0); | |
| 3043 group->ComputeTransitionInputValues(GetMaximumValueID()); | |
|
danno
2012/11/28 14:42:10
As discussed, this algorithm costs O(n x m), where
| |
| 3044 } | |
| 3045 | |
| 3046 MapHandleMap mapHandleMap(zone()); | |
| 3047 mapHandleMap.Populate(&marked_transitions_); | |
| 3048 | |
| 3049 TransitionInputDictionary transitionInputDictionary(zone()); | |
| 3050 transitionInputDictionary.Initialize(isolate(), &marked_transitions_); | |
| 3051 | |
| 3052 // Now that the map is created, run the unification algorithm | |
| 3053 bool done = false; | |
| 3054 while (!done) { | |
| 3055 bool changed = false; | |
| 3056 for (TransitionInputDictionaryValue* value = | |
| 3057 transitionInputDictionary.Start(); | |
| 3058 value != NULL; | |
| 3059 value = transitionInputDictionary.Next()) { | |
| 3060 MarkedTransitionElementsGroup* wrong_family_group = NULL; | |
| 3061 MostGeneralMapAndFamily new_most_general; | |
| 3062 value->ComputeMostGeneralMapAndFamily(&new_most_general, | |
| 3063 &wrong_family_group); | |
| 3064 if (!new_most_general.is_valid()) { | |
| 3065 ASSERT(wrong_family_group != NULL); | |
| 3066 transitionInputDictionary.Scorch(wrong_family_group); | |
| 3067 changed = true; | |
| 3068 break; | |
| 3069 } | |
| 3070 | |
| 3071 if (!value->most_general().Equals(new_most_general)) { | |
| 3072 value->set_most_general(new_most_general); | |
| 3073 changed = true; | |
| 3074 } | |
| 3075 } | |
| 3076 | |
| 3077 done = !changed; | |
| 3078 } | |
| 3079 | |
| 3080 // Now we have the "to" value for each location, and groups have been divided | |
| 3081 // into sets, including a set that couldn't be transitioned and is no longer | |
| 3082 // represented in the transitionInputDictionary Handle each todo again. | |
| 3083 if (FLAG_trace_transition_placement) { | |
| 3084 for (int i = 0; i < marked_transitions_.length(); i++) { | |
| 3085 MarkedTransitionElementsGroup* group = marked_transitions_.at(i); | |
| 3086 HeapStringAllocator string_allocator; | |
| 3087 StringStream stream(&string_allocator); | |
| 3088 group->PrintTo(&stream); | |
| 3089 PrintF("%s", *stream.ToCString()); | |
| 3090 } | |
| 3091 } | |
| 3092 | |
| 3093 // Do the work | |
| 3094 for (int i = 0; i < marked_transitions_.length(); i++) { | |
| 3095 MarkedTransitionElementsGroup* group = marked_transitions_.at(i); | |
|
danno
2012/11/28 14:42:10
Is this just an ArrayInterface?
| |
| 3096 | |
| 3097 // All groups need to be finalized, even if we don't take action on them. | |
| 3098 group->Finalize(); | |
| 3099 | |
| 3100 if (!group->hoistable()) { | |
| 3101 // We aren't moving this todo, leave it alone and visit the next | |
| 3102 continue; | |
| 3103 } | |
| 3104 | |
| 3105 // 1) Remove the nonsmicheck. | |
| 3106 if (group->smi_check()->IsLinked()) { | |
| 3107 group->smi_check()->DeleteAndReplaceWith(NULL); | |
| 3108 } | |
| 3109 | |
| 3110 // 2) alter the elementkind of the loadkeyed/storekeyed instruction if | |
| 3111 // required. (note that steps a,b,c won't happen if the transition was | |
| 3112 // marked as invalid because it operates on a different map family) 2a) | |
| 3113 // unlink transitions associated with this site from their current location | |
| 3114 // 2b) Create appropriate transition instructions up at the transition input | |
| 3115 // site. 2c) Fix the checkmaps instruction if required. | |
| 3116 | |
| 3117 Handle<Map>& handle = mapHandleMap.Lookup(group->most_general_map()); | |
| 3118 ASSERT(!handle.is_null()); | |
| 3119 | |
| 3120 HCheckMaps* map_check = group->map_check(); | |
| 3121 if (map_check != NULL) { | |
| 3122 ASSERT(map_check->map_set()->length() == 1); | |
| 3123 // Surgically replace the map in there if necessary | |
| 3124 if (*(map_check->map_set()->at(0).location()) != *handle.location()) { | |
| 3125 map_check->map_set()->Clear(); | |
| 3126 map_check->map_set()->Add(handle, zone()); | |
| 3127 } | |
| 3128 | |
| 3129 // The map check had a dependency on the transition elements statement | |
| 3130 // that was in place before. This is unnecessary now, just remove it. | |
| 3131 // After the operations above, the tree expresses dependency through | |
| 3132 // ordinary output values | |
| 3133 map_check->RemoveTypeCheck(); | |
| 3134 } | |
| 3135 | |
| 3136 for (int t = 0; t < group->transition_inputs(); t++) { | |
| 3137 TransitionInputDictionaryValue* value = | |
| 3138 transitionInputDictionary.Lookup(group->transition_input(t)); | |
| 3139 for (int r = 0; r < group->bookmarks(); r++) { | |
| 3140 TransitionElementsBookmark* record = group->bookmark_pointer(r); | |
| 3141 if (value->RequiresTransitionElementsKind( | |
| 3142 record->elementskind_from())) { | |
| 3143 // We need to emit a transition. | |
| 3144 value->InsertTransitionElementsKind(record->from(), handle); | |
| 3145 | |
| 3146 // Remove the transition from it's original location | |
| 3147 if (record->transition_instruction()->block() != NULL) { | |
| 3148 ASSERT(record->transition_instruction()->HasNoUses()); | |
| 3149 record->transition_instruction()->DeleteAndReplaceWith(NULL); | |
| 3150 } | |
| 3151 } | |
| 3152 } | |
| 3153 } | |
| 3154 } | |
| 3155 } | |
| 3156 | |
| 3157 | |
| 2452 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { | 3158 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { |
| 2453 HValue* current = value; | 3159 HValue* current = value; |
| 2454 while (current != NULL) { | 3160 while (current != NULL) { |
| 2455 if (visited->Contains(current->id())) return; | 3161 if (visited->Contains(current->id())) return; |
| 2456 | 3162 |
| 2457 // For phis, we must propagate the check to all of its inputs. | 3163 // For phis, we must propagate the check to all of its inputs. |
| 2458 if (current->IsPhi()) { | 3164 if (current->IsPhi()) { |
| 2459 visited->Add(current->id()); | 3165 visited->Add(current->id()); |
| 2460 HPhi* phi = HPhi::cast(current); | 3166 HPhi* phi = HPhi::cast(current); |
| 2461 for (int i = 0; i < phi->OperandCount(); ++i) { | 3167 for (int i = 0; i < phi->OperandCount(); ++i) { |
| (...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3267 } | 3973 } |
| 3268 EliminateRedundantPhis(); | 3974 EliminateRedundantPhis(); |
| 3269 if (!CheckArgumentsPhiUses()) { | 3975 if (!CheckArgumentsPhiUses()) { |
| 3270 *bailout_reason = SmartArrayPointer<char>(StrDup( | 3976 *bailout_reason = SmartArrayPointer<char>(StrDup( |
| 3271 "Unsupported phi use of arguments")); | 3977 "Unsupported phi use of arguments")); |
| 3272 return false; | 3978 return false; |
| 3273 } | 3979 } |
| 3274 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); | 3980 if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis(); |
| 3275 CollectPhis(); | 3981 CollectPhis(); |
| 3276 | 3982 |
| 3983 if (FLAG_use_place_elements_transitions) InsertElementsTransitions(); | |
| 3984 | |
| 3277 if (has_osr_loop_entry()) { | 3985 if (has_osr_loop_entry()) { |
| 3278 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); | 3986 const ZoneList<HPhi*>* phis = osr_loop_entry()->phis(); |
| 3279 for (int j = 0; j < phis->length(); j++) { | 3987 for (int j = 0; j < phis->length(); j++) { |
| 3280 HPhi* phi = phis->at(j); | 3988 HPhi* phi = phis->at(j); |
| 3281 osr_values()->at(phi->merged_index())->set_incoming_value(phi); | 3989 osr_values()->at(phi->merged_index())->set_incoming_value(phi); |
| 3282 } | 3990 } |
| 3283 } | 3991 } |
| 3284 | 3992 |
| 3285 HInferRepresentation rep(this); | 3993 HInferRepresentation rep(this); |
| 3286 rep.Analyze(); | 3994 rep.Analyze(); |
| (...skipping 2781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6068 return load; | 6776 return load; |
| 6069 } | 6777 } |
| 6070 } | 6778 } |
| 6071 | 6779 |
| 6072 | 6780 |
| 6073 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, | 6781 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
| 6074 HValue* checked_key, | 6782 HValue* checked_key, |
| 6075 HValue* val, | 6783 HValue* val, |
| 6076 HValue* load_dependency, | 6784 HValue* load_dependency, |
| 6077 ElementsKind elements_kind, | 6785 ElementsKind elements_kind, |
| 6078 bool is_store) { | 6786 bool is_store, |
| 6787 bool defer_initialization) { | |
| 6079 if (is_store) { | 6788 if (is_store) { |
| 6080 ASSERT(val != NULL); | 6789 ASSERT(val != NULL); |
| 6081 switch (elements_kind) { | 6790 switch (elements_kind) { |
| 6082 case FAST_SMI_ELEMENTS: | 6791 case FAST_SMI_ELEMENTS: |
| 6083 case FAST_HOLEY_SMI_ELEMENTS: | 6792 case FAST_HOLEY_SMI_ELEMENTS: |
| 6084 // Smi-only arrays need a smi check. | 6793 // Smi-only arrays need a smi check. |
| 6085 AddInstruction(new(zone()) HCheckSmi(val)); | 6794 AddInstruction(new(zone()) HCheckSmi(val)); |
| 6086 // Fall through. | 6795 // Fall through. |
| 6087 case FAST_ELEMENTS: | 6796 case FAST_ELEMENTS: |
| 6088 case FAST_HOLEY_ELEMENTS: | 6797 case FAST_HOLEY_ELEMENTS: |
| 6089 case FAST_DOUBLE_ELEMENTS: | 6798 case FAST_DOUBLE_ELEMENTS: |
| 6090 case FAST_HOLEY_DOUBLE_ELEMENTS: | 6799 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 6091 return new(zone()) HStoreKeyed( | 6800 return new(zone()) HStoreKeyed( |
| 6092 elements, checked_key, val, elements_kind); | 6801 elements, checked_key, val, elements_kind, defer_initialization); |
| 6093 default: | 6802 default: |
| 6094 UNREACHABLE(); | 6803 UNREACHABLE(); |
| 6095 return NULL; | 6804 return NULL; |
| 6096 } | 6805 } |
| 6097 } | 6806 } |
| 6098 // It's an element load (!is_store). | 6807 // It's an element load (!is_store). |
| 6099 return new(zone()) HLoadKeyed(elements, | 6808 return new(zone()) HLoadKeyed(elements, |
| 6100 checked_key, | 6809 checked_key, |
| 6101 load_dependency, | 6810 load_dependency, |
| 6102 elements_kind); | 6811 elements_kind, defer_initialization); |
| 6103 } | 6812 } |
| 6104 | 6813 |
| 6105 | 6814 |
| 6106 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 6815 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 6107 HValue* key, | 6816 HValue* key, |
| 6108 HValue* val, | 6817 HValue* val, |
| 6109 HValue* dependency, | 6818 HValue* dependency, |
| 6110 Handle<Map> map, | 6819 Handle<Map> map, |
| 6111 bool is_store) { | 6820 bool is_store, |
| 6821 HCheckMaps** checkmap_instr) { | |
| 6112 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, | 6822 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, |
| 6113 zone(), dependency); | 6823 zone(), dependency); |
| 6114 AddInstruction(mapcheck); | 6824 AddInstruction(mapcheck); |
| 6115 if (dependency) { | 6825 if (dependency) { |
| 6116 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 6826 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 6117 } | 6827 } |
| 6828 | |
| 6829 if (checkmap_instr != NULL) { | |
| 6830 *checkmap_instr = mapcheck; | |
| 6831 } | |
| 6832 | |
| 6833 // TODO(mvstanton): this is a bit opaque, maybe just pass in a | |
| 6834 // defer_initialization param | |
| 6835 bool defer_initialization = FLAG_use_place_elements_transitions && | |
| 6836 (dependency != NULL); | |
| 6118 return BuildUncheckedMonomorphicElementAccess(object, key, val, | 6837 return BuildUncheckedMonomorphicElementAccess(object, key, val, |
| 6119 mapcheck, map, is_store); | 6838 mapcheck, map, is_store, |
| 6839 defer_initialization); | |
| 6120 } | 6840 } |
| 6121 | 6841 |
| 6122 | 6842 |
| 6123 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 6843 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 6124 HValue* object, | 6844 HValue* object, |
| 6125 HValue* key, | 6845 HValue* key, |
| 6126 HValue* val, | 6846 HValue* val, |
| 6127 HCheckMaps* mapcheck, | 6847 HCheckMaps* mapcheck, |
| 6128 Handle<Map> map, | 6848 Handle<Map> map, |
| 6129 bool is_store) { | 6849 bool is_store, |
| 6850 bool defer_initialization) { | |
| 6130 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 6851 // 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 | 6852 // 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 | 6853 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
| 6133 // ElementsKind transitions. Finally, the dependency can be removed for stores | 6854 // ElementsKind transitions. Finally, the dependency can be removed for stores |
| 6134 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 6855 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 6135 // generated store code. | 6856 // generated store code. |
| 6136 if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) || | 6857 if ((map->elements_kind() == FAST_HOLEY_ELEMENTS) || |
| 6137 (map->elements_kind() == FAST_ELEMENTS && is_store)) { | 6858 (map->elements_kind() == FAST_ELEMENTS && is_store)) { |
| 6138 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 6859 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 6139 } | 6860 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 6165 map->has_fast_double_elements()); | 6886 map->has_fast_double_elements()); |
| 6166 if (map->instance_type() == JS_ARRAY_TYPE) { | 6887 if (map->instance_type() == JS_ARRAY_TYPE) { |
| 6167 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck, | 6888 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck, |
| 6168 HType::Smi())); | 6889 HType::Smi())); |
| 6169 } else { | 6890 } else { |
| 6170 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 6891 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 6171 } | 6892 } |
| 6172 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 6893 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6173 ALLOW_SMI_KEY)); | 6894 ALLOW_SMI_KEY)); |
| 6174 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 6895 return BuildFastElementAccess(elements, checked_key, val, mapcheck, |
| 6175 map->elements_kind(), is_store); | 6896 map->elements_kind(), is_store, |
| 6897 defer_initialization); | |
| 6176 } | 6898 } |
| 6177 | 6899 |
| 6178 | 6900 |
| 6179 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( | 6901 HInstruction* HGraphBuilder::TryBuildConsolidatedElementLoad( |
| 6180 HValue* object, | 6902 HValue* object, |
| 6181 HValue* key, | 6903 HValue* key, |
| 6182 HValue* val, | 6904 HValue* val, |
| 6183 SmallMapList* maps) { | 6905 SmallMapList* maps) { |
| 6184 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 6906 // 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 | 6907 // double), always use the "worst case" code without a transition. This is |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6217 most_general_consolidated_map->elements_kind(), | 6939 most_general_consolidated_map->elements_kind(), |
| 6218 map->elements_kind())) { | 6940 map->elements_kind())) { |
| 6219 most_general_consolidated_map = map; | 6941 most_general_consolidated_map = map; |
| 6220 } | 6942 } |
| 6221 } | 6943 } |
| 6222 if (!has_double_maps && !has_smi_or_object_maps) return NULL; | 6944 if (!has_double_maps && !has_smi_or_object_maps) return NULL; |
| 6223 | 6945 |
| 6224 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); | 6946 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); |
| 6225 AddInstruction(check_maps); | 6947 AddInstruction(check_maps); |
| 6226 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( | 6948 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( |
| 6227 object, key, val, check_maps, most_general_consolidated_map, false); | 6949 object, key, val, check_maps, most_general_consolidated_map, false, |
| 6950 false); | |
| 6228 return instr; | 6951 return instr; |
| 6229 } | 6952 } |
| 6230 | 6953 |
| 6231 | 6954 |
| 6232 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, | 6955 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
| 6233 HValue* key, | 6956 HValue* key, |
| 6234 HValue* val, | 6957 HValue* val, |
| 6235 Expression* prop, | 6958 Expression* prop, |
| 6236 BailoutId ast_id, | 6959 BailoutId ast_id, |
| 6237 int position, | 6960 int position, |
| 6238 bool is_store, | 6961 bool is_store, |
| 6239 bool* has_side_effects) { | 6962 bool* has_side_effects) { |
| 6240 *has_side_effects = false; | 6963 *has_side_effects = false; |
| 6241 AddInstruction(new(zone()) HCheckNonSmi(object)); | 6964 bool use_groups = FLAG_use_place_elements_transitions; |
| 6965 HCheckNonSmi* checknonsmi = new(zone()) HCheckNonSmi(object); | |
| 6966 AddInstruction(checknonsmi); | |
| 6242 SmallMapList* maps = prop->GetReceiverTypes(); | 6967 SmallMapList* maps = prop->GetReceiverTypes(); |
| 6243 bool todo_external_array = false; | 6968 bool todo_external_array = false; |
| 6244 | 6969 |
| 6245 if (!is_store) { | 6970 if (!is_store) { |
| 6246 HInstruction* consolidated_load = | 6971 HInstruction* consolidated_load = |
| 6247 TryBuildConsolidatedElementLoad(object, key, val, maps); | 6972 TryBuildConsolidatedElementLoad(object, key, val, maps); |
| 6248 if (consolidated_load != NULL) { | 6973 if (consolidated_load != NULL) { |
| 6249 AddInstruction(consolidated_load); | 6974 AddInstruction(consolidated_load); |
| 6250 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 6975 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
| 6251 if (position != RelocInfo::kNoPosition) { | 6976 if (position != RelocInfo::kNoPosition) { |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 6277 for (int i = 0; i < maps->length(); ++i) { | 7002 for (int i = 0; i < maps->length(); ++i) { |
| 6278 Handle<Map> map = maps->at(i); | 7003 Handle<Map> map = maps->at(i); |
| 6279 Handle<Map> transitioned_map = | 7004 Handle<Map> transitioned_map = |
| 6280 map->FindTransitionedMap(&possible_transitioned_maps); | 7005 map->FindTransitionedMap(&possible_transitioned_maps); |
| 6281 transition_target.Add(transitioned_map); | 7006 transition_target.Add(transitioned_map); |
| 6282 } | 7007 } |
| 6283 | 7008 |
| 6284 int num_untransitionable_maps = 0; | 7009 int num_untransitionable_maps = 0; |
| 6285 Handle<Map> untransitionable_map; | 7010 Handle<Map> untransitionable_map; |
| 6286 HTransitionElementsKind* transition = NULL; | 7011 HTransitionElementsKind* transition = NULL; |
| 7012 ZoneList<TransitionElementsBookmark> bookmarks(10, zone()); | |
| 6287 for (int i = 0; i < maps->length(); ++i) { | 7013 for (int i = 0; i < maps->length(); ++i) { |
| 6288 Handle<Map> map = maps->at(i); | 7014 Handle<Map> map = maps->at(i); |
| 6289 ASSERT(map->IsMap()); | 7015 ASSERT(map->IsMap()); |
| 6290 if (!transition_target.at(i).is_null()) { | 7016 if (!transition_target.at(i).is_null()) { |
| 6291 ASSERT(Map::IsValidElementsTransition( | 7017 ASSERT(Map::IsValidElementsTransition( |
| 6292 map->elements_kind(), | 7018 map->elements_kind(), |
| 6293 transition_target.at(i)->elements_kind())); | 7019 transition_target.at(i)->elements_kind())); |
| 6294 transition = new(zone()) HTransitionElementsKind( | 7020 transition = new(zone()) HTransitionElementsKind( |
| 6295 object, map, transition_target.at(i)); | 7021 object, map, transition_target.at(i)); |
| 6296 AddInstruction(transition); | 7022 AddInstruction(transition); |
| 7023 | |
| 7024 if (use_groups) { | |
| 7025 TransitionElementsBookmark tr(transition, | |
| 7026 map, | |
| 7027 transition_target.at(i), | |
| 7028 isolate()); | |
| 7029 bookmarks.Add(tr, zone()); | |
| 7030 } | |
| 6297 } else { | 7031 } else { |
| 6298 type_todo[map->elements_kind()] = true; | 7032 type_todo[map->elements_kind()] = true; |
| 6299 if (IsExternalArrayElementsKind(map->elements_kind())) { | 7033 if (IsExternalArrayElementsKind(map->elements_kind())) { |
| 6300 todo_external_array = true; | 7034 todo_external_array = true; |
| 6301 } | 7035 } |
| 6302 num_untransitionable_maps++; | 7036 num_untransitionable_maps++; |
| 6303 untransitionable_map = map; | 7037 untransitionable_map = map; |
| 6304 } | 7038 } |
| 6305 } | 7039 } |
| 6306 | 7040 |
| 6307 // If only one map is left after transitioning, handle this case | 7041 // If only one map is left after transitioning, handle this case |
| 6308 // monomorphically. | 7042 // monomorphically. |
| 6309 if (num_untransitionable_maps == 1) { | 7043 if (num_untransitionable_maps == 1) { |
| 6310 HInstruction* instr = NULL; | 7044 HInstruction* instr = NULL; |
| 6311 if (untransitionable_map->has_slow_elements_kind()) { | 7045 if (untransitionable_map->has_slow_elements_kind()) { |
| 6312 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 7046 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 6313 : BuildLoadKeyedGeneric(object, key)); | 7047 : BuildLoadKeyedGeneric(object, key)); |
| 6314 } else { | 7048 } else { |
| 7049 HCheckMaps *checkmaps = NULL; | |
| 6315 instr = AddInstruction(BuildMonomorphicElementAccess( | 7050 instr = AddInstruction(BuildMonomorphicElementAccess( |
| 6316 object, key, val, transition, untransitionable_map, is_store)); | 7051 object, key, val, transition, untransitionable_map, is_store, |
| 7052 &checkmaps)); | |
| 7053 | |
| 7054 if (use_groups && bookmarks.length() > 0) { | |
| 7055 MarkedTransitionElementsGroup* group = new(zone()) | |
| 7056 MarkedTransitionElementsGroup(instr, checknonsmi, | |
| 7057 checkmaps, zone()); | |
| 7058 group->AddBookmarks(bookmarks); | |
| 7059 graph()->AddMarkedTransitionElementsGroup(group); | |
| 7060 } | |
| 6317 } | 7061 } |
| 6318 *has_side_effects |= instr->HasObservableSideEffects(); | 7062 *has_side_effects |= instr->HasObservableSideEffects(); |
| 6319 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 7063 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
| 6320 return is_store ? NULL : instr; | 7064 return is_store ? NULL : instr; |
| 6321 } | 7065 } |
| 6322 | 7066 |
| 6323 HInstruction* checkspec = | 7067 HInstruction* checkspec = |
| 6324 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); | 7068 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); |
| 6325 HBasicBlock* join = graph()->CreateBasicBlock(); | 7069 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 6326 | 7070 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6358 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 7102 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6359 HCompareConstantEqAndBranch* elements_kind_branch = | 7103 HCompareConstantEqAndBranch* elements_kind_branch = |
| 6360 new(zone()) HCompareConstantEqAndBranch( | 7104 new(zone()) HCompareConstantEqAndBranch( |
| 6361 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 7105 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
| 6362 elements_kind_branch->SetSuccessorAt(0, if_true); | 7106 elements_kind_branch->SetSuccessorAt(0, if_true); |
| 6363 elements_kind_branch->SetSuccessorAt(1, if_false); | 7107 elements_kind_branch->SetSuccessorAt(1, if_false); |
| 6364 current_block()->Finish(elements_kind_branch); | 7108 current_block()->Finish(elements_kind_branch); |
| 6365 | 7109 |
| 6366 set_current_block(if_true); | 7110 set_current_block(if_true); |
| 6367 HInstruction* access; | 7111 HInstruction* access; |
| 7112 HCheckMaps* checkmaps = NULL; | |
| 6368 if (IsFastElementsKind(elements_kind)) { | 7113 if (IsFastElementsKind(elements_kind)) { |
| 6369 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { | 7114 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
| 6370 AddInstruction(new(zone()) HCheckMaps( | 7115 checkmaps = new(zone()) HCheckMaps( |
| 6371 elements, isolate()->factory()->fixed_array_map(), | 7116 elements, isolate()->factory()->fixed_array_map(), |
| 6372 zone(), elements_kind_branch)); | 7117 zone(), elements_kind_branch); |
| 7118 AddInstruction(checkmaps); | |
| 6373 } | 7119 } |
| 6374 // TODO(jkummerow): The need for these two blocks could be avoided | 7120 // TODO(jkummerow): The need for these two blocks could be avoided |
| 6375 // in one of two ways: | 7121 // in one of two ways: |
| 6376 // (1) Introduce ElementsKinds for JSArrays that are distinct from | 7122 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
| 6377 // those for fast objects. | 7123 // those for fast objects. |
| 6378 // (2) Put the common instructions into a third "join" block. This | 7124 // (2) Put the common instructions into a third "join" block. This |
| 6379 // requires additional AST IDs that we can deopt to from inside | 7125 // requires additional AST IDs that we can deopt to from inside |
| 6380 // that join block. They must be added to the Property class (when | 7126 // that join block. They must be added to the Property class (when |
| 6381 // it's a keyed property) and registered in the full codegen. | 7127 // it's a keyed property) and registered in the full codegen. |
| 6382 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | 7128 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
| 6383 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | 7129 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
| 6384 HHasInstanceTypeAndBranch* typecheck = | 7130 HHasInstanceTypeAndBranch* typecheck = |
| 6385 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | 7131 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
| 6386 typecheck->SetSuccessorAt(0, if_jsarray); | 7132 typecheck->SetSuccessorAt(0, if_jsarray); |
| 6387 typecheck->SetSuccessorAt(1, if_fastobject); | 7133 typecheck->SetSuccessorAt(1, if_fastobject); |
| 6388 current_block()->Finish(typecheck); | 7134 current_block()->Finish(typecheck); |
| 6389 | 7135 |
| 6390 set_current_block(if_jsarray); | 7136 set_current_block(if_jsarray); |
| 6391 HInstruction* length; | 7137 HInstruction* length; |
| 6392 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, | 7138 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, |
| 6393 HType::Smi())); | 7139 HType::Smi())); |
| 6394 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 7140 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6395 ALLOW_SMI_KEY)); | 7141 ALLOW_SMI_KEY)); |
| 6396 access = AddInstruction(BuildFastElementAccess( | 7142 access = AddInstruction(BuildFastElementAccess( |
| 6397 elements, checked_key, val, elements_kind_branch, | 7143 elements, checked_key, val, elements_kind_branch, |
| 6398 elements_kind, is_store)); | 7144 elements_kind, is_store, use_groups && bookmarks.length() > 0)); |
| 6399 if (!is_store) { | 7145 if (!is_store) { |
| 6400 Push(access); | 7146 Push(access); |
| 6401 } | 7147 } |
| 6402 | 7148 |
| 7149 if (use_groups && bookmarks.length() > 0) { | |
| 7150 ASSERT(access->IsLoadKeyed() || access->IsStoreKeyed()); | |
| 7151 MarkedTransitionElementsGroup* group = new(zone()) | |
| 7152 MarkedTransitionElementsGroup(access, checknonsmi, | |
| 7153 checkmaps, zone()); | |
| 7154 group->AddBookmarks(bookmarks); | |
| 7155 graph()->AddMarkedTransitionElementsGroup(group); | |
| 7156 } | |
| 7157 | |
| 6403 *has_side_effects |= access->HasObservableSideEffects(); | 7158 *has_side_effects |= access->HasObservableSideEffects(); |
| 6404 if (position != -1) { | 7159 if (position != -1) { |
| 6405 access->set_position(position); | 7160 access->set_position(position); |
| 6406 } | 7161 } |
| 6407 if_jsarray->Goto(join); | 7162 if_jsarray->Goto(join); |
| 6408 | 7163 |
| 6409 set_current_block(if_fastobject); | 7164 set_current_block(if_fastobject); |
| 6410 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 7165 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 6411 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 7166 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6412 ALLOW_SMI_KEY)); | 7167 ALLOW_SMI_KEY)); |
| 6413 access = AddInstruction(BuildFastElementAccess( | 7168 access = AddInstruction(BuildFastElementAccess( |
| 6414 elements, checked_key, val, elements_kind_branch, | 7169 elements, checked_key, val, elements_kind_branch, |
| 6415 elements_kind, is_store)); | 7170 elements_kind, is_store, use_groups && bookmarks.length() > 0)); |
| 7171 | |
| 7172 if (use_groups && bookmarks.length() > 0) { | |
| 7173 ASSERT(access->IsLoadKeyed() || access->IsStoreKeyed()); | |
| 7174 MarkedTransitionElementsGroup* group = new(zone()) | |
| 7175 MarkedTransitionElementsGroup(access, checknonsmi, | |
| 7176 checkmaps, zone()); | |
| 7177 group->AddBookmarks(bookmarks); | |
| 7178 graph()->AddMarkedTransitionElementsGroup(group); | |
| 7179 } | |
| 6416 } else if (elements_kind == DICTIONARY_ELEMENTS) { | 7180 } else if (elements_kind == DICTIONARY_ELEMENTS) { |
| 6417 if (is_store) { | 7181 if (is_store) { |
| 6418 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | 7182 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
| 6419 } else { | 7183 } else { |
| 6420 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | 7184 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 6421 } | 7185 } |
| 6422 } else { // External array elements. | 7186 } else { // External array elements. |
| 6423 access = AddInstruction(BuildExternalArrayElementAccess( | 7187 access = AddInstruction(BuildExternalArrayElementAccess( |
| 6424 external_elements, checked_key, val, elements_kind_branch, | 7188 external_elements, checked_key, val, elements_kind_branch, |
| 6425 elements_kind, is_store)); | 7189 elements_kind, is_store)); |
| 6426 } | 7190 } |
| 6427 *has_side_effects |= access->HasObservableSideEffects(); | 7191 *has_side_effects |= access->HasObservableSideEffects(); |
| 6428 if (position != RelocInfo::kNoPosition) access->set_position(position); | 7192 if (position != RelocInfo::kNoPosition) access->set_position(position); |
| 6429 if (!is_store) { | 7193 if (!is_store) { |
| 6430 Push(access); | 7194 Push(access); |
| 6431 } | 7195 } |
| 7196 | |
| 6432 current_block()->Goto(join); | 7197 current_block()->Goto(join); |
| 6433 set_current_block(if_false); | 7198 set_current_block(if_false); |
| 6434 } | 7199 } |
| 6435 } | 7200 } |
| 6436 | 7201 |
| 6437 // Deopt if none of the cases matched. | 7202 // Deopt if none of the cases matched. |
| 6438 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 7203 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
| 6439 join->SetJoinId(ast_id); | 7204 join->SetJoinId(ast_id); |
| 6440 set_current_block(join); | 7205 set_current_block(join); |
| 6441 return is_store ? NULL : Pop(); | 7206 return is_store ? NULL : Pop(); |
| (...skipping 3273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9715 | 10480 |
| 9716 | 10481 |
| 9717 void HEnvironment::PrintToStd() { | 10482 void HEnvironment::PrintToStd() { |
| 9718 HeapStringAllocator string_allocator; | 10483 HeapStringAllocator string_allocator; |
| 9719 StringStream trace(&string_allocator); | 10484 StringStream trace(&string_allocator); |
| 9720 PrintTo(&trace); | 10485 PrintTo(&trace); |
| 9721 PrintF("%s", *trace.ToCString()); | 10486 PrintF("%s", *trace.ToCString()); |
| 9722 } | 10487 } |
| 9723 | 10488 |
| 9724 | 10489 |
| 10490 TransitionElementsBookmark::TransitionElementsBookmark( | |
| 10491 HTransitionElementsKind* transition, | |
| 10492 Handle<Map> map_from, Handle<Map> map_to, Isolate* isolate) | |
| 10493 : transition_(transition), | |
| 10494 from_(map_from), | |
| 10495 to_(map_to), | |
| 10496 pessimistic_holey_() { | |
| 10497 | |
| 10498 // When transition records are created, we have the chance to create map | |
| 10499 // transitions we might need later. Transitions are unified during | |
| 10500 // optimization, and we may need to transition from a packed fastmap to a | |
| 10501 // holey version of same. But we can't create those transitions during | |
| 10502 // optimization. Do it now, recognizing that when the handle disappears these | |
| 10503 // maps may be collected if they didn't make it into usage in the optimized | |
| 10504 // graph. | |
| 10505 | |
| 10506 // TODO(mvstanton): generalize this service into | |
| 10507 // "MakeWorstCaseMapForElementsKindTransition" (ie, not "holey") | |
| 10508 if (IsFastPackedElementsKind(map_to->elements_kind())) { | |
| 10509 ElementsKind holey_kind = GetHoleyElementsKind(map_to->elements_kind()); | |
| 10510 // The transition might already exist | |
| 10511 Handle<Map> holey_map_handle(FindClosestElementsTransition(*map_to, | |
| 10512 holey_kind)); | |
| 10513 ASSERT(!holey_map_handle.is_null()); | |
| 10514 if (holey_map_handle->elements_kind() != holey_kind) { | |
| 10515 MaybeObject* holey_map = map_to->AddMissingElementsTransitions( | |
| 10516 holey_kind); | |
| 10517 holey_map->ToHandle<Map>(&pessimistic_holey_, isolate); | |
| 10518 } else { | |
| 10519 pessimistic_holey_ = holey_map_handle; | |
| 10520 } | |
| 10521 } else { | |
| 10522 pessimistic_holey_ = map_to; | |
| 10523 } | |
| 10524 | |
| 10525 ASSERT(!pessimistic_holey_.is_null()); | |
| 10526 | |
| 10527 // fill in map_family_ | |
| 10528 // Walk up to the base map from the map_to(); | |
| 10529 Handle<Map> end_map(FindClosestElementsTransition(*map_to, | |
| 10530 TERMINAL_FAST_ELEMENTS_KIND)); | |
| 10531 ASSERT(!end_map.is_null()); | |
| 10532 family_ = end_map; | |
| 10533 } | |
| 10534 | |
| 10535 | |
| 10536 void MarkedTransitionElementsGroup::AddBookmarks( | |
| 10537 const ZoneList<TransitionElementsBookmark>& records) { | |
| 10538 ASSERT(records.length() > 0); | |
| 10539 Map* first_to_map = *(records[0].to().location()); | |
| 10540 | |
| 10541 // Doesn't check for duplicates. | |
| 10542 // The "to" map values should be the same for the whole group | |
| 10543 for (int i = 0; i < records.length(); i++) { | |
| 10544 bookmarks_->Add(records[i], zone_); | |
| 10545 ASSERT(first_to_map == *(records[i].to().location())); | |
| 10546 } | |
| 10547 | |
| 10548 set_most_general_map(first_to_map); | |
| 10549 } | |
| 10550 | |
| 10551 | |
| 10552 void MarkedTransitionElementsGroup::ComputeTransitionInputValues( | |
| 10553 int maximumGraphValueID) { | |
| 10554 HValue* elements = NULL; | |
| 10555 | |
| 10556 HInstruction* instruction = load_or_store(); | |
| 10557 if (instruction->IsStoreKeyed()) { | |
| 10558 elements = HStoreKeyed::cast(instruction)->elements(); | |
|
danno
2012/11/28 14:42:10
Can you add elements to ArrayInterface?
| |
| 10559 } else { | |
| 10560 CHECK(instruction->IsLoadKeyed()); | |
| 10561 elements = HLoadKeyed::cast(instruction)->elements(); | |
| 10562 } | |
| 10563 | |
| 10564 ASSERT(elements != NULL); | |
| 10565 // Now get the item from the elements | |
| 10566 ASSERT(elements->IsLoadElements()); | |
| 10567 HLoadElements *start = HLoadElements::cast(elements); | |
| 10568 | |
| 10569 ASSERT(transition_inputs_->length() == 0); | |
| 10570 BitVector visited(maximumGraphValueID, zone()); | |
|
danno
2012/11/28 14:42:10
maximum_graph_value_id
| |
| 10571 | |
| 10572 ZoneList<HValue*> worklist(10, zone()); | |
| 10573 worklist.Add(start->value(), zone()); | |
| 10574 | |
| 10575 while (!worklist.is_empty()) { | |
| 10576 HValue* value = worklist.RemoveLast(); | |
| 10577 // Have we visited this node? | |
| 10578 if (!visited.Contains(value->id())) { | |
| 10579 visited.Add(value->id()); | |
| 10580 if (value->IsPhi()) { | |
| 10581 HPhi *phi = HPhi::cast(value); | |
| 10582 for (int i = 0; i < phi->OperandCount(); i++) { | |
| 10583 worklist.Add(phi->OperandAt(i), zone()); | |
| 10584 } | |
| 10585 } else { | |
| 10586 // It must be a transition input value. | |
| 10587 ASSERT(value->IsInstruction()); | |
| 10588 transition_inputs_->Add(HInstruction::cast(value), zone()); | |
| 10589 } | |
| 10590 } | |
| 10591 } | |
| 10592 | |
| 10593 // We must have found something. | |
| 10594 ASSERT(transition_inputs_->length() > 0); | |
| 10595 } | |
| 10596 | |
| 10597 | |
| 10598 void MarkedTransitionElementsGroup::PrintTo(StringStream* stream) const { | |
| 10599 HInstruction* instruction = load_or_store(); | |
| 10600 stream->Add("SITE: block%d %d: ", instruction->block()->block_id(), | |
| 10601 instruction->id()); | |
| 10602 instruction->PrintTo(stream); | |
| 10603 stream->Add("\n"); | |
| 10604 | |
| 10605 // Print validness | |
| 10606 stream->Add(" HOISTABLE: %s\n", hoistable() ? "true" : "false"); | |
| 10607 | |
| 10608 // Print score | |
| 10609 stream->Add(" SCORE: (+%d,%d,-%d)\n", score_[0], score_[1], score_[2]); | |
| 10610 | |
| 10611 // Find the def point for the instruction | |
| 10612 HValue *elements = NULL; | |
| 10613 if (instruction->IsStoreKeyed()) { | |
| 10614 elements = HStoreKeyed::cast(instruction)->elements(); | |
| 10615 } else { | |
| 10616 ASSERT(instruction->IsLoadKeyed()); | |
| 10617 elements = HLoadKeyed::cast(instruction)->elements(); | |
| 10618 } | |
| 10619 | |
| 10620 ASSERT(elements != NULL); | |
| 10621 // Now get the item from the elements | |
| 10622 ASSERT(elements->IsLoadElements()); | |
| 10623 HValue *elements_value = HLoadElements::cast(elements)->value(); | |
| 10624 stream->Add(" OBJECT: "); | |
| 10625 elements_value->PrintNameTo(stream); | |
| 10626 stream->Add(" "); | |
| 10627 elements_value->PrintTo(stream); | |
| 10628 stream->Add(" %s\n", elements_value->IsPhi() ? "PHI" : ""); | |
| 10629 stream->Add(" TRANSITIONS:\n"); | |
| 10630 ElementsKind transitionElementsKind = FAST_SMI_ELEMENTS; | |
| 10631 for (int i = 0; i < bookmarks(); i++) { | |
| 10632 const TransitionElementsBookmark& b = bookmark(i); | |
| 10633 stream->Add(" %s", ElementsKindToString(b.elementskind_from())); | |
| 10634 stream->Add("(0x%p)-> ", *(b.from())); | |
| 10635 transitionElementsKind = b.elementskind_to(); | |
| 10636 stream->Add("%s", ElementsKindToString(transitionElementsKind)); | |
| 10637 stream->Add("(0x%p)\n", *(b.to())); | |
| 10638 } | |
| 10639 | |
| 10640 // Print possibly externally computed map | |
| 10641 const char *signifier = (transitionElementsKind != | |
| 10642 most_general_map()->elements_kind()) | |
| 10643 ? "*" : ""; | |
| 10644 stream->Add(" COMPUTED MOST GENERAL MAP: %s%s(0x%p)\n", signifier, | |
| 10645 ElementsKindToString(most_general_map()->elements_kind()), | |
| 10646 most_general_map()); | |
| 10647 | |
| 10648 // Print terminal nodes if available | |
| 10649 stream->Add(" TRANSITION INPUT VALUES:\n"); | |
| 10650 for (int j = 0; j < transition_inputs(); j++) { | |
| 10651 HValue* node = transition_input(j); | |
| 10652 stream->Add(" block%d %d: ", node->block()->block_id(), node->id()); | |
| 10653 node->PrintNameTo(stream); | |
| 10654 stream->Add(" "); | |
| 10655 node->PrintTo(stream); | |
| 10656 stream->Add("\n"); | |
| 10657 } | |
| 10658 } | |
| 10659 | |
| 10660 | |
| 10661 void MarkedTransitionElementsGroup::PrintToStd() const { | |
| 10662 HeapStringAllocator string_allocator; | |
| 10663 StringStream trace(&string_allocator); | |
| 10664 PrintTo(&trace); | |
| 10665 PrintF("%s", *trace.ToCString()); | |
| 10666 } | |
| 10667 | |
| 10668 | |
| 9725 void HTracer::TraceCompilation(FunctionLiteral* function) { | 10669 void HTracer::TraceCompilation(FunctionLiteral* function) { |
| 9726 Tag tag(this, "compilation"); | 10670 Tag tag(this, "compilation"); |
| 9727 Handle<String> name = function->debug_name(); | 10671 Handle<String> name = function->debug_name(); |
| 9728 PrintStringProperty("name", *name->ToCString()); | 10672 PrintStringProperty("name", *name->ToCString()); |
| 9729 PrintStringProperty("method", *name->ToCString()); | 10673 PrintStringProperty("method", *name->ToCString()); |
| 9730 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); | 10674 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); |
| 9731 } | 10675 } |
| 9732 | 10676 |
| 9733 | 10677 |
| 9734 void HTracer::TraceLithium(const char* name, LChunk* chunk) { | 10678 void HTracer::TraceLithium(const char* name, LChunk* chunk) { |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10035 } | 10979 } |
| 10036 } | 10980 } |
| 10037 | 10981 |
| 10038 #ifdef DEBUG | 10982 #ifdef DEBUG |
| 10039 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10983 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 10040 if (allocator_ != NULL) allocator_->Verify(); | 10984 if (allocator_ != NULL) allocator_->Verify(); |
| 10041 #endif | 10985 #endif |
| 10042 } | 10986 } |
| 10043 | 10987 |
| 10044 } } // namespace v8::internal | 10988 } } // namespace v8::internal |
| OLD | NEW |