| 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 |