Chromium Code Reviews| 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 1470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1481 ExternalReference::address_of_stack_guard_limit(); | 1481 ExternalReference::address_of_stack_guard_limit(); |
| 1482 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); | 1482 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); |
| 1483 deferred->enter()->Branch(below, not_taken); | 1483 deferred->enter()->Branch(below, not_taken); |
| 1484 deferred->exit()->Bind(); | 1484 deferred->exit()->Bind(); |
| 1485 } | 1485 } |
| 1486 } | 1486 } |
| 1487 | 1487 |
| 1488 | 1488 |
| 1489 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 1489 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 1490 ASSERT(!in_spilled_code()); | 1490 ASSERT(!in_spilled_code()); |
| 1491 ASSERT(HasValidEntryRegisters()); | |
| 1491 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { | 1492 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { |
| 1492 Visit(statements->at(i)); | 1493 Visit(statements->at(i)); |
| 1493 } | 1494 } |
| 1494 } | 1495 } |
| 1495 | 1496 |
| 1496 | 1497 |
| 1497 void CodeGenerator::VisitBlock(Block* node) { | 1498 void CodeGenerator::VisitBlock(Block* node) { |
| 1498 ASSERT(!in_spilled_code()); | 1499 ASSERT(!in_spilled_code()); |
| 1500 ASSERT(HasValidEntryRegisters()); | |
| 1499 Comment cmnt(masm_, "[ Block"); | 1501 Comment cmnt(masm_, "[ Block"); |
| 1500 CodeForStatementPosition(node); | 1502 CodeForStatementPosition(node); |
| 1501 node->set_break_stack_height(break_stack_height_); | 1503 node->set_break_stack_height(break_stack_height_); |
| 1502 node->break_target()->Initialize(this); | 1504 node->break_target()->Initialize(this); |
| 1503 VisitStatements(node->statements()); | 1505 VisitStatements(node->statements()); |
| 1504 if (node->break_target()->is_linked()) { | 1506 if (node->break_target()->is_linked()) { |
| 1505 node->break_target()->Bind(); | 1507 node->break_target()->Bind(); |
| 1506 } | 1508 } |
| 1507 } | 1509 } |
| 1508 | 1510 |
| 1509 | 1511 |
| 1510 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1512 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1513 ASSERT(HasValidEntryRegisters()); | |
| 1511 frame_->Push(pairs); | 1514 frame_->Push(pairs); |
| 1512 | 1515 |
| 1513 // Duplicate the context register. | 1516 // Duplicate the context register. |
| 1514 Result context(esi, this); | 1517 Result context(esi, this); |
| 1515 frame_->Push(&context); | 1518 frame_->Push(&context); |
| 1516 | 1519 |
| 1517 frame_->Push(Smi::FromInt(is_eval() ? 1 : 0)); | 1520 frame_->Push(Smi::FromInt(is_eval() ? 1 : 0)); |
| 1518 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1521 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1519 // Return value is ignored. | 1522 // Return value is ignored. |
| 1520 } | 1523 } |
| 1521 | 1524 |
| 1522 | 1525 |
| 1523 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1526 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1527 ASSERT(HasValidEntryRegisters()); | |
| 1524 Comment cmnt(masm_, "[ Declaration"); | 1528 Comment cmnt(masm_, "[ Declaration"); |
| 1525 CodeForStatementPosition(node); | 1529 CodeForStatementPosition(node); |
| 1526 Variable* var = node->proxy()->var(); | 1530 Variable* var = node->proxy()->var(); |
| 1527 ASSERT(var != NULL); // must have been resolved | 1531 ASSERT(var != NULL); // must have been resolved |
| 1528 Slot* slot = var->slot(); | 1532 Slot* slot = var->slot(); |
| 1529 | 1533 |
| 1530 // If it was not possible to allocate the variable at compile time, | 1534 // If it was not possible to allocate the variable at compile time, |
| 1531 // we need to "declare" it at runtime to make sure it actually | 1535 // we need to "declare" it at runtime to make sure it actually |
| 1532 // exists in the local context. | 1536 // exists in the local context. |
| 1533 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1537 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1578 // it goes out of scope. | 1582 // it goes out of scope. |
| 1579 } | 1583 } |
| 1580 // Get rid of the assigned value (declarations are statements). | 1584 // Get rid of the assigned value (declarations are statements). |
| 1581 frame_->Drop(); | 1585 frame_->Drop(); |
| 1582 } | 1586 } |
| 1583 } | 1587 } |
| 1584 | 1588 |
| 1585 | 1589 |
| 1586 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1590 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1587 ASSERT(!in_spilled_code()); | 1591 ASSERT(!in_spilled_code()); |
| 1592 ASSERT(HasValidEntryRegisters()); | |
| 1588 Comment cmnt(masm_, "[ ExpressionStatement"); | 1593 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1589 CodeForStatementPosition(node); | 1594 CodeForStatementPosition(node); |
| 1590 Expression* expression = node->expression(); | 1595 Expression* expression = node->expression(); |
| 1591 expression->MarkAsStatement(); | 1596 expression->MarkAsStatement(); |
| 1592 Load(expression); | 1597 Load(expression); |
| 1593 // Remove the lingering expression result from the top of stack. | 1598 // Remove the lingering expression result from the top of stack. |
| 1594 frame_->Drop(); | 1599 frame_->Drop(); |
| 1595 } | 1600 } |
| 1596 | 1601 |
| 1597 | 1602 |
| 1598 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1603 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1599 ASSERT(!in_spilled_code()); | 1604 ASSERT(!in_spilled_code()); |
| 1605 ASSERT(HasValidEntryRegisters()); | |
| 1600 Comment cmnt(masm_, "// EmptyStatement"); | 1606 Comment cmnt(masm_, "// EmptyStatement"); |
| 1601 CodeForStatementPosition(node); | 1607 CodeForStatementPosition(node); |
| 1602 // nothing to do | 1608 // nothing to do |
| 1603 } | 1609 } |
| 1604 | 1610 |
| 1605 | 1611 |
| 1606 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1612 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1607 ASSERT(!in_spilled_code()); | 1613 ASSERT(!in_spilled_code()); |
| 1614 ASSERT(HasValidEntryRegisters()); | |
| 1608 Comment cmnt(masm_, "[ IfStatement"); | 1615 Comment cmnt(masm_, "[ IfStatement"); |
| 1609 // Generate different code depending on which parts of the if statement | 1616 // Generate different code depending on which parts of the if statement |
| 1610 // are present or not. | 1617 // are present or not. |
| 1611 bool has_then_stm = node->HasThenStatement(); | 1618 bool has_then_stm = node->HasThenStatement(); |
| 1612 bool has_else_stm = node->HasElseStatement(); | 1619 bool has_else_stm = node->HasElseStatement(); |
| 1613 | 1620 |
| 1614 CodeForStatementPosition(node); | 1621 CodeForStatementPosition(node); |
| 1615 JumpTarget exit(this); | 1622 JumpTarget exit(this); |
| 1616 if (has_then_stm && has_else_stm) { | 1623 if (has_then_stm && has_else_stm) { |
| 1617 JumpTarget then(this); | 1624 JumpTarget then(this); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1701 | 1708 |
| 1702 | 1709 |
| 1703 void CodeGenerator::CleanStack(int num_bytes) { | 1710 void CodeGenerator::CleanStack(int num_bytes) { |
| 1704 ASSERT(num_bytes % kPointerSize == 0); | 1711 ASSERT(num_bytes % kPointerSize == 0); |
| 1705 frame_->Drop(num_bytes / kPointerSize); | 1712 frame_->Drop(num_bytes / kPointerSize); |
| 1706 } | 1713 } |
| 1707 | 1714 |
| 1708 | 1715 |
| 1709 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1716 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1710 ASSERT(!in_spilled_code()); | 1717 ASSERT(!in_spilled_code()); |
| 1718 ASSERT(HasValidEntryRegisters()); | |
| 1711 Comment cmnt(masm_, "[ ContinueStatement"); | 1719 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1712 CodeForStatementPosition(node); | 1720 CodeForStatementPosition(node); |
| 1713 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1721 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1714 node->target()->continue_target()->Jump(); | 1722 node->target()->continue_target()->Jump(); |
| 1715 } | 1723 } |
| 1716 | 1724 |
| 1717 | 1725 |
| 1718 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1726 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1719 ASSERT(!in_spilled_code()); | 1727 ASSERT(!in_spilled_code()); |
| 1728 ASSERT(HasValidEntryRegisters()); | |
| 1720 Comment cmnt(masm_, "[ BreakStatement"); | 1729 Comment cmnt(masm_, "[ BreakStatement"); |
| 1721 CodeForStatementPosition(node); | 1730 CodeForStatementPosition(node); |
| 1722 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1731 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1723 node->target()->break_target()->Jump(); | 1732 node->target()->break_target()->Jump(); |
| 1724 } | 1733 } |
| 1725 | 1734 |
| 1726 | 1735 |
| 1727 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1736 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1728 ASSERT(!in_spilled_code()); | 1737 ASSERT(!in_spilled_code()); |
| 1738 ASSERT(HasValidEntryRegisters()); | |
| 1729 Comment cmnt(masm_, "[ ReturnStatement"); | 1739 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1730 | 1740 |
| 1731 if (function_return_is_shadowed_) { | 1741 if (function_return_is_shadowed_) { |
| 1732 // If the function return is shadowed, we spill all information | 1742 // If the function return is shadowed, we spill all information |
| 1733 // and just jump to the label. | 1743 // and just jump to the label. |
| 1734 VirtualFrame::SpilledScope spilled_scope(this); | 1744 VirtualFrame::SpilledScope spilled_scope(this); |
| 1735 CodeForStatementPosition(node); | 1745 CodeForStatementPosition(node); |
| 1736 LoadAndSpill(node->expression()); | 1746 LoadAndSpill(node->expression()); |
| 1737 frame_->EmitPop(eax); | 1747 frame_->EmitPop(eax); |
| 1738 function_return_.Jump(); | 1748 function_return_.Jump(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1787 | 1797 |
| 1788 // Check that the size of the code used for returning matches what is | 1798 // Check that the size of the code used for returning matches what is |
| 1789 // expected by the debugger. | 1799 // expected by the debugger. |
| 1790 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1800 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 1791 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1801 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1792 } | 1802 } |
| 1793 | 1803 |
| 1794 | 1804 |
| 1795 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1805 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1796 ASSERT(!in_spilled_code()); | 1806 ASSERT(!in_spilled_code()); |
| 1807 ASSERT(HasValidEntryRegisters()); | |
| 1797 Comment cmnt(masm_, "[ WithEnterStatement"); | 1808 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1798 CodeForStatementPosition(node); | 1809 CodeForStatementPosition(node); |
| 1799 Load(node->expression()); | 1810 Load(node->expression()); |
| 1800 Result context(this); | 1811 Result context(this); |
| 1801 if (node->is_catch_block()) { | 1812 if (node->is_catch_block()) { |
| 1802 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 1813 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); |
| 1803 } else { | 1814 } else { |
| 1804 context = frame_->CallRuntime(Runtime::kPushContext, 1); | 1815 context = frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1805 } | 1816 } |
| 1806 | 1817 |
| 1807 // Update context local. | 1818 // Update context local. |
| 1808 frame_->SaveContextRegister(); | 1819 frame_->SaveContextRegister(); |
| 1809 | 1820 |
| 1810 if (kDebug) { | 1821 if (kDebug) { |
| 1811 JumpTarget verified_true(this); | 1822 JumpTarget verified_true(this); |
| 1812 // Verify that the result of the runtime call and the esi register are | 1823 // Verify that the result of the runtime call and the esi register are |
| 1813 // the same in debug mode. | 1824 // the same in debug mode. |
| 1814 __ cmp(context.reg(), Operand(esi)); | 1825 __ cmp(context.reg(), Operand(esi)); |
| 1815 context.Unuse(); | 1826 context.Unuse(); |
| 1816 verified_true.Branch(equal); | 1827 verified_true.Branch(equal); |
| 1817 frame_->SpillAll(); | 1828 frame_->SpillAll(); |
| 1818 __ int3(); | 1829 __ int3(); |
| 1819 verified_true.Bind(); | 1830 verified_true.Bind(); |
| 1820 } | 1831 } |
| 1821 } | 1832 } |
| 1822 | 1833 |
| 1823 | 1834 |
| 1824 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1835 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1825 ASSERT(!in_spilled_code()); | 1836 ASSERT(!in_spilled_code()); |
| 1837 ASSERT(HasValidEntryRegisters()); | |
| 1826 Comment cmnt(masm_, "[ WithExitStatement"); | 1838 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1827 CodeForStatementPosition(node); | 1839 CodeForStatementPosition(node); |
| 1828 // Pop context. | 1840 // Pop context. |
| 1829 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1841 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 1830 // Update context local. | 1842 // Update context local. |
| 1831 frame_->SaveContextRegister(); | 1843 frame_->SaveContextRegister(); |
| 1832 } | 1844 } |
| 1833 | 1845 |
| 1834 | 1846 |
| 1835 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1847 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1952 __ WriteInternalReference(entry_pos, *case_targets[i]); | 1964 __ WriteInternalReference(entry_pos, *case_targets[i]); |
| 1953 } | 1965 } |
| 1954 } | 1966 } |
| 1955 | 1967 |
| 1956 delete start_frame; | 1968 delete start_frame; |
| 1957 } | 1969 } |
| 1958 | 1970 |
| 1959 | 1971 |
| 1960 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1972 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1961 ASSERT(!in_spilled_code()); | 1973 ASSERT(!in_spilled_code()); |
| 1974 ASSERT(HasValidEntryRegisters()); | |
| 1962 Comment cmnt(masm_, "[ SwitchStatement"); | 1975 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1963 CodeForStatementPosition(node); | 1976 CodeForStatementPosition(node); |
| 1964 node->set_break_stack_height(break_stack_height_); | 1977 node->set_break_stack_height(break_stack_height_); |
| 1965 node->break_target()->Initialize(this); | 1978 node->break_target()->Initialize(this); |
| 1966 | 1979 |
| 1967 Load(node->tag()); | 1980 Load(node->tag()); |
| 1968 if (TryGenerateFastCaseSwitchStatement(node)) { | 1981 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1969 return; | 1982 return; |
| 1970 } | 1983 } |
| 1971 | 1984 |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2093 fall_through.Bind(); | 2106 fall_through.Bind(); |
| 2094 } | 2107 } |
| 2095 if (node->break_target()->is_linked()) { | 2108 if (node->break_target()->is_linked()) { |
| 2096 node->break_target()->Bind(); | 2109 node->break_target()->Bind(); |
| 2097 } | 2110 } |
| 2098 } | 2111 } |
| 2099 | 2112 |
| 2100 | 2113 |
| 2101 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 2114 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 2102 ASSERT(!in_spilled_code()); | 2115 ASSERT(!in_spilled_code()); |
| 2116 ASSERT(HasValidEntryRegisters()); | |
| 2103 Comment cmnt(masm_, "[ LoopStatement"); | 2117 Comment cmnt(masm_, "[ LoopStatement"); |
| 2104 CodeForStatementPosition(node); | 2118 CodeForStatementPosition(node); |
| 2105 node->set_break_stack_height(break_stack_height_); | 2119 node->set_break_stack_height(break_stack_height_); |
| 2106 node->break_target()->Initialize(this); | 2120 node->break_target()->Initialize(this); |
| 2107 | 2121 |
| 2108 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 2122 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 2109 // known result for the test expression, with no side effects. | 2123 // known result for the test expression, with no side effects. |
| 2110 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 2124 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 2111 if (node->cond() == NULL) { | 2125 if (node->cond() == NULL) { |
| 2112 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 2126 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2307 break; | 2321 break; |
| 2308 } | 2322 } |
| 2309 } | 2323 } |
| 2310 | 2324 |
| 2311 DecrementLoopNesting(); | 2325 DecrementLoopNesting(); |
| 2312 } | 2326 } |
| 2313 | 2327 |
| 2314 | 2328 |
| 2315 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 2329 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 2316 ASSERT(!in_spilled_code()); | 2330 ASSERT(!in_spilled_code()); |
| 2317 VirtualFrame::SpilledScope spilled_scope(this); | 2331 ASSERT(HasValidEntryRegisters()); |
| 2318 Comment cmnt(masm_, "[ ForInStatement"); | 2332 Comment cmnt(masm_, "[ ForInStatement"); |
| 2319 CodeForStatementPosition(node); | 2333 CodeForStatementPosition(node); |
| 2320 | 2334 |
| 2321 // We keep stuff on the stack while the body is executing. | 2335 // We keep stuff on the stack while the body is executing. |
| 2322 // Record it, so that a break/continue crossing this statement | 2336 // Record it, so that a break/continue crossing this statement |
| 2323 // can restore the stack. | 2337 // can restore the stack. |
| 2324 const int kForInStackSize = 5 * kPointerSize; | 2338 const int kForInStackSize = 5 * kPointerSize; |
| 2325 break_stack_height_ += kForInStackSize; | 2339 break_stack_height_ += kForInStackSize; |
| 2326 node->set_break_stack_height(break_stack_height_); | 2340 node->set_break_stack_height(break_stack_height_); |
| 2327 node->break_target()->Initialize(this); | 2341 node->break_target()->Initialize(this); |
| 2328 node->continue_target()->Initialize(this); | 2342 node->continue_target()->Initialize(this); |
| 2329 | 2343 |
| 2344 // Stack layout in body (from the top of the frame downward). | |
| 2345 // [iteration counter (smi)] <- element 0 | |
| 2346 // [length of array (smi)] <- element 1 | |
| 2347 // [FixedArray] <- element 2 | |
| 2348 // [Map or 0] <- element 3 | |
| 2349 // [Object being iterated] <- element 4 | |
| 2350 | |
| 2330 JumpTarget primitive(this); | 2351 JumpTarget primitive(this); |
| 2331 JumpTarget jsobject(this); | 2352 JumpTarget jsobject(this); |
| 2332 JumpTarget fixed_array(this); | 2353 JumpTarget fixed_array(this); |
| 2333 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL); | 2354 JumpTarget condition(this, JumpTarget::BIDIRECTIONAL); |
| 2334 JumpTarget end_del_check(this); | 2355 JumpTarget end_del_check(this); |
| 2335 JumpTarget exit(this); | 2356 JumpTarget exit(this); |
| 2336 | 2357 |
| 2337 // Get the object to enumerate over (converted to JSObject). | 2358 // Get the object to iterate over. |
| 2338 LoadAndSpill(node->enumerable()); | 2359 Load(node->enumerable()); |
| 2339 | 2360 |
| 2340 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 2361 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 2341 // to the specification. 12.6.4 mandates a call to ToObject. | 2362 // to the specification. 12.6.4 mandates a call to ToObject. |
| 2342 frame_->EmitPop(eax); | 2363 Result object = frame_->Pop(); |
| 2343 | 2364 object.ToRegister(); |
| 2344 // eax: value to be iterated over | 2365 __ cmp(object.reg(), Factory::undefined_value()); |
| 2345 __ cmp(eax, Factory::undefined_value()); | |
| 2346 exit.Branch(equal); | 2366 exit.Branch(equal); |
| 2347 __ cmp(eax, Factory::null_value()); | 2367 __ cmp(object.reg(), Factory::null_value()); |
| 2348 exit.Branch(equal); | 2368 exit.Branch(equal); |
| 2349 | 2369 |
| 2350 // Stack layout in body: | |
| 2351 // [iteration counter (smi)] <- slot 0 | |
| 2352 // [length of array] <- slot 1 | |
| 2353 // [FixedArray] <- slot 2 | |
| 2354 // [Map or 0] <- slot 3 | |
| 2355 // [Object] <- slot 4 | |
| 2356 | |
| 2357 // Check if enumerable is already a JSObject | 2370 // Check if enumerable is already a JSObject |
| 2358 // eax: value to be iterated over | 2371 __ test(object.reg(), Immediate(kSmiTagMask)); |
| 2359 __ test(eax, Immediate(kSmiTagMask)); | 2372 primitive.Branch(zero, &object); |
| 2360 primitive.Branch(zero); | 2373 |
| 2361 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 2374 // Use a temporary register to check the instance type. |
| 2362 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 2375 Result temp = allocator_->Allocate(); |
| 2363 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 2376 ASSERT(temp.is_valid()); |
| 2364 jsobject.Branch(above_equal); | 2377 __ mov(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); |
| 2365 | 2378 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
| 2366 primitive.Bind(); | 2379 __ cmp(temp.reg(), FIRST_JS_OBJECT_TYPE); |
| 2367 frame_->EmitPush(eax); | 2380 temp.Unuse(); |
| 2368 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); | 2381 jsobject.Branch(above_equal, &object); |
| 2369 // function call returns the value in eax, which is where we want it below | 2382 |
| 2370 | 2383 primitive.Bind(&object); |
| 2371 jsobject.Bind(); | 2384 // Live results: |
| 2385 // object: the object being iterated over | |
| 2386 frame_->Push(&object); | |
| 2387 object = frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); | |
| 2388 | |
| 2389 jsobject.Bind(&object); | |
| 2390 // Live results: | |
| 2391 // object: the object being iterated over | |
| 2372 // Get the set of properties (as a FixedArray or Map). | 2392 // Get the set of properties (as a FixedArray or Map). |
| 2373 // eax: value to be iterated over | 2393 frame_->Push(&object); // Push the object being iterated over (slot 4). |
| 2374 frame_->EmitPush(eax); // push the object being iterated over (slot 4) | 2394 |
| 2375 | 2395 frame_->Dup(); // Duplicate it for the runtime call. |
| 2376 frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call | 2396 Result properties = frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 2377 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 2397 |
| 2378 | 2398 // If we got a Map, we can do a fast modification check. Otherwise, |
| 2379 // If we got a Map, we can do a fast modification check. | 2399 // we got a FixedArray, and we have to do a slow check. Use a fresh |
| 2380 // Otherwise, we got a FixedArray, and we have to do a slow check. | 2400 // temporary register to check the map. |
| 2381 // eax: map or fixed array (result from call to | 2401 temp = allocator_->Allocate(); |
| 2382 // Runtime::kGetPropertyNamesFast) | 2402 ASSERT(temp.is_valid()); |
| 2383 __ mov(edx, Operand(eax)); | 2403 __ mov(temp.reg(), FieldOperand(properties.reg(), HeapObject::kMapOffset)); |
| 2384 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 2404 __ cmp(temp.reg(), Factory::meta_map()); |
| 2385 __ cmp(ecx, Factory::meta_map()); | 2405 // Do not unuse the temp register, we will need one after the branch. |
| 2386 fixed_array.Branch(not_equal); | 2406 fixed_array.Branch(not_equal, &properties); |
| 2387 | 2407 |
| 2388 // Get enum cache | 2408 // Get enum cache. Properties is a map (from the call to |
| 2389 // eax: map (result from call to Runtime::kGetPropertyNamesFast) | 2409 // Runtime::kGetPropertyNamesFast) and temp is a live register |
| 2390 __ mov(ecx, Operand(eax)); | 2410 // reference (distinct from properties). |
| 2391 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); | 2411 __ mov(temp.reg(), |
| 2412 FieldOperand(properties.reg(), Map::kInstanceDescriptorsOffset)); | |
| 2392 // Get the bridge array held in the enumeration index field. | 2413 // Get the bridge array held in the enumeration index field. |
| 2393 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 2414 __ mov(temp.reg(), |
| 2415 FieldOperand(temp.reg(), DescriptorArray::kEnumerationIndexOffset)); | |
| 2394 // Get the cache from the bridge array. | 2416 // Get the cache from the bridge array. |
| 2395 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 2417 __ mov(temp.reg(), |
| 2396 | 2418 FieldOperand(temp.reg(), |
| 2397 frame_->EmitPush(eax); // <- slot 3 | 2419 DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 2398 frame_->EmitPush(edx); // <- slot 2 | 2420 |
| 2399 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); | 2421 frame_->Push(&properties); // <- slot 3 |
| 2400 __ shl(eax, kSmiTagSize); | 2422 // Duplicate the enum cache so we can fetch the length from it. |
| 2401 frame_->EmitPush(eax); // <- slot 1 | 2423 Result cache = temp; |
| 2402 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 | 2424 frame_->Push(&temp); // <- slot 2 |
| 2403 entry.Jump(); | 2425 |
| 2404 | 2426 // Use a fresh temp register to fetch the length. |
| 2405 fixed_array.Bind(); | 2427 temp = allocator_->Allocate(); |
| 2406 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) | 2428 ASSERT(temp.is_valid()); |
| 2407 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 3 | 2429 __ mov(temp.reg(), FieldOperand(cache.reg(), FixedArray::kLengthOffset)); |
| 2408 frame_->EmitPush(eax); // <- slot 2 | 2430 cache.Unuse(); |
| 2409 | 2431 __ shl(temp.reg(), kSmiTagSize); |
| 2410 // Push the length of the array and the initial index onto the stack. | 2432 frame_->Push(&temp); // <- slot 1 |
| 2411 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 2433 frame_->Push(Smi::FromInt(0)); // <- slot 0 |
| 2412 __ shl(eax, kSmiTagSize); | 2434 condition.Jump(); |
| 2413 frame_->EmitPush(eax); // <- slot 1 | 2435 |
| 2414 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 | 2436 fixed_array.Bind(&properties); |
| 2415 | 2437 // Live results: |
| 2416 // Condition. | 2438 // properties: the set of properties as a fixed array (from the call |
| 2417 entry.Bind(); | 2439 // to Runtime::kGetPropertyNamesFast). |
| 2418 __ mov(eax, frame_->ElementAt(0)); // load the current count | 2440 frame_->Push(Smi::FromInt(0)); // <- slot 3 |
| 2419 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length | 2441 // Use a fresh temporary register to fetch the length from the |
| 2442 // properties array. | |
| 2443 temp = allocator_->Allocate(); | |
| 2444 ASSERT(temp.is_valid()); | |
| 2445 properties.ToRegister(); | |
| 2446 __ mov(temp.reg(), | |
| 2447 FieldOperand(properties.reg(), FixedArray::kLengthOffset)); | |
| 2448 __ shl(temp.reg(), kSmiTagSize); | |
| 2449 | |
| 2450 frame_->Push(&properties); // <- slot 2 | |
| 2451 frame_->Push(&temp); // <- slot 1 | |
| 2452 frame_->Push(Smi::FromInt(0)); // <- slot 0 | |
| 2453 | |
| 2454 condition.Bind(); | |
| 2455 // Live results: none. | |
| 2456 // Compare the current count (frame element 0) to the array length | |
| 2457 // (frame element 1). | |
| 2458 frame_->Dup(); | |
| 2459 Result count = frame_->Pop(); | |
| 2460 | |
| 2461 frame_->PushElementAt(1); | |
| 2462 Result length = frame_->Pop(); | |
| 2463 | |
| 2464 count.ToRegister(); | |
| 2465 if (length.is_register()) { | |
| 2466 // Count and length can be the same register, which is OK here. | |
| 2467 __ cmp(count.reg(), Operand(length.reg())); | |
| 2468 } else { | |
| 2469 ASSERT(length.is_constant()); | |
| 2470 __ cmp(count.reg(), length.handle()); | |
| 2471 } | |
| 2472 length.Unuse(); | |
| 2420 node->break_target()->Branch(above_equal); | 2473 node->break_target()->Branch(above_equal); |
| 2421 | 2474 |
| 2422 // Get the i'th entry of the array. | 2475 // Get the i'th entry of the array. |
| 2423 __ mov(edx, frame_->ElementAt(2)); | 2476 frame_->PushElementAt(2); |
| 2424 __ mov(ebx, Operand(edx, eax, times_2, | 2477 Result entry = frame_->Pop(); |
| 2425 FixedArray::kHeaderSize - kHeapObjectTag)); | 2478 entry.ToRegister(); |
| 2426 | 2479 frame_->Spill(entry.reg()); |
| 2427 // Get the expected map from the stack or a zero map in the | 2480 // Entry and count can be the same register. That's OK here because |
| 2428 // permanent slow case eax: current iteration count ebx: i'th entry | 2481 // they will both be absent from the frame after spilling entry and |
| 2429 // of the enum cache | 2482 // count is not needed after being read (before entry is written). |
| 2430 __ mov(edx, frame_->ElementAt(3)); | 2483 __ mov(entry.reg(), Operand(entry.reg(), |
| 2484 count.reg(), | |
| 2485 times_2, | |
| 2486 FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 2487 count.Unuse(); | |
| 2488 | |
| 2431 // Check if the expected map still matches that of the enumerable. | 2489 // Check if the expected map still matches that of the enumerable. |
| 2432 // If not, we have to filter the key. | 2490 // If not, we have to filter the key. |
| 2433 // eax: current iteration count | 2491 |
| 2434 // ebx: i'th entry of the enum cache | 2492 // Begin with the enumerable and fetch its map. |
| 2435 // edx: expected map value | 2493 frame_->PushElementAt(4); |
| 2436 __ mov(ecx, frame_->ElementAt(4)); | 2494 temp = frame_->Pop(); |
| 2437 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 2495 temp.ToRegister(); |
| 2438 __ cmp(ecx, Operand(edx)); | 2496 // We will write to temp. If it is the same register as entry we |
| 2439 end_del_check.Branch(equal); | 2497 // will allocate a fresh register. Otherwise we can just spill it |
| 2498 // from the frame. | |
| 2499 if (temp.reg().is(entry.reg())) { | |
|
William Hesse
2009/02/18 10:33:28
This cannot happen because entry.reg() is spilled
| |
| 2500 Result fresh = allocator_->Allocate(); | |
| 2501 ASSERT(fresh.is_valid()); | |
| 2502 __ mov(fresh.reg(), temp.reg()); | |
| 2503 temp = fresh; | |
| 2504 } else { | |
| 2505 frame_->Spill(temp.reg()); | |
| 2506 } | |
| 2507 __ mov(temp.reg(), FieldOperand(temp.reg(), HeapObject::kMapOffset)); | |
| 2508 | |
| 2509 // Get the expected map from the stack or a zero map in the | |
| 2510 // permanent slow case. | |
| 2511 frame_->PushElementAt(3); | |
| 2512 Result expected_map = frame_->Pop(); | |
| 2513 if (expected_map.is_register()) { | |
| 2514 __ cmp(temp.reg(), Operand(expected_map.reg())); | |
| 2515 } else { | |
| 2516 ASSERT(expected_map.is_constant()); | |
| 2517 __ cmp(temp.reg(), expected_map.handle()); | |
| 2518 } | |
| 2519 expected_map.Unuse(); | |
| 2520 temp.Unuse(); | |
| 2521 end_del_check.Branch(equal, &entry); | |
| 2440 | 2522 |
| 2441 // Convert the entry to a string (or null if it isn't a property anymore). | 2523 // Convert the entry to a string (or null if it isn't a property anymore). |
| 2442 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable | 2524 frame_->PushElementAt(4); // Duplicate the enumerable. |
| 2443 frame_->EmitPush(ebx); // push entry | 2525 frame_->Push(&entry); // Push the entry. |
| 2444 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | 2526 entry = frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
| 2445 __ mov(ebx, Operand(eax)); | |
| 2446 | 2527 |
| 2447 // If the property has been removed while iterating, we just skip it. | 2528 // If the property has been removed while iterating, we just skip it. |
| 2448 __ cmp(ebx, Factory::null_value()); | 2529 __ cmp(entry.reg(), Factory::null_value()); |
| 2449 node->continue_target()->Branch(equal); | 2530 node->continue_target()->Branch(equal); |
| 2450 | 2531 |
| 2451 end_del_check.Bind(); | 2532 end_del_check.Bind(&entry); |
| 2452 // Store the entry in the 'each' expression and take another spin in the | 2533 // Live results: |
| 2453 // loop. edx: i'th entry of the enum cache (or string there of) | 2534 // entry: the i'th entry of the enum cache. |
| 2454 frame_->EmitPush(ebx); | 2535 // Store the entry in the 'each' expression and take another spin in |
| 2536 // the loop. | |
| 2537 // | |
| 2538 // Push the entry before loading the reference, because loading a | |
| 2539 // reference can visit code (requiring all non-reserved registers to | |
| 2540 // be held by the frame). | |
| 2541 frame_->Push(&entry); | |
| 2542 bool entry_was_duplicated = false; | |
| 2455 { Reference each(this, node->each()); | 2543 { Reference each(this, node->each()); |
| 2456 // Loading a reference may leave the frame in an unspilled state. | |
| 2457 frame_->SpillAll(); | |
| 2458 if (!each.is_illegal()) { | 2544 if (!each.is_illegal()) { |
| 2459 if (each.size() > 0) { | 2545 // Duplicate the entry and store to the reference. |
| 2460 frame_->EmitPush(frame_->ElementAt(each.size())); | 2546 frame_->PushElementAt(each.size()); |
| 2461 } | 2547 entry_was_duplicated = true; |
| 2462 // If the reference was to a slot we rely on the convenient property | |
| 2463 // that it doesn't matter whether a value (eg, ebx pushed above) is | |
| 2464 // right on top of or right underneath a zero-sized reference. | |
| 2465 each.SetValue(NOT_CONST_INIT); | 2548 each.SetValue(NOT_CONST_INIT); |
| 2466 if (each.size() > 0) { | |
| 2467 // It's safe to pop the value lying on top of the reference before | |
| 2468 // unloading the reference itself (which preserves the top of stack, | |
| 2469 // ie, now the topmost value of the non-zero sized reference), since | |
| 2470 // we will discard the top of stack after unloading the reference | |
| 2471 // anyway. | |
| 2472 frame_->Drop(); | |
| 2473 } | |
| 2474 } | 2549 } |
| 2475 } | 2550 } |
| 2476 // Unloading a reference may leave the frame in an unspilled state. | 2551 // Discard the i'th entry (and its duplicate if it was duplicated). |
| 2477 frame_->SpillAll(); | 2552 frame_->Drop(entry_was_duplicated ? 2 : 1); |
| 2478 | |
| 2479 // Discard the i'th entry pushed above or else the remainder of the | |
| 2480 // reference, whichever is currently on top of the stack. | |
| 2481 frame_->Drop(); | |
| 2482 | 2553 |
| 2483 // Body. | 2554 // Body. |
| 2484 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2555 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2485 VisitAndSpill(node->body()); | 2556 Visit(node->body()); |
| 2486 | 2557 |
| 2487 // Next. | 2558 // Next. |
| 2488 node->continue_target()->Bind(); | 2559 node->continue_target()->Bind(); |
| 2489 frame_->EmitPop(eax); | 2560 // Live results: none. |
| 2490 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 2561 count = frame_->Pop(); |
| 2491 frame_->EmitPush(eax); | 2562 count.ToRegister(); |
| 2492 entry.Jump(); | 2563 frame_->Spill(count.reg()); |
| 2564 __ add(Operand(count.reg()), Immediate(Smi::FromInt(1))); | |
| 2565 frame_->Push(&count); | |
| 2566 condition.Jump(); | |
| 2493 | 2567 |
| 2494 // Cleanup. | 2568 // Cleanup. |
| 2495 node->break_target()->Bind(); | 2569 node->break_target()->Bind(); |
| 2570 // Live results: none. | |
| 2496 frame_->Drop(5); | 2571 frame_->Drop(5); |
| 2497 | 2572 |
| 2498 // Exit. | 2573 // Exit. |
| 2499 exit.Bind(); | 2574 exit.Bind(); |
| 2500 | 2575 |
| 2501 break_stack_height_ -= kForInStackSize; | 2576 break_stack_height_ -= kForInStackSize; |
| 2502 } | 2577 } |
| 2503 | 2578 |
| 2504 | 2579 |
| 2505 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2580 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2506 ASSERT(!in_spilled_code()); | 2581 ASSERT(!in_spilled_code()); |
| 2582 ASSERT(HasValidEntryRegisters()); | |
| 2507 VirtualFrame::SpilledScope spilled_scope(this); | 2583 VirtualFrame::SpilledScope spilled_scope(this); |
| 2508 Comment cmnt(masm_, "[ TryCatch"); | 2584 Comment cmnt(masm_, "[ TryCatch"); |
| 2509 CodeForStatementPosition(node); | 2585 CodeForStatementPosition(node); |
| 2510 | 2586 |
| 2511 JumpTarget try_block(this); | 2587 JumpTarget try_block(this); |
| 2512 JumpTarget exit(this); | 2588 JumpTarget exit(this); |
| 2513 | 2589 |
| 2514 try_block.Call(); | 2590 try_block.Call(); |
| 2515 // --- Catch block --- | 2591 // --- Catch block --- |
| 2516 frame_->EmitPush(eax); | 2592 frame_->EmitPush(eax); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2626 shadows[i]->other_target()->Jump(); | 2702 shadows[i]->other_target()->Jump(); |
| 2627 } | 2703 } |
| 2628 } | 2704 } |
| 2629 | 2705 |
| 2630 exit.Bind(); | 2706 exit.Bind(); |
| 2631 } | 2707 } |
| 2632 | 2708 |
| 2633 | 2709 |
| 2634 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2710 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2635 ASSERT(!in_spilled_code()); | 2711 ASSERT(!in_spilled_code()); |
| 2712 ASSERT(HasValidEntryRegisters()); | |
| 2636 VirtualFrame::SpilledScope spilled_scope(this); | 2713 VirtualFrame::SpilledScope spilled_scope(this); |
| 2637 Comment cmnt(masm_, "[ TryFinally"); | 2714 Comment cmnt(masm_, "[ TryFinally"); |
| 2638 CodeForStatementPosition(node); | 2715 CodeForStatementPosition(node); |
| 2639 | 2716 |
| 2640 // State: Used to keep track of reason for entering the finally | 2717 // State: Used to keep track of reason for entering the finally |
| 2641 // block. Should probably be extended to hold information for | 2718 // block. Should probably be extended to hold information for |
| 2642 // break/continue from within the try block. | 2719 // break/continue from within the try block. |
| 2643 enum { FALLING, THROWING, JUMPING }; | 2720 enum { FALLING, THROWING, JUMPING }; |
| 2644 | 2721 |
| 2645 JumpTarget unlink(this); | 2722 JumpTarget unlink(this); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2795 frame_->CallRuntime(Runtime::kReThrow, 1); | 2872 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2796 | 2873 |
| 2797 // Done. | 2874 // Done. |
| 2798 exit.Bind(); | 2875 exit.Bind(); |
| 2799 } | 2876 } |
| 2800 } | 2877 } |
| 2801 | 2878 |
| 2802 | 2879 |
| 2803 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2880 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2804 ASSERT(!in_spilled_code()); | 2881 ASSERT(!in_spilled_code()); |
| 2882 ASSERT(HasValidEntryRegisters()); | |
| 2805 Comment cmnt(masm_, "[ DebuggerStatement"); | 2883 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2806 CodeForStatementPosition(node); | 2884 CodeForStatementPosition(node); |
| 2807 // Spill everything, even constants, to the frame. | 2885 // Spill everything, even constants, to the frame. |
| 2808 frame_->SpillAll(); | 2886 frame_->SpillAll(); |
| 2809 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 2887 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2810 // Ignore the return value. | 2888 // Ignore the return value. |
| 2811 } | 2889 } |
| 2812 | 2890 |
| 2813 | 2891 |
| 2814 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2892 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2815 ASSERT(boilerplate->IsBoilerplate()); | 2893 ASSERT(boilerplate->IsBoilerplate()); |
| 2816 | 2894 |
| 2817 // Push the boilerplate on the stack. | 2895 // Push the boilerplate on the stack. |
| 2818 frame_->Push(boilerplate); | 2896 frame_->Push(boilerplate); |
| 2819 | 2897 |
| 2820 // Create a new closure. | 2898 // Create a new closure. |
| 2821 frame_->Push(esi); | 2899 frame_->Push(esi); |
| 2822 Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); | 2900 Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); |
| 2823 frame_->Push(&result); | 2901 frame_->Push(&result); |
| 2824 } | 2902 } |
| 2825 | 2903 |
| 2826 | 2904 |
| 2827 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2905 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2906 ASSERT(HasValidEntryRegisters()); | |
| 2828 Comment cmnt(masm_, "[ FunctionLiteral"); | 2907 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2829 | 2908 |
| 2830 // Build the function boilerplate and instantiate it. | 2909 // Build the function boilerplate and instantiate it. |
| 2831 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2910 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2832 // Check for stack-overflow exception. | 2911 // Check for stack-overflow exception. |
| 2833 if (HasStackOverflow()) return; | 2912 if (HasStackOverflow()) return; |
| 2834 InstantiateBoilerplate(boilerplate); | 2913 InstantiateBoilerplate(boilerplate); |
| 2835 } | 2914 } |
| 2836 | 2915 |
| 2837 | 2916 |
| 2838 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 2917 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2839 FunctionBoilerplateLiteral* node) { | 2918 FunctionBoilerplateLiteral* node) { |
| 2919 ASSERT(HasValidEntryRegisters()); | |
| 2840 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2920 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2841 InstantiateBoilerplate(node->boilerplate()); | 2921 InstantiateBoilerplate(node->boilerplate()); |
| 2842 } | 2922 } |
| 2843 | 2923 |
| 2844 | 2924 |
| 2845 void CodeGenerator::VisitConditional(Conditional* node) { | 2925 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2926 ASSERT(HasValidEntryRegisters()); | |
| 2846 Comment cmnt(masm_, "[ Conditional"); | 2927 Comment cmnt(masm_, "[ Conditional"); |
| 2847 JumpTarget then(this); | 2928 JumpTarget then(this); |
| 2848 JumpTarget else_(this); | 2929 JumpTarget else_(this); |
| 2849 JumpTarget exit(this); | 2930 JumpTarget exit(this); |
| 2850 ControlDestination dest(&then, &else_, true); | 2931 ControlDestination dest(&then, &else_, true); |
| 2851 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 2932 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); |
| 2852 | 2933 |
| 2853 if (dest.false_was_fall_through()) { | 2934 if (dest.false_was_fall_through()) { |
| 2854 // The else target was bound, so we compile the else part first. | 2935 // The else target was bound, so we compile the else part first. |
| 2855 Load(node->else_expression(), typeof_state()); | 2936 Load(node->else_expression(), typeof_state()); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3017 // The results start, value, and temp are unused by going out of | 3098 // The results start, value, and temp are unused by going out of |
| 3018 // scope. | 3099 // scope. |
| 3019 } | 3100 } |
| 3020 | 3101 |
| 3021 exit.Bind(); | 3102 exit.Bind(); |
| 3022 } | 3103 } |
| 3023 } | 3104 } |
| 3024 | 3105 |
| 3025 | 3106 |
| 3026 void CodeGenerator::VisitSlot(Slot* node) { | 3107 void CodeGenerator::VisitSlot(Slot* node) { |
| 3108 ASSERT(HasValidEntryRegisters()); | |
| 3027 Comment cmnt(masm_, "[ Slot"); | 3109 Comment cmnt(masm_, "[ Slot"); |
| 3028 LoadFromSlot(node, typeof_state()); | 3110 LoadFromSlot(node, typeof_state()); |
| 3029 } | 3111 } |
| 3030 | 3112 |
| 3031 | 3113 |
| 3032 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 3114 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 3115 ASSERT(HasValidEntryRegisters()); | |
| 3033 Comment cmnt(masm_, "[ VariableProxy"); | 3116 Comment cmnt(masm_, "[ VariableProxy"); |
| 3034 Variable* var = node->var(); | 3117 Variable* var = node->var(); |
| 3035 Expression* expr = var->rewrite(); | 3118 Expression* expr = var->rewrite(); |
| 3036 if (expr != NULL) { | 3119 if (expr != NULL) { |
| 3037 Visit(expr); | 3120 Visit(expr); |
| 3038 } else { | 3121 } else { |
| 3039 ASSERT(var->is_global()); | 3122 ASSERT(var->is_global()); |
| 3040 Reference ref(this, node); | 3123 Reference ref(this, node); |
| 3041 ref.GetValue(typeof_state()); | 3124 ref.GetValue(typeof_state()); |
| 3042 } | 3125 } |
| 3043 } | 3126 } |
| 3044 | 3127 |
| 3045 | 3128 |
| 3046 void CodeGenerator::VisitLiteral(Literal* node) { | 3129 void CodeGenerator::VisitLiteral(Literal* node) { |
| 3130 ASSERT(HasValidEntryRegisters()); | |
| 3047 Comment cmnt(masm_, "[ Literal"); | 3131 Comment cmnt(masm_, "[ Literal"); |
| 3048 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 3132 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
| 3049 // To prevent long attacker-controlled byte sequences in code, larger | 3133 // To prevent long attacker-controlled byte sequences in code, larger |
| 3050 // Smis are loaded in two steps via a temporary register. | 3134 // Smis are loaded in two steps via a temporary register. |
| 3051 Result temp = allocator_->Allocate(); | 3135 Result temp = allocator_->Allocate(); |
| 3052 ASSERT(temp.is_valid()); | 3136 ASSERT(temp.is_valid()); |
| 3053 int bits = reinterpret_cast<int>(*node->handle()); | 3137 int bits = reinterpret_cast<int>(*node->handle()); |
| 3054 __ Set(temp.reg(), Immediate(bits & 0x0000FFFF)); | 3138 __ Set(temp.reg(), Immediate(bits & 0x0000FFFF)); |
| 3055 __ xor_(temp.reg(), bits & 0xFFFF0000); | 3139 __ xor_(temp.reg(), bits & 0xFFFF0000); |
| 3056 frame_->Push(&temp); | 3140 frame_->Push(&temp); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3089 frame->Push(node_->pattern()); | 3173 frame->Push(node_->pattern()); |
| 3090 // RegExp flags (3). | 3174 // RegExp flags (3). |
| 3091 frame->Push(node_->flags()); | 3175 frame->Push(node_->flags()); |
| 3092 Result boilerplate = | 3176 Result boilerplate = |
| 3093 frame->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 3177 frame->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 3094 exit()->Jump(&boilerplate); | 3178 exit()->Jump(&boilerplate); |
| 3095 } | 3179 } |
| 3096 | 3180 |
| 3097 | 3181 |
| 3098 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 3182 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 3183 ASSERT(HasValidEntryRegisters()); | |
| 3099 Comment cmnt(masm_, "[ RegExp Literal"); | 3184 Comment cmnt(masm_, "[ RegExp Literal"); |
| 3100 DeferredRegExpLiteral* deferred = new DeferredRegExpLiteral(this, node); | 3185 DeferredRegExpLiteral* deferred = new DeferredRegExpLiteral(this, node); |
| 3101 | 3186 |
| 3102 // Retrieve the literals array and check the allocated entry. Begin | 3187 // Retrieve the literals array and check the allocated entry. Begin |
| 3103 // with a writable copy of the function of this activation in a | 3188 // with a writable copy of the function of this activation in a |
| 3104 // register. | 3189 // register. |
| 3105 frame_->PushFunction(); | 3190 frame_->PushFunction(); |
| 3106 Result literals = frame_->Pop(); | 3191 Result literals = frame_->Pop(); |
| 3107 literals.ToRegister(); | 3192 literals.ToRegister(); |
| 3108 frame_->Spill(literals.reg()); | 3193 frame_->Spill(literals.reg()); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3164 frame->Push(Smi::FromInt(node_->literal_index())); | 3249 frame->Push(Smi::FromInt(node_->literal_index())); |
| 3165 // Constant properties (2). | 3250 // Constant properties (2). |
| 3166 frame->Push(node_->constant_properties()); | 3251 frame->Push(node_->constant_properties()); |
| 3167 Result boilerplate = | 3252 Result boilerplate = |
| 3168 frame->CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 3253 frame->CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
| 3169 exit()->Jump(&boilerplate); | 3254 exit()->Jump(&boilerplate); |
| 3170 } | 3255 } |
| 3171 | 3256 |
| 3172 | 3257 |
| 3173 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 3258 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 3259 ASSERT(HasValidEntryRegisters()); | |
| 3174 Comment cmnt(masm_, "[ ObjectLiteral"); | 3260 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 3175 DeferredObjectLiteral* deferred = new DeferredObjectLiteral(this, node); | 3261 DeferredObjectLiteral* deferred = new DeferredObjectLiteral(this, node); |
| 3176 | 3262 |
| 3177 // Retrieve the literals array and check the allocated entry. Begin | 3263 // Retrieve the literals array and check the allocated entry. Begin |
| 3178 // with a writable copy of the function of this activation in a | 3264 // with a writable copy of the function of this activation in a |
| 3179 // register. | 3265 // register. |
| 3180 frame_->PushFunction(); | 3266 frame_->PushFunction(); |
| 3181 Result literals = frame_->Pop(); | 3267 Result literals = frame_->Pop(); |
| 3182 literals.ToRegister(); | 3268 literals.ToRegister(); |
| 3183 frame_->Spill(literals.reg()); | 3269 frame_->Spill(literals.reg()); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3265 // Ignore the result. | 3351 // Ignore the result. |
| 3266 break; | 3352 break; |
| 3267 } | 3353 } |
| 3268 default: UNREACHABLE(); | 3354 default: UNREACHABLE(); |
| 3269 } | 3355 } |
| 3270 } | 3356 } |
| 3271 } | 3357 } |
| 3272 | 3358 |
| 3273 | 3359 |
| 3274 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 3360 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 3361 ASSERT(HasValidEntryRegisters()); | |
| 3275 Comment cmnt(masm_, "[ ArrayLiteral"); | 3362 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 3276 | 3363 |
| 3277 // Call the runtime to create the array literal. | 3364 // Call the runtime to create the array literal. |
| 3278 frame_->Push(node->literals()); | 3365 frame_->Push(node->literals()); |
| 3279 // Load the literals array of the current function. | 3366 // Load the literals array of the current function. |
| 3280 frame_->PushFunction(); | 3367 frame_->PushFunction(); |
| 3281 Result literals = frame_->Pop(); | 3368 Result literals = frame_->Pop(); |
| 3282 literals.ToRegister(); | 3369 literals.ToRegister(); |
| 3283 frame_->Spill(literals.reg()); // Make it writable. | 3370 frame_->Spill(literals.reg()); // Make it writable. |
| 3284 __ mov(literals.reg(), | 3371 __ mov(literals.reg(), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3323 Result scratch = allocator_->Allocate(); | 3410 Result scratch = allocator_->Allocate(); |
| 3324 ASSERT(scratch.is_valid()); | 3411 ASSERT(scratch.is_valid()); |
| 3325 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); | 3412 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); |
| 3326 } | 3413 } |
| 3327 } | 3414 } |
| 3328 } | 3415 } |
| 3329 | 3416 |
| 3330 | 3417 |
| 3331 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { | 3418 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { |
| 3332 ASSERT(!in_spilled_code()); | 3419 ASSERT(!in_spilled_code()); |
| 3420 ASSERT(HasValidEntryRegisters()); | |
| 3333 // Call runtime routine to allocate the catch extension object and | 3421 // Call runtime routine to allocate the catch extension object and |
| 3334 // assign the exception value to the catch variable. | 3422 // assign the exception value to the catch variable. |
| 3335 Comment cmnt(masm_, "[ CatchExtensionObject"); | 3423 Comment cmnt(masm_, "[ CatchExtensionObject"); |
| 3336 Load(node->key()); | 3424 Load(node->key()); |
| 3337 Load(node->value()); | 3425 Load(node->value()); |
| 3338 Result result = | 3426 Result result = |
| 3339 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); | 3427 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); |
| 3340 frame_->Push(&result); | 3428 frame_->Push(&result); |
| 3341 } | 3429 } |
| 3342 | 3430 |
| 3343 | 3431 |
| 3344 bool CodeGenerator::IsInlineSmi(Literal* literal) { | 3432 bool CodeGenerator::IsInlineSmi(Literal* literal) { |
| 3345 if (literal == NULL || !literal->handle()->IsSmi()) return false; | 3433 if (literal == NULL || !literal->handle()->IsSmi()) return false; |
| 3346 int int_value = Smi::cast(*literal->handle())->value(); | 3434 int int_value = Smi::cast(*literal->handle())->value(); |
| 3347 return is_intn(int_value, kMaxSmiInlinedBits); | 3435 return is_intn(int_value, kMaxSmiInlinedBits); |
| 3348 } | 3436 } |
| 3349 | 3437 |
| 3350 | 3438 |
| 3351 void CodeGenerator::VisitAssignment(Assignment* node) { | 3439 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 3440 ASSERT(HasValidEntryRegisters()); | |
| 3352 Comment cmnt(masm_, "[ Assignment"); | 3441 Comment cmnt(masm_, "[ Assignment"); |
| 3353 CodeForStatementPosition(node); | 3442 CodeForStatementPosition(node); |
| 3354 | 3443 |
| 3355 { Reference target(this, node->target()); | 3444 { Reference target(this, node->target()); |
| 3356 if (target.is_illegal()) { | 3445 if (target.is_illegal()) { |
| 3357 // Fool the virtual frame into thinking that we left the assignment's | 3446 // Fool the virtual frame into thinking that we left the assignment's |
| 3358 // value on the frame. | 3447 // value on the frame. |
| 3359 frame_->Push(Smi::FromInt(0)); | 3448 frame_->Push(Smi::FromInt(0)); |
| 3360 return; | 3449 return; |
| 3361 } | 3450 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3400 target.SetValue(CONST_INIT); | 3489 target.SetValue(CONST_INIT); |
| 3401 } else { | 3490 } else { |
| 3402 target.SetValue(NOT_CONST_INIT); | 3491 target.SetValue(NOT_CONST_INIT); |
| 3403 } | 3492 } |
| 3404 } | 3493 } |
| 3405 } | 3494 } |
| 3406 } | 3495 } |
| 3407 | 3496 |
| 3408 | 3497 |
| 3409 void CodeGenerator::VisitThrow(Throw* node) { | 3498 void CodeGenerator::VisitThrow(Throw* node) { |
| 3499 ASSERT(HasValidEntryRegisters()); | |
| 3410 Comment cmnt(masm_, "[ Throw"); | 3500 Comment cmnt(masm_, "[ Throw"); |
| 3411 CodeForStatementPosition(node); | 3501 CodeForStatementPosition(node); |
| 3412 | 3502 |
| 3413 Load(node->exception()); | 3503 Load(node->exception()); |
| 3414 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 3504 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
| 3415 frame_->Push(&result); | 3505 frame_->Push(&result); |
| 3416 } | 3506 } |
| 3417 | 3507 |
| 3418 | 3508 |
| 3419 void CodeGenerator::VisitProperty(Property* node) { | 3509 void CodeGenerator::VisitProperty(Property* node) { |
| 3510 ASSERT(HasValidEntryRegisters()); | |
| 3420 Comment cmnt(masm_, "[ Property"); | 3511 Comment cmnt(masm_, "[ Property"); |
| 3421 Reference property(this, node); | 3512 Reference property(this, node); |
| 3422 property.GetValue(typeof_state()); | 3513 property.GetValue(typeof_state()); |
| 3423 } | 3514 } |
| 3424 | 3515 |
| 3425 | 3516 |
| 3426 void CodeGenerator::VisitCall(Call* node) { | 3517 void CodeGenerator::VisitCall(Call* node) { |
| 3518 ASSERT(HasValidEntryRegisters()); | |
| 3427 Comment cmnt(masm_, "[ Call"); | 3519 Comment cmnt(masm_, "[ Call"); |
| 3428 | 3520 |
| 3429 ZoneList<Expression*>* args = node->arguments(); | 3521 ZoneList<Expression*>* args = node->arguments(); |
| 3430 | 3522 |
| 3431 CodeForStatementPosition(node); | 3523 CodeForStatementPosition(node); |
| 3432 | 3524 |
| 3433 // Check if the function is a variable or a property. | 3525 // Check if the function is a variable or a property. |
| 3434 Expression* function = node->expression(); | 3526 Expression* function = node->expression(); |
| 3435 Variable* var = function->AsVariableProxy()->AsVariable(); | 3527 Variable* var = function->AsVariableProxy()->AsVariable(); |
| 3436 Property* property = function->AsProperty(); | 3528 Property* property = function->AsProperty(); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3556 // Pass the global proxy as the receiver. | 3648 // Pass the global proxy as the receiver. |
| 3557 LoadGlobalReceiver(); | 3649 LoadGlobalReceiver(); |
| 3558 | 3650 |
| 3559 // Call the function. | 3651 // Call the function. |
| 3560 CallWithArguments(args, node->position()); | 3652 CallWithArguments(args, node->position()); |
| 3561 } | 3653 } |
| 3562 } | 3654 } |
| 3563 | 3655 |
| 3564 | 3656 |
| 3565 void CodeGenerator::VisitCallNew(CallNew* node) { | 3657 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 3658 ASSERT(HasValidEntryRegisters()); | |
| 3566 Comment cmnt(masm_, "[ CallNew"); | 3659 Comment cmnt(masm_, "[ CallNew"); |
| 3567 CodeForStatementPosition(node); | 3660 CodeForStatementPosition(node); |
| 3568 | 3661 |
| 3569 // According to ECMA-262, section 11.2.2, page 44, the function | 3662 // According to ECMA-262, section 11.2.2, page 44, the function |
| 3570 // expression in new calls must be evaluated before the | 3663 // expression in new calls must be evaluated before the |
| 3571 // arguments. This is different from ordinary calls, where the | 3664 // arguments. This is different from ordinary calls, where the |
| 3572 // actual function to call is resolved after the arguments have been | 3665 // actual function to call is resolved after the arguments have been |
| 3573 // evaluated. | 3666 // evaluated. |
| 3574 | 3667 |
| 3575 // Compute function to call and use the global object as the | 3668 // Compute function to call and use the global object as the |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3608 &num_args, | 3701 &num_args, |
| 3609 &function, | 3702 &function, |
| 3610 arg_count + 1); | 3703 arg_count + 1); |
| 3611 | 3704 |
| 3612 // Replace the function on the stack with the result. | 3705 // Replace the function on the stack with the result. |
| 3613 frame_->SetElementAt(0, &result); | 3706 frame_->SetElementAt(0, &result); |
| 3614 } | 3707 } |
| 3615 | 3708 |
| 3616 | 3709 |
| 3617 void CodeGenerator::VisitCallEval(CallEval* node) { | 3710 void CodeGenerator::VisitCallEval(CallEval* node) { |
| 3711 ASSERT(HasValidEntryRegisters()); | |
| 3618 Comment cmnt(masm_, "[ CallEval"); | 3712 Comment cmnt(masm_, "[ CallEval"); |
| 3619 | 3713 |
| 3620 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve | 3714 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve |
| 3621 // the function we need to call and the receiver of the call. | 3715 // the function we need to call and the receiver of the call. |
| 3622 // Then we call the resolved function using the given arguments. | 3716 // Then we call the resolved function using the given arguments. |
| 3623 | 3717 |
| 3624 ZoneList<Expression*>* args = node->arguments(); | 3718 ZoneList<Expression*>* args = node->arguments(); |
| 3625 Expression* function = node->expression(); | 3719 Expression* function = node->expression(); |
| 3626 | 3720 |
| 3627 CodeForStatementPosition(node); | 3721 CodeForStatementPosition(node); |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3995 right.ToRegister(); | 4089 right.ToRegister(); |
| 3996 left.ToRegister(); | 4090 left.ToRegister(); |
| 3997 __ cmp(right.reg(), Operand(left.reg())); | 4091 __ cmp(right.reg(), Operand(left.reg())); |
| 3998 right.Unuse(); | 4092 right.Unuse(); |
| 3999 left.Unuse(); | 4093 left.Unuse(); |
| 4000 destination()->Split(equal); | 4094 destination()->Split(equal); |
| 4001 } | 4095 } |
| 4002 | 4096 |
| 4003 | 4097 |
| 4004 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 4098 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 4099 ASSERT(HasValidEntryRegisters()); | |
| 4005 if (CheckForInlineRuntimeCall(node)) { | 4100 if (CheckForInlineRuntimeCall(node)) { |
| 4006 return; | 4101 return; |
| 4007 } | 4102 } |
| 4008 | 4103 |
| 4009 ZoneList<Expression*>* args = node->arguments(); | 4104 ZoneList<Expression*>* args = node->arguments(); |
| 4010 Comment cmnt(masm_, "[ CallRuntime"); | 4105 Comment cmnt(masm_, "[ CallRuntime"); |
| 4011 Runtime::Function* function = node->function(); | 4106 Runtime::Function* function = node->function(); |
| 4012 | 4107 |
| 4013 if (function == NULL) { | 4108 if (function == NULL) { |
| 4014 // Prepare stack for calling JS runtime function. | 4109 // Prepare stack for calling JS runtime function. |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 4040 frame_->SetElementAt(0, &answer); | 4135 frame_->SetElementAt(0, &answer); |
| 4041 } else { | 4136 } else { |
| 4042 // Call the C runtime function. | 4137 // Call the C runtime function. |
| 4043 Result answer = frame_->CallRuntime(function, arg_count); | 4138 Result answer = frame_->CallRuntime(function, arg_count); |
| 4044 frame_->Push(&answer); | 4139 frame_->Push(&answer); |
| 4045 } | 4140 } |
| 4046 } | 4141 } |
| 4047 | 4142 |
| 4048 | 4143 |
| 4049 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 4144 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 4145 ASSERT(HasValidEntryRegisters()); | |
| 4050 // Note that because of NOT and an optimization in comparison of a typeof | 4146 // Note that because of NOT and an optimization in comparison of a typeof |
| 4051 // expression to a literal string, this function can fail to leave a value | 4147 // expression to a literal string, this function can fail to leave a value |
| 4052 // on top of the frame or in the cc register. | 4148 // on top of the frame or in the cc register. |
| 4053 Comment cmnt(masm_, "[ UnaryOperation"); | 4149 Comment cmnt(masm_, "[ UnaryOperation"); |
| 4054 | 4150 |
| 4055 Token::Value op = node->op(); | 4151 Token::Value op = node->op(); |
| 4056 | 4152 |
| 4057 if (op == Token::NOT) { | 4153 if (op == Token::NOT) { |
| 4058 // Swap the true and false targets but keep the same actual label | 4154 // Swap the true and false targets but keep the same actual label |
| 4059 // as the fall through. | 4155 // as the fall through. |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4272 value = generator()->frame()->CallStub(&to_number_stub, &value, 0); | 4368 value = generator()->frame()->CallStub(&to_number_stub, &value, 0); |
| 4273 } | 4369 } |
| 4274 | 4370 |
| 4275 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); | 4371 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); |
| 4276 value = generator()->frame()->CallStub(&stub, &value, 0); | 4372 value = generator()->frame()->CallStub(&stub, &value, 0); |
| 4277 exit()->Jump(&value); | 4373 exit()->Jump(&value); |
| 4278 } | 4374 } |
| 4279 | 4375 |
| 4280 | 4376 |
| 4281 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 4377 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 4378 ASSERT(HasValidEntryRegisters()); | |
| 4282 Comment cmnt(masm_, "[ CountOperation"); | 4379 Comment cmnt(masm_, "[ CountOperation"); |
| 4283 | 4380 |
| 4284 bool is_postfix = node->is_postfix(); | 4381 bool is_postfix = node->is_postfix(); |
| 4285 bool is_increment = node->op() == Token::INC; | 4382 bool is_increment = node->op() == Token::INC; |
| 4286 | 4383 |
| 4287 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 4384 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 4288 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 4385 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 4289 | 4386 |
| 4290 // Postfix: Make room for the result. | 4387 // Postfix: Make room for the result. |
| 4291 if (is_postfix) { | 4388 if (is_postfix) { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4368 } | 4465 } |
| 4369 | 4466 |
| 4370 // Postfix: Discard the new value and use the old. | 4467 // Postfix: Discard the new value and use the old. |
| 4371 if (is_postfix) { | 4468 if (is_postfix) { |
| 4372 frame_->Drop(); | 4469 frame_->Drop(); |
| 4373 } | 4470 } |
| 4374 } | 4471 } |
| 4375 | 4472 |
| 4376 | 4473 |
| 4377 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 4474 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 4475 ASSERT(HasValidEntryRegisters()); | |
| 4378 // Note that due to an optimization in comparison operations (typeof | 4476 // Note that due to an optimization in comparison operations (typeof |
| 4379 // compared to a string literal), we can evaluate a binary expression such | 4477 // compared to a string literal), we can evaluate a binary expression such |
| 4380 // as AND or OR and not leave a value on the frame or in the cc register. | 4478 // as AND or OR and not leave a value on the frame or in the cc register. |
| 4381 Comment cmnt(masm_, "[ BinaryOperation"); | 4479 Comment cmnt(masm_, "[ BinaryOperation"); |
| 4382 Token::Value op = node->op(); | 4480 Token::Value op = node->op(); |
| 4383 | 4481 |
| 4384 // According to ECMA-262 section 11.11, page 58, the binary logical | 4482 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 4385 // operators must yield the result of one of the two expressions | 4483 // operators must yield the result of one of the two expressions |
| 4386 // before any ToBoolean() conversions. This means that the value | 4484 // before any ToBoolean() conversions. This means that the value |
| 4387 // produced by a && or || operator is not necessarily a boolean. | 4485 // produced by a && or || operator is not necessarily a boolean. |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4510 } else { | 4608 } else { |
| 4511 Load(node->left()); | 4609 Load(node->left()); |
| 4512 Load(node->right()); | 4610 Load(node->right()); |
| 4513 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); | 4611 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
| 4514 } | 4612 } |
| 4515 } | 4613 } |
| 4516 } | 4614 } |
| 4517 | 4615 |
| 4518 | 4616 |
| 4519 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 4617 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 4618 ASSERT(HasValidEntryRegisters()); | |
| 4520 frame_->PushFunction(); | 4619 frame_->PushFunction(); |
| 4521 } | 4620 } |
| 4522 | 4621 |
| 4523 | 4622 |
| 4524 class InstanceofStub: public CodeStub { | 4623 class InstanceofStub: public CodeStub { |
| 4525 public: | 4624 public: |
| 4526 InstanceofStub() { } | 4625 InstanceofStub() { } |
| 4527 | 4626 |
| 4528 void Generate(MacroAssembler* masm); | 4627 void Generate(MacroAssembler* masm); |
| 4529 | 4628 |
| 4530 private: | 4629 private: |
| 4531 Major MajorKey() { return Instanceof; } | 4630 Major MajorKey() { return Instanceof; } |
| 4532 int MinorKey() { return 0; } | 4631 int MinorKey() { return 0; } |
| 4533 }; | 4632 }; |
| 4534 | 4633 |
| 4535 | 4634 |
| 4536 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 4635 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 4636 ASSERT(HasValidEntryRegisters()); | |
| 4537 Comment cmnt(masm_, "[ CompareOperation"); | 4637 Comment cmnt(masm_, "[ CompareOperation"); |
| 4538 | 4638 |
| 4539 // Get the expressions from the node. | 4639 // Get the expressions from the node. |
| 4540 Expression* left = node->left(); | 4640 Expression* left = node->left(); |
| 4541 Expression* right = node->right(); | 4641 Expression* right = node->right(); |
| 4542 Token::Value op = node->op(); | 4642 Token::Value op = node->op(); |
| 4543 | 4643 |
| 4544 // To make null checks efficient, we check if either left or right is the | 4644 // To make null checks efficient, we check if either left or right is the |
| 4545 // literal 'null'. If so, we optimize the code by inlining a null check | 4645 // literal 'null'. If so, we optimize the code by inlining a null check |
| 4546 // instead of calling the (very) general runtime routine for checking | 4646 // instead of calling the (very) general runtime routine for checking |
| (...skipping 2008 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6555 | 6655 |
| 6556 // Slow-case: Go through the JavaScript implementation. | 6656 // Slow-case: Go through the JavaScript implementation. |
| 6557 __ bind(&slow); | 6657 __ bind(&slow); |
| 6558 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6658 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6559 } | 6659 } |
| 6560 | 6660 |
| 6561 | 6661 |
| 6562 #undef __ | 6662 #undef __ |
| 6563 | 6663 |
| 6564 } } // namespace v8::internal | 6664 } } // namespace v8::internal |
| OLD | NEW |