| 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 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 | 119 |
| 120 | 120 |
| 121 // Calling conventions: | 121 // Calling conventions: |
| 122 // ebp: frame pointer | 122 // ebp: frame pointer |
| 123 // esp: stack pointer | 123 // esp: stack pointer |
| 124 // edi: caller's parameter pointer | 124 // edi: caller's parameter pointer |
| 125 // esi: callee's context | 125 // esi: callee's context |
| 126 | 126 |
| 127 void CodeGenerator::GenCode(FunctionLiteral* fun) { | 127 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 128 // Record the position for debugging purposes. | 128 // Record the position for debugging purposes. |
| 129 CodeForSourcePosition(fun->start_position()); | 129 CodeForFunctionPosition(fun); |
| 130 | 130 |
| 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); |
| (...skipping 1248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 }; | 1388 }; |
| 1389 | 1389 |
| 1390 | 1390 |
| 1391 void DeferredStackCheck::Generate() { | 1391 void DeferredStackCheck::Generate() { |
| 1392 enter()->Bind(); | 1392 enter()->Bind(); |
| 1393 // The stack check can trigger the debugger. Before calling it, all | 1393 // The stack check can trigger the debugger. Before calling it, all |
| 1394 // values including constants must be spilled to the frame. | 1394 // values including constants must be spilled to the frame. |
| 1395 generator()->frame()->SpillAll(); | 1395 generator()->frame()->SpillAll(); |
| 1396 StackCheckStub stub; | 1396 StackCheckStub stub; |
| 1397 Result ignored = generator()->frame()->CallStub(&stub, 0); | 1397 Result ignored = generator()->frame()->CallStub(&stub, 0); |
| 1398 ignored.Unuse(); |
| 1398 exit()->Jump(); | 1399 exit()->Jump(); |
| 1399 } | 1400 } |
| 1400 | 1401 |
| 1401 | 1402 |
| 1402 void CodeGenerator::CheckStack() { | 1403 void CodeGenerator::CheckStack() { |
| 1403 if (FLAG_check_stack) { | 1404 if (FLAG_check_stack) { |
| 1404 DeferredStackCheck* deferred = new DeferredStackCheck(this); | 1405 DeferredStackCheck* deferred = new DeferredStackCheck(this); |
| 1405 ExternalReference stack_guard_limit = | 1406 ExternalReference stack_guard_limit = |
| 1406 ExternalReference::address_of_stack_guard_limit(); | 1407 ExternalReference::address_of_stack_guard_limit(); |
| 1407 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); | 1408 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); |
| 1408 deferred->enter()->Branch(below, not_taken); | 1409 deferred->enter()->Branch(below, not_taken); |
| 1409 deferred->exit()->Bind(); | 1410 deferred->exit()->Bind(); |
| 1410 } | 1411 } |
| 1411 } | 1412 } |
| 1412 | 1413 |
| 1413 | 1414 |
| 1414 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 1415 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 1415 ASSERT(!in_spilled_code()); | 1416 ASSERT(!in_spilled_code()); |
| 1416 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { | 1417 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { |
| 1417 Visit(statements->at(i)); | 1418 Visit(statements->at(i)); |
| 1418 } | 1419 } |
| 1419 } | 1420 } |
| 1420 | 1421 |
| 1421 | 1422 |
| 1422 void CodeGenerator::VisitBlock(Block* node) { | 1423 void CodeGenerator::VisitBlock(Block* node) { |
| 1423 ASSERT(!in_spilled_code()); | 1424 ASSERT(!in_spilled_code()); |
| 1424 Comment cmnt(masm_, "[ Block"); | 1425 Comment cmnt(masm_, "[ Block"); |
| 1425 CodeForStatement(node); | 1426 CodeForStatementPosition(node); |
| 1426 node->set_break_stack_height(break_stack_height_); | 1427 node->set_break_stack_height(break_stack_height_); |
| 1427 node->break_target()->Initialize(this); | 1428 node->break_target()->Initialize(this); |
| 1428 VisitStatements(node->statements()); | 1429 VisitStatements(node->statements()); |
| 1429 if (node->break_target()->is_linked()) { | 1430 if (node->break_target()->is_linked()) { |
| 1430 node->break_target()->Bind(); | 1431 node->break_target()->Bind(); |
| 1431 } | 1432 } |
| 1432 } | 1433 } |
| 1433 | 1434 |
| 1434 | 1435 |
| 1435 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1436 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1436 VirtualFrame::SpilledScope spilled_scope(this); | 1437 VirtualFrame::SpilledScope spilled_scope(this); |
| 1437 frame_->EmitPush(Immediate(pairs)); | 1438 frame_->EmitPush(Immediate(pairs)); |
| 1438 frame_->EmitPush(esi); | 1439 frame_->EmitPush(esi); |
| 1439 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1440 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1440 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1441 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1441 // Return value is ignored. | 1442 // Return value is ignored. |
| 1442 } | 1443 } |
| 1443 | 1444 |
| 1444 | 1445 |
| 1445 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1446 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1446 Comment cmnt(masm_, "[ Declaration"); | 1447 Comment cmnt(masm_, "[ Declaration"); |
| 1447 CodeForStatement(node); | 1448 CodeForStatementPosition(node); |
| 1448 Variable* var = node->proxy()->var(); | 1449 Variable* var = node->proxy()->var(); |
| 1449 ASSERT(var != NULL); // must have been resolved | 1450 ASSERT(var != NULL); // must have been resolved |
| 1450 Slot* slot = var->slot(); | 1451 Slot* slot = var->slot(); |
| 1451 | 1452 |
| 1452 // If it was not possible to allocate the variable at compile time, | 1453 // If it was not possible to allocate the variable at compile time, |
| 1453 // we need to "declare" it at runtime to make sure it actually | 1454 // we need to "declare" it at runtime to make sure it actually |
| 1454 // exists in the local context. | 1455 // exists in the local context. |
| 1455 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1456 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1456 // Variables with a "LOOKUP" slot were introduced as non-locals | 1457 // Variables with a "LOOKUP" slot were introduced as non-locals |
| 1457 // during variable resolution and must have mode DYNAMIC. | 1458 // during variable resolution and must have mode DYNAMIC. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 // the reference itself (which preserves the top of stack) because we | 1503 // the reference itself (which preserves the top of stack) because we |
| 1503 // know that it is a zero-sized reference. | 1504 // know that it is a zero-sized reference. |
| 1504 frame_->Drop(); | 1505 frame_->Drop(); |
| 1505 } | 1506 } |
| 1506 } | 1507 } |
| 1507 | 1508 |
| 1508 | 1509 |
| 1509 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1510 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1510 ASSERT(!in_spilled_code()); | 1511 ASSERT(!in_spilled_code()); |
| 1511 Comment cmnt(masm_, "[ ExpressionStatement"); | 1512 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1512 CodeForStatement(node); | 1513 CodeForStatementPosition(node); |
| 1513 Expression* expression = node->expression(); | 1514 Expression* expression = node->expression(); |
| 1514 expression->MarkAsStatement(); | 1515 expression->MarkAsStatement(); |
| 1515 Load(expression); | 1516 Load(expression); |
| 1516 // Remove the lingering expression result from the top of stack. | 1517 // Remove the lingering expression result from the top of stack. |
| 1517 frame_->Drop(); | 1518 frame_->Drop(); |
| 1518 } | 1519 } |
| 1519 | 1520 |
| 1520 | 1521 |
| 1521 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1522 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1522 ASSERT(!in_spilled_code()); | 1523 ASSERT(!in_spilled_code()); |
| 1523 Comment cmnt(masm_, "// EmptyStatement"); | 1524 Comment cmnt(masm_, "// EmptyStatement"); |
| 1524 CodeForStatement(node); | 1525 CodeForStatementPosition(node); |
| 1525 // nothing to do | 1526 // nothing to do |
| 1526 } | 1527 } |
| 1527 | 1528 |
| 1528 | 1529 |
| 1529 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1530 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1530 ASSERT(!in_spilled_code()); | 1531 ASSERT(!in_spilled_code()); |
| 1531 Comment cmnt(masm_, "[ IfStatement"); | 1532 Comment cmnt(masm_, "[ IfStatement"); |
| 1532 // Generate different code depending on which parts of the if statement | 1533 // Generate different code depending on which parts of the if statement |
| 1533 // are present or not. | 1534 // are present or not. |
| 1534 bool has_then_stm = node->HasThenStatement(); | 1535 bool has_then_stm = node->HasThenStatement(); |
| 1535 bool has_else_stm = node->HasElseStatement(); | 1536 bool has_else_stm = node->HasElseStatement(); |
| 1536 | 1537 |
| 1537 CodeForStatement(node); | 1538 CodeForStatementPosition(node); |
| 1538 JumpTarget exit(this); | 1539 JumpTarget exit(this); |
| 1539 if (has_then_stm && has_else_stm) { | 1540 if (has_then_stm && has_else_stm) { |
| 1540 JumpTarget then(this); | 1541 JumpTarget then(this); |
| 1541 JumpTarget else_(this); | 1542 JumpTarget else_(this); |
| 1542 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1543 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 1543 if (then.is_linked()) { | 1544 if (then.is_linked()) { |
| 1544 then.Bind(); | 1545 then.Bind(); |
| 1545 Visit(node->then_statement()); | 1546 Visit(node->then_statement()); |
| 1546 if (has_valid_frame() && else_.is_linked()) { | 1547 if (has_valid_frame() && else_.is_linked()) { |
| 1547 // We have fallen through from the then block and we need to compile | 1548 // We have fallen through from the then block and we need to compile |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1593 | 1594 |
| 1594 void CodeGenerator::CleanStack(int num_bytes) { | 1595 void CodeGenerator::CleanStack(int num_bytes) { |
| 1595 ASSERT(num_bytes % kPointerSize == 0); | 1596 ASSERT(num_bytes % kPointerSize == 0); |
| 1596 frame_->Drop(num_bytes / kPointerSize); | 1597 frame_->Drop(num_bytes / kPointerSize); |
| 1597 } | 1598 } |
| 1598 | 1599 |
| 1599 | 1600 |
| 1600 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1601 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1601 ASSERT(!in_spilled_code()); | 1602 ASSERT(!in_spilled_code()); |
| 1602 Comment cmnt(masm_, "[ ContinueStatement"); | 1603 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1603 CodeForStatement(node); | 1604 CodeForStatementPosition(node); |
| 1604 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1605 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1605 node->target()->continue_target()->Jump(); | 1606 node->target()->continue_target()->Jump(); |
| 1606 } | 1607 } |
| 1607 | 1608 |
| 1608 | 1609 |
| 1609 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1610 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1610 ASSERT(!in_spilled_code()); | 1611 ASSERT(!in_spilled_code()); |
| 1611 Comment cmnt(masm_, "[ BreakStatement"); | 1612 Comment cmnt(masm_, "[ BreakStatement"); |
| 1612 CodeForStatement(node); | 1613 CodeForStatementPosition(node); |
| 1613 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1614 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1614 node->target()->break_target()->Jump(); | 1615 node->target()->break_target()->Jump(); |
| 1615 } | 1616 } |
| 1616 | 1617 |
| 1617 | 1618 |
| 1618 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1619 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1619 ASSERT(!in_spilled_code()); | 1620 ASSERT(!in_spilled_code()); |
| 1620 Comment cmnt(masm_, "[ ReturnStatement"); | 1621 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1621 | 1622 |
| 1622 if (function_return_is_shadowed_) { | 1623 if (function_return_is_shadowed_) { |
| 1623 // If the function return is shadowed, we spill all information | 1624 // If the function return is shadowed, we spill all information |
| 1624 // and just jump to the label. | 1625 // and just jump to the label. |
| 1625 VirtualFrame::SpilledScope spilled_scope(this); | 1626 VirtualFrame::SpilledScope spilled_scope(this); |
| 1626 CodeForStatement(node); | 1627 CodeForStatementPosition(node); |
| 1627 LoadAndSpill(node->expression()); | 1628 LoadAndSpill(node->expression()); |
| 1628 frame_->EmitPop(eax); | 1629 frame_->EmitPop(eax); |
| 1629 function_return_.Jump(); | 1630 function_return_.Jump(); |
| 1630 } else { | 1631 } else { |
| 1631 // Load the returned value. | 1632 // Load the returned value. |
| 1632 CodeForStatement(node); | 1633 CodeForStatementPosition(node); |
| 1633 Load(node->expression()); | 1634 Load(node->expression()); |
| 1634 | 1635 |
| 1635 // Pop the result from the frame and prepare the frame for | 1636 // Pop the result from the frame and prepare the frame for |
| 1636 // returning thus making it easier to merge. | 1637 // returning thus making it easier to merge. |
| 1637 Result result = frame_->Pop(); | 1638 Result result = frame_->Pop(); |
| 1638 frame_->PrepareForReturn(); | 1639 frame_->PrepareForReturn(); |
| 1639 | 1640 |
| 1640 // Move the result into register eax where it belongs. | 1641 // Move the result into register eax where it belongs. |
| 1641 result.ToRegister(eax); | 1642 result.ToRegister(eax); |
| 1642 // TODO(203): Instead of explictly calling Unuse on the result, it | 1643 // TODO(203): Instead of explictly calling Unuse on the result, it |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1679 // Check that the size of the code used for returning matches what is | 1680 // Check that the size of the code used for returning matches what is |
| 1680 // expected by the debugger. | 1681 // expected by the debugger. |
| 1681 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1682 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 1682 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1683 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1683 } | 1684 } |
| 1684 | 1685 |
| 1685 | 1686 |
| 1686 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1687 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1687 ASSERT(!in_spilled_code()); | 1688 ASSERT(!in_spilled_code()); |
| 1688 Comment cmnt(masm_, "[ WithEnterStatement"); | 1689 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1689 CodeForStatement(node); | 1690 CodeForStatementPosition(node); |
| 1690 Load(node->expression()); | 1691 Load(node->expression()); |
| 1691 Result context(this); | 1692 Result context(this); |
| 1692 if (node->is_catch_block()) { | 1693 if (node->is_catch_block()) { |
| 1693 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 1694 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); |
| 1694 } else { | 1695 } else { |
| 1695 context = frame_->CallRuntime(Runtime::kPushContext, 1); | 1696 context = frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1696 } | 1697 } |
| 1697 | 1698 |
| 1698 if (kDebug) { | 1699 if (kDebug) { |
| 1699 JumpTarget verified_true(this); | 1700 JumpTarget verified_true(this); |
| 1700 // Verify that the result of the runtime call and the esi register are | 1701 // Verify that the result of the runtime call and the esi register are |
| 1701 // the same in debug mode. | 1702 // the same in debug mode. |
| 1702 __ cmp(context.reg(), Operand(esi)); | 1703 __ cmp(context.reg(), Operand(esi)); |
| 1703 context.Unuse(); | 1704 context.Unuse(); |
| 1704 verified_true.Branch(equal); | 1705 verified_true.Branch(equal); |
| 1705 frame_->SpillAll(); | 1706 frame_->SpillAll(); |
| 1706 __ int3(); | 1707 __ int3(); |
| 1707 verified_true.Bind(); | 1708 verified_true.Bind(); |
| 1708 } | 1709 } |
| 1709 | 1710 |
| 1710 // Update context local. | 1711 // Update context local. |
| 1711 frame_->SaveContextRegister(); | 1712 frame_->SaveContextRegister(); |
| 1712 } | 1713 } |
| 1713 | 1714 |
| 1714 | 1715 |
| 1715 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1716 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1716 ASSERT(!in_spilled_code()); | 1717 ASSERT(!in_spilled_code()); |
| 1717 Comment cmnt(masm_, "[ WithExitStatement"); | 1718 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1718 CodeForStatement(node); | 1719 CodeForStatementPosition(node); |
| 1719 // Pop context. | 1720 // Pop context. |
| 1720 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1721 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 1721 // Update context local. | 1722 // Update context local. |
| 1722 frame_->SaveContextRegister(); | 1723 frame_->SaveContextRegister(); |
| 1723 } | 1724 } |
| 1724 | 1725 |
| 1725 | 1726 |
| 1726 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1727 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1727 return kFastSwitchMaxOverheadFactor; | 1728 return kFastSwitchMaxOverheadFactor; |
| 1728 } | 1729 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1797 i < range; | 1798 i < range; |
| 1798 i++, entry_pos += sizeof(uint32_t)) { | 1799 i++, entry_pos += sizeof(uint32_t)) { |
| 1799 __ WriteInternalReference(entry_pos, *case_targets[i]->entry_label()); | 1800 __ WriteInternalReference(entry_pos, *case_targets[i]->entry_label()); |
| 1800 } | 1801 } |
| 1801 } | 1802 } |
| 1802 | 1803 |
| 1803 | 1804 |
| 1804 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1805 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1805 ASSERT(!in_spilled_code()); | 1806 ASSERT(!in_spilled_code()); |
| 1806 Comment cmnt(masm_, "[ SwitchStatement"); | 1807 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1807 CodeForStatement(node); | 1808 CodeForStatementPosition(node); |
| 1808 node->set_break_stack_height(break_stack_height_); | 1809 node->set_break_stack_height(break_stack_height_); |
| 1809 node->break_target()->Initialize(this); | 1810 node->break_target()->Initialize(this); |
| 1810 | 1811 |
| 1811 Load(node->tag()); | 1812 Load(node->tag()); |
| 1812 | 1813 |
| 1813 if (TryGenerateFastCaseSwitchStatement(node)) { | 1814 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1814 return; | 1815 return; |
| 1815 } | 1816 } |
| 1816 | 1817 |
| 1817 JumpTarget next_test(this); | 1818 JumpTarget next_test(this); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1896 | 1897 |
| 1897 if (node->break_target()->is_linked()) { | 1898 if (node->break_target()->is_linked()) { |
| 1898 node->break_target()->Bind(); | 1899 node->break_target()->Bind(); |
| 1899 } | 1900 } |
| 1900 } | 1901 } |
| 1901 | 1902 |
| 1902 | 1903 |
| 1903 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1904 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1904 ASSERT(!in_spilled_code()); | 1905 ASSERT(!in_spilled_code()); |
| 1905 Comment cmnt(masm_, "[ LoopStatement"); | 1906 Comment cmnt(masm_, "[ LoopStatement"); |
| 1906 CodeForStatement(node); | 1907 CodeForStatementPosition(node); |
| 1907 node->set_break_stack_height(break_stack_height_); | 1908 node->set_break_stack_height(break_stack_height_); |
| 1908 node->break_target()->Initialize(this); | 1909 node->break_target()->Initialize(this); |
| 1909 | 1910 |
| 1910 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 1911 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1911 // known result for the test expression, with no side effects. | 1912 // known result for the test expression, with no side effects. |
| 1912 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1913 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1913 if (node->cond() == NULL) { | 1914 if (node->cond() == NULL) { |
| 1914 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1915 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1915 info = ALWAYS_TRUE; | 1916 info = ALWAYS_TRUE; |
| 1916 } else { | 1917 } else { |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2057 // If there is an update statement and control flow can reach it | 2058 // If there is an update statement and control flow can reach it |
| 2058 // via falling out of the body of the loop or continuing, we | 2059 // via falling out of the body of the loop or continuing, we |
| 2059 // compile the update statement. | 2060 // compile the update statement. |
| 2060 if (node->continue_target()->is_linked()) { | 2061 if (node->continue_target()->is_linked()) { |
| 2061 node->continue_target()->Bind(); | 2062 node->continue_target()->Bind(); |
| 2062 } | 2063 } |
| 2063 if (has_valid_frame()) { | 2064 if (has_valid_frame()) { |
| 2064 // Record source position of the statement as this code which is | 2065 // Record source position of the statement as this code which is |
| 2065 // after the code for the body actually belongs to the loop | 2066 // after the code for the body actually belongs to the loop |
| 2066 // statement and not the body. | 2067 // statement and not the body. |
| 2067 CodeForStatement(node); | 2068 CodeForStatementPosition(node); |
| 2068 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 2069 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 2069 Visit(node->next()); | 2070 Visit(node->next()); |
| 2070 loop.Jump(); | 2071 loop.Jump(); |
| 2071 } | 2072 } |
| 2072 } | 2073 } |
| 2073 } | 2074 } |
| 2074 break; | 2075 break; |
| 2075 } | 2076 } |
| 2076 } | 2077 } |
| 2077 | 2078 |
| 2078 DecrementLoopNesting(); | 2079 DecrementLoopNesting(); |
| 2079 if (node->break_target()->is_linked()) { | 2080 if (node->break_target()->is_linked()) { |
| 2080 node->break_target()->Bind(); | 2081 node->break_target()->Bind(); |
| 2081 } | 2082 } |
| 2082 } | 2083 } |
| 2083 | 2084 |
| 2084 | 2085 |
| 2085 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 2086 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 2086 ASSERT(!in_spilled_code()); | 2087 ASSERT(!in_spilled_code()); |
| 2087 VirtualFrame::SpilledScope spilled_scope(this); | 2088 VirtualFrame::SpilledScope spilled_scope(this); |
| 2088 Comment cmnt(masm_, "[ ForInStatement"); | 2089 Comment cmnt(masm_, "[ ForInStatement"); |
| 2089 CodeForStatement(node); | 2090 CodeForStatementPosition(node); |
| 2090 | 2091 |
| 2091 // We keep stuff on the stack while the body is executing. | 2092 // We keep stuff on the stack while the body is executing. |
| 2092 // Record it, so that a break/continue crossing this statement | 2093 // Record it, so that a break/continue crossing this statement |
| 2093 // can restore the stack. | 2094 // can restore the stack. |
| 2094 const int kForInStackSize = 5 * kPointerSize; | 2095 const int kForInStackSize = 5 * kPointerSize; |
| 2095 break_stack_height_ += kForInStackSize; | 2096 break_stack_height_ += kForInStackSize; |
| 2096 node->set_break_stack_height(break_stack_height_); | 2097 node->set_break_stack_height(break_stack_height_); |
| 2097 node->break_target()->Initialize(this); | 2098 node->break_target()->Initialize(this); |
| 2098 node->continue_target()->Initialize(this); | 2099 node->continue_target()->Initialize(this); |
| 2099 | 2100 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2271 exit.Bind(); | 2272 exit.Bind(); |
| 2272 | 2273 |
| 2273 break_stack_height_ -= kForInStackSize; | 2274 break_stack_height_ -= kForInStackSize; |
| 2274 } | 2275 } |
| 2275 | 2276 |
| 2276 | 2277 |
| 2277 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2278 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2278 ASSERT(!in_spilled_code()); | 2279 ASSERT(!in_spilled_code()); |
| 2279 VirtualFrame::SpilledScope spilled_scope(this); | 2280 VirtualFrame::SpilledScope spilled_scope(this); |
| 2280 Comment cmnt(masm_, "[ TryCatch"); | 2281 Comment cmnt(masm_, "[ TryCatch"); |
| 2281 CodeForStatement(node); | 2282 CodeForStatementPosition(node); |
| 2282 | 2283 |
| 2283 JumpTarget try_block(this); | 2284 JumpTarget try_block(this); |
| 2284 JumpTarget exit(this); | 2285 JumpTarget exit(this); |
| 2285 | 2286 |
| 2286 try_block.Call(); | 2287 try_block.Call(); |
| 2287 // --- Catch block --- | 2288 // --- Catch block --- |
| 2288 frame_->EmitPush(eax); | 2289 frame_->EmitPush(eax); |
| 2289 | 2290 |
| 2290 // Store the caught exception in the catch variable. | 2291 // Store the caught exception in the catch variable. |
| 2291 { Reference ref(this, node->catch_var()); | 2292 { Reference ref(this, node->catch_var()); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2400 } | 2401 } |
| 2401 | 2402 |
| 2402 exit.Bind(); | 2403 exit.Bind(); |
| 2403 } | 2404 } |
| 2404 | 2405 |
| 2405 | 2406 |
| 2406 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2407 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2407 ASSERT(!in_spilled_code()); | 2408 ASSERT(!in_spilled_code()); |
| 2408 VirtualFrame::SpilledScope spilled_scope(this); | 2409 VirtualFrame::SpilledScope spilled_scope(this); |
| 2409 Comment cmnt(masm_, "[ TryFinally"); | 2410 Comment cmnt(masm_, "[ TryFinally"); |
| 2410 CodeForStatement(node); | 2411 CodeForStatementPosition(node); |
| 2411 | 2412 |
| 2412 // State: Used to keep track of reason for entering the finally | 2413 // State: Used to keep track of reason for entering the finally |
| 2413 // block. Should probably be extended to hold information for | 2414 // block. Should probably be extended to hold information for |
| 2414 // break/continue from within the try block. | 2415 // break/continue from within the try block. |
| 2415 enum { FALLING, THROWING, JUMPING }; | 2416 enum { FALLING, THROWING, JUMPING }; |
| 2416 | 2417 |
| 2417 JumpTarget unlink(this); | 2418 JumpTarget unlink(this); |
| 2418 JumpTarget try_block(this); | 2419 JumpTarget try_block(this); |
| 2419 JumpTarget finally_block(this); | 2420 JumpTarget finally_block(this); |
| 2420 | 2421 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2568 | 2569 |
| 2569 // Done. | 2570 // Done. |
| 2570 exit.Bind(); | 2571 exit.Bind(); |
| 2571 } | 2572 } |
| 2572 } | 2573 } |
| 2573 | 2574 |
| 2574 | 2575 |
| 2575 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2576 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2576 ASSERT(!in_spilled_code()); | 2577 ASSERT(!in_spilled_code()); |
| 2577 Comment cmnt(masm_, "[ DebuggerStatement"); | 2578 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2578 CodeForStatement(node); | 2579 CodeForStatementPosition(node); |
| 2579 // Spill everything, even constants, to the frame. | 2580 // Spill everything, even constants, to the frame. |
| 2580 frame_->SpillAll(); | 2581 frame_->SpillAll(); |
| 2581 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 2582 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2582 // Ignore the return value. | 2583 // Ignore the return value. |
| 2583 } | 2584 } |
| 2584 | 2585 |
| 2585 | 2586 |
| 2586 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2587 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2587 ASSERT(boilerplate->IsBoilerplate()); | 2588 ASSERT(boilerplate->IsBoilerplate()); |
| 2588 | 2589 |
| (...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3073 | 3074 |
| 3074 bool CodeGenerator::IsInlineSmi(Literal* literal) { | 3075 bool CodeGenerator::IsInlineSmi(Literal* literal) { |
| 3075 if (literal == NULL || !literal->handle()->IsSmi()) return false; | 3076 if (literal == NULL || !literal->handle()->IsSmi()) return false; |
| 3076 int int_value = Smi::cast(*literal->handle())->value(); | 3077 int int_value = Smi::cast(*literal->handle())->value(); |
| 3077 return is_intn(int_value, kMaxSmiInlinedBits); | 3078 return is_intn(int_value, kMaxSmiInlinedBits); |
| 3078 } | 3079 } |
| 3079 | 3080 |
| 3080 | 3081 |
| 3081 void CodeGenerator::VisitAssignment(Assignment* node) { | 3082 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 3082 Comment cmnt(masm_, "[ Assignment"); | 3083 Comment cmnt(masm_, "[ Assignment"); |
| 3083 CodeForStatement(node); | 3084 CodeForStatementPosition(node); |
| 3084 | 3085 |
| 3085 { Reference target(this, node->target()); | 3086 { Reference target(this, node->target()); |
| 3086 if (target.is_illegal()) { | 3087 if (target.is_illegal()) { |
| 3087 // Fool the virtual frame into thinking that we left the assignment's | 3088 // Fool the virtual frame into thinking that we left the assignment's |
| 3088 // value on the frame. | 3089 // value on the frame. |
| 3089 frame_->Push(Smi::FromInt(0)); | 3090 frame_->Push(Smi::FromInt(0)); |
| 3090 return; | 3091 return; |
| 3091 } | 3092 } |
| 3092 | 3093 |
| 3093 if (node->op() == Token::ASSIGN || | 3094 if (node->op() == Token::ASSIGN || |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3124 target.SetValue(NOT_CONST_INIT); | 3125 target.SetValue(NOT_CONST_INIT); |
| 3125 } | 3126 } |
| 3126 } | 3127 } |
| 3127 } | 3128 } |
| 3128 } | 3129 } |
| 3129 | 3130 |
| 3130 | 3131 |
| 3131 void CodeGenerator::VisitThrow(Throw* node) { | 3132 void CodeGenerator::VisitThrow(Throw* node) { |
| 3132 VirtualFrame::SpilledScope spilled_scope(this); | 3133 VirtualFrame::SpilledScope spilled_scope(this); |
| 3133 Comment cmnt(masm_, "[ Throw"); | 3134 Comment cmnt(masm_, "[ Throw"); |
| 3134 CodeForStatement(node); | 3135 CodeForStatementPosition(node); |
| 3135 | 3136 |
| 3136 LoadAndSpill(node->exception()); | 3137 LoadAndSpill(node->exception()); |
| 3137 frame_->CallRuntime(Runtime::kThrow, 1); | 3138 frame_->CallRuntime(Runtime::kThrow, 1); |
| 3138 frame_->EmitPush(eax); | 3139 frame_->EmitPush(eax); |
| 3139 } | 3140 } |
| 3140 | 3141 |
| 3141 | 3142 |
| 3142 void CodeGenerator::VisitProperty(Property* node) { | 3143 void CodeGenerator::VisitProperty(Property* node) { |
| 3143 Comment cmnt(masm_, "[ Property"); | 3144 Comment cmnt(masm_, "[ Property"); |
| 3144 Reference property(this, node); | 3145 Reference property(this, node); |
| 3145 property.GetValue(typeof_state()); | 3146 property.GetValue(typeof_state()); |
| 3146 } | 3147 } |
| 3147 | 3148 |
| 3148 | 3149 |
| 3149 void CodeGenerator::VisitCall(Call* node) { | 3150 void CodeGenerator::VisitCall(Call* node) { |
| 3150 Comment cmnt(masm_, "[ Call"); | 3151 Comment cmnt(masm_, "[ Call"); |
| 3151 | 3152 |
| 3152 ZoneList<Expression*>* args = node->arguments(); | 3153 ZoneList<Expression*>* args = node->arguments(); |
| 3153 | 3154 |
| 3154 CodeForStatement(node); | 3155 CodeForStatementPosition(node); |
| 3155 | 3156 |
| 3156 // Check if the function is a variable or a property. | 3157 // Check if the function is a variable or a property. |
| 3157 Expression* function = node->expression(); | 3158 Expression* function = node->expression(); |
| 3158 Variable* var = function->AsVariableProxy()->AsVariable(); | 3159 Variable* var = function->AsVariableProxy()->AsVariable(); |
| 3159 Property* property = function->AsProperty(); | 3160 Property* property = function->AsProperty(); |
| 3160 | 3161 |
| 3161 // ------------------------------------------------------------------------ | 3162 // ------------------------------------------------------------------------ |
| 3162 // Fast-case: Use inline caching. | 3163 // Fast-case: Use inline caching. |
| 3163 // --- | 3164 // --- |
| 3164 // According to ECMA-262, section 11.2.3, page 44, the function to call | 3165 // According to ECMA-262, section 11.2.3, page 44, the function to call |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3280 LoadGlobalReceiver(); | 3281 LoadGlobalReceiver(); |
| 3281 | 3282 |
| 3282 // Call the function. | 3283 // Call the function. |
| 3283 CallWithArguments(args, node->position()); | 3284 CallWithArguments(args, node->position()); |
| 3284 } | 3285 } |
| 3285 } | 3286 } |
| 3286 | 3287 |
| 3287 | 3288 |
| 3288 void CodeGenerator::VisitCallNew(CallNew* node) { | 3289 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 3289 Comment cmnt(masm_, "[ CallNew"); | 3290 Comment cmnt(masm_, "[ CallNew"); |
| 3290 CodeForStatement(node); | 3291 CodeForStatementPosition(node); |
| 3291 | 3292 |
| 3292 // According to ECMA-262, section 11.2.2, page 44, the function | 3293 // According to ECMA-262, section 11.2.2, page 44, the function |
| 3293 // expression in new calls must be evaluated before the | 3294 // expression in new calls must be evaluated before the |
| 3294 // arguments. This is different from ordinary calls, where the | 3295 // arguments. This is different from ordinary calls, where the |
| 3295 // actual function to call is resolved after the arguments have been | 3296 // actual function to call is resolved after the arguments have been |
| 3296 // evaluated. | 3297 // evaluated. |
| 3297 | 3298 |
| 3298 // Compute function to call and use the global object as the | 3299 // Compute function to call and use the global object as the |
| 3299 // receiver. There is no need to use the global proxy here because | 3300 // receiver. There is no need to use the global proxy here because |
| 3300 // it will always be replaced with a newly allocated object. | 3301 // it will always be replaced with a newly allocated object. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3338 VirtualFrame::SpilledScope spilled_scope(this); | 3339 VirtualFrame::SpilledScope spilled_scope(this); |
| 3339 Comment cmnt(masm_, "[ CallEval"); | 3340 Comment cmnt(masm_, "[ CallEval"); |
| 3340 | 3341 |
| 3341 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve | 3342 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve |
| 3342 // the function we need to call and the receiver of the call. | 3343 // the function we need to call and the receiver of the call. |
| 3343 // Then we call the resolved function using the given arguments. | 3344 // Then we call the resolved function using the given arguments. |
| 3344 | 3345 |
| 3345 ZoneList<Expression*>* args = node->arguments(); | 3346 ZoneList<Expression*>* args = node->arguments(); |
| 3346 Expression* function = node->expression(); | 3347 Expression* function = node->expression(); |
| 3347 | 3348 |
| 3348 CodeForStatement(node); | 3349 CodeForStatementPosition(node); |
| 3349 | 3350 |
| 3350 // Prepare stack for call to resolved function. | 3351 // Prepare stack for call to resolved function. |
| 3351 LoadAndSpill(function); | 3352 LoadAndSpill(function); |
| 3352 | 3353 |
| 3353 // Allocate a frame slot for the receiver. | 3354 // Allocate a frame slot for the receiver. |
| 3354 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3355 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3355 int arg_count = args->length(); | 3356 int arg_count = args->length(); |
| 3356 for (int i = 0; i < arg_count; i++) { | 3357 for (int i = 0; i < arg_count; i++) { |
| 3357 LoadAndSpill(args->at(i)); | 3358 LoadAndSpill(args->at(i)); |
| 3358 } | 3359 } |
| (...skipping 2827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6186 | 6187 |
| 6187 // Slow-case: Go through the JavaScript implementation. | 6188 // Slow-case: Go through the JavaScript implementation. |
| 6188 __ bind(&slow); | 6189 __ bind(&slow); |
| 6189 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6190 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6190 } | 6191 } |
| 6191 | 6192 |
| 6192 | 6193 |
| 6193 #undef __ | 6194 #undef __ |
| 6194 | 6195 |
| 6195 } } // namespace v8::internal | 6196 } } // namespace v8::internal |
| OLD | NEW |