OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 // stack frame was an arguments adapter frame. | 200 // stack frame was an arguments adapter frame. |
201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
202 __ CallStub(&stub); | 202 __ CallStub(&stub); |
203 // Store new arguments object in both "arguments" and ".arguments" slots. | 203 // Store new arguments object in both "arguments" and ".arguments" slots. |
204 __ movq(rcx, rax); | 204 __ movq(rcx, rax); |
205 Move(arguments->AsSlot(), rax, rbx, rdx); | 205 Move(arguments->AsSlot(), rax, rbx, rdx); |
206 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); | 206 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); |
207 Move(dot_arguments_slot, rcx, rbx, rdx); | 207 Move(dot_arguments_slot, rcx, rbx, rdx); |
208 } | 208 } |
209 | 209 |
210 { Comment cmnt(masm_, "[ Declarations"); | |
211 // For named function expressions, declare the function name as a | |
212 // constant. | |
213 if (scope()->is_function_scope() && scope()->function() != NULL) { | |
214 EmitDeclaration(scope()->function(), Variable::CONST, NULL); | |
215 } | |
216 // Visit all the explicit declarations unless there is an illegal | |
217 // redeclaration. | |
218 if (scope()->HasIllegalRedeclaration()) { | |
219 scope()->VisitIllegalRedeclaration(this); | |
220 } else { | |
221 VisitDeclarations(scope()->declarations()); | |
222 } | |
223 } | |
224 | |
225 if (FLAG_trace) { | 210 if (FLAG_trace) { |
226 __ CallRuntime(Runtime::kTraceEnter, 0); | 211 __ CallRuntime(Runtime::kTraceEnter, 0); |
227 } | 212 } |
228 | 213 |
229 { Comment cmnt(masm_, "[ Stack check"); | 214 // Visit the declarations and body unless there is an illegal |
230 PrepareForBailout(info->function(), NO_REGISTERS); | 215 // redeclaration. |
231 NearLabel ok; | 216 if (scope()->HasIllegalRedeclaration()) { |
232 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 217 Comment cmnt(masm_, "[ Declarations"); |
233 __ j(above_equal, &ok); | 218 scope()->VisitIllegalRedeclaration(this); |
234 StackCheckStub stub; | 219 } else { |
235 __ CallStub(&stub); | 220 { Comment cmnt(masm_, "[ Declarations"); |
236 __ bind(&ok); | 221 // For named function expressions, declare the function name as a |
| 222 // constant. |
| 223 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 224 EmitDeclaration(scope()->function(), Variable::CONST, NULL); |
| 225 } |
| 226 VisitDeclarations(scope()->declarations()); |
| 227 } |
| 228 |
| 229 { Comment cmnt(masm_, "[ Stack check"); |
| 230 PrepareForBailout(info->function(), NO_REGISTERS); |
| 231 NearLabel ok; |
| 232 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 233 __ j(above_equal, &ok); |
| 234 StackCheckStub stub; |
| 235 __ CallStub(&stub); |
| 236 __ bind(&ok); |
| 237 } |
| 238 |
| 239 { Comment cmnt(masm_, "[ Body"); |
| 240 ASSERT(loop_depth() == 0); |
| 241 VisitStatements(function()->body()); |
| 242 ASSERT(loop_depth() == 0); |
| 243 } |
237 } | 244 } |
238 | 245 |
239 { Comment cmnt(masm_, "[ Body"); | 246 // Always emit a 'return undefined' in case control fell off the end of |
240 ASSERT(loop_depth() == 0); | 247 // the body. |
241 VisitStatements(function()->body()); | |
242 ASSERT(loop_depth() == 0); | |
243 } | |
244 | |
245 { Comment cmnt(masm_, "[ return <undefined>;"); | 248 { Comment cmnt(masm_, "[ return <undefined>;"); |
246 // Emit a 'return undefined' in case control fell off the end of the body. | |
247 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 249 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
248 EmitReturnSequence(); | 250 EmitReturnSequence(); |
249 } | 251 } |
250 } | 252 } |
251 | 253 |
252 | 254 |
253 void FullCodeGenerator::ClearAccumulator() { | 255 void FullCodeGenerator::ClearAccumulator() { |
254 __ Set(rax, 0); | 256 __ Set(rax, 0); |
255 } | 257 } |
256 | 258 |
(...skipping 818 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1075 } | 1077 } |
1076 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1078 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
1077 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1079 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
1078 // Walk the rest of the chain without clobbering rsi. | 1080 // Walk the rest of the chain without clobbering rsi. |
1079 context = temp; | 1081 context = temp; |
1080 } | 1082 } |
1081 } | 1083 } |
1082 // Check that last extension is NULL. | 1084 // Check that last extension is NULL. |
1083 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1085 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
1084 __ j(not_equal, slow); | 1086 __ j(not_equal, slow); |
1085 __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 1087 |
| 1088 // This function is used only for loads, not stores, so it's safe to |
| 1089 // return an rsi-based operand (the write barrier cannot be allowed to |
| 1090 // destroy the rsi register). |
1086 return ContextOperand(temp, slot->index()); | 1091 return ContextOperand(temp, slot->index()); |
1087 } | 1092 } |
1088 | 1093 |
1089 | 1094 |
1090 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( | 1095 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( |
1091 Slot* slot, | 1096 Slot* slot, |
1092 TypeofState typeof_state, | 1097 TypeofState typeof_state, |
1093 Label* slow, | 1098 Label* slow, |
1094 Label* done) { | 1099 Label* done) { |
1095 // Generate fast-case code for variables that might be shadowed by | 1100 // Generate fast-case code for variables that might be shadowed by |
(...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1723 // Assignment to a global variable. Use inline caching for the | 1728 // Assignment to a global variable. Use inline caching for the |
1724 // assignment. Right-hand-side value is passed in rax, variable name in | 1729 // assignment. Right-hand-side value is passed in rax, variable name in |
1725 // rcx, and the global object on the stack. | 1730 // rcx, and the global object on the stack. |
1726 __ Move(rcx, var->name()); | 1731 __ Move(rcx, var->name()); |
1727 __ movq(rdx, GlobalObjectOperand()); | 1732 __ movq(rdx, GlobalObjectOperand()); |
1728 Handle<Code> ic(Builtins::builtin(is_strict() | 1733 Handle<Code> ic(Builtins::builtin(is_strict() |
1729 ? Builtins::StoreIC_Initialize_Strict | 1734 ? Builtins::StoreIC_Initialize_Strict |
1730 : Builtins::StoreIC_Initialize)); | 1735 : Builtins::StoreIC_Initialize)); |
1731 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1736 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
1732 | 1737 |
1733 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { | 1738 } else if (op == Token::INIT_CONST) { |
1734 // Perform the assignment for non-const variables and for initialization | 1739 // Like var declarations, const declarations are hoisted to function |
1735 // of const variables. Const assignments are simply skipped. | 1740 // scope. However, unlike var initializers, const initializers are able |
1736 Label done; | 1741 // to drill a hole to that function context, even from inside a 'with' |
| 1742 // context. We thus bypass the normal static scope lookup. |
| 1743 Slot* slot = var->AsSlot(); |
| 1744 Label skip; |
| 1745 switch (slot->type()) { |
| 1746 case Slot::PARAMETER: |
| 1747 // No const parameters. |
| 1748 UNREACHABLE(); |
| 1749 break; |
| 1750 case Slot::LOCAL: |
| 1751 __ movq(rdx, Operand(rbp, SlotOffset(slot))); |
| 1752 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1753 __ j(not_equal, &skip); |
| 1754 __ movq(Operand(rbp, SlotOffset(slot)), rax); |
| 1755 break; |
| 1756 case Slot::CONTEXT: { |
| 1757 __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
| 1758 __ movq(rdx, ContextOperand(rcx, slot->index())); |
| 1759 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1760 __ j(not_equal, &skip); |
| 1761 __ movq(ContextOperand(rcx, slot->index()), rax); |
| 1762 int offset = Context::SlotOffset(slot->index()); |
| 1763 __ movq(rdx, rax); // Preserve the stored value in eax. |
| 1764 __ RecordWrite(rcx, offset, rdx, rbx); |
| 1765 break; |
| 1766 } |
| 1767 case Slot::LOOKUP: |
| 1768 __ push(rax); |
| 1769 __ push(rsi); |
| 1770 __ Push(var->name()); |
| 1771 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1772 break; |
| 1773 } |
| 1774 __ bind(&skip); |
| 1775 |
| 1776 } else if (var->mode() != Variable::CONST) { |
| 1777 // Perform the assignment for non-const variables. Const assignments |
| 1778 // are simply skipped. |
1737 Slot* slot = var->AsSlot(); | 1779 Slot* slot = var->AsSlot(); |
1738 switch (slot->type()) { | 1780 switch (slot->type()) { |
1739 case Slot::PARAMETER: | 1781 case Slot::PARAMETER: |
1740 case Slot::LOCAL: | 1782 case Slot::LOCAL: |
1741 if (op == Token::INIT_CONST) { | |
1742 // Detect const reinitialization by checking for the hole value. | |
1743 __ movq(rdx, Operand(rbp, SlotOffset(slot))); | |
1744 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
1745 __ j(not_equal, &done); | |
1746 } | |
1747 // Perform the assignment. | 1783 // Perform the assignment. |
1748 __ movq(Operand(rbp, SlotOffset(slot)), rax); | 1784 __ movq(Operand(rbp, SlotOffset(slot)), rax); |
1749 break; | 1785 break; |
1750 | 1786 |
1751 case Slot::CONTEXT: { | 1787 case Slot::CONTEXT: { |
1752 MemOperand target = EmitSlotSearch(slot, rcx); | 1788 MemOperand target = EmitSlotSearch(slot, rcx); |
1753 if (op == Token::INIT_CONST) { | |
1754 // Detect const reinitialization by checking for the hole value. | |
1755 __ movq(rdx, target); | |
1756 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
1757 __ j(not_equal, &done); | |
1758 } | |
1759 // Perform the assignment and issue the write barrier. | 1789 // Perform the assignment and issue the write barrier. |
1760 __ movq(target, rax); | 1790 __ movq(target, rax); |
1761 // The value of the assignment is in rax. RecordWrite clobbers its | 1791 // The value of the assignment is in rax. RecordWrite clobbers its |
1762 // register arguments. | 1792 // register arguments. |
1763 __ movq(rdx, rax); | 1793 __ movq(rdx, rax); |
1764 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 1794 int offset = Context::SlotOffset(slot->index()); |
1765 __ RecordWrite(rcx, offset, rdx, rbx); | 1795 __ RecordWrite(rcx, offset, rdx, rbx); |
1766 break; | 1796 break; |
1767 } | 1797 } |
1768 | 1798 |
1769 case Slot::LOOKUP: | 1799 case Slot::LOOKUP: |
1770 // Call the runtime for the assignment. The runtime will ignore | 1800 // Call the runtime for the assignment. |
1771 // const reinitialization. | |
1772 __ push(rax); // Value. | 1801 __ push(rax); // Value. |
1773 __ push(rsi); // Context. | 1802 __ push(rsi); // Context. |
1774 __ Push(var->name()); | 1803 __ Push(var->name()); |
1775 if (op == Token::INIT_CONST) { | 1804 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
1776 // The runtime will ignore const redeclaration. | |
1777 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
1778 } else { | |
1779 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
1780 } | |
1781 break; | 1805 break; |
1782 } | 1806 } |
1783 __ bind(&done); | |
1784 } | 1807 } |
1785 } | 1808 } |
1786 | 1809 |
1787 | 1810 |
1788 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1811 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1789 // Assignment to a property, using a named store IC. | 1812 // Assignment to a property, using a named store IC. |
1790 Property* prop = expr->target()->AsProperty(); | 1813 Property* prop = expr->target()->AsProperty(); |
1791 ASSERT(prop != NULL); | 1814 ASSERT(prop != NULL); |
1792 ASSERT(prop->key()->AsLiteral() != NULL); | 1815 ASSERT(prop->key()->AsLiteral() != NULL); |
1793 | 1816 |
(...skipping 1974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3768 __ ret(0); | 3791 __ ret(0); |
3769 } | 3792 } |
3770 | 3793 |
3771 | 3794 |
3772 #undef __ | 3795 #undef __ |
3773 | 3796 |
3774 | 3797 |
3775 } } // namespace v8::internal | 3798 } } // namespace v8::internal |
3776 | 3799 |
3777 #endif // V8_TARGET_ARCH_X64 | 3800 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |