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 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 Comment cmnt(masm_, "[ Declarations"); | 259 Comment cmnt(masm_, "[ Declarations"); |
260 scope()->VisitIllegalRedeclaration(this); | 260 scope()->VisitIllegalRedeclaration(this); |
261 | 261 |
262 } else { | 262 } else { |
263 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 263 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
264 { Comment cmnt(masm_, "[ Declarations"); | 264 { Comment cmnt(masm_, "[ Declarations"); |
265 // For named function expressions, declare the function name as a | 265 // For named function expressions, declare the function name as a |
266 // constant. | 266 // constant. |
267 if (scope()->is_function_scope() && scope()->function() != NULL) { | 267 if (scope()->is_function_scope() && scope()->function() != NULL) { |
268 int ignored = 0; | 268 int ignored = 0; |
269 EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); | 269 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); |
270 } | 270 } |
271 VisitDeclarations(scope()->declarations()); | 271 VisitDeclarations(scope()->declarations()); |
272 } | 272 } |
273 | 273 |
274 { Comment cmnt(masm_, "[ Stack check"); | 274 { Comment cmnt(masm_, "[ Stack check"); |
275 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 275 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
276 Label ok; | 276 Label ok; |
277 ExternalReference stack_limit = | 277 ExternalReference stack_limit = |
278 ExternalReference::address_of_stack_limit(isolate()); | 278 ExternalReference::address_of_stack_limit(isolate()); |
279 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 279 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
697 | 697 |
698 if (should_normalize) { | 698 if (should_normalize) { |
699 __ cmp(eax, isolate()->factory()->true_value()); | 699 __ cmp(eax, isolate()->factory()->true_value()); |
700 Split(equal, if_true, if_false, NULL); | 700 Split(equal, if_true, if_false, NULL); |
701 __ bind(&skip); | 701 __ bind(&skip); |
702 } | 702 } |
703 } | 703 } |
704 | 704 |
705 | 705 |
706 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 706 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
707 Variable::Mode mode, | 707 VariableMode mode, |
708 FunctionLiteral* function, | 708 FunctionLiteral* function, |
709 int* global_count) { | 709 int* global_count) { |
710 // If it was not possible to allocate the variable at compile time, we | 710 // If it was not possible to allocate the variable at compile time, we |
711 // need to "declare" it at runtime to make sure it actually exists in the | 711 // need to "declare" it at runtime to make sure it actually exists in the |
712 // local context. | 712 // local context. |
713 Variable* variable = proxy->var(); | 713 Variable* variable = proxy->var(); |
714 switch (variable->location()) { | 714 switch (variable->location()) { |
715 case Variable::UNALLOCATED: | 715 case Variable::UNALLOCATED: |
716 ++(*global_count); | 716 ++(*global_count); |
717 break; | 717 break; |
718 | 718 |
719 case Variable::PARAMETER: | 719 case Variable::PARAMETER: |
720 case Variable::LOCAL: | 720 case Variable::LOCAL: |
721 if (function != NULL) { | 721 if (function != NULL) { |
722 Comment cmnt(masm_, "[ Declaration"); | 722 Comment cmnt(masm_, "[ Declaration"); |
723 VisitForAccumulatorValue(function); | 723 VisitForAccumulatorValue(function); |
724 __ mov(StackOperand(variable), result_register()); | 724 __ mov(StackOperand(variable), result_register()); |
725 } else if (mode == Variable::CONST || mode == Variable::LET) { | 725 } else if (mode == CONST || mode == LET) { |
726 Comment cmnt(masm_, "[ Declaration"); | 726 Comment cmnt(masm_, "[ Declaration"); |
727 __ mov(StackOperand(variable), | 727 __ mov(StackOperand(variable), |
728 Immediate(isolate()->factory()->the_hole_value())); | 728 Immediate(isolate()->factory()->the_hole_value())); |
729 } | 729 } |
730 break; | 730 break; |
731 | 731 |
732 case Variable::CONTEXT: | 732 case Variable::CONTEXT: |
733 // The variable in the decl always resides in the current function | 733 // The variable in the decl always resides in the current function |
734 // context. | 734 // context. |
735 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 735 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
(...skipping 11 matching lines...) Expand all Loading... |
747 __ mov(ContextOperand(esi, variable->index()), result_register()); | 747 __ mov(ContextOperand(esi, variable->index()), result_register()); |
748 // We know that we have written a function, which is not a smi. | 748 // We know that we have written a function, which is not a smi. |
749 __ RecordWriteContextSlot(esi, | 749 __ RecordWriteContextSlot(esi, |
750 Context::SlotOffset(variable->index()), | 750 Context::SlotOffset(variable->index()), |
751 result_register(), | 751 result_register(), |
752 ecx, | 752 ecx, |
753 kDontSaveFPRegs, | 753 kDontSaveFPRegs, |
754 EMIT_REMEMBERED_SET, | 754 EMIT_REMEMBERED_SET, |
755 OMIT_SMI_CHECK); | 755 OMIT_SMI_CHECK); |
756 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 756 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
757 } else if (mode == Variable::CONST || mode == Variable::LET) { | 757 } else if (mode == CONST || mode == LET) { |
758 Comment cmnt(masm_, "[ Declaration"); | 758 Comment cmnt(masm_, "[ Declaration"); |
759 __ mov(ContextOperand(esi, variable->index()), | 759 __ mov(ContextOperand(esi, variable->index()), |
760 Immediate(isolate()->factory()->the_hole_value())); | 760 Immediate(isolate()->factory()->the_hole_value())); |
761 // No write barrier since the hole value is in old space. | 761 // No write barrier since the hole value is in old space. |
762 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 762 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
763 } | 763 } |
764 break; | 764 break; |
765 | 765 |
766 case Variable::LOOKUP: { | 766 case Variable::LOOKUP: { |
767 Comment cmnt(masm_, "[ Declaration"); | 767 Comment cmnt(masm_, "[ Declaration"); |
768 __ push(esi); | 768 __ push(esi); |
769 __ push(Immediate(variable->name())); | 769 __ push(Immediate(variable->name())); |
770 // Declaration nodes are always introduced in one of three modes. | 770 // Declaration nodes are always introduced in one of three modes. |
771 ASSERT(mode == Variable::VAR || | 771 ASSERT(mode == VAR || mode == CONST || mode == LET); |
772 mode == Variable::CONST || | 772 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; |
773 mode == Variable::LET); | |
774 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | |
775 __ push(Immediate(Smi::FromInt(attr))); | 773 __ push(Immediate(Smi::FromInt(attr))); |
776 // Push initial value, if any. | 774 // Push initial value, if any. |
777 // Note: For variables we must not push an initial value (such as | 775 // Note: For variables we must not push an initial value (such as |
778 // 'undefined') because we may have a (legal) redeclaration and we | 776 // 'undefined') because we may have a (legal) redeclaration and we |
779 // must not destroy the current value. | 777 // must not destroy the current value. |
780 increment_stack_height(3); | 778 increment_stack_height(3); |
781 if (function != NULL) { | 779 if (function != NULL) { |
782 VisitForStackValue(function); | 780 VisitForStackValue(function); |
783 } else if (mode == Variable::CONST || mode == Variable::LET) { | 781 } else if (mode == CONST || mode == LET) { |
784 __ push(Immediate(isolate()->factory()->the_hole_value())); | 782 __ push(Immediate(isolate()->factory()->the_hole_value())); |
785 increment_stack_height(); | 783 increment_stack_height(); |
786 } else { | 784 } else { |
787 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. | 785 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. |
788 increment_stack_height(); | 786 increment_stack_height(); |
789 } | 787 } |
790 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 788 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
791 decrement_stack_height(4); | 789 decrement_stack_height(4); |
792 break; | 790 break; |
793 } | 791 } |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1194 | 1192 |
1195 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, | 1193 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
1196 TypeofState typeof_state, | 1194 TypeofState typeof_state, |
1197 Label* slow, | 1195 Label* slow, |
1198 Label* done) { | 1196 Label* done) { |
1199 // Generate fast-case code for variables that might be shadowed by | 1197 // Generate fast-case code for variables that might be shadowed by |
1200 // eval-introduced variables. Eval is used a lot without | 1198 // eval-introduced variables. Eval is used a lot without |
1201 // introducing variables. In those cases, we do not want to | 1199 // introducing variables. In those cases, we do not want to |
1202 // perform a runtime call for all variables in the scope | 1200 // perform a runtime call for all variables in the scope |
1203 // containing the eval. | 1201 // containing the eval. |
1204 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 1202 if (var->mode() == DYNAMIC_GLOBAL) { |
1205 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1203 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1206 __ jmp(done); | 1204 __ jmp(done); |
1207 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | 1205 } else if (var->mode() == DYNAMIC_LOCAL) { |
1208 Variable* local = var->local_if_not_shadowed(); | 1206 Variable* local = var->local_if_not_shadowed(); |
1209 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); | 1207 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); |
1210 if (local->mode() == Variable::CONST || | 1208 if (local->mode() == CONST || |
1211 local->mode() == Variable::LET) { | 1209 local->mode() == LET) { |
1212 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1210 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1213 __ j(not_equal, done); | 1211 __ j(not_equal, done); |
1214 if (local->mode() == Variable::CONST) { | 1212 if (local->mode() == CONST) { |
1215 __ mov(eax, isolate()->factory()->undefined_value()); | 1213 __ mov(eax, isolate()->factory()->undefined_value()); |
1216 } else { // Variable::LET | 1214 } else { // LET |
1217 __ push(Immediate(var->name())); | 1215 __ push(Immediate(var->name())); |
1218 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1216 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1219 } | 1217 } |
1220 } | 1218 } |
1221 __ jmp(done); | 1219 __ jmp(done); |
1222 } | 1220 } |
1223 } | 1221 } |
1224 | 1222 |
1225 | 1223 |
1226 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1224 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
(...skipping 15 matching lines...) Expand all Loading... |
1242 context()->Plug(eax); | 1240 context()->Plug(eax); |
1243 break; | 1241 break; |
1244 } | 1242 } |
1245 | 1243 |
1246 case Variable::PARAMETER: | 1244 case Variable::PARAMETER: |
1247 case Variable::LOCAL: | 1245 case Variable::LOCAL: |
1248 case Variable::CONTEXT: { | 1246 case Variable::CONTEXT: { |
1249 Comment cmnt(masm_, var->IsContextSlot() | 1247 Comment cmnt(masm_, var->IsContextSlot() |
1250 ? "Context variable" | 1248 ? "Context variable" |
1251 : "Stack variable"); | 1249 : "Stack variable"); |
1252 if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { | 1250 if (var->mode() != LET && var->mode() != CONST) { |
1253 context()->Plug(var); | 1251 context()->Plug(var); |
1254 } else { | 1252 } else { |
1255 // Let and const need a read barrier. | 1253 // Let and const need a read barrier. |
1256 Label done; | 1254 Label done; |
1257 GetVar(eax, var); | 1255 GetVar(eax, var); |
1258 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1256 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1259 __ j(not_equal, &done, Label::kNear); | 1257 __ j(not_equal, &done, Label::kNear); |
1260 if (var->mode() == Variable::LET) { | 1258 if (var->mode() == LET) { |
1261 __ push(Immediate(var->name())); | 1259 __ push(Immediate(var->name())); |
1262 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1260 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1263 } else { // Variable::CONST | 1261 } else { // CONST |
1264 __ mov(eax, isolate()->factory()->undefined_value()); | 1262 __ mov(eax, isolate()->factory()->undefined_value()); |
1265 } | 1263 } |
1266 __ bind(&done); | 1264 __ bind(&done); |
1267 context()->Plug(eax); | 1265 context()->Plug(eax); |
1268 } | 1266 } |
1269 break; | 1267 break; |
1270 } | 1268 } |
1271 | 1269 |
1272 case Variable::LOOKUP: { | 1270 case Variable::LOOKUP: { |
1273 Label done, slow; | 1271 Label done, slow; |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1859 // scope. However, unlike var initializers, const initializers are | 1857 // scope. However, unlike var initializers, const initializers are |
1860 // able to drill a hole to that function context, even from inside a | 1858 // able to drill a hole to that function context, even from inside a |
1861 // 'with' context. We thus bypass the normal static scope lookup for | 1859 // 'with' context. We thus bypass the normal static scope lookup for |
1862 // var->IsContextSlot(). | 1860 // var->IsContextSlot(). |
1863 __ push(eax); | 1861 __ push(eax); |
1864 __ push(esi); | 1862 __ push(esi); |
1865 __ push(Immediate(var->name())); | 1863 __ push(Immediate(var->name())); |
1866 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1864 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
1867 } | 1865 } |
1868 | 1866 |
1869 } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { | 1867 } else if (var->mode() == LET && op != Token::INIT_LET) { |
1870 // Non-initializing assignment to let variable needs a write barrier. | 1868 // Non-initializing assignment to let variable needs a write barrier. |
1871 if (var->IsLookupSlot()) { | 1869 if (var->IsLookupSlot()) { |
1872 __ push(eax); // Value. | 1870 __ push(eax); // Value. |
1873 __ push(esi); // Context. | 1871 __ push(esi); // Context. |
1874 __ push(Immediate(var->name())); | 1872 __ push(Immediate(var->name())); |
1875 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 1873 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
1876 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1874 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1877 } else { | 1875 } else { |
1878 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 1876 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
1879 Label assign; | 1877 Label assign; |
1880 MemOperand location = VarOperand(var, ecx); | 1878 MemOperand location = VarOperand(var, ecx); |
1881 __ mov(edx, location); | 1879 __ mov(edx, location); |
1882 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1880 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1883 __ j(not_equal, &assign, Label::kNear); | 1881 __ j(not_equal, &assign, Label::kNear); |
1884 __ push(Immediate(var->name())); | 1882 __ push(Immediate(var->name())); |
1885 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1883 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1886 __ bind(&assign); | 1884 __ bind(&assign); |
1887 __ mov(location, eax); | 1885 __ mov(location, eax); |
1888 if (var->IsContextSlot()) { | 1886 if (var->IsContextSlot()) { |
1889 __ mov(edx, eax); | 1887 __ mov(edx, eax); |
1890 int offset = Context::SlotOffset(var->index()); | 1888 int offset = Context::SlotOffset(var->index()); |
1891 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | 1889 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
1892 } | 1890 } |
1893 } | 1891 } |
1894 | 1892 |
1895 } else if (var->mode() != Variable::CONST) { | 1893 } else if (var->mode() != CONST) { |
1896 // Assignment to var or initializing assignment to let. | 1894 // Assignment to var or initializing assignment to let. |
1897 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1895 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1898 MemOperand location = VarOperand(var, ecx); | 1896 MemOperand location = VarOperand(var, ecx); |
1899 if (FLAG_debug_code && op == Token::INIT_LET) { | 1897 if (FLAG_debug_code && op == Token::INIT_LET) { |
1900 // Check for an uninitialized let binding. | 1898 // Check for an uninitialized let binding. |
1901 __ mov(edx, location); | 1899 __ mov(edx, location); |
1902 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1900 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1903 __ Check(equal, "Let binding re-initialization."); | 1901 __ Check(equal, "Let binding re-initialization."); |
1904 } | 1902 } |
1905 // Perform the assignment. | 1903 // Perform the assignment. |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2184 for (int i = 0; i < arg_count; i++) { | 2182 for (int i = 0; i < arg_count; i++) { |
2185 VisitForStackValue(args->at(i)); | 2183 VisitForStackValue(args->at(i)); |
2186 } | 2184 } |
2187 | 2185 |
2188 // If we know that eval can only be shadowed by eval-introduced | 2186 // If we know that eval can only be shadowed by eval-introduced |
2189 // variables we attempt to load the global eval function directly in | 2187 // variables we attempt to load the global eval function directly in |
2190 // generated code. If we succeed, there is no need to perform a | 2188 // generated code. If we succeed, there is no need to perform a |
2191 // context lookup in the runtime system. | 2189 // context lookup in the runtime system. |
2192 Label done; | 2190 Label done; |
2193 Variable* var = proxy->var(); | 2191 Variable* var = proxy->var(); |
2194 if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { | 2192 if (!var->IsUnallocated() && var->mode() == DYNAMIC_GLOBAL) { |
2195 Label slow; | 2193 Label slow; |
2196 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); | 2194 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); |
2197 // Push the function and resolve eval. | 2195 // Push the function and resolve eval. |
2198 __ push(eax); | 2196 __ push(eax); |
2199 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); | 2197 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
2200 __ jmp(&done); | 2198 __ jmp(&done); |
2201 __ bind(&slow); | 2199 __ bind(&slow); |
2202 } | 2200 } |
2203 | 2201 |
2204 // Push a copy of the function (found below the arguments) and | 2202 // Push a copy of the function (found below the arguments) and |
(...skipping 2142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4347 *context_length = 0; | 4345 *context_length = 0; |
4348 return previous_; | 4346 return previous_; |
4349 } | 4347 } |
4350 | 4348 |
4351 | 4349 |
4352 #undef __ | 4350 #undef __ |
4353 | 4351 |
4354 } } // namespace v8::internal | 4352 } } // namespace v8::internal |
4355 | 4353 |
4356 #endif // V8_TARGET_ARCH_IA32 | 4354 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |