| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 1425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1436 } | 1436 } |
| 1437 | 1437 |
| 1438 | 1438 |
| 1439 void CodeGenerator::VisitBlock(Block* node) { | 1439 void CodeGenerator::VisitBlock(Block* node) { |
| 1440 ASSERT(!in_spilled_code()); | 1440 ASSERT(!in_spilled_code()); |
| 1441 Comment cmnt(masm_, "[ Block"); | 1441 Comment cmnt(masm_, "[ Block"); |
| 1442 CodeForStatementPosition(node); | 1442 CodeForStatementPosition(node); |
| 1443 node->set_break_stack_height(break_stack_height_); | 1443 node->set_break_stack_height(break_stack_height_); |
| 1444 node->break_target()->Initialize(this); | 1444 node->break_target()->Initialize(this); |
| 1445 VisitStatements(node->statements()); | 1445 VisitStatements(node->statements()); |
| 1446 if (node->break_target()->is_linked()) { | 1446 node->break_target()->Bind(); |
| 1447 node->break_target()->Bind(); | |
| 1448 } | |
| 1449 } | 1447 } |
| 1450 | 1448 |
| 1451 | 1449 |
| 1452 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1450 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1453 VirtualFrame::SpilledScope spilled_scope(this); | 1451 VirtualFrame::SpilledScope spilled_scope(this); |
| 1454 frame_->EmitPush(Immediate(pairs)); | 1452 frame_->EmitPush(Immediate(pairs)); |
| 1455 frame_->EmitPush(esi); | 1453 frame_->EmitPush(esi); |
| 1456 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1454 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1457 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1455 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1458 // Return value is ignored. | 1456 // Return value is ignored. |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 // or control flow effect). LoadCondition is called without | 1593 // or control flow effect). LoadCondition is called without |
| 1596 // forcing control flow. | 1594 // forcing control flow. |
| 1597 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1595 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1598 if (has_valid_frame()) { | 1596 if (has_valid_frame()) { |
| 1599 // Control flow can fall off the end of the condition with a | 1597 // Control flow can fall off the end of the condition with a |
| 1600 // value on the frame. | 1598 // value on the frame. |
| 1601 frame_->Drop(); | 1599 frame_->Drop(); |
| 1602 } | 1600 } |
| 1603 } | 1601 } |
| 1604 | 1602 |
| 1605 if (exit.is_linked()) { | 1603 exit.Bind(); |
| 1606 exit.Bind(); | |
| 1607 } | |
| 1608 } | 1604 } |
| 1609 | 1605 |
| 1610 | 1606 |
| 1611 void CodeGenerator::CleanStack(int num_bytes) { | 1607 void CodeGenerator::CleanStack(int num_bytes) { |
| 1612 ASSERT(num_bytes % kPointerSize == 0); | 1608 ASSERT(num_bytes % kPointerSize == 0); |
| 1613 frame_->Drop(num_bytes / kPointerSize); | 1609 frame_->Drop(num_bytes / kPointerSize); |
| 1614 } | 1610 } |
| 1615 | 1611 |
| 1616 | 1612 |
| 1617 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1613 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1748 int CodeGenerator::FastCaseSwitchMinCaseCount() { | 1744 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
| 1749 return kFastSwitchMinCaseCount; | 1745 return kFastSwitchMinCaseCount; |
| 1750 } | 1746 } |
| 1751 | 1747 |
| 1752 | 1748 |
| 1753 // Generate a computed jump to a switch case. | 1749 // Generate a computed jump to a switch case. |
| 1754 void CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1750 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1755 SwitchStatement* node, | 1751 SwitchStatement* node, |
| 1756 int min_index, | 1752 int min_index, |
| 1757 int range, | 1753 int range, |
| 1758 JumpTarget* fail_label, | 1754 Label* default_label, |
| 1759 Vector<JumpTarget*> case_targets, | 1755 Vector<Label*> case_targets, |
| 1760 Vector<JumpTarget> case_labels) { | 1756 Vector<Label> case_labels) { |
| 1761 // Notice: Internal references, used by both the jmp instruction and | 1757 // Notice: Internal references, used by both the jmp instruction and |
| 1762 // the table entries, need to be relocated if the buffer grows. This | 1758 // the table entries, need to be relocated if the buffer grows. This |
| 1763 // prevents the forward use of Labels, since a displacement cannot | 1759 // prevents the forward use of Labels, since a displacement cannot |
| 1764 // survive relocation, and it also cannot safely be distinguished | 1760 // survive relocation, and it also cannot safely be distinguished |
| 1765 // from a real address. Instead we put in zero-values as | 1761 // from a real address. Instead we put in zero-values as |
| 1766 // placeholders, and fill in the addresses after the labels have been | 1762 // placeholders, and fill in the addresses after the labels have been |
| 1767 // bound. | 1763 // bound. |
| 1768 | 1764 |
| 1769 Result switch_value = frame_->Pop(); // supposed Smi | 1765 JumpTarget setup_default(this); |
| 1770 // If value is not in range [0..length-1] then jump to the default/end label. | 1766 JumpTarget is_smi(this); |
| 1767 |
| 1768 // A non-null default label pointer indicates a default case among |
| 1769 // the case labels. Otherwise we use the break target as a |
| 1770 // "default". |
| 1771 JumpTarget* default_target = |
| 1772 (default_label == NULL) ? node->break_target() : &setup_default; |
| 1773 |
| 1774 // Test whether input is a smi. |
| 1771 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 1775 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| 1772 | 1776 Result switch_value = frame_->Pop(); |
| 1773 // Test whether input is a HeapNumber that is really a Smi | |
| 1774 JumpTarget is_smi(this); | |
| 1775 switch_value.ToRegister(); | 1777 switch_value.ToRegister(); |
| 1776 __ test(switch_value.reg(), Immediate(kSmiTagMask)); | 1778 __ test(switch_value.reg(), Immediate(kSmiTagMask)); |
| 1777 is_smi.Branch(equal, &switch_value, taken); | 1779 is_smi.Branch(equal, &switch_value, taken); |
| 1778 // It's a heap object, not a Smi or a Failure | 1780 |
| 1781 // It's a heap object, not a smi or a failure. Check if it is a |
| 1782 // heap number. |
| 1779 Result temp = allocator()->Allocate(); | 1783 Result temp = allocator()->Allocate(); |
| 1780 ASSERT(temp.is_valid()); | 1784 ASSERT(temp.is_valid()); |
| 1781 __ mov(temp.reg(), FieldOperand(switch_value.reg(), HeapObject::kMapOffset)); | 1785 __ mov(temp.reg(), FieldOperand(switch_value.reg(), HeapObject::kMapOffset)); |
| 1782 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); | 1786 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
| 1783 __ cmp(temp.reg(), HEAP_NUMBER_TYPE); | 1787 __ cmp(temp.reg(), HEAP_NUMBER_TYPE); |
| 1784 temp.Unuse(); | 1788 temp.Unuse(); |
| 1785 fail_label->Branch(not_equal); | 1789 default_target->Branch(not_equal); |
| 1786 // Result switch_value is a heap number. | 1790 |
| 1791 // The switch value is a heap number. Convert it to a smi. |
| 1787 frame_->Push(&switch_value); | 1792 frame_->Push(&switch_value); |
| 1788 Result smi_value = frame_->CallRuntime(Runtime::kNumberToSmi, 1); | 1793 Result smi_value = frame_->CallRuntime(Runtime::kNumberToSmi, 1); |
| 1794 |
| 1789 is_smi.Bind(&smi_value); | 1795 is_smi.Bind(&smi_value); |
| 1790 smi_value.ToRegister(); | 1796 smi_value.ToRegister(); |
| 1791 | 1797 // Convert the switch value to a 0-based table index. |
| 1792 if (min_index != 0) { | 1798 if (min_index != 0) { |
| 1793 frame_->Spill(smi_value.reg()); | 1799 frame_->Spill(smi_value.reg()); |
| 1794 __ sub(Operand(smi_value.reg()), Immediate(min_index << kSmiTagSize)); | 1800 __ sub(Operand(smi_value.reg()), Immediate(min_index << kSmiTagSize)); |
| 1795 } | 1801 } |
| 1802 // Go to the default case if the table index is negative or not a smi. |
| 1796 __ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask)); | 1803 __ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask)); |
| 1797 // Go to slow case if adjusted index is negative or not a Smi. | 1804 default_target->Branch(not_equal, not_taken); |
| 1798 fail_label->Branch(not_equal, not_taken); | |
| 1799 __ cmp(smi_value.reg(), range << kSmiTagSize); | 1805 __ cmp(smi_value.reg(), range << kSmiTagSize); |
| 1800 fail_label->Branch(greater_equal, not_taken); | 1806 default_target->Branch(greater_equal, not_taken); |
| 1801 | 1807 |
| 1802 // 0 is placeholder. | 1808 // 0 is placeholder. |
| 1803 // Jump to the address at table_address + 2 * smi_value.reg(). | 1809 // Jump to the address at table_address + 2 * smi_value.reg(). |
| 1804 // The target of the jump is read from table_address + 4 * switch_value. | 1810 // The target of the jump is read from table_address + 4 * switch_value. |
| 1805 // The Smi encoding of smi_value.reg() is 2 * switch_value. | 1811 // The Smi encoding of smi_value.reg() is 2 * switch_value. |
| 1806 __ jmp(Operand(smi_value.reg(), smi_value.reg(), | 1812 __ jmp(Operand(smi_value.reg(), smi_value.reg(), |
| 1807 times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); | 1813 times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); |
| 1814 smi_value.Unuse(); |
| 1815 |
| 1816 // The expected frame at all the case labels is the (mergable |
| 1817 // version of the) current one. Keep a copy to restore at the start |
| 1818 // of every label. |
| 1819 frame_->MakeMergable(); |
| 1820 VirtualFrame* start_frame = new VirtualFrame(frame_); |
| 1821 |
| 1808 // Calculate address to overwrite later with actual address of table. | 1822 // Calculate address to overwrite later with actual address of table. |
| 1809 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); | 1823 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); |
| 1810 | |
| 1811 __ Align(4); | 1824 __ Align(4); |
| 1812 JumpTarget table_start(this); | 1825 Label table_start; |
| 1813 smi_value.Unuse(); | 1826 __ bind(&table_start); |
| 1814 table_start.Bind(); | 1827 __ WriteInternalReference(jump_table_ref, table_start); |
| 1815 __ WriteInternalReference(jump_table_ref, *table_start.entry_label()); | |
| 1816 | 1828 |
| 1817 for (int i = 0; i < range; i++) { | 1829 for (int i = 0; i < range; i++) { |
| 1818 // These are the table entries. 0x0 is the placeholder for case address. | 1830 // These are the table entries. 0x0 is the placeholder for case address. |
| 1819 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE); | 1831 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE); |
| 1820 } | 1832 } |
| 1821 | 1833 |
| 1822 GenerateFastCaseSwitchCases(node, case_labels, &table_start); | 1834 GenerateFastCaseSwitchCases(node, case_labels, start_frame); |
| 1823 | 1835 |
| 1824 for (int i = 0, entry_pos = table_start.entry_label()->pos(); | 1836 // If there was a default case, we need to emit the code to match it. |
| 1837 if (default_label != NULL) { |
| 1838 node->break_target()->Jump(); |
| 1839 setup_default.Bind(); |
| 1840 frame_->MergeTo(start_frame); |
| 1841 __ jmp(default_label); |
| 1842 DeleteFrame(); |
| 1843 } |
| 1844 node->break_target()->Bind(); |
| 1845 |
| 1846 for (int i = 0, entry_pos = table_start.pos(); |
| 1825 i < range; | 1847 i < range; |
| 1826 i++, entry_pos += sizeof(uint32_t)) { | 1848 i++, entry_pos += sizeof(uint32_t)) { |
| 1827 __ WriteInternalReference(entry_pos, *case_targets[i]->entry_label()); | 1849 if (case_targets[i] == NULL) { |
| 1850 __ WriteInternalReference(entry_pos, |
| 1851 *node->break_target()->entry_label()); |
| 1852 } else { |
| 1853 __ WriteInternalReference(entry_pos, *case_targets[i]); |
| 1854 } |
| 1828 } | 1855 } |
| 1856 |
| 1857 delete start_frame; |
| 1829 } | 1858 } |
| 1830 | 1859 |
| 1831 | 1860 |
| 1832 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1861 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1833 ASSERT(!in_spilled_code()); | 1862 ASSERT(!in_spilled_code()); |
| 1834 Comment cmnt(masm_, "[ SwitchStatement"); | 1863 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1835 CodeForStatementPosition(node); | 1864 CodeForStatementPosition(node); |
| 1836 node->set_break_stack_height(break_stack_height_); | 1865 node->set_break_stack_height(break_stack_height_); |
| 1837 node->break_target()->Initialize(this); | 1866 node->break_target()->Initialize(this); |
| 1838 | 1867 |
| 1839 Load(node->tag()); | 1868 Load(node->tag()); |
| 1840 | |
| 1841 if (TryGenerateFastCaseSwitchStatement(node)) { | 1869 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1842 return; | 1870 return; |
| 1843 } | 1871 } |
| 1844 | 1872 |
| 1845 JumpTarget next_test(this); | 1873 JumpTarget next_test(this); |
| 1846 JumpTarget fall_through(this); | 1874 JumpTarget fall_through(this); |
| 1847 JumpTarget default_entry(this); | 1875 JumpTarget default_entry(this); |
| 1848 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL); | 1876 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL); |
| 1849 ZoneList<CaseClause*>* cases = node->cases(); | 1877 ZoneList<CaseClause*>* cases = node->cases(); |
| 1850 int length = cases->length(); | 1878 int length = cases->length(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1911 Comment cmnt(masm_, "[ Default clause"); | 1939 Comment cmnt(masm_, "[ Default clause"); |
| 1912 default_entry.Bind(); | 1940 default_entry.Bind(); |
| 1913 VisitStatements(default_clause->statements()); | 1941 VisitStatements(default_clause->statements()); |
| 1914 // If control flow can fall out of the default and there is a case after | 1942 // If control flow can fall out of the default and there is a case after |
| 1915 // it, jump to that case's body. | 1943 // it, jump to that case's body. |
| 1916 if (has_valid_frame() && default_exit.is_bound()) { | 1944 if (has_valid_frame() && default_exit.is_bound()) { |
| 1917 default_exit.Jump(); | 1945 default_exit.Jump(); |
| 1918 } | 1946 } |
| 1919 } | 1947 } |
| 1920 | 1948 |
| 1921 if (fall_through.is_linked()) { | 1949 fall_through.Bind(); |
| 1922 fall_through.Bind(); | 1950 node->break_target()->Bind(); |
| 1923 } | |
| 1924 | |
| 1925 if (node->break_target()->is_linked()) { | |
| 1926 node->break_target()->Bind(); | |
| 1927 } | |
| 1928 } | 1951 } |
| 1929 | 1952 |
| 1930 | 1953 |
| 1931 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1954 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1932 ASSERT(!in_spilled_code()); | 1955 ASSERT(!in_spilled_code()); |
| 1933 Comment cmnt(masm_, "[ LoopStatement"); | 1956 Comment cmnt(masm_, "[ LoopStatement"); |
| 1934 CodeForStatementPosition(node); | 1957 CodeForStatementPosition(node); |
| 1935 node->set_break_stack_height(break_stack_height_); | 1958 node->set_break_stack_height(break_stack_height_); |
| 1936 node->break_target()->Initialize(this); | 1959 node->break_target()->Initialize(this); |
| 1937 | 1960 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1977 | 2000 |
| 1978 // Compile the test. | 2001 // Compile the test. |
| 1979 if (info == ALWAYS_TRUE) { | 2002 if (info == ALWAYS_TRUE) { |
| 1980 // If control flow can fall off the end of the body, jump back to | 2003 // If control flow can fall off the end of the body, jump back to |
| 1981 // the top. | 2004 // the top. |
| 1982 if (has_valid_frame()) { | 2005 if (has_valid_frame()) { |
| 1983 node->continue_target()->Jump(); | 2006 node->continue_target()->Jump(); |
| 1984 } | 2007 } |
| 1985 } else if (info == ALWAYS_FALSE) { | 2008 } else if (info == ALWAYS_FALSE) { |
| 1986 // If we had a continue in the body we have to bind its jump target. | 2009 // If we had a continue in the body we have to bind its jump target. |
| 1987 if (node->continue_target()->is_linked()) { | 2010 node->continue_target()->Bind(); |
| 1988 node->continue_target()->Bind(); | |
| 1989 } | |
| 1990 } else { | 2011 } else { |
| 1991 ASSERT(info == DONT_KNOW); | 2012 ASSERT(info == DONT_KNOW); |
| 1992 // We have to compile the test expression if it can be reached by | 2013 // We have to compile the test expression if it can be reached by |
| 1993 // control flow falling out of the body or via continue. | 2014 // control flow falling out of the body or via continue. |
| 1994 if (node->continue_target()->is_linked()) { | 2015 node->continue_target()->Bind(); |
| 1995 node->continue_target()->Bind(); | |
| 1996 } | |
| 1997 if (has_valid_frame()) { | 2016 if (has_valid_frame()) { |
| 1998 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 2017 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1999 &body, node->break_target(), true); | 2018 &body, node->break_target(), true); |
| 2000 } | 2019 } |
| 2001 } | 2020 } |
| 2002 break; | 2021 break; |
| 2003 } | 2022 } |
| 2004 | 2023 |
| 2005 case LoopStatement::WHILE_LOOP: { | 2024 case LoopStatement::WHILE_LOOP: { |
| 2006 IncrementLoopNesting(); | 2025 IncrementLoopNesting(); |
| 2007 | 2026 |
| 2008 // If the test is never true and has no side effects there is no need | 2027 // If the test is never true and has no side effects there is no need |
| 2009 // to compile the test or body. | 2028 // to compile the test or body. |
| 2010 if (info == ALWAYS_FALSE) break; | 2029 if (info == ALWAYS_FALSE) break; |
| 2011 | 2030 |
| 2012 // Label the top of the loop with the continue target for the backward | 2031 // Label the top of the loop with the continue target for the backward |
| 2013 // CFG edge. | 2032 // CFG edge. |
| 2014 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2033 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 2015 node->continue_target()->Bind(); | 2034 node->continue_target()->Bind(); |
| 2016 | 2035 |
| 2017 // If the test is always true and has no side effects there is no need | 2036 // If the test is always true and has no side effects there is no need |
| 2018 // to compile it. We only compile the test when we do not know its | 2037 // to compile it. We only compile the test when we do not know its |
| 2019 // outcome or it may have side effects. | 2038 // outcome or it may have side effects. |
| 2020 if (info == DONT_KNOW) { | 2039 if (info == DONT_KNOW) { |
| 2021 JumpTarget body(this); | 2040 JumpTarget body(this); |
| 2022 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 2041 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 2023 &body, node->break_target(), true); | 2042 &body, node->break_target(), true); |
| 2024 if (body.is_linked()) { | 2043 body.Bind(); |
| 2025 body.Bind(); | |
| 2026 } | |
| 2027 } | 2044 } |
| 2028 | 2045 |
| 2029 if (has_valid_frame()) { | 2046 if (has_valid_frame()) { |
| 2030 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2047 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2031 Visit(node->body()); | 2048 Visit(node->body()); |
| 2032 | 2049 |
| 2033 // If control flow can fall out of the body, jump back to the top. | 2050 // If control flow can fall out of the body, jump back to the top. |
| 2034 if (has_valid_frame()) { | 2051 if (has_valid_frame()) { |
| 2035 node->continue_target()->Jump(); | 2052 node->continue_target()->Jump(); |
| 2036 } | 2053 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2059 loop.Bind(); | 2076 loop.Bind(); |
| 2060 } | 2077 } |
| 2061 | 2078 |
| 2062 // If the test is always true and has no side effects there is no need | 2079 // If the test is always true and has no side effects there is no need |
| 2063 // to compile it. We only compile the test when we do not know its | 2080 // to compile it. We only compile the test when we do not know its |
| 2064 // outcome or it has side effects. | 2081 // outcome or it has side effects. |
| 2065 if (info == DONT_KNOW) { | 2082 if (info == DONT_KNOW) { |
| 2066 JumpTarget body(this); | 2083 JumpTarget body(this); |
| 2067 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 2084 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 2068 &body, node->break_target(), true); | 2085 &body, node->break_target(), true); |
| 2069 if (body.is_linked()) { | 2086 body.Bind(); |
| 2070 body.Bind(); | |
| 2071 } | |
| 2072 } | 2087 } |
| 2073 | 2088 |
| 2074 if (has_valid_frame()) { | 2089 if (has_valid_frame()) { |
| 2075 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2090 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2076 Visit(node->body()); | 2091 Visit(node->body()); |
| 2077 | 2092 |
| 2078 if (node->next() == NULL) { | 2093 if (node->next() == NULL) { |
| 2079 // If there is no update statement and control flow can fall out | 2094 // If there is no update statement and control flow can fall out |
| 2080 // of the loop, jump to the continue label. | 2095 // of the loop, jump to the continue label. |
| 2081 if (has_valid_frame()) { | 2096 if (has_valid_frame()) { |
| 2082 node->continue_target()->Jump(); | 2097 node->continue_target()->Jump(); |
| 2083 } | 2098 } |
| 2084 } else { | 2099 } else { |
| 2085 // If there is an update statement and control flow can reach it | 2100 // If there is an update statement and control flow can reach it |
| 2086 // via falling out of the body of the loop or continuing, we | 2101 // via falling out of the body of the loop or continuing, we |
| 2087 // compile the update statement. | 2102 // compile the update statement. |
| 2088 if (node->continue_target()->is_linked()) { | 2103 node->continue_target()->Bind(); |
| 2089 node->continue_target()->Bind(); | |
| 2090 } | |
| 2091 if (has_valid_frame()) { | 2104 if (has_valid_frame()) { |
| 2092 // Record source position of the statement as this code which is | 2105 // Record source position of the statement as this code which is |
| 2093 // after the code for the body actually belongs to the loop | 2106 // after the code for the body actually belongs to the loop |
| 2094 // statement and not the body. | 2107 // statement and not the body. |
| 2095 CodeForStatementPosition(node); | 2108 CodeForStatementPosition(node); |
| 2096 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 2109 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 2097 Visit(node->next()); | 2110 Visit(node->next()); |
| 2098 loop.Jump(); | 2111 loop.Jump(); |
| 2099 } | 2112 } |
| 2100 } | 2113 } |
| 2101 } | 2114 } |
| 2102 break; | 2115 break; |
| 2103 } | 2116 } |
| 2104 } | 2117 } |
| 2105 | 2118 |
| 2106 DecrementLoopNesting(); | 2119 DecrementLoopNesting(); |
| 2107 if (node->break_target()->is_linked()) { | 2120 node->break_target()->Bind(); |
| 2108 node->break_target()->Bind(); | |
| 2109 } | |
| 2110 } | 2121 } |
| 2111 | 2122 |
| 2112 | 2123 |
| 2113 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 2124 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 2114 ASSERT(!in_spilled_code()); | 2125 ASSERT(!in_spilled_code()); |
| 2115 VirtualFrame::SpilledScope spilled_scope(this); | 2126 VirtualFrame::SpilledScope spilled_scope(this); |
| 2116 Comment cmnt(masm_, "[ ForInStatement"); | 2127 Comment cmnt(masm_, "[ ForInStatement"); |
| 2117 CodeForStatementPosition(node); | 2128 CodeForStatementPosition(node); |
| 2118 | 2129 |
| 2119 // We keep stuff on the stack while the body is executing. | 2130 // We keep stuff on the stack while the body is executing. |
| 2120 // Record it, so that a break/continue crossing this statement | 2131 // Record it, so that a break/continue crossing this statement |
| 2121 // can restore the stack. | 2132 // can restore the stack. |
| 2122 const int kForInStackSize = 5 * kPointerSize; | 2133 const int kForInStackSize = 5 * kPointerSize; |
| 2123 break_stack_height_ += kForInStackSize; | 2134 break_stack_height_ += kForInStackSize; |
| 2124 node->set_break_stack_height(break_stack_height_); | 2135 node->set_break_stack_height(break_stack_height_); |
| 2125 node->break_target()->Initialize(this); | 2136 node->break_target()->Initialize(this); |
| 2126 node->continue_target()->Initialize(this); | 2137 node->continue_target()->Initialize(this); |
| 2127 | 2138 |
| 2128 JumpTarget primitive(this); | 2139 JumpTarget primitive(this); |
| 2129 JumpTarget jsobject(this); | 2140 JumpTarget jsobject(this); |
| 2130 JumpTarget fixed_array(this); | 2141 JumpTarget fixed_array(this); |
| 2131 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL); | 2142 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL); |
| 2132 JumpTarget end_del_check(this); | 2143 JumpTarget end_del_check(this); |
| 2133 JumpTarget cleanup(this); | |
| 2134 JumpTarget exit(this); | 2144 JumpTarget exit(this); |
| 2135 | 2145 |
| 2136 // Get the object to enumerate over (converted to JSObject). | 2146 // Get the object to enumerate over (converted to JSObject). |
| 2137 LoadAndSpill(node->enumerable()); | 2147 LoadAndSpill(node->enumerable()); |
| 2138 | 2148 |
| 2139 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 2149 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 2140 // to the specification. 12.6.4 mandates a call to ToObject. | 2150 // to the specification. 12.6.4 mandates a call to ToObject. |
| 2141 frame_->EmitPop(eax); | 2151 frame_->EmitPop(eax); |
| 2142 | 2152 |
| 2143 // eax: value to be iterated over | 2153 // eax: value to be iterated over |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2209 // Push the length of the array and the initial index onto the stack. | 2219 // Push the length of the array and the initial index onto the stack. |
| 2210 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 2220 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 2211 __ shl(eax, kSmiTagSize); | 2221 __ shl(eax, kSmiTagSize); |
| 2212 frame_->EmitPush(eax); // <- slot 1 | 2222 frame_->EmitPush(eax); // <- slot 1 |
| 2213 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 | 2223 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 2214 | 2224 |
| 2215 // Condition. | 2225 // Condition. |
| 2216 entry.Bind(); | 2226 entry.Bind(); |
| 2217 __ mov(eax, frame_->ElementAt(0)); // load the current count | 2227 __ mov(eax, frame_->ElementAt(0)); // load the current count |
| 2218 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length | 2228 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length |
| 2219 cleanup.Branch(above_equal); | 2229 node->break_target()->Branch(above_equal); |
| 2220 | 2230 |
| 2221 // Get the i'th entry of the array. | 2231 // Get the i'th entry of the array. |
| 2222 __ mov(edx, frame_->ElementAt(2)); | 2232 __ mov(edx, frame_->ElementAt(2)); |
| 2223 __ mov(ebx, Operand(edx, eax, times_2, | 2233 __ mov(ebx, Operand(edx, eax, times_2, |
| 2224 FixedArray::kHeaderSize - kHeapObjectTag)); | 2234 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 2225 | 2235 |
| 2226 // Get the expected map from the stack or a zero map in the | 2236 // Get the expected map from the stack or a zero map in the |
| 2227 // permanent slow case eax: current iteration count ebx: i'th entry | 2237 // permanent slow case eax: current iteration count ebx: i'th entry |
| 2228 // of the enum cache | 2238 // of the enum cache |
| 2229 __ mov(edx, frame_->ElementAt(3)); | 2239 __ mov(edx, frame_->ElementAt(3)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2284 VisitAndSpill(node->body()); | 2294 VisitAndSpill(node->body()); |
| 2285 | 2295 |
| 2286 // Next. | 2296 // Next. |
| 2287 node->continue_target()->Bind(); | 2297 node->continue_target()->Bind(); |
| 2288 frame_->EmitPop(eax); | 2298 frame_->EmitPop(eax); |
| 2289 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 2299 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 2290 frame_->EmitPush(eax); | 2300 frame_->EmitPush(eax); |
| 2291 entry.Jump(); | 2301 entry.Jump(); |
| 2292 | 2302 |
| 2293 // Cleanup. | 2303 // Cleanup. |
| 2294 cleanup.Bind(); | |
| 2295 node->break_target()->Bind(); | 2304 node->break_target()->Bind(); |
| 2296 frame_->Drop(5); | 2305 frame_->Drop(5); |
| 2297 | 2306 |
| 2298 // Exit. | 2307 // Exit. |
| 2299 exit.Bind(); | 2308 exit.Bind(); |
| 2300 | 2309 |
| 2301 break_stack_height_ -= kForInStackSize; | 2310 break_stack_height_ -= kForInStackSize; |
| 2302 } | 2311 } |
| 2303 | 2312 |
| 2304 | 2313 |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2654 if (else_.is_linked()) { | 2663 if (else_.is_linked()) { |
| 2655 exit.Jump(); | 2664 exit.Jump(); |
| 2656 } | 2665 } |
| 2657 } | 2666 } |
| 2658 | 2667 |
| 2659 if (else_.is_linked()) { | 2668 if (else_.is_linked()) { |
| 2660 else_.Bind(); | 2669 else_.Bind(); |
| 2661 Load(node->else_expression(), typeof_state()); | 2670 Load(node->else_expression(), typeof_state()); |
| 2662 } | 2671 } |
| 2663 | 2672 |
| 2664 if (exit.is_linked()) { | 2673 exit.Bind(); |
| 2665 exit.Bind(); | |
| 2666 } | |
| 2667 } | 2674 } |
| 2668 | 2675 |
| 2669 | 2676 |
| 2670 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2677 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2671 if (slot->type() == Slot::LOOKUP) { | 2678 if (slot->type() == Slot::LOOKUP) { |
| 2672 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2679 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2673 | 2680 |
| 2674 // For now, just do a runtime call. | 2681 // For now, just do a runtime call. |
| 2675 frame_->Push(esi); | 2682 frame_->Push(esi); |
| 2676 frame_->Push(slot->var()->name()); | 2683 frame_->Push(slot->var()->name()); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2794 // needed (probably the common case). | 2801 // needed (probably the common case). |
| 2795 frame_->Spill(value.reg()); | 2802 frame_->Spill(value.reg()); |
| 2796 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 2803 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 2797 Result temp = allocator_->Allocate(); | 2804 Result temp = allocator_->Allocate(); |
| 2798 ASSERT(temp.is_valid()); | 2805 ASSERT(temp.is_valid()); |
| 2799 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); | 2806 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); |
| 2800 // The results start, value, and temp are unused by going out of | 2807 // The results start, value, and temp are unused by going out of |
| 2801 // scope. | 2808 // scope. |
| 2802 } | 2809 } |
| 2803 | 2810 |
| 2804 // If we definitely did not jump over the assignment, we do not need | 2811 exit.Bind(); |
| 2805 // to bind the exit label. Doing so can defeat peephole | |
| 2806 // optimization. | |
| 2807 if (exit.is_linked()) { | |
| 2808 exit.Bind(); | |
| 2809 } | |
| 2810 } | 2812 } |
| 2811 } | 2813 } |
| 2812 | 2814 |
| 2813 | 2815 |
| 2814 void CodeGenerator::VisitSlot(Slot* node) { | 2816 void CodeGenerator::VisitSlot(Slot* node) { |
| 2815 Comment cmnt(masm_, "[ Slot"); | 2817 Comment cmnt(masm_, "[ Slot"); |
| 2816 LoadFromSlot(node, typeof_state()); | 2818 LoadFromSlot(node, typeof_state()); |
| 2817 } | 2819 } |
| 2818 | 2820 |
| 2819 | 2821 |
| (...skipping 3468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6288 | 6290 |
| 6289 // Slow-case: Go through the JavaScript implementation. | 6291 // Slow-case: Go through the JavaScript implementation. |
| 6290 __ bind(&slow); | 6292 __ bind(&slow); |
| 6291 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6293 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6292 } | 6294 } |
| 6293 | 6295 |
| 6294 | 6296 |
| 6295 #undef __ | 6297 #undef __ |
| 6296 | 6298 |
| 6297 } } // namespace v8::internal | 6299 } } // namespace v8::internal |
| OLD | NEW |