| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 14 matching lines...) Expand all Loading... |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "codegen-inl.h" | 30 #include "codegen-inl.h" |
| 31 #include "compiler.h" | 31 #include "compiler.h" |
| 32 #include "debug.h" | 32 #include "debug.h" |
| 33 #include "full-codegen.h" | 33 #include "full-codegen.h" |
| 34 #include "parser.h" | 34 #include "parser.h" |
| 35 #include "scopes.h" |
| 35 | 36 |
| 36 namespace v8 { | 37 namespace v8 { |
| 37 namespace internal { | 38 namespace internal { |
| 38 | 39 |
| 39 #define __ ACCESS_MASM(masm_) | 40 #define __ ACCESS_MASM(masm_) |
| 40 | 41 |
| 41 // Generate code for a JS function. On entry to the function the receiver | 42 // Generate code for a JS function. On entry to the function the receiver |
| 42 // and arguments have been pushed on the stack left to right, with the | 43 // and arguments have been pushed on the stack left to right, with the |
| 43 // return address on top of them. The actual argument count matches the | 44 // return address on top of them. The actual argument count matches the |
| 44 // formal parameter count expected by the function. | 45 // formal parameter count expected by the function. |
| 45 // | 46 // |
| 46 // The live registers are: | 47 // The live registers are: |
| 47 // o edi: the JS function object being called (ie, ourselves) | 48 // o edi: the JS function object being called (ie, ourselves) |
| 48 // o esi: our context | 49 // o esi: our context |
| 49 // o ebp: our caller's frame pointer | 50 // o ebp: our caller's frame pointer |
| 50 // o esp: stack pointer (pointing to return address) | 51 // o esp: stack pointer (pointing to return address) |
| 51 // | 52 // |
| 52 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 53 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 53 // frames-ia32.h for its layout. | 54 // frames-ia32.h for its layout. |
| 54 void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) { | 55 void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) { |
| 55 ASSERT(info_ == NULL); | 56 ASSERT(info_ == NULL); |
| 56 info_ = info; | 57 info_ = info; |
| 57 SetFunctionPosition(function()); | 58 SetFunctionPosition(function()); |
| 59 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 58 | 60 |
| 59 if (mode == PRIMARY) { | 61 if (mode == PRIMARY) { |
| 60 __ push(ebp); // Caller's frame pointer. | 62 __ push(ebp); // Caller's frame pointer. |
| 61 __ mov(ebp, esp); | 63 __ mov(ebp, esp); |
| 62 __ push(esi); // Callee's context. | 64 __ push(esi); // Callee's context. |
| 63 __ push(edi); // Callee's JS Function. | 65 __ push(edi); // Callee's JS Function. |
| 64 | 66 |
| 65 { Comment cmnt(masm_, "[ Allocate locals"); | 67 { Comment cmnt(masm_, "[ Allocate locals"); |
| 66 int locals_count = scope()->num_stack_slots(); | 68 int locals_count = scope()->num_stack_slots(); |
| 67 if (locals_count == 1) { | 69 if (locals_count == 1) { |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 735 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 734 break; | 736 break; |
| 735 } | 737 } |
| 736 } | 738 } |
| 737 | 739 |
| 738 } else if (prop != NULL) { | 740 } else if (prop != NULL) { |
| 739 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 741 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { |
| 740 // We are declaring a function or constant that rewrites to a | 742 // We are declaring a function or constant that rewrites to a |
| 741 // property. Use (keyed) IC to set the initial value. | 743 // property. Use (keyed) IC to set the initial value. |
| 742 VisitForValue(prop->obj(), kStack); | 744 VisitForValue(prop->obj(), kStack); |
| 743 VisitForValue(prop->key(), kStack); | |
| 744 | |
| 745 if (decl->fun() != NULL) { | 745 if (decl->fun() != NULL) { |
| 746 VisitForValue(prop->key(), kStack); |
| 746 VisitForValue(decl->fun(), kAccumulator); | 747 VisitForValue(decl->fun(), kAccumulator); |
| 748 __ pop(ecx); |
| 747 } else { | 749 } else { |
| 750 VisitForValue(prop->key(), kAccumulator); |
| 751 __ mov(ecx, result_register()); |
| 748 __ mov(result_register(), Factory::the_hole_value()); | 752 __ mov(result_register(), Factory::the_hole_value()); |
| 749 } | 753 } |
| 754 __ pop(edx); |
| 750 | 755 |
| 751 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 756 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 752 __ call(ic, RelocInfo::CODE_TARGET); | 757 __ call(ic, RelocInfo::CODE_TARGET); |
| 753 // Absence of a test eax instruction following the call | 758 // Absence of a test eax instruction following the call |
| 754 // indicates that none of the load was inlined. | 759 // indicates that none of the load was inlined. |
| 755 __ nop(); | 760 __ nop(); |
| 756 | |
| 757 // Value in eax is ignored (declarations are statements). Receiver | |
| 758 // and key on stack are discarded. | |
| 759 __ Drop(2); | |
| 760 } | 761 } |
| 761 } | 762 } |
| 762 } | 763 } |
| 763 | 764 |
| 764 | 765 |
| 765 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 766 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 766 // Call the runtime to declare the globals. | 767 // Call the runtime to declare the globals. |
| 767 __ push(esi); // The context is the first argument. | 768 __ push(esi); // The context is the first argument. |
| 768 __ push(Immediate(pairs)); | 769 __ push(Immediate(pairs)); |
| 769 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 770 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 __ call(ic, RelocInfo::CODE_TARGET); | 1123 __ call(ic, RelocInfo::CODE_TARGET); |
| 1123 __ nop(); | 1124 __ nop(); |
| 1124 } | 1125 } |
| 1125 | 1126 |
| 1126 | 1127 |
| 1127 void FullCodeGenerator::EmitBinaryOp(Token::Value op, | 1128 void FullCodeGenerator::EmitBinaryOp(Token::Value op, |
| 1128 Expression::Context context) { | 1129 Expression::Context context) { |
| 1129 __ push(result_register()); | 1130 __ push(result_register()); |
| 1130 GenericBinaryOpStub stub(op, | 1131 GenericBinaryOpStub stub(op, |
| 1131 NO_OVERWRITE, | 1132 NO_OVERWRITE, |
| 1132 NO_GENERIC_BINARY_FLAGS); | 1133 NO_GENERIC_BINARY_FLAGS, |
| 1134 NumberInfo::Unknown()); |
| 1133 __ CallStub(&stub); | 1135 __ CallStub(&stub); |
| 1134 Apply(context, eax); | 1136 Apply(context, eax); |
| 1135 } | 1137 } |
| 1136 | 1138 |
| 1137 | 1139 |
| 1138 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1140 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1139 Expression::Context context) { | 1141 Expression::Context context) { |
| 1140 // Three main cases: global variables, lookup slots, and all other | 1142 // Three main cases: global variables, lookup slots, and all other |
| 1141 // types of slots. Left-hand-side parameters that rewrite to | 1143 // types of slots. Left-hand-side parameters that rewrite to |
| 1142 // explicit property accesses do not reach here. | 1144 // explicit property accesses do not reach here. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1243 // change to slow case to avoid the quadratic behavior of repeatedly | 1245 // change to slow case to avoid the quadratic behavior of repeatedly |
| 1244 // adding fast properties. | 1246 // adding fast properties. |
| 1245 if (expr->starts_initialization_block()) { | 1247 if (expr->starts_initialization_block()) { |
| 1246 __ push(result_register()); | 1248 __ push(result_register()); |
| 1247 // Receiver is now under the key and value. | 1249 // Receiver is now under the key and value. |
| 1248 __ push(Operand(esp, 2 * kPointerSize)); | 1250 __ push(Operand(esp, 2 * kPointerSize)); |
| 1249 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1251 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1250 __ pop(result_register()); | 1252 __ pop(result_register()); |
| 1251 } | 1253 } |
| 1252 | 1254 |
| 1255 __ pop(ecx); |
| 1256 if (expr->ends_initialization_block()) { |
| 1257 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. |
| 1258 } else { |
| 1259 __ pop(edx); |
| 1260 } |
| 1253 // Record source code position before IC call. | 1261 // Record source code position before IC call. |
| 1254 SetSourcePosition(expr->position()); | 1262 SetSourcePosition(expr->position()); |
| 1255 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1263 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 1256 __ call(ic, RelocInfo::CODE_TARGET); | 1264 __ call(ic, RelocInfo::CODE_TARGET); |
| 1257 // This nop signals to the IC that there is no inlined code at the call | 1265 // This nop signals to the IC that there is no inlined code at the call |
| 1258 // site for it to patch. | 1266 // site for it to patch. |
| 1259 __ nop(); | 1267 __ nop(); |
| 1260 | 1268 |
| 1261 // If the assignment ends an initialization block, revert to fast case. | 1269 // If the assignment ends an initialization block, revert to fast case. |
| 1262 if (expr->ends_initialization_block()) { | 1270 if (expr->ends_initialization_block()) { |
| 1271 __ pop(edx); |
| 1263 __ push(eax); // Result of assignment, saved even if not needed. | 1272 __ push(eax); // Result of assignment, saved even if not needed. |
| 1264 // Receiver is under the key and value. | 1273 __ push(edx); |
| 1265 __ push(Operand(esp, 2 * kPointerSize)); | |
| 1266 __ CallRuntime(Runtime::kToFastProperties, 1); | 1274 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1267 __ pop(eax); | 1275 __ pop(eax); |
| 1268 } | 1276 } |
| 1269 | 1277 |
| 1270 // Receiver and key are still on stack. | 1278 Apply(context_, eax); |
| 1271 DropAndApply(2, context_, eax); | |
| 1272 } | 1279 } |
| 1273 | 1280 |
| 1274 | 1281 |
| 1275 void FullCodeGenerator::VisitProperty(Property* expr) { | 1282 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 1276 Comment cmnt(masm_, "[ Property"); | 1283 Comment cmnt(masm_, "[ Property"); |
| 1277 Expression* key = expr->key(); | 1284 Expression* key = expr->key(); |
| 1278 | 1285 |
| 1279 if (key->IsPropertyName()) { | 1286 if (key->IsPropertyName()) { |
| 1280 VisitForValue(expr->obj(), kAccumulator); | 1287 VisitForValue(expr->obj(), kAccumulator); |
| 1281 EmitNamedPropertyLoad(expr); | 1288 EmitNamedPropertyLoad(expr); |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1731 // Call stub. Undo operation first. | 1738 // Call stub. Undo operation first. |
| 1732 if (expr->op() == Token::INC) { | 1739 if (expr->op() == Token::INC) { |
| 1733 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 1740 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 1734 } else { | 1741 } else { |
| 1735 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 1742 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 1736 } | 1743 } |
| 1737 } | 1744 } |
| 1738 // Call stub for +1/-1. | 1745 // Call stub for +1/-1. |
| 1739 GenericBinaryOpStub stub(expr->binary_op(), | 1746 GenericBinaryOpStub stub(expr->binary_op(), |
| 1740 NO_OVERWRITE, | 1747 NO_OVERWRITE, |
| 1741 NO_GENERIC_BINARY_FLAGS); | 1748 NO_GENERIC_BINARY_FLAGS, |
| 1749 NumberInfo::Unknown()); |
| 1742 stub.GenerateCall(masm(), eax, Smi::FromInt(1)); | 1750 stub.GenerateCall(masm(), eax, Smi::FromInt(1)); |
| 1743 __ bind(&done); | 1751 __ bind(&done); |
| 1744 | 1752 |
| 1745 // Store the value returned in eax. | 1753 // Store the value returned in eax. |
| 1746 switch (assign_type) { | 1754 switch (assign_type) { |
| 1747 case VARIABLE: | 1755 case VARIABLE: |
| 1748 if (expr->is_postfix()) { | 1756 if (expr->is_postfix()) { |
| 1749 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1757 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1750 Expression::kEffect); | 1758 Expression::kEffect); |
| 1751 // For all contexts except kEffect: We have the result on | 1759 // For all contexts except kEffect: We have the result on |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1769 if (expr->is_postfix()) { | 1777 if (expr->is_postfix()) { |
| 1770 if (context_ != Expression::kEffect) { | 1778 if (context_ != Expression::kEffect) { |
| 1771 ApplyTOS(context_); | 1779 ApplyTOS(context_); |
| 1772 } | 1780 } |
| 1773 } else { | 1781 } else { |
| 1774 Apply(context_, eax); | 1782 Apply(context_, eax); |
| 1775 } | 1783 } |
| 1776 break; | 1784 break; |
| 1777 } | 1785 } |
| 1778 case KEYED_PROPERTY: { | 1786 case KEYED_PROPERTY: { |
| 1787 __ pop(ecx); |
| 1788 __ pop(edx); |
| 1779 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1789 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 1780 __ call(ic, RelocInfo::CODE_TARGET); | 1790 __ call(ic, RelocInfo::CODE_TARGET); |
| 1781 // This nop signals to the IC that there is no inlined code at the call | 1791 // This nop signals to the IC that there is no inlined code at the call |
| 1782 // site for it to patch. | 1792 // site for it to patch. |
| 1783 __ nop(); | 1793 __ nop(); |
| 1784 if (expr->is_postfix()) { | 1794 if (expr->is_postfix()) { |
| 1785 __ Drop(2); // Result is on the stack under the key and the receiver. | 1795 // Result is on the stack |
| 1786 if (context_ != Expression::kEffect) { | 1796 if (context_ != Expression::kEffect) { |
| 1787 ApplyTOS(context_); | 1797 ApplyTOS(context_); |
| 1788 } | 1798 } |
| 1789 } else { | 1799 } else { |
| 1790 DropAndApply(2, context_, eax); | 1800 Apply(context_, eax); |
| 1791 } | 1801 } |
| 1792 break; | 1802 break; |
| 1793 } | 1803 } |
| 1794 } | 1804 } |
| 1795 } | 1805 } |
| 1796 | 1806 |
| 1797 | 1807 |
| 1798 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 1808 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 1799 Comment cmnt(masm_, "[ BinaryOperation"); | 1809 Comment cmnt(masm_, "[ BinaryOperation"); |
| 1800 switch (expr->op()) { | 1810 switch (expr->op()) { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1995 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 2005 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
| 1996 __ mov(Operand(esp, 0), edx); | 2006 __ mov(Operand(esp, 0), edx); |
| 1997 // And return. | 2007 // And return. |
| 1998 __ ret(0); | 2008 __ ret(0); |
| 1999 } | 2009 } |
| 2000 | 2010 |
| 2001 | 2011 |
| 2002 #undef __ | 2012 #undef __ |
| 2003 | 2013 |
| 2004 } } // namespace v8::internal | 2014 } } // namespace v8::internal |
| OLD | NEW |