| 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 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 Comment cmnt(masm_, "[ Declarations"); | 271 Comment cmnt(masm_, "[ Declarations"); |
| 272 scope()->VisitIllegalRedeclaration(this); | 272 scope()->VisitIllegalRedeclaration(this); |
| 273 | 273 |
| 274 } else { | 274 } else { |
| 275 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 275 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
| 276 { Comment cmnt(masm_, "[ Declarations"); | 276 { Comment cmnt(masm_, "[ Declarations"); |
| 277 // For named function expressions, declare the function name as a | 277 // For named function expressions, declare the function name as a |
| 278 // constant. | 278 // constant. |
| 279 if (scope()->is_function_scope() && scope()->function() != NULL) { | 279 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 280 int ignored = 0; | 280 int ignored = 0; |
| 281 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); | 281 VariableProxy* proxy = scope()->function(); |
| 282 ASSERT(proxy->var()->mode() == CONST || |
| 283 proxy->var()->mode() == CONST_HARMONY); |
| 284 EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); |
| 282 } | 285 } |
| 283 VisitDeclarations(scope()->declarations()); | 286 VisitDeclarations(scope()->declarations()); |
| 284 } | 287 } |
| 285 | 288 |
| 286 { Comment cmnt(masm_, "[ Stack check"); | 289 { Comment cmnt(masm_, "[ Stack check"); |
| 287 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 290 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
| 288 Label ok; | 291 Label ok; |
| 289 __ LoadRoot(t0, Heap::kStackLimitRootIndex); | 292 __ LoadRoot(t0, Heap::kStackLimitRootIndex); |
| 290 __ Branch(&ok, hs, sp, Operand(t0)); | 293 __ Branch(&ok, hs, sp, Operand(t0)); |
| 291 StackCheckStub stub; | 294 StackCheckStub stub; |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 | 724 |
| 722 | 725 |
| 723 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 726 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
| 724 VariableMode mode, | 727 VariableMode mode, |
| 725 FunctionLiteral* function, | 728 FunctionLiteral* function, |
| 726 int* global_count) { | 729 int* global_count) { |
| 727 // If it was not possible to allocate the variable at compile time, we | 730 // If it was not possible to allocate the variable at compile time, we |
| 728 // need to "declare" it at runtime to make sure it actually exists in the | 731 // need to "declare" it at runtime to make sure it actually exists in the |
| 729 // local context. | 732 // local context. |
| 730 Variable* variable = proxy->var(); | 733 Variable* variable = proxy->var(); |
| 734 bool binding_needs_init = |
| 735 mode == CONST || mode == CONST_HARMONY || mode == LET; |
| 731 switch (variable->location()) { | 736 switch (variable->location()) { |
| 732 case Variable::UNALLOCATED: | 737 case Variable::UNALLOCATED: |
| 733 ++(*global_count); | 738 ++(*global_count); |
| 734 break; | 739 break; |
| 735 | 740 |
| 736 case Variable::PARAMETER: | 741 case Variable::PARAMETER: |
| 737 case Variable::LOCAL: | 742 case Variable::LOCAL: |
| 738 if (function != NULL) { | 743 if (function != NULL) { |
| 739 Comment cmnt(masm_, "[ Declaration"); | 744 Comment cmnt(masm_, "[ Declaration"); |
| 740 VisitForAccumulatorValue(function); | 745 VisitForAccumulatorValue(function); |
| 741 __ sw(result_register(), StackOperand(variable)); | 746 __ sw(result_register(), StackOperand(variable)); |
| 742 } else if (mode == CONST || mode == LET) { | 747 } else if (binding_needs_init) { |
| 743 Comment cmnt(masm_, "[ Declaration"); | 748 Comment cmnt(masm_, "[ Declaration"); |
| 744 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 749 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 745 __ sw(t0, StackOperand(variable)); | 750 __ sw(t0, StackOperand(variable)); |
| 746 } | 751 } |
| 747 break; | 752 break; |
| 748 | 753 |
| 749 case Variable::CONTEXT: | 754 case Variable::CONTEXT: |
| 750 // The variable in the decl always resides in the current function | 755 // The variable in the decl always resides in the current function |
| 751 // context. | 756 // context. |
| 752 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 757 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 768 // We know that we have written a function, which is not a smi. | 773 // We know that we have written a function, which is not a smi. |
| 769 __ RecordWriteContextSlot(cp, | 774 __ RecordWriteContextSlot(cp, |
| 770 offset, | 775 offset, |
| 771 result_register(), | 776 result_register(), |
| 772 a2, | 777 a2, |
| 773 kRAHasBeenSaved, | 778 kRAHasBeenSaved, |
| 774 kDontSaveFPRegs, | 779 kDontSaveFPRegs, |
| 775 EMIT_REMEMBERED_SET, | 780 EMIT_REMEMBERED_SET, |
| 776 OMIT_SMI_CHECK); | 781 OMIT_SMI_CHECK); |
| 777 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 782 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 778 } else if (mode == CONST || mode == LET) { | 783 } else if (binding_needs_init) { |
| 779 Comment cmnt(masm_, "[ Declaration"); | 784 Comment cmnt(masm_, "[ Declaration"); |
| 780 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 785 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 781 __ sw(at, ContextOperand(cp, variable->index())); | 786 __ sw(at, ContextOperand(cp, variable->index())); |
| 782 // No write barrier since the_hole_value is in old space. | 787 // No write barrier since the_hole_value is in old space. |
| 783 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 788 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 784 } | 789 } |
| 785 break; | 790 break; |
| 786 | 791 |
| 787 case Variable::LOOKUP: { | 792 case Variable::LOOKUP: { |
| 788 Comment cmnt(masm_, "[ Declaration"); | 793 Comment cmnt(masm_, "[ Declaration"); |
| 789 __ li(a2, Operand(variable->name())); | 794 __ li(a2, Operand(variable->name())); |
| 790 // Declaration nodes are always introduced in one of three modes. | 795 // Declaration nodes are always introduced in one of four modes. |
| 791 ASSERT(mode == VAR || mode == CONST || mode == LET); | 796 ASSERT(mode == VAR || |
| 792 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; | 797 mode == CONST || |
| 798 mode == CONST_HARMONY || |
| 799 mode == LET); |
| 800 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) |
| 801 ? READ_ONLY : NONE; |
| 793 __ li(a1, Operand(Smi::FromInt(attr))); | 802 __ li(a1, Operand(Smi::FromInt(attr))); |
| 794 // Push initial value, if any. | 803 // Push initial value, if any. |
| 795 // Note: For variables we must not push an initial value (such as | 804 // Note: For variables we must not push an initial value (such as |
| 796 // 'undefined') because we may have a (legal) redeclaration and we | 805 // 'undefined') because we may have a (legal) redeclaration and we |
| 797 // must not destroy the current value. | 806 // must not destroy the current value. |
| 798 if (function != NULL) { | 807 if (function != NULL) { |
| 799 __ Push(cp, a2, a1); | 808 __ Push(cp, a2, a1); |
| 800 // Push initial value for function declaration. | 809 // Push initial value for function declaration. |
| 801 VisitForStackValue(function); | 810 VisitForStackValue(function); |
| 802 } else if (mode == CONST || mode == LET) { | 811 } else if (binding_needs_init) { |
| 803 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); | 812 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); |
| 804 __ Push(cp, a2, a1, a0); | 813 __ Push(cp, a2, a1, a0); |
| 805 } else { | 814 } else { |
| 806 ASSERT(Smi::FromInt(0) == 0); | 815 ASSERT(Smi::FromInt(0) == 0); |
| 807 __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value. | 816 __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value. |
| 808 __ Push(cp, a2, a1, a0); | 817 __ Push(cp, a2, a1, a0); |
| 809 } | 818 } |
| 810 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 819 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 811 break; | 820 break; |
| 812 } | 821 } |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 // introducing variables. In those cases, we do not want to | 1230 // introducing variables. In those cases, we do not want to |
| 1222 // perform a runtime call for all variables in the scope | 1231 // perform a runtime call for all variables in the scope |
| 1223 // containing the eval. | 1232 // containing the eval. |
| 1224 if (var->mode() == DYNAMIC_GLOBAL) { | 1233 if (var->mode() == DYNAMIC_GLOBAL) { |
| 1225 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1234 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
| 1226 __ Branch(done); | 1235 __ Branch(done); |
| 1227 } else if (var->mode() == DYNAMIC_LOCAL) { | 1236 } else if (var->mode() == DYNAMIC_LOCAL) { |
| 1228 Variable* local = var->local_if_not_shadowed(); | 1237 Variable* local = var->local_if_not_shadowed(); |
| 1229 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); | 1238 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); |
| 1230 if (local->mode() == CONST || | 1239 if (local->mode() == CONST || |
| 1240 local->mode() == CONST_HARMONY || |
| 1231 local->mode() == LET) { | 1241 local->mode() == LET) { |
| 1232 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1242 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 1233 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1243 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
| 1234 if (local->mode() == CONST) { | 1244 if (local->mode() == CONST) { |
| 1235 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1245 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
| 1236 __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole. | 1246 __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole. |
| 1237 } else { // LET | 1247 } else { // LET || CONST_HARMONY |
| 1238 __ Branch(done, ne, at, Operand(zero_reg)); | 1248 __ Branch(done, ne, at, Operand(zero_reg)); |
| 1239 __ li(a0, Operand(var->name())); | 1249 __ li(a0, Operand(var->name())); |
| 1240 __ push(a0); | 1250 __ push(a0); |
| 1241 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1251 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1242 } | 1252 } |
| 1243 } | 1253 } |
| 1244 __ Branch(done); | 1254 __ Branch(done); |
| 1245 } | 1255 } |
| 1246 } | 1256 } |
| 1247 | 1257 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1265 context()->Plug(v0); | 1275 context()->Plug(v0); |
| 1266 break; | 1276 break; |
| 1267 } | 1277 } |
| 1268 | 1278 |
| 1269 case Variable::PARAMETER: | 1279 case Variable::PARAMETER: |
| 1270 case Variable::LOCAL: | 1280 case Variable::LOCAL: |
| 1271 case Variable::CONTEXT: { | 1281 case Variable::CONTEXT: { |
| 1272 Comment cmnt(masm_, var->IsContextSlot() | 1282 Comment cmnt(masm_, var->IsContextSlot() |
| 1273 ? "Context variable" | 1283 ? "Context variable" |
| 1274 : "Stack variable"); | 1284 : "Stack variable"); |
| 1275 if (var->mode() != LET && var->mode() != CONST) { | 1285 if (!var->binding_needs_init()) { |
| 1276 context()->Plug(var); | 1286 context()->Plug(var); |
| 1277 } else { | 1287 } else { |
| 1278 // Let and const need a read barrier. | 1288 // Let and const need a read barrier. |
| 1279 GetVar(v0, var); | 1289 GetVar(v0, var); |
| 1280 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1290 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 1281 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1291 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
| 1282 if (var->mode() == LET) { | 1292 if (var->mode() == LET || var->mode() == CONST_HARMONY) { |
| 1293 // Throw a reference error when using an uninitialized let/const |
| 1294 // binding in harmony mode. |
| 1283 Label done; | 1295 Label done; |
| 1284 __ Branch(&done, ne, at, Operand(zero_reg)); | 1296 __ Branch(&done, ne, at, Operand(zero_reg)); |
| 1285 __ li(a0, Operand(var->name())); | 1297 __ li(a0, Operand(var->name())); |
| 1286 __ push(a0); | 1298 __ push(a0); |
| 1287 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1299 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1288 __ bind(&done); | 1300 __ bind(&done); |
| 1289 } else { | 1301 } else { |
| 1302 // Uninitalized const bindings outside of harmony mode are unholed. |
| 1303 ASSERT(var->mode() == CONST); |
| 1290 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1304 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
| 1291 __ movz(v0, a0, at); // Conditional move: Undefined if TheHole. | 1305 __ movz(v0, a0, at); // Conditional move: Undefined if TheHole. |
| 1292 } | 1306 } |
| 1293 context()->Plug(v0); | 1307 context()->Plug(v0); |
| 1294 } | 1308 } |
| 1295 break; | 1309 break; |
| 1296 } | 1310 } |
| 1297 | 1311 |
| 1298 case Variable::LOOKUP: { | 1312 case Variable::LOOKUP: { |
| 1299 Label done, slow; | 1313 Label done, slow; |
| (...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1957 __ sw(result_register(), location); | 1971 __ sw(result_register(), location); |
| 1958 if (var->IsContextSlot()) { | 1972 if (var->IsContextSlot()) { |
| 1959 // RecordWrite may destroy all its register arguments. | 1973 // RecordWrite may destroy all its register arguments. |
| 1960 __ mov(a3, result_register()); | 1974 __ mov(a3, result_register()); |
| 1961 int offset = Context::SlotOffset(var->index()); | 1975 int offset = Context::SlotOffset(var->index()); |
| 1962 __ RecordWriteContextSlot( | 1976 __ RecordWriteContextSlot( |
| 1963 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | 1977 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
| 1964 } | 1978 } |
| 1965 } | 1979 } |
| 1966 | 1980 |
| 1967 } else if (var->mode() != CONST) { | 1981 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 1968 // Assignment to var or initializing assignment to let. | 1982 // Assignment to var or initializing assignment to let/const |
| 1983 // in harmony mode. |
| 1969 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1984 if (var->IsStackAllocated() || var->IsContextSlot()) { |
| 1970 MemOperand location = VarOperand(var, a1); | 1985 MemOperand location = VarOperand(var, a1); |
| 1971 if (FLAG_debug_code && op == Token::INIT_LET) { | 1986 if (FLAG_debug_code && op == Token::INIT_LET) { |
| 1972 // Check for an uninitialized let binding. | 1987 // Check for an uninitialized let binding. |
| 1973 __ lw(a2, location); | 1988 __ lw(a2, location); |
| 1974 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 1989 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 1975 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); | 1990 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); |
| 1976 } | 1991 } |
| 1977 // Perform the assignment. | 1992 // Perform the assignment. |
| 1978 __ sw(v0, location); | 1993 __ sw(v0, location); |
| (...skipping 2357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4336 *context_length = 0; | 4351 *context_length = 0; |
| 4337 return previous_; | 4352 return previous_; |
| 4338 } | 4353 } |
| 4339 | 4354 |
| 4340 | 4355 |
| 4341 #undef __ | 4356 #undef __ |
| 4342 | 4357 |
| 4343 } } // namespace v8::internal | 4358 } } // namespace v8::internal |
| 4344 | 4359 |
| 4345 #endif // V8_TARGET_ARCH_MIPS | 4360 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |