| 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 1583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1594 | 1594 |
| 1595 | 1595 |
| 1596 void CodeGenerator::CleanStack(int num_bytes) { | 1596 void CodeGenerator::CleanStack(int num_bytes) { |
| 1597 ASSERT(num_bytes % kPointerSize == 0); | 1597 ASSERT(num_bytes % kPointerSize == 0); |
| 1598 frame_->Drop(num_bytes / kPointerSize); | 1598 frame_->Drop(num_bytes / kPointerSize); |
| 1599 } | 1599 } |
| 1600 | 1600 |
| 1601 | 1601 |
| 1602 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1602 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1603 ASSERT(!in_spilled_code()); | 1603 ASSERT(!in_spilled_code()); |
| 1604 VirtualFrame::SpilledScope spilled_scope(this); | |
| 1605 Comment cmnt(masm_, "[ ContinueStatement"); | 1604 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1606 CodeForStatement(node); | 1605 CodeForStatement(node); |
| 1607 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1606 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1608 node->target()->continue_target()->Jump(); | 1607 node->target()->continue_target()->Jump(); |
| 1609 } | 1608 } |
| 1610 | 1609 |
| 1611 | 1610 |
| 1612 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1611 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1613 ASSERT(!in_spilled_code()); | 1612 ASSERT(!in_spilled_code()); |
| 1614 VirtualFrame::SpilledScope spilled_scope(this); | |
| 1615 Comment cmnt(masm_, "[ BreakStatement"); | 1613 Comment cmnt(masm_, "[ BreakStatement"); |
| 1616 CodeForStatement(node); | 1614 CodeForStatement(node); |
| 1617 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1615 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1618 node->target()->break_target()->Jump(); | 1616 node->target()->break_target()->Jump(); |
| 1619 } | 1617 } |
| 1620 | 1618 |
| 1621 | 1619 |
| 1622 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1620 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1623 ASSERT(!in_spilled_code()); | 1621 ASSERT(!in_spilled_code()); |
| 1624 VirtualFrame::SpilledScope spilled_scope(this); | 1622 VirtualFrame::SpilledScope spilled_scope(this); |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1886 if (lit->IsTrue()) { | 1884 if (lit->IsTrue()) { |
| 1887 info = ALWAYS_TRUE; | 1885 info = ALWAYS_TRUE; |
| 1888 } else if (lit->IsFalse()) { | 1886 } else if (lit->IsFalse()) { |
| 1889 info = ALWAYS_FALSE; | 1887 info = ALWAYS_FALSE; |
| 1890 } | 1888 } |
| 1891 } | 1889 } |
| 1892 } | 1890 } |
| 1893 | 1891 |
| 1894 switch (node->type()) { | 1892 switch (node->type()) { |
| 1895 case LoopStatement::DO_LOOP: { | 1893 case LoopStatement::DO_LOOP: { |
| 1896 // The new code generator does not yet compile do loops. | |
| 1897 VirtualFrame::SpilledScope spilled_scope(this); | |
| 1898 JumpTarget body(this); | 1894 JumpTarget body(this); |
| 1899 IncrementLoopNesting(); | 1895 IncrementLoopNesting(); |
| 1900 // Label the body. | 1896 |
| 1897 // Label the top of the loop for the backward CFG edge. If the test |
| 1898 // is always true we can use the continue target, and if the test is |
| 1899 // always false there is no need. |
| 1901 if (info == ALWAYS_TRUE) { | 1900 if (info == ALWAYS_TRUE) { |
| 1902 node->continue_target()->Bind(); | 1901 node->continue_target()->Bind(); |
| 1903 } else if (info == ALWAYS_FALSE) { | 1902 } else if (info == ALWAYS_FALSE) { |
| 1904 // There is no need, we will never jump back. | 1903 // There is no need, we will never jump back. |
| 1905 } else { | 1904 } else { |
| 1906 ASSERT(info == DONT_KNOW); | 1905 ASSERT(info == DONT_KNOW); |
| 1907 body.Bind(); | 1906 body.Bind(); |
| 1908 } | 1907 } |
| 1908 |
| 1909 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1909 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1910 VisitAndSpill(node->body()); | 1910 Visit(node->body()); |
| 1911 | 1911 |
| 1912 // Compile the "test". | 1912 // Compile the test. |
| 1913 if (info == ALWAYS_TRUE) { | 1913 if (info == ALWAYS_TRUE) { |
| 1914 // If control flow can fall off the end of the body, jump back to |
| 1915 // the top. |
| 1914 if (has_valid_frame()) { | 1916 if (has_valid_frame()) { |
| 1915 // If control flow can fall off the end of the body, jump back to | |
| 1916 // the top. | |
| 1917 node->continue_target()->Jump(); | 1917 node->continue_target()->Jump(); |
| 1918 } | 1918 } |
| 1919 } else if (info == ALWAYS_FALSE) { | 1919 } else if (info == ALWAYS_FALSE) { |
| 1920 // If we have a continue in the body, we only have to bind its jump | 1920 // If we had a continue in the body we have to bind its jump target. |
| 1921 // target. | |
| 1922 if (node->continue_target()->is_linked()) { | 1921 if (node->continue_target()->is_linked()) { |
| 1923 node->continue_target()->Bind(); | 1922 node->continue_target()->Bind(); |
| 1924 } | 1923 } |
| 1925 } else { | 1924 } else { |
| 1926 ASSERT(info == DONT_KNOW); | 1925 ASSERT(info == DONT_KNOW); |
| 1927 // We have to compile the test expression if it can be reached by | 1926 // We have to compile the test expression if it can be reached by |
| 1928 // control flow falling out of the body or via continue. | 1927 // control flow falling out of the body or via continue. |
| 1929 if (has_valid_frame() || node->continue_target()->is_linked()) { | 1928 if (node->continue_target()->is_linked()) { |
| 1930 node->continue_target()->Bind(); | 1929 node->continue_target()->Bind(); |
| 1931 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1930 } |
| 1932 &body, node->break_target(), true); | 1931 if (has_valid_frame()) { |
| 1932 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1933 &body, node->break_target(), true); |
| 1933 // An invalid frame here indicates that control flow did not fall | 1934 // An invalid frame here indicates that control flow did not fall |
| 1934 // out of the test expression. | 1935 // out of the test expression. |
| 1935 if (has_valid_frame()) { | 1936 if (has_valid_frame()) { |
| 1936 Branch(true, &body); | 1937 Branch(true, &body); |
| 1937 } | 1938 } |
| 1938 } | 1939 } |
| 1939 } | 1940 } |
| 1940 break; | 1941 break; |
| 1941 } | 1942 } |
| 1942 | 1943 |
| 1943 case LoopStatement::WHILE_LOOP: { | 1944 case LoopStatement::WHILE_LOOP: { |
| 1944 // The new code generator does not yet compile while loops. | |
| 1945 VirtualFrame::SpilledScope spilled_scope(this); | |
| 1946 JumpTarget body(this); | |
| 1947 IncrementLoopNesting(); | 1945 IncrementLoopNesting(); |
| 1948 // Generate the loop header. | 1946 |
| 1949 if (info == ALWAYS_TRUE) { | 1947 // If the test is never true and has no side effects there is no need |
| 1950 // Merely label the body with the continue target. | 1948 // to compile the test or body. |
| 1951 node->continue_target()->Bind(); | 1949 if (info == ALWAYS_FALSE) break; |
| 1952 } else if (info == ALWAYS_FALSE) { | 1950 |
| 1953 // There is no need to even compile the test or body. | 1951 // Label the top of the loop with the continue target for the backward |
| 1954 break; | 1952 // CFG edge. |
| 1955 } else { | 1953 node->continue_target()->Bind(); |
| 1956 // Compile the test labeled with the continue target and label the | 1954 |
| 1957 // body with the body target. | 1955 // If the test is always true and has no side effects there is no need |
| 1958 ASSERT(info == DONT_KNOW); | 1956 // to compile it. We only compile the test when we do not know its |
| 1959 node->continue_target()->Bind(); | 1957 // outcome or it may have side effects. |
| 1960 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1958 if (info == DONT_KNOW) { |
| 1961 &body, node->break_target(), true); | 1959 JumpTarget body(this); |
| 1960 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1961 &body, node->break_target(), true); |
| 1962 // An invalid frame indicates that control did not fall out of the | 1962 // An invalid frame indicates that control did not fall out of the |
| 1963 // test expression. | 1963 // test expression. |
| 1964 if (has_valid_frame()) { | 1964 if (has_valid_frame()) { |
| 1965 Branch(false, node->break_target()); | 1965 Branch(false, node->break_target()); |
| 1966 } | 1966 } |
| 1967 if (has_valid_frame() || body.is_linked()) { | 1967 if (body.is_linked()) { |
| 1968 body.Bind(); | 1968 body.Bind(); |
| 1969 } | 1969 } |
| 1970 } | 1970 } |
| 1971 |
| 1971 if (has_valid_frame()) { | 1972 if (has_valid_frame()) { |
| 1972 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1973 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1973 VisitAndSpill(node->body()); | 1974 Visit(node->body()); |
| 1974 | 1975 |
| 1975 // If control flow can fall out of the body, jump back to the top. | 1976 // If control flow can fall out of the body, jump back to the top. |
| 1976 if (has_valid_frame()) { | 1977 if (has_valid_frame()) { |
| 1977 node->continue_target()->Jump(); | 1978 node->continue_target()->Jump(); |
| 1978 } | 1979 } |
| 1979 } | 1980 } |
| 1980 break; | 1981 break; |
| 1981 } | 1982 } |
| 1982 | 1983 |
| 1983 case LoopStatement::FOR_LOOP: { | 1984 case LoopStatement::FOR_LOOP: { |
| 1984 JumpTarget loop(this); | 1985 JumpTarget loop(this); |
| 1985 JumpTarget body(this); | |
| 1986 if (node->init() != NULL) { | 1986 if (node->init() != NULL) { |
| 1987 Visit(node->init()); | 1987 Visit(node->init()); |
| 1988 } | 1988 } |
| 1989 | 1989 |
| 1990 IncrementLoopNesting(); | 1990 IncrementLoopNesting(); |
| 1991 // There is no need to compile the test or body. | 1991 // If the test is never true and has no side effects there is no need |
| 1992 // to compile the test or body. |
| 1992 if (info == ALWAYS_FALSE) break; | 1993 if (info == ALWAYS_FALSE) break; |
| 1993 | 1994 |
| 1994 // Label the top of the loop for the backward CFG edge. If there is | 1995 // Label the top of the loop for the backward CFG edge. If there is |
| 1995 // no update expression label it with the continue target, otherwise | 1996 // no update expression we can use the continue target. |
| 1996 // with the loop target. | |
| 1997 if (node->next() == NULL) { | 1997 if (node->next() == NULL) { |
| 1998 node->continue_target()->Bind(); | 1998 node->continue_target()->Bind(); |
| 1999 } else { | 1999 } else { |
| 2000 loop.Bind(); | 2000 loop.Bind(); |
| 2001 } | 2001 } |
| 2002 | 2002 |
| 2003 // If the test is always true, there is no need to compile it. | 2003 // If the test is always true and has no side effects there is no need |
| 2004 // to compile it. We only compile the test when we do not know its |
| 2005 // outcome or it has side effects. |
| 2004 if (info == DONT_KNOW) { | 2006 if (info == DONT_KNOW) { |
| 2007 JumpTarget body(this); |
| 2005 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 2008 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 2006 &body, node->break_target(), true); | 2009 &body, node->break_target(), true); |
| 2007 if (has_valid_frame()) { | 2010 if (has_valid_frame()) { |
| 2008 Branch(false, node->break_target()); | 2011 Branch(false, node->break_target()); |
| 2009 } | 2012 } |
| 2010 if (has_valid_frame() || body.is_linked()) { | 2013 if (body.is_linked()) { |
| 2011 body.Bind(); | 2014 body.Bind(); |
| 2012 } | 2015 } |
| 2013 } | 2016 } |
| 2014 | 2017 |
| 2015 if (has_valid_frame()) { | 2018 if (has_valid_frame()) { |
| 2016 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2019 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2017 Visit(node->body()); | 2020 Visit(node->body()); |
| 2018 | 2021 |
| 2019 if (node->next() == NULL) { | 2022 if (node->next() == NULL) { |
| 2020 // If there is no update statement and control flow can fall out | 2023 // If there is no update statement and control flow can fall out |
| 2021 // of the loop, jump to the continue label. | 2024 // of the loop, jump to the continue label. |
| 2022 if (has_valid_frame()) { | 2025 if (has_valid_frame()) { |
| 2023 node->continue_target()->Jump(); | 2026 node->continue_target()->Jump(); |
| 2024 } | 2027 } |
| 2025 } else { | 2028 } else { |
| 2026 // If there is an update statement and control flow can reach it | 2029 // If there is an update statement and control flow can reach it |
| 2027 // via falling out of the body of the loop or continuing, we | 2030 // via falling out of the body of the loop or continuing, we |
| 2028 // compile the update statement. | 2031 // compile the update statement. |
| 2029 if (has_valid_frame() || node->continue_target()->is_linked()) { | 2032 if (node->continue_target()->is_linked()) { |
| 2030 node->continue_target()->Bind(); | 2033 node->continue_target()->Bind(); |
| 2034 } |
| 2035 if (has_valid_frame()) { |
| 2031 // Record source position of the statement as this code which is | 2036 // Record source position of the statement as this code which is |
| 2032 // after the code for the body actually belongs to the loop | 2037 // after the code for the body actually belongs to the loop |
| 2033 // statement and not the body. | 2038 // statement and not the body. |
| 2034 CodeForStatement(node); | 2039 CodeForStatement(node); |
| 2035 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 2040 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 2036 Visit(node->next()); | 2041 Visit(node->next()); |
| 2037 loop.Jump(); | 2042 loop.Jump(); |
| 2038 } | 2043 } |
| 2039 } | 2044 } |
| 2040 } | 2045 } |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2325 if (nof_unlinks > 0) { | 2330 if (nof_unlinks > 0) { |
| 2326 exit.Jump(); | 2331 exit.Jump(); |
| 2327 } | 2332 } |
| 2328 } | 2333 } |
| 2329 | 2334 |
| 2330 // Generate unlink code for the (formerly) shadowing targets that have been | 2335 // Generate unlink code for the (formerly) shadowing targets that have been |
| 2331 // jumped to. | 2336 // jumped to. |
| 2332 for (int i = 0; i <= nof_escapes; i++) { | 2337 for (int i = 0; i <= nof_escapes; i++) { |
| 2333 if (shadows[i]->is_linked()) { | 2338 if (shadows[i]->is_linked()) { |
| 2334 // Unlink from try chain; be careful not to destroy the TOS. | 2339 // Unlink from try chain; be careful not to destroy the TOS. |
| 2340 // |
| 2341 // Because we can be jumping here (to spilled code) from unspilled |
| 2342 // code, we need to reestablish a spilled frame at this block. |
| 2335 shadows[i]->Bind(); | 2343 shadows[i]->Bind(); |
| 2344 frame_->SpillAll(); |
| 2336 | 2345 |
| 2337 // Reload sp from the top handler, because some statements that we | 2346 // Reload sp from the top handler, because some statements that we |
| 2338 // break from (eg, for...in) may have left stuff on the stack. | 2347 // break from (eg, for...in) may have left stuff on the stack. |
| 2339 __ mov(edx, Operand::StaticVariable(handler_address)); | 2348 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2340 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2349 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2341 StackHandlerConstants::kAddressDisplacement; | 2350 StackHandlerConstants::kAddressDisplacement; |
| 2342 __ lea(esp, Operand(edx, kNextOffset)); | 2351 __ lea(esp, Operand(edx, kNextOffset)); |
| 2343 frame_->Forget(frame_->height() - handler_height); | 2352 frame_->Forget(frame_->height() - handler_height); |
| 2344 | 2353 |
| 2345 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 2354 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2420 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); | 2429 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); |
| 2421 if (nof_unlinks > 0) { | 2430 if (nof_unlinks > 0) { |
| 2422 unlink.Jump(); | 2431 unlink.Jump(); |
| 2423 } | 2432 } |
| 2424 } | 2433 } |
| 2425 | 2434 |
| 2426 // Generate code to set the state for the (formerly) shadowing targets that | 2435 // Generate code to set the state for the (formerly) shadowing targets that |
| 2427 // have been jumped to. | 2436 // have been jumped to. |
| 2428 for (int i = 0; i <= nof_escapes; i++) { | 2437 for (int i = 0; i <= nof_escapes; i++) { |
| 2429 if (shadows[i]->is_linked()) { | 2438 if (shadows[i]->is_linked()) { |
| 2439 // Because we can be jumping here (to spilled code) from unspilled |
| 2440 // code, we need to reestablish a spilled frame at this block. |
| 2430 shadows[i]->Bind(); | 2441 shadows[i]->Bind(); |
| 2442 frame_->SpillAll(); |
| 2431 if (shadows[i]->original_target() == &function_return_) { | 2443 if (shadows[i]->original_target() == &function_return_) { |
| 2432 // If this target shadowed the function return, materialize the | 2444 // If this target shadowed the function return, materialize the |
| 2433 // return value on the stack. | 2445 // return value on the stack. |
| 2434 frame_->EmitPush(eax); | 2446 frame_->EmitPush(eax); |
| 2435 } else { | 2447 } else { |
| 2436 // Fake TOS for targets that shadowed breaks and continues. | 2448 // Fake TOS for targets that shadowed breaks and continues. |
| 2437 frame_->EmitPush(Immediate(Factory::undefined_value())); | 2449 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 2438 } | 2450 } |
| 2439 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); | 2451 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); |
| 2440 unlink.Jump(); | 2452 unlink.Jump(); |
| (...skipping 3344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5785 | 5797 |
| 5786 // Slow-case: Go through the JavaScript implementation. | 5798 // Slow-case: Go through the JavaScript implementation. |
| 5787 __ bind(&slow); | 5799 __ bind(&slow); |
| 5788 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5800 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5789 } | 5801 } |
| 5790 | 5802 |
| 5791 | 5803 |
| 5792 #undef __ | 5804 #undef __ |
| 5793 | 5805 |
| 5794 } } // namespace v8::internal | 5806 } } // namespace v8::internal |
| OLD | NEW |