Chromium Code Reviews| 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 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 704 | 704 |
| 705 | 705 |
| 706 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 706 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
| 707 VariableMode 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 bool binding_needs_init = | |
|
fschneider
2011/10/24 12:58:13
EmitDeclaration is used in two places. Is it possi
Steven
2011/10/24 14:05:18
Unfortunately for DYNAMIC_GLOBAL variables we can
fschneider
2011/10/24 15:33:44
Yes, passing a declaration object would be the rig
| |
| 715 mode == CONST || mode == CONST_HARMONY || mode == LET; | |
| 714 switch (variable->location()) { | 716 switch (variable->location()) { |
| 715 case Variable::UNALLOCATED: | 717 case Variable::UNALLOCATED: |
| 716 ++(*global_count); | 718 ++(*global_count); |
| 717 break; | 719 break; |
| 718 | 720 |
| 719 case Variable::PARAMETER: | 721 case Variable::PARAMETER: |
| 720 case Variable::LOCAL: | 722 case Variable::LOCAL: |
| 721 if (function != NULL) { | 723 if (function != NULL) { |
| 722 Comment cmnt(masm_, "[ Declaration"); | 724 Comment cmnt(masm_, "[ Declaration"); |
| 723 VisitForAccumulatorValue(function); | 725 VisitForAccumulatorValue(function); |
| 724 __ mov(StackOperand(variable), result_register()); | 726 __ mov(StackOperand(variable), result_register()); |
| 725 } else if (mode == CONST || mode == LET) { | 727 } else if (binding_needs_init) { |
| 726 Comment cmnt(masm_, "[ Declaration"); | 728 Comment cmnt(masm_, "[ Declaration"); |
| 727 __ mov(StackOperand(variable), | 729 __ mov(StackOperand(variable), |
| 728 Immediate(isolate()->factory()->the_hole_value())); | 730 Immediate(isolate()->factory()->the_hole_value())); |
| 729 } | 731 } |
| 730 break; | 732 break; |
| 731 | 733 |
| 732 case Variable::CONTEXT: | 734 case Variable::CONTEXT: |
| 733 // The variable in the decl always resides in the current function | 735 // The variable in the decl always resides in the current function |
| 734 // context. | 736 // context. |
| 735 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 737 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 747 __ mov(ContextOperand(esi, variable->index()), result_register()); | 749 __ mov(ContextOperand(esi, variable->index()), result_register()); |
| 748 // We know that we have written a function, which is not a smi. | 750 // We know that we have written a function, which is not a smi. |
| 749 __ RecordWriteContextSlot(esi, | 751 __ RecordWriteContextSlot(esi, |
| 750 Context::SlotOffset(variable->index()), | 752 Context::SlotOffset(variable->index()), |
| 751 result_register(), | 753 result_register(), |
| 752 ecx, | 754 ecx, |
| 753 kDontSaveFPRegs, | 755 kDontSaveFPRegs, |
| 754 EMIT_REMEMBERED_SET, | 756 EMIT_REMEMBERED_SET, |
| 755 OMIT_SMI_CHECK); | 757 OMIT_SMI_CHECK); |
| 756 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 758 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 757 } else if (mode == CONST || mode == LET) { | 759 } else if (binding_needs_init) { |
| 758 Comment cmnt(masm_, "[ Declaration"); | 760 Comment cmnt(masm_, "[ Declaration"); |
| 759 __ mov(ContextOperand(esi, variable->index()), | 761 __ mov(ContextOperand(esi, variable->index()), |
| 760 Immediate(isolate()->factory()->the_hole_value())); | 762 Immediate(isolate()->factory()->the_hole_value())); |
| 761 // No write barrier since the hole value is in old space. | 763 // No write barrier since the hole value is in old space. |
| 762 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 764 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 763 } | 765 } |
| 764 break; | 766 break; |
| 765 | 767 |
| 766 case Variable::LOOKUP: { | 768 case Variable::LOOKUP: { |
| 767 Comment cmnt(masm_, "[ Declaration"); | 769 Comment cmnt(masm_, "[ Declaration"); |
| 768 __ push(esi); | 770 __ push(esi); |
| 769 __ push(Immediate(variable->name())); | 771 __ push(Immediate(variable->name())); |
| 770 // Declaration nodes are always introduced in one of three modes. | 772 // Declaration nodes are always introduced in one of four modes. |
| 771 ASSERT(mode == VAR || mode == CONST || mode == LET); | 773 ASSERT(mode == VAR || |
| 772 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; | 774 mode == CONST || |
| 775 mode == CONST_HARMONY || | |
| 776 mode == LET); | |
| 777 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) | |
| 778 ? READ_ONLY : NONE; | |
| 773 __ push(Immediate(Smi::FromInt(attr))); | 779 __ push(Immediate(Smi::FromInt(attr))); |
| 774 // Push initial value, if any. | 780 // Push initial value, if any. |
| 775 // Note: For variables we must not push an initial value (such as | 781 // Note: For variables we must not push an initial value (such as |
| 776 // 'undefined') because we may have a (legal) redeclaration and we | 782 // 'undefined') because we may have a (legal) redeclaration and we |
| 777 // must not destroy the current value. | 783 // must not destroy the current value. |
| 778 increment_stack_height(3); | 784 increment_stack_height(3); |
| 779 if (function != NULL) { | 785 if (function != NULL) { |
| 780 VisitForStackValue(function); | 786 VisitForStackValue(function); |
| 781 } else if (mode == CONST || mode == LET) { | 787 } else if (binding_needs_init) { |
| 782 __ push(Immediate(isolate()->factory()->the_hole_value())); | 788 __ push(Immediate(isolate()->factory()->the_hole_value())); |
| 783 increment_stack_height(); | 789 increment_stack_height(); |
| 784 } else { | 790 } else { |
| 785 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. | 791 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. |
| 786 increment_stack_height(); | 792 increment_stack_height(); |
| 787 } | 793 } |
| 788 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 794 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 789 decrement_stack_height(4); | 795 decrement_stack_height(4); |
| 790 break; | 796 break; |
| 791 } | 797 } |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1199 // introducing variables. In those cases, we do not want to | 1205 // introducing variables. In those cases, we do not want to |
| 1200 // perform a runtime call for all variables in the scope | 1206 // perform a runtime call for all variables in the scope |
| 1201 // containing the eval. | 1207 // containing the eval. |
| 1202 if (var->mode() == DYNAMIC_GLOBAL) { | 1208 if (var->mode() == DYNAMIC_GLOBAL) { |
| 1203 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1209 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
| 1204 __ jmp(done); | 1210 __ jmp(done); |
| 1205 } else if (var->mode() == DYNAMIC_LOCAL) { | 1211 } else if (var->mode() == DYNAMIC_LOCAL) { |
| 1206 Variable* local = var->local_if_not_shadowed(); | 1212 Variable* local = var->local_if_not_shadowed(); |
| 1207 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); | 1213 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); |
| 1208 if (local->mode() == CONST || | 1214 if (local->mode() == CONST || |
| 1215 local->mode() == CONST_HARMONY || | |
| 1209 local->mode() == LET) { | 1216 local->mode() == LET) { |
| 1210 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1217 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1211 __ j(not_equal, done); | 1218 __ j(not_equal, done); |
| 1212 if (local->mode() == CONST) { | 1219 if (local->mode() == CONST) { |
| 1213 __ mov(eax, isolate()->factory()->undefined_value()); | 1220 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1214 } else { // LET | 1221 } else { // LET || CONST_HARMONY |
| 1215 __ push(Immediate(var->name())); | 1222 __ push(Immediate(var->name())); |
| 1216 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1223 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1217 } | 1224 } |
| 1218 } | 1225 } |
| 1219 __ jmp(done); | 1226 __ jmp(done); |
| 1220 } | 1227 } |
| 1221 } | 1228 } |
| 1222 | 1229 |
| 1223 | 1230 |
| 1224 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1231 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1240 context()->Plug(eax); | 1247 context()->Plug(eax); |
| 1241 break; | 1248 break; |
| 1242 } | 1249 } |
| 1243 | 1250 |
| 1244 case Variable::PARAMETER: | 1251 case Variable::PARAMETER: |
| 1245 case Variable::LOCAL: | 1252 case Variable::LOCAL: |
| 1246 case Variable::CONTEXT: { | 1253 case Variable::CONTEXT: { |
| 1247 Comment cmnt(masm_, var->IsContextSlot() | 1254 Comment cmnt(masm_, var->IsContextSlot() |
| 1248 ? "Context variable" | 1255 ? "Context variable" |
| 1249 : "Stack variable"); | 1256 : "Stack variable"); |
| 1250 if (var->mode() != LET && var->mode() != CONST) { | 1257 if (!var->binding_needs_init()) { |
| 1251 context()->Plug(var); | 1258 context()->Plug(var); |
| 1252 } else { | 1259 } else { |
| 1253 // Let and const need a read barrier. | 1260 // Let and const need a read barrier. |
| 1254 Label done; | 1261 Label done; |
| 1255 GetVar(eax, var); | 1262 GetVar(eax, var); |
| 1256 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1263 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1257 __ j(not_equal, &done, Label::kNear); | 1264 __ j(not_equal, &done, Label::kNear); |
| 1258 if (var->mode() == LET) { | 1265 if (var->mode() == LET || var->mode() == CONST_HARMONY) { |
| 1266 // Throw a reference error when using an uninitialized let/const | |
| 1267 // binding in harmony mode. | |
| 1259 __ push(Immediate(var->name())); | 1268 __ push(Immediate(var->name())); |
| 1260 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1269 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1261 } else { // CONST | 1270 } else { |
| 1271 // Uninitalized const bindings outside of harmony mode are unholed. | |
| 1272 ASSERT(var->mode() == CONST); | |
| 1262 __ mov(eax, isolate()->factory()->undefined_value()); | 1273 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1263 } | 1274 } |
| 1264 __ bind(&done); | 1275 __ bind(&done); |
| 1265 context()->Plug(eax); | 1276 context()->Plug(eax); |
| 1266 } | 1277 } |
| 1267 break; | 1278 break; |
| 1268 } | 1279 } |
| 1269 | 1280 |
| 1270 case Variable::LOOKUP: { | 1281 case Variable::LOOKUP: { |
| 1271 Label done, slow; | 1282 Label done, slow; |
| (...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1934 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1945 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1935 __ bind(&assign); | 1946 __ bind(&assign); |
| 1936 __ mov(location, eax); | 1947 __ mov(location, eax); |
| 1937 if (var->IsContextSlot()) { | 1948 if (var->IsContextSlot()) { |
| 1938 __ mov(edx, eax); | 1949 __ mov(edx, eax); |
| 1939 int offset = Context::SlotOffset(var->index()); | 1950 int offset = Context::SlotOffset(var->index()); |
| 1940 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | 1951 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
| 1941 } | 1952 } |
| 1942 } | 1953 } |
| 1943 | 1954 |
| 1944 } else if (var->mode() != CONST) { | 1955 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 1945 // Assignment to var or initializing assignment to let. | 1956 // Assignment to var or initializing assignment to let/const |
| 1957 // in harmony mode. | |
| 1946 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1958 if (var->IsStackAllocated() || var->IsContextSlot()) { |
| 1947 MemOperand location = VarOperand(var, ecx); | 1959 MemOperand location = VarOperand(var, ecx); |
| 1948 if (FLAG_debug_code && op == Token::INIT_LET) { | 1960 if (FLAG_debug_code && op == Token::INIT_LET) { |
| 1949 // Check for an uninitialized let binding. | 1961 // Check for an uninitialized let binding. |
| 1950 __ mov(edx, location); | 1962 __ mov(edx, location); |
| 1951 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1963 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1952 __ Check(equal, "Let binding re-initialization."); | 1964 __ Check(equal, "Let binding re-initialization."); |
| 1953 } | 1965 } |
| 1954 // Perform the assignment. | 1966 // Perform the assignment. |
| 1955 __ mov(location, eax); | 1967 __ mov(location, eax); |
| (...skipping 2430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4386 *context_length = 0; | 4398 *context_length = 0; |
| 4387 return previous_; | 4399 return previous_; |
| 4388 } | 4400 } |
| 4389 | 4401 |
| 4390 | 4402 |
| 4391 #undef __ | 4403 #undef __ |
| 4392 | 4404 |
| 4393 } } // namespace v8::internal | 4405 } } // namespace v8::internal |
| 4394 | 4406 |
| 4395 #endif // V8_TARGET_ARCH_IA32 | 4407 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |