| 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 ZoneList<Statement*>* body = fun->body(); | 131 ZoneList<Statement*>* body = fun->body(); |
| 132 | 132 |
| 133 // Initialize state. | 133 // Initialize state. |
| 134 ASSERT(scope_ == NULL); | 134 ASSERT(scope_ == NULL); |
| 135 scope_ = fun->scope(); | 135 scope_ = fun->scope(); |
| 136 ASSERT(allocator_ == NULL); | 136 ASSERT(allocator_ == NULL); |
| 137 RegisterAllocator register_allocator(this); | 137 RegisterAllocator register_allocator(this); |
| 138 allocator_ = ®ister_allocator; | 138 allocator_ = ®ister_allocator; |
| 139 ASSERT(frame_ == NULL); | 139 ASSERT(frame_ == NULL); |
| 140 frame_ = new VirtualFrame(this); | 140 frame_ = new VirtualFrame(this); |
| 141 function_return_.set_code_generator(this); | 141 function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 142 function_return_is_shadowed_ = false; | 142 function_return_is_shadowed_ = false; |
| 143 set_in_spilled_code(false); | 143 set_in_spilled_code(false); |
| 144 | 144 |
| 145 // Adjust for function-level loop nesting. | 145 // Adjust for function-level loop nesting. |
| 146 loop_nesting_ += fun->loop_nesting(); | 146 loop_nesting_ += fun->loop_nesting(); |
| 147 | 147 |
| 148 { | 148 { |
| 149 CodeGenState state(this); | 149 CodeGenState state(this); |
| 150 | 150 |
| 151 // Entry | 151 // Entry |
| (...skipping 1198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1350 Visit(statements->at(i)); | 1350 Visit(statements->at(i)); |
| 1351 } | 1351 } |
| 1352 } | 1352 } |
| 1353 | 1353 |
| 1354 | 1354 |
| 1355 void CodeGenerator::VisitBlock(Block* node) { | 1355 void CodeGenerator::VisitBlock(Block* node) { |
| 1356 ASSERT(!in_spilled_code()); | 1356 ASSERT(!in_spilled_code()); |
| 1357 Comment cmnt(masm_, "[ Block"); | 1357 Comment cmnt(masm_, "[ Block"); |
| 1358 CodeForStatement(node); | 1358 CodeForStatement(node); |
| 1359 node->set_break_stack_height(break_stack_height_); | 1359 node->set_break_stack_height(break_stack_height_); |
| 1360 node->break_target()->set_code_generator(this); | 1360 node->break_target()->Initialize(this); |
| 1361 VisitStatements(node->statements()); | 1361 VisitStatements(node->statements()); |
| 1362 if (node->break_target()->is_linked()) { | 1362 if (node->break_target()->is_linked()) { |
| 1363 node->break_target()->Bind(); | 1363 node->break_target()->Bind(); |
| 1364 } | 1364 } |
| 1365 } | 1365 } |
| 1366 | 1366 |
| 1367 | 1367 |
| 1368 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1368 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1369 VirtualFrame::SpilledScope spilled_scope(this); | 1369 VirtualFrame::SpilledScope spilled_scope(this); |
| 1370 frame_->EmitPush(Immediate(pairs)); | 1370 frame_->EmitPush(Immediate(pairs)); |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1732 __ WriteInternalReference(entry_pos, *case_targets[i]->entry_label()); | 1732 __ WriteInternalReference(entry_pos, *case_targets[i]->entry_label()); |
| 1733 } | 1733 } |
| 1734 } | 1734 } |
| 1735 | 1735 |
| 1736 | 1736 |
| 1737 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1737 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1738 ASSERT(!in_spilled_code()); | 1738 ASSERT(!in_spilled_code()); |
| 1739 Comment cmnt(masm_, "[ SwitchStatement"); | 1739 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1740 CodeForStatement(node); | 1740 CodeForStatement(node); |
| 1741 node->set_break_stack_height(break_stack_height_); | 1741 node->set_break_stack_height(break_stack_height_); |
| 1742 node->break_target()->set_code_generator(this); | 1742 node->break_target()->Initialize(this); |
| 1743 | 1743 |
| 1744 Load(node->tag()); | 1744 Load(node->tag()); |
| 1745 | 1745 |
| 1746 if (TryGenerateFastCaseSwitchStatement(node)) { | 1746 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1747 return; | 1747 return; |
| 1748 } | 1748 } |
| 1749 | 1749 |
| 1750 JumpTarget next_test(this); | 1750 JumpTarget next_test(this); |
| 1751 JumpTarget fall_through(this); | 1751 JumpTarget fall_through(this); |
| 1752 JumpTarget default_entry(this); | 1752 JumpTarget default_entry(this); |
| 1753 JumpTarget default_exit(this); | 1753 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL); |
| 1754 ZoneList<CaseClause*>* cases = node->cases(); | 1754 ZoneList<CaseClause*>* cases = node->cases(); |
| 1755 int length = cases->length(); | 1755 int length = cases->length(); |
| 1756 CaseClause* default_clause = NULL; | 1756 CaseClause* default_clause = NULL; |
| 1757 | 1757 |
| 1758 for (int i = 0; i < length; i++) { | 1758 for (int i = 0; i < length; i++) { |
| 1759 CaseClause* clause = cases->at(i); | 1759 CaseClause* clause = cases->at(i); |
| 1760 if (clause->is_default()) { | 1760 if (clause->is_default()) { |
| 1761 // Remember the default clause and compile it at the end. | 1761 // Remember the default clause and compile it at the end. |
| 1762 default_clause = clause; | 1762 default_clause = clause; |
| 1763 continue; | 1763 continue; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1831 node->break_target()->Bind(); | 1831 node->break_target()->Bind(); |
| 1832 } | 1832 } |
| 1833 } | 1833 } |
| 1834 | 1834 |
| 1835 | 1835 |
| 1836 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1836 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1837 ASSERT(!in_spilled_code()); | 1837 ASSERT(!in_spilled_code()); |
| 1838 Comment cmnt(masm_, "[ LoopStatement"); | 1838 Comment cmnt(masm_, "[ LoopStatement"); |
| 1839 CodeForStatement(node); | 1839 CodeForStatement(node); |
| 1840 node->set_break_stack_height(break_stack_height_); | 1840 node->set_break_stack_height(break_stack_height_); |
| 1841 node->break_target()->set_code_generator(this); | 1841 node->break_target()->Initialize(this); |
| 1842 node->continue_target()->set_code_generator(this); | |
| 1843 | 1842 |
| 1844 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 1843 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1845 // known result for the test expression, with no side effects. | 1844 // known result for the test expression, with no side effects. |
| 1846 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1845 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1847 if (node->cond() == NULL) { | 1846 if (node->cond() == NULL) { |
| 1848 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1847 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1849 info = ALWAYS_TRUE; | 1848 info = ALWAYS_TRUE; |
| 1850 } else { | 1849 } else { |
| 1851 Literal* lit = node->cond()->AsLiteral(); | 1850 Literal* lit = node->cond()->AsLiteral(); |
| 1852 if (lit != NULL) { | 1851 if (lit != NULL) { |
| 1853 if (lit->IsTrue()) { | 1852 if (lit->IsTrue()) { |
| 1854 info = ALWAYS_TRUE; | 1853 info = ALWAYS_TRUE; |
| 1855 } else if (lit->IsFalse()) { | 1854 } else if (lit->IsFalse()) { |
| 1856 info = ALWAYS_FALSE; | 1855 info = ALWAYS_FALSE; |
| 1857 } | 1856 } |
| 1858 } | 1857 } |
| 1859 } | 1858 } |
| 1860 | 1859 |
| 1861 switch (node->type()) { | 1860 switch (node->type()) { |
| 1862 case LoopStatement::DO_LOOP: { | 1861 case LoopStatement::DO_LOOP: { |
| 1863 JumpTarget body(this); | 1862 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); |
| 1864 IncrementLoopNesting(); | 1863 IncrementLoopNesting(); |
| 1865 | 1864 |
| 1866 // Label the top of the loop for the backward CFG edge. If the test | 1865 // Label the top of the loop for the backward CFG edge. If the test |
| 1867 // is always true we can use the continue target, and if the test is | 1866 // is always true we can use the continue target, and if the test is |
| 1868 // always false there is no need. | 1867 // always false there is no need. |
| 1869 if (info == ALWAYS_TRUE) { | 1868 if (info == ALWAYS_TRUE) { |
| 1869 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 1870 node->continue_target()->Bind(); | 1870 node->continue_target()->Bind(); |
| 1871 } else if (info == ALWAYS_FALSE) { | 1871 } else if (info == ALWAYS_FALSE) { |
| 1872 node->continue_target()->Initialize(this); |
| 1872 // There is no need, we will never jump back. | 1873 // There is no need, we will never jump back. |
| 1873 } else { | 1874 } else { |
| 1874 ASSERT(info == DONT_KNOW); | 1875 ASSERT(info == DONT_KNOW); |
| 1876 node->continue_target()->Initialize(this); |
| 1875 body.Bind(); | 1877 body.Bind(); |
| 1876 } | 1878 } |
| 1877 | 1879 |
| 1878 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1880 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1879 Visit(node->body()); | 1881 Visit(node->body()); |
| 1880 | 1882 |
| 1881 // Compile the test. | 1883 // Compile the test. |
| 1882 if (info == ALWAYS_TRUE) { | 1884 if (info == ALWAYS_TRUE) { |
| 1883 // If control flow can fall off the end of the body, jump back to | 1885 // If control flow can fall off the end of the body, jump back to |
| 1884 // the top. | 1886 // the top. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1907 | 1909 |
| 1908 case LoopStatement::WHILE_LOOP: { | 1910 case LoopStatement::WHILE_LOOP: { |
| 1909 IncrementLoopNesting(); | 1911 IncrementLoopNesting(); |
| 1910 | 1912 |
| 1911 // If the test is never true and has no side effects there is no need | 1913 // If the test is never true and has no side effects there is no need |
| 1912 // to compile the test or body. | 1914 // to compile the test or body. |
| 1913 if (info == ALWAYS_FALSE) break; | 1915 if (info == ALWAYS_FALSE) break; |
| 1914 | 1916 |
| 1915 // Label the top of the loop with the continue target for the backward | 1917 // Label the top of the loop with the continue target for the backward |
| 1916 // CFG edge. | 1918 // CFG edge. |
| 1919 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 1917 node->continue_target()->Bind(); | 1920 node->continue_target()->Bind(); |
| 1918 | 1921 |
| 1919 // If the test is always true and has no side effects there is no need | 1922 // If the test is always true and has no side effects there is no need |
| 1920 // to compile it. We only compile the test when we do not know its | 1923 // to compile it. We only compile the test when we do not know its |
| 1921 // outcome or it may have side effects. | 1924 // outcome or it may have side effects. |
| 1922 if (info == DONT_KNOW) { | 1925 if (info == DONT_KNOW) { |
| 1923 JumpTarget body(this); | 1926 JumpTarget body(this); |
| 1924 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1927 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1925 &body, node->break_target(), true); | 1928 &body, node->break_target(), true); |
| 1926 if (body.is_linked()) { | 1929 if (body.is_linked()) { |
| 1927 body.Bind(); | 1930 body.Bind(); |
| 1928 } | 1931 } |
| 1929 } | 1932 } |
| 1930 | 1933 |
| 1931 if (has_valid_frame()) { | 1934 if (has_valid_frame()) { |
| 1932 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1935 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1933 Visit(node->body()); | 1936 Visit(node->body()); |
| 1934 | 1937 |
| 1935 // If control flow can fall out of the body, jump back to the top. | 1938 // If control flow can fall out of the body, jump back to the top. |
| 1936 if (has_valid_frame()) { | 1939 if (has_valid_frame()) { |
| 1937 node->continue_target()->Jump(); | 1940 node->continue_target()->Jump(); |
| 1938 } | 1941 } |
| 1939 } | 1942 } |
| 1940 break; | 1943 break; |
| 1941 } | 1944 } |
| 1942 | 1945 |
| 1943 case LoopStatement::FOR_LOOP: { | 1946 case LoopStatement::FOR_LOOP: { |
| 1944 JumpTarget loop(this); | 1947 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL); |
| 1945 if (node->init() != NULL) { | 1948 if (node->init() != NULL) { |
| 1946 Visit(node->init()); | 1949 Visit(node->init()); |
| 1947 } | 1950 } |
| 1948 | 1951 |
| 1949 IncrementLoopNesting(); | 1952 IncrementLoopNesting(); |
| 1950 // If the test is never true and has no side effects there is no need | 1953 // If the test is never true and has no side effects there is no need |
| 1951 // to compile the test or body. | 1954 // to compile the test or body. |
| 1952 if (info == ALWAYS_FALSE) break; | 1955 if (info == ALWAYS_FALSE) break; |
| 1953 | 1956 |
| 1954 // Label the top of the loop for the backward CFG edge. If there is | 1957 // Label the top of the loop for the backward CFG edge. If there is |
| 1955 // no update expression we can use the continue target. | 1958 // no update expression we can use the continue target. |
| 1956 if (node->next() == NULL) { | 1959 if (node->next() == NULL) { |
| 1960 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 1957 node->continue_target()->Bind(); | 1961 node->continue_target()->Bind(); |
| 1958 } else { | 1962 } else { |
| 1963 node->continue_target()->Initialize(this); |
| 1959 loop.Bind(); | 1964 loop.Bind(); |
| 1960 } | 1965 } |
| 1961 | 1966 |
| 1962 // If the test is always true and has no side effects there is no need | 1967 // If the test is always true and has no side effects there is no need |
| 1963 // to compile it. We only compile the test when we do not know its | 1968 // to compile it. We only compile the test when we do not know its |
| 1964 // outcome or it has side effects. | 1969 // outcome or it has side effects. |
| 1965 if (info == DONT_KNOW) { | 1970 if (info == DONT_KNOW) { |
| 1966 JumpTarget body(this); | 1971 JumpTarget body(this); |
| 1967 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1972 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1968 &body, node->break_target(), true); | 1973 &body, node->break_target(), true); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2015 VirtualFrame::SpilledScope spilled_scope(this); | 2020 VirtualFrame::SpilledScope spilled_scope(this); |
| 2016 Comment cmnt(masm_, "[ ForInStatement"); | 2021 Comment cmnt(masm_, "[ ForInStatement"); |
| 2017 CodeForStatement(node); | 2022 CodeForStatement(node); |
| 2018 | 2023 |
| 2019 // We keep stuff on the stack while the body is executing. | 2024 // We keep stuff on the stack while the body is executing. |
| 2020 // Record it, so that a break/continue crossing this statement | 2025 // Record it, so that a break/continue crossing this statement |
| 2021 // can restore the stack. | 2026 // can restore the stack. |
| 2022 const int kForInStackSize = 5 * kPointerSize; | 2027 const int kForInStackSize = 5 * kPointerSize; |
| 2023 break_stack_height_ += kForInStackSize; | 2028 break_stack_height_ += kForInStackSize; |
| 2024 node->set_break_stack_height(break_stack_height_); | 2029 node->set_break_stack_height(break_stack_height_); |
| 2025 node->break_target()->set_code_generator(this); | 2030 node->break_target()->Initialize(this); |
| 2026 node->continue_target()->set_code_generator(this); | 2031 node->continue_target()->Initialize(this); |
| 2027 | 2032 |
| 2028 JumpTarget primitive(this); | 2033 JumpTarget primitive(this); |
| 2029 JumpTarget jsobject(this); | 2034 JumpTarget jsobject(this); |
| 2030 JumpTarget fixed_array(this); | 2035 JumpTarget fixed_array(this); |
| 2031 JumpTarget entry(this); | 2036 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL); |
| 2032 JumpTarget end_del_check(this); | 2037 JumpTarget end_del_check(this); |
| 2033 JumpTarget cleanup(this); | 2038 JumpTarget cleanup(this); |
| 2034 JumpTarget exit(this); | 2039 JumpTarget exit(this); |
| 2035 | 2040 |
| 2036 // Get the object to enumerate over (converted to JSObject). | 2041 // Get the object to enumerate over (converted to JSObject). |
| 2037 LoadAndSpill(node->enumerable()); | 2042 LoadAndSpill(node->enumerable()); |
| 2038 | 2043 |
| 2039 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 2044 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 2040 // to the specification. 12.6.4 mandates a call to ToObject. | 2045 // to the specification. 12.6.4 mandates a call to ToObject. |
| 2041 frame_->EmitPop(eax); | 2046 frame_->EmitPop(eax); |
| (...skipping 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3357 // cons strings where the answer is found in the left hand branch of the | 3362 // cons strings where the answer is found in the left hand branch of the |
| 3358 // cons. The slow case will flatten the string, which will ensure that | 3363 // cons. The slow case will flatten the string, which will ensure that |
| 3359 // the answer is in the left hand side the next time around. | 3364 // the answer is in the left hand side the next time around. |
| 3360 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3365 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 3361 ASSERT(args->length() == 2); | 3366 ASSERT(args->length() == 2); |
| 3362 | 3367 |
| 3363 JumpTarget slow_case(this); | 3368 JumpTarget slow_case(this); |
| 3364 JumpTarget end(this); | 3369 JumpTarget end(this); |
| 3365 JumpTarget not_a_flat_string(this); | 3370 JumpTarget not_a_flat_string(this); |
| 3366 JumpTarget not_a_cons_string_either(this); | 3371 JumpTarget not_a_cons_string_either(this); |
| 3367 JumpTarget try_again_with_new_string(this); | 3372 JumpTarget try_again_with_new_string(this, JumpTarget::BIDIRECTIONAL); |
| 3368 JumpTarget ascii_string(this); | 3373 JumpTarget ascii_string(this); |
| 3369 JumpTarget got_char_code(this); | 3374 JumpTarget got_char_code(this); |
| 3370 | 3375 |
| 3371 // Load the string into eax and the index into ebx. | 3376 // Load the string into eax and the index into ebx. |
| 3372 LoadAndSpill(args->at(0)); | 3377 LoadAndSpill(args->at(0)); |
| 3373 LoadAndSpill(args->at(1)); | 3378 LoadAndSpill(args->at(1)); |
| 3374 frame_->EmitPop(ebx); | 3379 frame_->EmitPop(ebx); |
| 3375 frame_->EmitPop(eax); | 3380 frame_->EmitPop(eax); |
| 3376 // If the receiver is a smi return undefined. | 3381 // If the receiver is a smi return undefined. |
| 3377 ASSERT(kSmiTag == 0); | 3382 ASSERT(kSmiTag == 0); |
| (...skipping 2706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6084 | 6089 |
| 6085 // Slow-case: Go through the JavaScript implementation. | 6090 // Slow-case: Go through the JavaScript implementation. |
| 6086 __ bind(&slow); | 6091 __ bind(&slow); |
| 6087 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6092 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6088 } | 6093 } |
| 6089 | 6094 |
| 6090 | 6095 |
| 6091 #undef __ | 6096 #undef __ |
| 6092 | 6097 |
| 6093 } } // namespace v8::internal | 6098 } } // namespace v8::internal |
| OLD | NEW |