Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: src/codegen-ia32.cc

Issue 21446: Experimental: allow the register allocator to work for for...in... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698