| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 } | 551 } |
| 552 | 552 |
| 553 | 553 |
| 554 void HBasicBlock::FinishExit(HControlInstruction* instruction) { | 554 void HBasicBlock::FinishExit(HControlInstruction* instruction) { |
| 555 Finish(instruction); | 555 Finish(instruction); |
| 556 ClearEnvironment(); | 556 ClearEnvironment(); |
| 557 } | 557 } |
| 558 | 558 |
| 559 | 559 |
| 560 HGraph::HGraph(CompilationInfo* info) | 560 HGraph::HGraph(CompilationInfo* info) |
| 561 : HSubgraph(this), | 561 : next_block_id_(0), |
| 562 next_block_id_(0), | 562 entry_block_(NULL), |
| 563 blocks_(8), | 563 blocks_(8), |
| 564 values_(16), | 564 values_(16), |
| 565 phi_list_(NULL) { | 565 phi_list_(NULL) { |
| 566 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); | 566 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); |
| 567 start_environment_->set_ast_id(info->function()->id()); | 567 start_environment_->set_ast_id(info->function()->id()); |
| 568 entry_block_ = CreateBasicBlock(); |
| 569 entry_block_->SetInitialEnvironment(start_environment_); |
| 568 } | 570 } |
| 569 | 571 |
| 570 | 572 |
| 571 Handle<Code> HGraph::Compile(CompilationInfo* info) { | 573 Handle<Code> HGraph::Compile(CompilationInfo* info) { |
| 572 int values = GetMaximumValueID(); | 574 int values = GetMaximumValueID(); |
| 573 if (values > LAllocator::max_initial_value_ids()) { | 575 if (values > LAllocator::max_initial_value_ids()) { |
| 574 if (FLAG_trace_bailout) PrintF("Function is too big\n"); | 576 if (FLAG_trace_bailout) PrintF("Function is too big\n"); |
| 575 return Handle<Code>::null(); | 577 return Handle<Code>::null(); |
| 576 } | 578 } |
| 577 | 579 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 | 634 |
| 633 | 635 |
| 634 void HGraph::OrderBlocks() { | 636 void HGraph::OrderBlocks() { |
| 635 HPhase phase("Block ordering"); | 637 HPhase phase("Block ordering"); |
| 636 BitVector visited(blocks_.length()); | 638 BitVector visited(blocks_.length()); |
| 637 | 639 |
| 638 ZoneList<HBasicBlock*> reverse_result(8); | 640 ZoneList<HBasicBlock*> reverse_result(8); |
| 639 HBasicBlock* start = blocks_[0]; | 641 HBasicBlock* start = blocks_[0]; |
| 640 Postorder(start, &visited, &reverse_result, NULL); | 642 Postorder(start, &visited, &reverse_result, NULL); |
| 641 | 643 |
| 642 blocks_.Clear(); | 644 blocks_.Rewind(0); |
| 643 int index = 0; | 645 int index = 0; |
| 644 for (int i = reverse_result.length() - 1; i >= 0; --i) { | 646 for (int i = reverse_result.length() - 1; i >= 0; --i) { |
| 645 HBasicBlock* b = reverse_result[i]; | 647 HBasicBlock* b = reverse_result[i]; |
| 646 blocks_.Add(b); | 648 blocks_.Add(b); |
| 647 b->set_block_id(index++); | 649 b->set_block_id(index++); |
| 648 } | 650 } |
| 649 } | 651 } |
| 650 | 652 |
| 651 | 653 |
| 652 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, | 654 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 // because in case of throwing an error we need this value to | 751 // because in case of throwing an error we need this value to |
| 750 // construct a stack trace. | 752 // construct a stack trace. |
| 751 block->RemovePhi(phi); | 753 block->RemovePhi(phi); |
| 752 block->RecordDeletedPhi(phi->merged_index()); | 754 block->RecordDeletedPhi(phi->merged_index()); |
| 753 } | 755 } |
| 754 } | 756 } |
| 755 } | 757 } |
| 756 | 758 |
| 757 | 759 |
| 758 bool HGraph::CollectPhis() { | 760 bool HGraph::CollectPhis() { |
| 759 const ZoneList<HBasicBlock*>* blocks = graph_->blocks(); | 761 int block_count = blocks_.length(); |
| 760 phi_list_ = new ZoneList<HPhi*>(blocks->length()); | 762 phi_list_ = new ZoneList<HPhi*>(block_count); |
| 761 for (int i = 0; i < blocks->length(); ++i) { | 763 for (int i = 0; i < block_count; ++i) { |
| 762 for (int j = 0; j < blocks->at(i)->phis()->length(); j++) { | 764 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 763 HPhi* phi = blocks->at(i)->phis()->at(j); | 765 HPhi* phi = blocks_[i]->phis()->at(j); |
| 764 phi_list_->Add(phi); | 766 phi_list_->Add(phi); |
| 765 // We don't support phi uses of arguments for now. | 767 // We don't support phi uses of arguments for now. |
| 766 if (phi->CheckFlag(HValue::kIsArguments)) return false; | 768 if (phi->CheckFlag(HValue::kIsArguments)) return false; |
| 767 } | 769 } |
| 768 } | 770 } |
| 769 return true; | 771 return true; |
| 770 } | 772 } |
| 771 | 773 |
| 772 | 774 |
| 773 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { | 775 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { |
| (...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1739 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32); | 1741 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32); |
| 1740 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32); | 1742 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32); |
| 1741 if (a_truncate != b_truncate) { | 1743 if (a_truncate != b_truncate) { |
| 1742 return a_truncate ? -1 : 1; | 1744 return a_truncate ? -1 : 1; |
| 1743 } | 1745 } |
| 1744 // Sort by increasing block ID. | 1746 // Sort by increasing block ID. |
| 1745 return a->block()->block_id() - b->block()->block_id(); | 1747 return a->block()->block_id() - b->block()->block_id(); |
| 1746 } | 1748 } |
| 1747 | 1749 |
| 1748 | 1750 |
| 1749 void HGraph::InsertRepresentationChanges(HValue* current) { | 1751 void HGraph::InsertRepresentationChangesForValue( |
| 1752 HValue* current, |
| 1753 ZoneList<HValue*>* to_convert, |
| 1754 ZoneList<Representation>* to_convert_reps) { |
| 1750 Representation r = current->representation(); | 1755 Representation r = current->representation(); |
| 1751 if (r.IsNone()) return; | 1756 if (r.IsNone()) return; |
| 1752 if (current->uses()->length() == 0) return; | 1757 if (current->uses()->length() == 0) return; |
| 1753 | 1758 |
| 1754 // Collect the representation changes in a sorted list. This allows | 1759 // Collect the representation changes in a sorted list. This allows |
| 1755 // us to avoid duplicate changes without searching the list. | 1760 // us to avoid duplicate changes without searching the list. |
| 1756 ZoneList<HValue*> to_convert(2); | 1761 ASSERT(to_convert->is_empty()); |
| 1757 ZoneList<Representation> to_convert_reps(2); | 1762 ASSERT(to_convert_reps->is_empty()); |
| 1758 for (int i = 0; i < current->uses()->length(); ++i) { | 1763 for (int i = 0; i < current->uses()->length(); ++i) { |
| 1759 HValue* use = current->uses()->at(i); | 1764 HValue* use = current->uses()->at(i); |
| 1760 // The occurrences index means the index within the operand array of "use" | 1765 // The occurrences index means the index within the operand array of "use" |
| 1761 // at which "current" is used. While iterating through the use array we | 1766 // at which "current" is used. While iterating through the use array we |
| 1762 // also have to iterate over the different occurrence indices. | 1767 // also have to iterate over the different occurrence indices. |
| 1763 int occurrence_index = 0; | 1768 int occurrence_index = 0; |
| 1764 if (use->UsesMultipleTimes(current)) { | 1769 if (use->UsesMultipleTimes(current)) { |
| 1765 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1); | 1770 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1); |
| 1766 if (FLAG_trace_representation) { | 1771 if (FLAG_trace_representation) { |
| 1767 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n", | 1772 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n", |
| 1768 current->id(), | 1773 current->id(), |
| 1769 use->id(), | 1774 use->id(), |
| 1770 occurrence_index); | 1775 occurrence_index); |
| 1771 } | 1776 } |
| 1772 } | 1777 } |
| 1773 int operand_index = use->LookupOperandIndex(occurrence_index, current); | 1778 int operand_index = use->LookupOperandIndex(occurrence_index, current); |
| 1774 Representation req = use->RequiredInputRepresentation(operand_index); | 1779 Representation req = use->RequiredInputRepresentation(operand_index); |
| 1775 if (req.IsNone() || req.Equals(r)) continue; | 1780 if (req.IsNone() || req.Equals(r)) continue; |
| 1776 int index = 0; | 1781 int index = 0; |
| 1777 while (to_convert.length() > index && | 1782 while (index < to_convert->length() && |
| 1778 CompareConversionUses(to_convert[index], | 1783 CompareConversionUses(to_convert->at(index), |
| 1779 use, | 1784 use, |
| 1780 to_convert_reps[index], | 1785 to_convert_reps->at(index), |
| 1781 req) < 0) { | 1786 req) < 0) { |
| 1782 ++index; | 1787 ++index; |
| 1783 } | 1788 } |
| 1784 if (FLAG_trace_representation) { | 1789 if (FLAG_trace_representation) { |
| 1785 PrintF("Inserting a representation change to %s of %d for use at %d\n", | 1790 PrintF("Inserting a representation change to %s of %d for use at %d\n", |
| 1786 req.Mnemonic(), | 1791 req.Mnemonic(), |
| 1787 current->id(), | 1792 current->id(), |
| 1788 use->id()); | 1793 use->id()); |
| 1789 } | 1794 } |
| 1790 to_convert.InsertAt(index, use); | 1795 to_convert->InsertAt(index, use); |
| 1791 to_convert_reps.InsertAt(index, req); | 1796 to_convert_reps->InsertAt(index, req); |
| 1792 } | 1797 } |
| 1793 | 1798 |
| 1794 for (int i = 0; i < to_convert.length(); ++i) { | 1799 for (int i = 0; i < to_convert->length(); ++i) { |
| 1795 HValue* use = to_convert[i]; | 1800 HValue* use = to_convert->at(i); |
| 1796 Representation r_to = to_convert_reps[i]; | 1801 Representation r_to = to_convert_reps->at(i); |
| 1797 InsertRepresentationChangeForUse(current, use, r_to); | 1802 InsertRepresentationChangeForUse(current, use, r_to); |
| 1798 } | 1803 } |
| 1799 | 1804 |
| 1800 if (current->uses()->is_empty()) { | 1805 if (current->uses()->is_empty()) { |
| 1801 ASSERT(current->IsConstant()); | 1806 ASSERT(current->IsConstant()); |
| 1802 current->Delete(); | 1807 current->Delete(); |
| 1803 } | 1808 } |
| 1809 to_convert->Rewind(0); |
| 1810 to_convert_reps->Rewind(0); |
| 1804 } | 1811 } |
| 1805 | 1812 |
| 1806 | 1813 |
| 1807 void HGraph::InsertRepresentationChanges() { | 1814 void HGraph::InsertRepresentationChanges() { |
| 1808 HPhase phase("Insert representation changes", this); | 1815 HPhase phase("Insert representation changes", this); |
| 1809 | 1816 |
| 1810 | 1817 |
| 1811 // Compute truncation flag for phis: Initially assume that all | 1818 // Compute truncation flag for phis: Initially assume that all |
| 1812 // int32-phis allow truncation and iteratively remove the ones that | 1819 // int32-phis allow truncation and iteratively remove the ones that |
| 1813 // are used in an operation that does not allow a truncating | 1820 // are used in an operation that does not allow a truncating |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1829 HValue* use = phi->uses()->at(j); | 1836 HValue* use = phi->uses()->at(j); |
| 1830 if (!use->CheckFlag(HValue::kTruncatingToInt32)) { | 1837 if (!use->CheckFlag(HValue::kTruncatingToInt32)) { |
| 1831 phi->ClearFlag(HValue::kTruncatingToInt32); | 1838 phi->ClearFlag(HValue::kTruncatingToInt32); |
| 1832 change = true; | 1839 change = true; |
| 1833 break; | 1840 break; |
| 1834 } | 1841 } |
| 1835 } | 1842 } |
| 1836 } | 1843 } |
| 1837 } | 1844 } |
| 1838 | 1845 |
| 1846 ZoneList<HValue*> value_list(4); |
| 1847 ZoneList<Representation> rep_list(4); |
| 1839 for (int i = 0; i < blocks_.length(); ++i) { | 1848 for (int i = 0; i < blocks_.length(); ++i) { |
| 1840 // Process phi instructions first. | 1849 // Process phi instructions first. |
| 1841 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { | 1850 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { |
| 1842 HPhi* phi = blocks_[i]->phis()->at(j); | 1851 HPhi* phi = blocks_[i]->phis()->at(j); |
| 1843 InsertRepresentationChanges(phi); | 1852 InsertRepresentationChangesForValue(phi, &value_list, &rep_list); |
| 1844 } | 1853 } |
| 1845 | 1854 |
| 1846 // Process normal instructions. | 1855 // Process normal instructions. |
| 1847 HInstruction* current = blocks_[i]->first(); | 1856 HInstruction* current = blocks_[i]->first(); |
| 1848 while (current != NULL) { | 1857 while (current != NULL) { |
| 1849 InsertRepresentationChanges(current); | 1858 InsertRepresentationChangesForValue(current, &value_list, &rep_list); |
| 1850 current = current->next(); | 1859 current = current->next(); |
| 1851 } | 1860 } |
| 1852 } | 1861 } |
| 1853 } | 1862 } |
| 1854 | 1863 |
| 1855 | 1864 |
| 1856 void HGraph::ComputeMinusZeroChecks() { | 1865 void HGraph::ComputeMinusZeroChecks() { |
| 1857 BitVector visited(GetMaximumValueID()); | 1866 BitVector visited(GetMaximumValueID()); |
| 1858 for (int i = 0; i < blocks_.length(); ++i) { | 1867 for (int i = 0; i < blocks_.length(); ++i) { |
| 1859 for (HInstruction* current = blocks_[i]->first(); | 1868 for (HInstruction* current = blocks_[i]->first(); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2037 } while (false) | 2046 } while (false) |
| 2038 | 2047 |
| 2039 | 2048 |
| 2040 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \ | 2049 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \ |
| 2041 do { \ | 2050 do { \ |
| 2042 VisitForControl(expr, true_block, false_block); \ | 2051 VisitForControl(expr, true_block, false_block); \ |
| 2043 if (HasStackOverflow()) return; \ | 2052 if (HasStackOverflow()) return; \ |
| 2044 } while (false) | 2053 } while (false) |
| 2045 | 2054 |
| 2046 | 2055 |
| 2047 // 'thing' could be an expression, statement, or list of statements. | |
| 2048 #define ADD_TO_SUBGRAPH(graph, thing) \ | |
| 2049 do { \ | |
| 2050 AddToSubgraph(graph, thing); \ | |
| 2051 if (HasStackOverflow()) return; \ | |
| 2052 } while (false) | |
| 2053 | |
| 2054 | |
| 2055 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { | |
| 2056 public: | |
| 2057 SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph) | |
| 2058 : builder_(builder) { | |
| 2059 old_subgraph_ = builder_->current_subgraph_; | |
| 2060 subgraph_ = new_subgraph; | |
| 2061 builder_->current_subgraph_ = subgraph_; | |
| 2062 } | |
| 2063 | |
| 2064 ~SubgraphScope() { | |
| 2065 builder_->current_subgraph_ = old_subgraph_; | |
| 2066 } | |
| 2067 | |
| 2068 HSubgraph* subgraph() const { return subgraph_; } | |
| 2069 | |
| 2070 private: | |
| 2071 HGraphBuilder* builder_; | |
| 2072 HSubgraph* old_subgraph_; | |
| 2073 HSubgraph* subgraph_; | |
| 2074 }; | |
| 2075 | |
| 2076 | |
| 2077 void HGraphBuilder::Bailout(const char* reason) { | 2056 void HGraphBuilder::Bailout(const char* reason) { |
| 2078 if (FLAG_trace_bailout) { | 2057 if (FLAG_trace_bailout) { |
| 2079 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); | 2058 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 2080 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason); | 2059 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason); |
| 2081 } | 2060 } |
| 2082 SetStackOverflow(); | 2061 SetStackOverflow(); |
| 2083 } | 2062 } |
| 2084 | 2063 |
| 2085 | 2064 |
| 2086 void HGraphBuilder::VisitForEffect(Expression* expr) { | 2065 void HGraphBuilder::VisitForEffect(Expression* expr) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2118 | 2097 |
| 2119 | 2098 |
| 2120 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { | 2099 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { |
| 2121 for (int i = 0; i < exprs->length(); ++i) { | 2100 for (int i = 0; i < exprs->length(); ++i) { |
| 2122 VISIT_FOR_VALUE(exprs->at(i)); | 2101 VISIT_FOR_VALUE(exprs->at(i)); |
| 2123 } | 2102 } |
| 2124 } | 2103 } |
| 2125 | 2104 |
| 2126 | 2105 |
| 2127 HGraph* HGraphBuilder::CreateGraph() { | 2106 HGraph* HGraphBuilder::CreateGraph() { |
| 2128 ASSERT(subgraph() == NULL); | |
| 2129 graph_ = new HGraph(info()); | 2107 graph_ = new HGraph(info()); |
| 2130 | |
| 2131 { | 2108 { |
| 2132 HPhase phase("Block building"); | 2109 HPhase phase("Block building"); |
| 2133 graph()->Initialize(CreateBasicBlock(graph()->start_environment())); | 2110 current_block_ = graph()->entry_block(); |
| 2134 current_subgraph_ = graph(); | |
| 2135 | 2111 |
| 2136 Scope* scope = info()->scope(); | 2112 Scope* scope = info()->scope(); |
| 2137 if (scope->HasIllegalRedeclaration()) { | 2113 if (scope->HasIllegalRedeclaration()) { |
| 2138 Bailout("function with illegal redeclaration"); | 2114 Bailout("function with illegal redeclaration"); |
| 2139 return NULL; | 2115 return NULL; |
| 2140 } | 2116 } |
| 2141 SetupScope(scope); | 2117 SetupScope(scope); |
| 2142 VisitDeclarations(scope->declarations()); | 2118 VisitDeclarations(scope->declarations()); |
| 2143 AddInstruction(new HStackCheck()); | 2119 AddInstruction(new HStackCheck()); |
| 2144 | 2120 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2201 if (FLAG_use_gvn) { | 2177 if (FLAG_use_gvn) { |
| 2202 HPhase phase("Global value numbering", graph()); | 2178 HPhase phase("Global value numbering", graph()); |
| 2203 HGlobalValueNumberer gvn(graph(), info()); | 2179 HGlobalValueNumberer gvn(graph(), info()); |
| 2204 gvn.Analyze(); | 2180 gvn.Analyze(); |
| 2205 } | 2181 } |
| 2206 | 2182 |
| 2207 return graph(); | 2183 return graph(); |
| 2208 } | 2184 } |
| 2209 | 2185 |
| 2210 | 2186 |
| 2211 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { | |
| 2212 SubgraphScope scope(this, graph); | |
| 2213 Visit(stmt); | |
| 2214 } | |
| 2215 | |
| 2216 | |
| 2217 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { | |
| 2218 SubgraphScope scope(this, graph); | |
| 2219 VisitForValue(expr); | |
| 2220 } | |
| 2221 | |
| 2222 | |
| 2223 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, | |
| 2224 ZoneList<Statement*>* stmts) { | |
| 2225 SubgraphScope scope(this, graph); | |
| 2226 VisitStatements(stmts); | |
| 2227 } | |
| 2228 | |
| 2229 | |
| 2230 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 2187 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 2231 ASSERT(current_block() != NULL); | 2188 ASSERT(current_block() != NULL); |
| 2232 current_block()->AddInstruction(instr); | 2189 current_block()->AddInstruction(instr); |
| 2233 return instr; | 2190 return instr; |
| 2234 } | 2191 } |
| 2235 | 2192 |
| 2236 | 2193 |
| 2237 void HGraphBuilder::AddSimulate(int id) { | 2194 void HGraphBuilder::AddSimulate(int id) { |
| 2238 ASSERT(current_block() != NULL); | 2195 ASSERT(current_block() != NULL); |
| 2239 current_block()->AddSimulate(id); | 2196 current_block()->AddSimulate(id); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2316 } | 2273 } |
| 2317 | 2274 |
| 2318 | 2275 |
| 2319 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 2276 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 2320 HBasicBlock* b = graph()->CreateBasicBlock(); | 2277 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 2321 b->SetInitialEnvironment(env); | 2278 b->SetInitialEnvironment(env); |
| 2322 return b; | 2279 return b; |
| 2323 } | 2280 } |
| 2324 | 2281 |
| 2325 | 2282 |
| 2326 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { | |
| 2327 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2328 subgraph->Initialize(graph()->CreateBasicBlock()); | |
| 2329 return subgraph; | |
| 2330 } | |
| 2331 | |
| 2332 | |
| 2333 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 2283 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 2334 HBasicBlock* header = graph()->CreateBasicBlock(); | 2284 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 2335 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 2285 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 2336 header->SetInitialEnvironment(entry_env); | 2286 header->SetInitialEnvironment(entry_env); |
| 2337 header->AttachLoopInformation(); | 2287 header->AttachLoopInformation(); |
| 2338 return header; | 2288 return header; |
| 2339 } | 2289 } |
| 2340 | 2290 |
| 2341 | 2291 |
| 2342 void HGraphBuilder::VisitBlock(Block* stmt) { | 2292 void HGraphBuilder::VisitBlock(Block* stmt) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2470 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2420 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
| 2471 BAILOUT("WithEnterStatement"); | 2421 BAILOUT("WithEnterStatement"); |
| 2472 } | 2422 } |
| 2473 | 2423 |
| 2474 | 2424 |
| 2475 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 2425 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
| 2476 BAILOUT("WithExitStatement"); | 2426 BAILOUT("WithExitStatement"); |
| 2477 } | 2427 } |
| 2478 | 2428 |
| 2479 | 2429 |
| 2480 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph, | |
| 2481 HValue* switch_value, | |
| 2482 CaseClause* clause) { | |
| 2483 AddToSubgraph(subgraph, clause->label()); | |
| 2484 if (HasStackOverflow()) return NULL; | |
| 2485 HValue* clause_value = subgraph->exit_block()->last_environment()->Pop(); | |
| 2486 HCompare* compare = new HCompare(switch_value, | |
| 2487 clause_value, | |
| 2488 Token::EQ_STRICT); | |
| 2489 compare->SetInputRepresentation(Representation::Integer32()); | |
| 2490 subgraph->exit_block()->AddInstruction(compare); | |
| 2491 return compare; | |
| 2492 } | |
| 2493 | |
| 2494 | |
| 2495 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2430 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2431 // We only optimize switch statements with smi-literal smi comparisons, |
| 2432 // with a bounded number of clauses. |
| 2433 const int kCaseClauseLimit = 128; |
| 2434 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2435 int clause_count = clauses->length(); |
| 2436 if (clause_count > kCaseClauseLimit) { |
| 2437 BAILOUT("SwitchStatement: too many clauses"); |
| 2438 } |
| 2439 |
| 2496 VISIT_FOR_VALUE(stmt->tag()); | 2440 VISIT_FOR_VALUE(stmt->tag()); |
| 2497 // TODO(3168478): simulate added for tag should be enough. | 2441 HValue* tag_value = Pop(); |
| 2498 AddSimulate(stmt->EntryId()); | 2442 HBasicBlock* first_test_block = current_block(); |
| 2499 HValue* switch_value = Pop(); | |
| 2500 | 2443 |
| 2501 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2444 // 1. Build all the tests, with dangling true branches. Unconditionally |
| 2502 int num_clauses = clauses->length(); | 2445 // deoptimize if we encounter a non-smi comparison. |
| 2503 if (num_clauses == 0) return; | 2446 for (int i = 0; i < clause_count; ++i) { |
| 2504 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); | |
| 2505 | |
| 2506 int num_smi_clauses = num_clauses; | |
| 2507 for (int i = 0; i < num_clauses; i++) { | |
| 2508 CaseClause* clause = clauses->at(i); | 2447 CaseClause* clause = clauses->at(i); |
| 2509 if (clause->is_default()) continue; | 2448 if (clause->is_default()) continue; |
| 2510 clause->RecordTypeFeedback(oracle()); | |
| 2511 if (!clause->IsSmiCompare()) { | |
| 2512 if (i == 0) BAILOUT("SwitchStatement: no smi compares"); | |
| 2513 // We will deoptimize if the first non-smi compare is reached. | |
| 2514 num_smi_clauses = i; | |
| 2515 break; | |
| 2516 } | |
| 2517 if (!clause->label()->IsSmiLiteral()) { | 2449 if (!clause->label()->IsSmiLiteral()) { |
| 2518 BAILOUT("SwitchStatement: non-literal switch label"); | 2450 BAILOUT("SwitchStatement: non-literal switch label"); |
| 2519 } | 2451 } |
| 2452 |
| 2453 // Unconditionally deoptimize on the first non-smi compare. |
| 2454 clause->RecordTypeFeedback(oracle()); |
| 2455 if (!clause->IsSmiCompare()) { |
| 2456 if (current_block() == first_test_block) { |
| 2457 // If the first test is the one that deopts and if the tag value is |
| 2458 // a phi, we need to have some use of that phi to prevent phi |
| 2459 // elimination from removing it. This HSimulate is such a use. |
| 2460 Push(tag_value); |
| 2461 AddSimulate(stmt->EntryId()); |
| 2462 Drop(1); |
| 2463 } |
| 2464 current_block()->Finish(new HDeoptimize()); |
| 2465 set_current_block(NULL); |
| 2466 break; |
| 2467 } |
| 2468 |
| 2469 // Otherwise generate a compare and branch. |
| 2470 VISIT_FOR_VALUE(clause->label()); |
| 2471 HValue* label_value = Pop(); |
| 2472 HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT); |
| 2473 compare->SetInputRepresentation(Representation::Integer32()); |
| 2474 ASSERT(!compare->HasSideEffects()); |
| 2475 AddInstruction(compare); |
| 2476 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 2477 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 2478 HTest* branch = new HTest(compare, body_block, next_test_block); |
| 2479 current_block()->Finish(branch); |
| 2480 set_current_block(next_test_block); |
| 2520 } | 2481 } |
| 2521 | 2482 |
| 2522 // The single exit block of the whole switch statement. | 2483 // Save the current block to use for the default or to join with the |
| 2523 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); | 2484 // exit. This block is NULL if we deoptimized. |
| 2485 HBasicBlock* last_block = current_block(); |
| 2524 | 2486 |
| 2525 // Build a series of empty subgraphs for the comparisons. | 2487 // 2. Loop over the clauses and the linked list of tests in lockstep, |
| 2526 // The default clause does not have a comparison subgraph. | 2488 // translating the clause bodies. |
| 2527 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); | 2489 HBasicBlock* curr_test_block = first_test_block; |
| 2528 for (int i = 0; i < num_smi_clauses; i++) { | 2490 HBasicBlock* fall_through_block = NULL; |
| 2529 if (clauses->at(i)->is_default()) { | 2491 BreakAndContinueInfo break_info(stmt); |
| 2530 compare_graphs.Add(NULL); | 2492 { BreakAndContinueScope push(&break_info, this); |
| 2531 } else { | 2493 for (int i = 0; i < clause_count; ++i) { |
| 2532 compare_graphs.Add(CreateEmptySubgraph()); | 2494 CaseClause* clause = clauses->at(i); |
| 2495 |
| 2496 // Identify the block where normal (non-fall-through) control flow |
| 2497 // goes to. |
| 2498 HBasicBlock* normal_block = NULL; |
| 2499 if (clause->is_default() && last_block != NULL) { |
| 2500 normal_block = last_block; |
| 2501 last_block = NULL; // Cleared to indicate we've handled it. |
| 2502 } else if (!curr_test_block->end()->IsDeoptimize()) { |
| 2503 normal_block = curr_test_block->end()->FirstSuccessor(); |
| 2504 curr_test_block = curr_test_block->end()->SecondSuccessor(); |
| 2505 } |
| 2506 |
| 2507 // Identify a block to emit the body into. |
| 2508 if (normal_block == NULL) { |
| 2509 if (fall_through_block == NULL) { |
| 2510 // (a) Unreachable. |
| 2511 if (clause->is_default()) { |
| 2512 continue; // Might still be reachable clause bodies. |
| 2513 } else { |
| 2514 break; |
| 2515 } |
| 2516 } else { |
| 2517 // (b) Reachable only as fall through. |
| 2518 set_current_block(fall_through_block); |
| 2519 } |
| 2520 } else if (fall_through_block == NULL) { |
| 2521 // (c) Reachable only normally. |
| 2522 set_current_block(normal_block); |
| 2523 } else { |
| 2524 // (d) Reachable both ways. |
| 2525 HBasicBlock* join = CreateJoin(fall_through_block, |
| 2526 normal_block, |
| 2527 clause->EntryId()); |
| 2528 set_current_block(join); |
| 2529 } |
| 2530 |
| 2531 VisitStatements(clause->statements()); |
| 2532 CHECK_BAILOUT; |
| 2533 fall_through_block = current_block(); |
| 2533 } | 2534 } |
| 2534 } | 2535 } |
| 2535 | 2536 |
| 2536 HSubgraph* prev_graph = current_subgraph_; | 2537 // Create an up-to-3-way join. Use the break block if it exists since |
| 2537 HCompare* prev_compare_inst = NULL; | 2538 // it's already a join block. |
| 2538 for (int i = 0; i < num_smi_clauses; i++) { | 2539 HBasicBlock* break_block = break_info.break_block(); |
| 2539 CaseClause* clause = clauses->at(i); | 2540 if (break_block == NULL) { |
| 2540 if (clause->is_default()) continue; | 2541 set_current_block(CreateJoin(fall_through_block, |
| 2541 | 2542 last_block, |
| 2542 // Finish the previous graph by connecting it to the current. | 2543 stmt->ExitId())); |
| 2543 HSubgraph* subgraph = compare_graphs.at(i); | |
| 2544 if (prev_compare_inst == NULL) { | |
| 2545 ASSERT(prev_graph == current_subgraph_); | |
| 2546 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | |
| 2547 } else { | |
| 2548 HBasicBlock* empty = graph()->CreateBasicBlock(); | |
| 2549 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | |
| 2550 empty, | |
| 2551 subgraph->entry_block())); | |
| 2552 } | |
| 2553 | |
| 2554 // Build instructions for current subgraph. | |
| 2555 ASSERT(clause->IsSmiCompare()); | |
| 2556 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | |
| 2557 if (HasStackOverflow()) return; | |
| 2558 | |
| 2559 prev_graph = subgraph; | |
| 2560 } | |
| 2561 | |
| 2562 // Finish last comparison if there was at least one comparison. | |
| 2563 // last_false_block is the (empty) false-block of the last comparison. If | |
| 2564 // there are no comparisons at all (a single default clause), it is just | |
| 2565 // the last block of the current subgraph. | |
| 2566 HBasicBlock* last_false_block = current_block(); | |
| 2567 if (prev_graph != current_subgraph_) { | |
| 2568 last_false_block = graph()->CreateBasicBlock(); | |
| 2569 HBasicBlock* empty = graph()->CreateBasicBlock(); | |
| 2570 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | |
| 2571 empty, | |
| 2572 last_false_block)); | |
| 2573 } | |
| 2574 | |
| 2575 // If we have a non-smi compare clause, we deoptimize after trying | |
| 2576 // all the previous compares. | |
| 2577 if (num_smi_clauses < num_clauses) { | |
| 2578 last_false_block->Finish(new HDeoptimize); | |
| 2579 } | |
| 2580 | |
| 2581 // Build statement blocks, connect them to their comparison block and | |
| 2582 // to the previous statement block, if there is a fall-through. | |
| 2583 HSubgraph* previous_subgraph = NULL; | |
| 2584 for (int i = 0; i < num_clauses; i++) { | |
| 2585 CaseClause* clause = clauses->at(i); | |
| 2586 // Subgraph for the statements of the clause is only created when | |
| 2587 // it's reachable either from the corresponding compare or as a | |
| 2588 // fall-through from previous statements. | |
| 2589 HSubgraph* subgraph = NULL; | |
| 2590 | |
| 2591 if (i < num_smi_clauses) { | |
| 2592 if (clause->is_default()) { | |
| 2593 if (!last_false_block->IsFinished()) { | |
| 2594 // Default clause: Connect it to the last false block. | |
| 2595 subgraph = CreateEmptySubgraph(); | |
| 2596 last_false_block->Finish(new HGoto(subgraph->entry_block())); | |
| 2597 } | |
| 2598 } else { | |
| 2599 ASSERT(clause->IsSmiCompare()); | |
| 2600 // Connect with the corresponding comparison. | |
| 2601 subgraph = CreateEmptySubgraph(); | |
| 2602 HBasicBlock* empty = | |
| 2603 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | |
| 2604 empty->Finish(new HGoto(subgraph->entry_block())); | |
| 2605 } | |
| 2606 } | |
| 2607 | |
| 2608 // Check for fall-through from previous statement block. | |
| 2609 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) { | |
| 2610 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); | |
| 2611 previous_subgraph->exit_block()-> | |
| 2612 Finish(new HGoto(subgraph->entry_block())); | |
| 2613 } | |
| 2614 | |
| 2615 if (subgraph != NULL) { | |
| 2616 BreakAndContinueInfo break_info(stmt); | |
| 2617 { BreakAndContinueScope push(&break_info, this); | |
| 2618 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | |
| 2619 } | |
| 2620 if (break_info.break_block() != NULL) { | |
| 2621 break_info.break_block()->SetJoinId(stmt->ExitId()); | |
| 2622 break_info.break_block()->Finish(new HGoto(single_exit_block)); | |
| 2623 } | |
| 2624 } | |
| 2625 | |
| 2626 previous_subgraph = subgraph; | |
| 2627 } | |
| 2628 | |
| 2629 // If the last statement block has a fall-through, connect it to the | |
| 2630 // single exit block. | |
| 2631 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) { | |
| 2632 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | |
| 2633 } | |
| 2634 | |
| 2635 // If there is no default clause finish the last comparison's false target. | |
| 2636 if (!last_false_block->IsFinished()) { | |
| 2637 last_false_block->Finish(new HGoto(single_exit_block)); | |
| 2638 } | |
| 2639 | |
| 2640 if (single_exit_block->HasPredecessor()) { | |
| 2641 set_current_block(single_exit_block); | |
| 2642 } else { | 2544 } else { |
| 2643 set_current_block(NULL); | 2545 if (fall_through_block != NULL) fall_through_block->Goto(break_block); |
| 2546 if (last_block != NULL) last_block->Goto(break_block); |
| 2547 break_block->SetJoinId(stmt->ExitId()); |
| 2548 set_current_block(break_block); |
| 2644 } | 2549 } |
| 2645 } | 2550 } |
| 2646 | 2551 |
| 2552 |
| 2647 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { | 2553 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { |
| 2648 return statement->OsrEntryId() == info()->osr_ast_id(); | 2554 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2649 } | 2555 } |
| 2650 | 2556 |
| 2651 | 2557 |
| 2652 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { | 2558 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
| 2653 if (!HasOsrEntryAt(statement)) return; | 2559 if (!HasOsrEntryAt(statement)) return; |
| 2654 | 2560 |
| 2655 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2561 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2656 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2562 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3245 } else { | 3151 } else { |
| 3246 // Keyed store. | 3152 // Keyed store. |
| 3247 VISIT_FOR_VALUE(prop->key()); | 3153 VISIT_FOR_VALUE(prop->key()); |
| 3248 VISIT_FOR_VALUE(expr->value()); | 3154 VISIT_FOR_VALUE(expr->value()); |
| 3249 value = Pop(); | 3155 value = Pop(); |
| 3250 HValue* key = Pop(); | 3156 HValue* key = Pop(); |
| 3251 HValue* object = Pop(); | 3157 HValue* object = Pop(); |
| 3252 | 3158 |
| 3253 if (expr->IsMonomorphic()) { | 3159 if (expr->IsMonomorphic()) { |
| 3254 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); | 3160 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3255 // An object has either fast elements or pixel array elements, but never | 3161 // An object has either fast elements or external array elements, but |
| 3256 // both. Pixel array maps that are assigned to pixel array elements are | 3162 // never both. Pixel array maps that are assigned to pixel array elements |
| 3257 // always created with the fast elements flag cleared. | 3163 // are always created with the fast elements flag cleared. |
| 3258 if (receiver_type->has_pixel_array_elements()) { | 3164 if (receiver_type->has_external_array_elements()) { |
| 3259 instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr); | 3165 if (expr->GetExternalArrayType() == kExternalPixelArray) { |
| 3166 instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr); |
| 3167 } |
| 3260 } else if (receiver_type->has_fast_elements()) { | 3168 } else if (receiver_type->has_fast_elements()) { |
| 3261 instr = BuildStoreKeyedFastElement(object, key, value, expr); | 3169 instr = BuildStoreKeyedFastElement(object, key, value, expr); |
| 3262 } | 3170 } |
| 3263 } | 3171 } |
| 3264 if (instr == NULL) { | 3172 if (instr == NULL) { |
| 3265 instr = BuildStoreKeyedGeneric(object, key, value); | 3173 instr = BuildStoreKeyedGeneric(object, key, value); |
| 3266 } | 3174 } |
| 3267 } | 3175 } |
| 3268 | 3176 |
| 3269 Push(value); | 3177 Push(value); |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3632 } | 3540 } |
| 3633 | 3541 |
| 3634 | 3542 |
| 3635 HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, | 3543 HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, |
| 3636 HValue* key, | 3544 HValue* key, |
| 3637 Property* expr) { | 3545 Property* expr) { |
| 3638 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3546 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3639 AddInstruction(new HCheckNonSmi(object)); | 3547 AddInstruction(new HCheckNonSmi(object)); |
| 3640 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3548 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3641 ASSERT(!map->has_fast_elements()); | 3549 ASSERT(!map->has_fast_elements()); |
| 3642 ASSERT(map->has_pixel_array_elements()); | 3550 ASSERT(map->has_external_array_elements()); |
| 3643 AddInstruction(new HCheckMap(object, map)); | 3551 AddInstruction(new HCheckMap(object, map)); |
| 3644 HLoadElements* elements = new HLoadElements(object); | 3552 HLoadElements* elements = new HLoadElements(object); |
| 3645 AddInstruction(elements); | 3553 AddInstruction(elements); |
| 3646 HInstruction* length = new HPixelArrayLength(elements); | 3554 HInstruction* length = new HExternalArrayLength(elements); |
| 3647 AddInstruction(length); | 3555 AddInstruction(length); |
| 3648 AddInstruction(new HBoundsCheck(key, length)); | 3556 AddInstruction(new HBoundsCheck(key, length)); |
| 3649 HLoadPixelArrayExternalPointer* external_elements = | 3557 HLoadExternalArrayPointer* external_elements = |
| 3650 new HLoadPixelArrayExternalPointer(elements); | 3558 new HLoadExternalArrayPointer(elements); |
| 3651 AddInstruction(external_elements); | 3559 AddInstruction(external_elements); |
| 3652 HLoadPixelArrayElement* pixel_array_value = | 3560 HLoadPixelArrayElement* pixel_array_value = |
| 3653 new HLoadPixelArrayElement(external_elements, key); | 3561 new HLoadPixelArrayElement(external_elements, key); |
| 3654 return pixel_array_value; | 3562 return pixel_array_value; |
| 3655 } | 3563 } |
| 3656 | 3564 |
| 3657 | 3565 |
| 3658 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 3566 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3659 HValue* key, | 3567 HValue* key, |
| 3660 HValue* value) { | 3568 HValue* value) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3689 | 3597 |
| 3690 HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement( | 3598 HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement( |
| 3691 HValue* object, | 3599 HValue* object, |
| 3692 HValue* key, | 3600 HValue* key, |
| 3693 HValue* val, | 3601 HValue* val, |
| 3694 Expression* expr) { | 3602 Expression* expr) { |
| 3695 ASSERT(expr->IsMonomorphic()); | 3603 ASSERT(expr->IsMonomorphic()); |
| 3696 AddInstruction(new HCheckNonSmi(object)); | 3604 AddInstruction(new HCheckNonSmi(object)); |
| 3697 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3605 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3698 ASSERT(!map->has_fast_elements()); | 3606 ASSERT(!map->has_fast_elements()); |
| 3699 ASSERT(map->has_pixel_array_elements()); | 3607 ASSERT(map->has_external_array_elements()); |
| 3700 AddInstruction(new HCheckMap(object, map)); | 3608 AddInstruction(new HCheckMap(object, map)); |
| 3701 HLoadElements* elements = new HLoadElements(object); | 3609 HLoadElements* elements = new HLoadElements(object); |
| 3702 AddInstruction(elements); | 3610 AddInstruction(elements); |
| 3703 HInstruction* length = AddInstruction(new HPixelArrayLength(elements)); | 3611 HInstruction* length = AddInstruction(new HExternalArrayLength(elements)); |
| 3704 AddInstruction(new HBoundsCheck(key, length)); | 3612 AddInstruction(new HBoundsCheck(key, length)); |
| 3705 HLoadPixelArrayExternalPointer* external_elements = | 3613 HLoadExternalArrayPointer* external_elements = |
| 3706 new HLoadPixelArrayExternalPointer(elements); | 3614 new HLoadExternalArrayPointer(elements); |
| 3707 AddInstruction(external_elements); | 3615 AddInstruction(external_elements); |
| 3708 return new HStorePixelArrayElement(external_elements, key, val); | 3616 return new HStorePixelArrayElement(external_elements, key, val); |
| 3709 } | 3617 } |
| 3710 | 3618 |
| 3711 | 3619 |
| 3712 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 3620 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3713 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 3621 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3714 if (proxy == NULL) return false; | 3622 if (proxy == NULL) return false; |
| 3715 if (!proxy->var()->IsStackAllocated()) return false; | 3623 if (!proxy->var()->IsStackAllocated()) return false; |
| 3716 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 3624 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3786 VISIT_FOR_VALUE(expr->key()); | 3694 VISIT_FOR_VALUE(expr->key()); |
| 3787 | 3695 |
| 3788 HValue* key = Pop(); | 3696 HValue* key = Pop(); |
| 3789 HValue* obj = Pop(); | 3697 HValue* obj = Pop(); |
| 3790 | 3698 |
| 3791 if (expr->IsMonomorphic()) { | 3699 if (expr->IsMonomorphic()) { |
| 3792 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); | 3700 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3793 // An object has either fast elements or pixel array elements, but never | 3701 // An object has either fast elements or pixel array elements, but never |
| 3794 // both. Pixel array maps that are assigned to pixel array elements are | 3702 // both. Pixel array maps that are assigned to pixel array elements are |
| 3795 // always created with the fast elements flag cleared. | 3703 // always created with the fast elements flag cleared. |
| 3796 if (receiver_type->has_pixel_array_elements()) { | 3704 if (receiver_type->has_external_array_elements()) { |
| 3797 instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); | 3705 if (expr->GetExternalArrayType() == kExternalPixelArray) { |
| 3706 instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); |
| 3707 } |
| 3798 } else if (receiver_type->has_fast_elements()) { | 3708 } else if (receiver_type->has_fast_elements()) { |
| 3799 instr = BuildLoadKeyedFastElement(obj, key, expr); | 3709 instr = BuildLoadKeyedFastElement(obj, key, expr); |
| 3800 } | 3710 } |
| 3801 } | 3711 } |
| 3802 if (instr == NULL) { | 3712 if (instr == NULL) { |
| 3803 instr = BuildLoadKeyedGeneric(obj, key); | 3713 instr = BuildLoadKeyedGeneric(obj, key); |
| 3804 } | 3714 } |
| 3805 } | 3715 } |
| 3806 instr->set_position(expr->position()); | 3716 instr->set_position(expr->position()); |
| 3807 ast_context()->ReturnInstruction(instr, expr->id()); | 3717 ast_context()->ReturnInstruction(instr, expr->id()); |
| (...skipping 2146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5954 } | 5864 } |
| 5955 } | 5865 } |
| 5956 | 5866 |
| 5957 #ifdef DEBUG | 5867 #ifdef DEBUG |
| 5958 if (graph_ != NULL) graph_->Verify(); | 5868 if (graph_ != NULL) graph_->Verify(); |
| 5959 if (allocator_ != NULL) allocator_->Verify(); | 5869 if (allocator_ != NULL) allocator_->Verify(); |
| 5960 #endif | 5870 #endif |
| 5961 } | 5871 } |
| 5962 | 5872 |
| 5963 } } // namespace v8::internal | 5873 } } // namespace v8::internal |
| OLD | NEW |