OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 #ifdef DEBUG | 131 #ifdef DEBUG |
132 if (strlen(FLAG_stop_at) > 0 && | 132 if (strlen(FLAG_stop_at) > 0 && |
133 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 133 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
134 __ int3(); | 134 __ int3(); |
135 } | 135 } |
136 #endif | 136 #endif |
137 | 137 |
138 // Sloppy mode functions and builtins need to replace the receiver with the | 138 // Sloppy mode functions and builtins need to replace the receiver with the |
139 // global proxy when called as functions (without an explicit receiver | 139 // global proxy when called as functions (without an explicit receiver |
140 // object). | 140 // object). |
141 if (info->is_sloppy_mode() && !info->is_native()) { | 141 if (info->strict_mode() == SLOPPY && !info->is_native()) { |
142 Label ok; | 142 Label ok; |
143 // +1 for return address. | 143 // +1 for return address. |
144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; | 144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
145 __ mov(ecx, Operand(esp, receiver_offset)); | 145 __ mov(ecx, Operand(esp, receiver_offset)); |
146 | 146 |
147 __ cmp(ecx, isolate()->factory()->undefined_value()); | 147 __ cmp(ecx, isolate()->factory()->undefined_value()); |
148 __ j(not_equal, &ok, Label::kNear); | 148 __ j(not_equal, &ok, Label::kNear); |
149 | 149 |
150 __ mov(ecx, GlobalObjectOperand()); | 150 __ mov(ecx, GlobalObjectOperand()); |
151 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | 151 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 int offset = num_parameters * kPointerSize; | 238 int offset = num_parameters * kPointerSize; |
239 __ lea(edx, | 239 __ lea(edx, |
240 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); | 240 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); |
241 __ push(edx); | 241 __ push(edx); |
242 __ push(Immediate(Smi::FromInt(num_parameters))); | 242 __ push(Immediate(Smi::FromInt(num_parameters))); |
243 // Arguments to ArgumentsAccessStub: | 243 // Arguments to ArgumentsAccessStub: |
244 // function, receiver address, parameter count. | 244 // function, receiver address, parameter count. |
245 // The stub will rewrite receiver and parameter count if the previous | 245 // The stub will rewrite receiver and parameter count if the previous |
246 // stack frame was an arguments adapter frame. | 246 // stack frame was an arguments adapter frame. |
247 ArgumentsAccessStub::Type type; | 247 ArgumentsAccessStub::Type type; |
248 if (!is_sloppy_mode()) { | 248 if (strict_mode() == STRICT) { |
249 type = ArgumentsAccessStub::NEW_STRICT; | 249 type = ArgumentsAccessStub::NEW_STRICT; |
250 } else if (function()->has_duplicate_parameters()) { | 250 } else if (function()->has_duplicate_parameters()) { |
251 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; | 251 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; |
252 } else { | 252 } else { |
253 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; | 253 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; |
254 } | 254 } |
255 ArgumentsAccessStub stub(type); | 255 ArgumentsAccessStub stub(type); |
256 __ CallStub(&stub); | 256 __ CallStub(&stub); |
257 | 257 |
258 SetVar(arguments, eax, ebx, edx); | 258 SetVar(arguments, eax, ebx, edx); |
(...skipping 10 matching lines...) Expand all Loading... |
269 scope()->VisitIllegalRedeclaration(this); | 269 scope()->VisitIllegalRedeclaration(this); |
270 | 270 |
271 } else { | 271 } else { |
272 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); | 272 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); |
273 { Comment cmnt(masm_, "[ Declarations"); | 273 { Comment cmnt(masm_, "[ Declarations"); |
274 // For named function expressions, declare the function name as a | 274 // For named function expressions, declare the function name as a |
275 // constant. | 275 // constant. |
276 if (scope()->is_function_scope() && scope()->function() != NULL) { | 276 if (scope()->is_function_scope() && scope()->function() != NULL) { |
277 VariableDeclaration* function = scope()->function(); | 277 VariableDeclaration* function = scope()->function(); |
278 ASSERT(function->proxy()->var()->mode() == CONST || | 278 ASSERT(function->proxy()->var()->mode() == CONST || |
279 function->proxy()->var()->mode() == CONST_HARMONY); | 279 function->proxy()->var()->mode() == CONST_LEGACY); |
280 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); | 280 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
281 VisitVariableDeclaration(function); | 281 VisitVariableDeclaration(function); |
282 } | 282 } |
283 VisitDeclarations(scope()->declarations()); | 283 VisitDeclarations(scope()->declarations()); |
284 } | 284 } |
285 | 285 |
286 { Comment cmnt(masm_, "[ Stack check"); | 286 { Comment cmnt(masm_, "[ Stack check"); |
287 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); | 287 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
288 Label ok; | 288 Label ok; |
289 ExternalReference stack_limit = | 289 ExternalReference stack_limit = |
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 | 739 |
740 | 740 |
741 void FullCodeGenerator::VisitVariableDeclaration( | 741 void FullCodeGenerator::VisitVariableDeclaration( |
742 VariableDeclaration* declaration) { | 742 VariableDeclaration* declaration) { |
743 // If it was not possible to allocate the variable at compile time, we | 743 // If it was not possible to allocate the variable at compile time, we |
744 // need to "declare" it at runtime to make sure it actually exists in the | 744 // need to "declare" it at runtime to make sure it actually exists in the |
745 // local context. | 745 // local context. |
746 VariableProxy* proxy = declaration->proxy(); | 746 VariableProxy* proxy = declaration->proxy(); |
747 VariableMode mode = declaration->mode(); | 747 VariableMode mode = declaration->mode(); |
748 Variable* variable = proxy->var(); | 748 Variable* variable = proxy->var(); |
749 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; | 749 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; |
750 switch (variable->location()) { | 750 switch (variable->location()) { |
751 case Variable::UNALLOCATED: | 751 case Variable::UNALLOCATED: |
752 globals_->Add(variable->name(), zone()); | 752 globals_->Add(variable->name(), zone()); |
753 globals_->Add(variable->binding_needs_init() | 753 globals_->Add(variable->binding_needs_init() |
754 ? isolate()->factory()->the_hole_value() | 754 ? isolate()->factory()->the_hole_value() |
755 : isolate()->factory()->undefined_value(), zone()); | 755 : isolate()->factory()->undefined_value(), zone()); |
756 break; | 756 break; |
757 | 757 |
758 case Variable::PARAMETER: | 758 case Variable::PARAMETER: |
759 case Variable::LOCAL: | 759 case Variable::LOCAL: |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1260 // space for nested functions that don't need literals cloning. If | 1260 // space for nested functions that don't need literals cloning. If |
1261 // we're running with the --always-opt or the --prepare-always-opt | 1261 // we're running with the --always-opt or the --prepare-always-opt |
1262 // flag, we need to use the runtime function so that the new function | 1262 // flag, we need to use the runtime function so that the new function |
1263 // we are creating here gets a chance to have its code optimized and | 1263 // we are creating here gets a chance to have its code optimized and |
1264 // doesn't just get a copy of the existing unoptimized code. | 1264 // doesn't just get a copy of the existing unoptimized code. |
1265 if (!FLAG_always_opt && | 1265 if (!FLAG_always_opt && |
1266 !FLAG_prepare_always_opt && | 1266 !FLAG_prepare_always_opt && |
1267 !pretenure && | 1267 !pretenure && |
1268 scope()->is_function_scope() && | 1268 scope()->is_function_scope() && |
1269 info->num_literals() == 0) { | 1269 info->num_literals() == 0) { |
1270 FastNewClosureStub stub(info->language_mode(), info->is_generator()); | 1270 FastNewClosureStub stub(info->strict_mode(), info->is_generator()); |
1271 __ mov(ebx, Immediate(info)); | 1271 __ mov(ebx, Immediate(info)); |
1272 __ CallStub(&stub); | 1272 __ CallStub(&stub); |
1273 } else { | 1273 } else { |
1274 __ push(esi); | 1274 __ push(esi); |
1275 __ push(Immediate(info)); | 1275 __ push(Immediate(info)); |
1276 __ push(Immediate(pretenure | 1276 __ push(Immediate(pretenure |
1277 ? isolate()->factory()->true_value() | 1277 ? isolate()->factory()->true_value() |
1278 : isolate()->factory()->false_value())); | 1278 : isolate()->factory()->false_value())); |
1279 __ CallRuntime(Runtime::kNewClosure, 3); | 1279 __ CallRuntime(Runtime::kNewClosure, 3); |
1280 } | 1280 } |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1386 // eval-introduced variables. Eval is used a lot without | 1386 // eval-introduced variables. Eval is used a lot without |
1387 // introducing variables. In those cases, we do not want to | 1387 // introducing variables. In those cases, we do not want to |
1388 // perform a runtime call for all variables in the scope | 1388 // perform a runtime call for all variables in the scope |
1389 // containing the eval. | 1389 // containing the eval. |
1390 if (var->mode() == DYNAMIC_GLOBAL) { | 1390 if (var->mode() == DYNAMIC_GLOBAL) { |
1391 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1391 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1392 __ jmp(done); | 1392 __ jmp(done); |
1393 } else if (var->mode() == DYNAMIC_LOCAL) { | 1393 } else if (var->mode() == DYNAMIC_LOCAL) { |
1394 Variable* local = var->local_if_not_shadowed(); | 1394 Variable* local = var->local_if_not_shadowed(); |
1395 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); | 1395 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); |
1396 if (local->mode() == LET || | 1396 if (local->mode() == LET || local->mode() == CONST || |
1397 local->mode() == CONST || | 1397 local->mode() == CONST_LEGACY) { |
1398 local->mode() == CONST_HARMONY) { | |
1399 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1398 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1400 __ j(not_equal, done); | 1399 __ j(not_equal, done); |
1401 if (local->mode() == CONST) { | 1400 if (local->mode() == CONST_LEGACY) { |
1402 __ mov(eax, isolate()->factory()->undefined_value()); | 1401 __ mov(eax, isolate()->factory()->undefined_value()); |
1403 } else { // LET || CONST_HARMONY | 1402 } else { // LET || CONST |
1404 __ push(Immediate(var->name())); | 1403 __ push(Immediate(var->name())); |
1405 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1404 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1406 } | 1405 } |
1407 } | 1406 } |
1408 __ jmp(done); | 1407 __ jmp(done); |
1409 } | 1408 } |
1410 } | 1409 } |
1411 | 1410 |
1412 | 1411 |
1413 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1412 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1458 // binding is initialized: | 1457 // binding is initialized: |
1459 // function() { f(); let x = 1; function f() { x = 2; } } | 1458 // function() { f(); let x = 1; function f() { x = 2; } } |
1460 // | 1459 // |
1461 bool skip_init_check; | 1460 bool skip_init_check; |
1462 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { | 1461 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { |
1463 skip_init_check = false; | 1462 skip_init_check = false; |
1464 } else { | 1463 } else { |
1465 // Check that we always have valid source position. | 1464 // Check that we always have valid source position. |
1466 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); | 1465 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); |
1467 ASSERT(proxy->position() != RelocInfo::kNoPosition); | 1466 ASSERT(proxy->position() != RelocInfo::kNoPosition); |
1468 skip_init_check = var->mode() != CONST && | 1467 skip_init_check = var->mode() != CONST_LEGACY && |
1469 var->initializer_position() < proxy->position(); | 1468 var->initializer_position() < proxy->position(); |
1470 } | 1469 } |
1471 | 1470 |
1472 if (!skip_init_check) { | 1471 if (!skip_init_check) { |
1473 // Let and const need a read barrier. | 1472 // Let and const need a read barrier. |
1474 Label done; | 1473 Label done; |
1475 GetVar(eax, var); | 1474 GetVar(eax, var); |
1476 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1475 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1477 __ j(not_equal, &done, Label::kNear); | 1476 __ j(not_equal, &done, Label::kNear); |
1478 if (var->mode() == LET || var->mode() == CONST_HARMONY) { | 1477 if (var->mode() == LET || var->mode() == CONST) { |
1479 // Throw a reference error when using an uninitialized let/const | 1478 // Throw a reference error when using an uninitialized let/const |
1480 // binding in harmony mode. | 1479 // binding in harmony mode. |
1481 __ push(Immediate(var->name())); | 1480 __ push(Immediate(var->name())); |
1482 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1481 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1483 } else { | 1482 } else { |
1484 // Uninitalized const bindings outside of harmony mode are unholed. | 1483 // Uninitalized const bindings outside of harmony mode are unholed. |
1485 ASSERT(var->mode() == CONST); | 1484 ASSERT(var->mode() == CONST_LEGACY); |
1486 __ mov(eax, isolate()->factory()->undefined_value()); | 1485 __ mov(eax, isolate()->factory()->undefined_value()); |
1487 } | 1486 } |
1488 __ bind(&done); | 1487 __ bind(&done); |
1489 context()->Plug(eax); | 1488 context()->Plug(eax); |
1490 break; | 1489 break; |
1491 } | 1490 } |
1492 } | 1491 } |
1493 context()->Plug(var); | 1492 context()->Plug(var); |
1494 break; | 1493 break; |
1495 } | 1494 } |
(...skipping 894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2390 CallStoreIC(); | 2389 CallStoreIC(); |
2391 break; | 2390 break; |
2392 } | 2391 } |
2393 case KEYED_PROPERTY: { | 2392 case KEYED_PROPERTY: { |
2394 __ push(eax); // Preserve value. | 2393 __ push(eax); // Preserve value. |
2395 VisitForStackValue(prop->obj()); | 2394 VisitForStackValue(prop->obj()); |
2396 VisitForAccumulatorValue(prop->key()); | 2395 VisitForAccumulatorValue(prop->key()); |
2397 __ mov(ecx, eax); | 2396 __ mov(ecx, eax); |
2398 __ pop(edx); // Receiver. | 2397 __ pop(edx); // Receiver. |
2399 __ pop(eax); // Restore value. | 2398 __ pop(eax); // Restore value. |
2400 Handle<Code> ic = is_sloppy_mode() | 2399 Handle<Code> ic = strict_mode() == SLOPPY |
2401 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2400 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2402 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2401 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2403 CallIC(ic); | 2402 CallIC(ic); |
2404 break; | 2403 break; |
2405 } | 2404 } |
2406 } | 2405 } |
2407 context()->Plug(eax); | 2406 context()->Plug(eax); |
2408 } | 2407 } |
2409 | 2408 |
2410 | 2409 |
2411 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | 2410 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
2412 Variable* var, MemOperand location) { | 2411 Variable* var, MemOperand location) { |
2413 __ mov(location, eax); | 2412 __ mov(location, eax); |
2414 if (var->IsContextSlot()) { | 2413 if (var->IsContextSlot()) { |
2415 __ mov(edx, eax); | 2414 __ mov(edx, eax); |
2416 int offset = Context::SlotOffset(var->index()); | 2415 int offset = Context::SlotOffset(var->index()); |
2417 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | 2416 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
2418 } | 2417 } |
2419 } | 2418 } |
2420 | 2419 |
2421 | 2420 |
2422 void FullCodeGenerator::EmitCallStoreContextSlot( | 2421 void FullCodeGenerator::EmitCallStoreContextSlot( |
2423 Handle<String> name, LanguageMode mode) { | 2422 Handle<String> name, StrictMode strict_mode) { |
2424 __ push(eax); // Value. | 2423 __ push(eax); // Value. |
2425 __ push(esi); // Context. | 2424 __ push(esi); // Context. |
2426 __ push(Immediate(name)); | 2425 __ push(Immediate(name)); |
2427 __ push(Immediate(Smi::FromInt(mode))); | 2426 __ push(Immediate(Smi::FromInt(strict_mode))); |
2428 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 2427 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
2429 } | 2428 } |
2430 | 2429 |
2431 | 2430 |
2432 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2431 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
2433 Token::Value op) { | 2432 Token::Value op) { |
2434 if (var->IsUnallocated()) { | 2433 if (var->IsUnallocated()) { |
2435 // Global var, const, or let. | 2434 // Global var, const, or let. |
2436 __ mov(ecx, var->name()); | 2435 __ mov(ecx, var->name()); |
2437 __ mov(edx, GlobalObjectOperand()); | 2436 __ mov(edx, GlobalObjectOperand()); |
2438 CallStoreIC(); | 2437 CallStoreIC(); |
2439 | 2438 |
2440 } else if (op == Token::INIT_CONST) { | 2439 } else if (op == Token::INIT_CONST_LEGACY) { |
2441 // Const initializers need a write barrier. | 2440 // Const initializers need a write barrier. |
2442 ASSERT(!var->IsParameter()); // No const parameters. | 2441 ASSERT(!var->IsParameter()); // No const parameters. |
2443 if (var->IsLookupSlot()) { | 2442 if (var->IsLookupSlot()) { |
2444 __ push(eax); | 2443 __ push(eax); |
2445 __ push(esi); | 2444 __ push(esi); |
2446 __ push(Immediate(var->name())); | 2445 __ push(Immediate(var->name())); |
2447 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2446 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
2448 } else { | 2447 } else { |
2449 ASSERT(var->IsStackLocal() || var->IsContextSlot()); | 2448 ASSERT(var->IsStackLocal() || var->IsContextSlot()); |
2450 Label skip; | 2449 Label skip; |
2451 MemOperand location = VarOperand(var, ecx); | 2450 MemOperand location = VarOperand(var, ecx); |
2452 __ mov(edx, location); | 2451 __ mov(edx, location); |
2453 __ cmp(edx, isolate()->factory()->the_hole_value()); | 2452 __ cmp(edx, isolate()->factory()->the_hole_value()); |
2454 __ j(not_equal, &skip, Label::kNear); | 2453 __ j(not_equal, &skip, Label::kNear); |
2455 EmitStoreToStackLocalOrContextSlot(var, location); | 2454 EmitStoreToStackLocalOrContextSlot(var, location); |
2456 __ bind(&skip); | 2455 __ bind(&skip); |
2457 } | 2456 } |
2458 | 2457 |
2459 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2458 } else if (var->mode() == LET && op != Token::INIT_LET) { |
2460 // Non-initializing assignment to let variable needs a write barrier. | 2459 // Non-initializing assignment to let variable needs a write barrier. |
2461 if (var->IsLookupSlot()) { | 2460 if (var->IsLookupSlot()) { |
2462 EmitCallStoreContextSlot(var->name(), language_mode()); | 2461 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2463 } else { | 2462 } else { |
2464 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2463 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2465 Label assign; | 2464 Label assign; |
2466 MemOperand location = VarOperand(var, ecx); | 2465 MemOperand location = VarOperand(var, ecx); |
2467 __ mov(edx, location); | 2466 __ mov(edx, location); |
2468 __ cmp(edx, isolate()->factory()->the_hole_value()); | 2467 __ cmp(edx, isolate()->factory()->the_hole_value()); |
2469 __ j(not_equal, &assign, Label::kNear); | 2468 __ j(not_equal, &assign, Label::kNear); |
2470 __ push(Immediate(var->name())); | 2469 __ push(Immediate(var->name())); |
2471 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2470 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
2472 __ bind(&assign); | 2471 __ bind(&assign); |
2473 EmitStoreToStackLocalOrContextSlot(var, location); | 2472 EmitStoreToStackLocalOrContextSlot(var, location); |
2474 } | 2473 } |
2475 | 2474 |
2476 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2475 } else if (!var->is_const_mode() || op == Token::INIT_CONST) { |
2477 // Assignment to var or initializing assignment to let/const | 2476 // Assignment to var or initializing assignment to let/const |
2478 // in harmony mode. | 2477 // in harmony mode. |
2479 if (var->IsLookupSlot()) { | 2478 if (var->IsLookupSlot()) { |
2480 EmitCallStoreContextSlot(var->name(), language_mode()); | 2479 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2481 } else { | 2480 } else { |
2482 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2481 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2483 MemOperand location = VarOperand(var, ecx); | 2482 MemOperand location = VarOperand(var, ecx); |
2484 if (generate_debug_code_ && op == Token::INIT_LET) { | 2483 if (generate_debug_code_ && op == Token::INIT_LET) { |
2485 // Check for an uninitialized let binding. | 2484 // Check for an uninitialized let binding. |
2486 __ mov(edx, location); | 2485 __ mov(edx, location); |
2487 __ cmp(edx, isolate()->factory()->the_hole_value()); | 2486 __ cmp(edx, isolate()->factory()->the_hole_value()); |
2488 __ Check(equal, kLetBindingReInitialization); | 2487 __ Check(equal, kLetBindingReInitialization); |
2489 } | 2488 } |
2490 EmitStoreToStackLocalOrContextSlot(var, location); | 2489 EmitStoreToStackLocalOrContextSlot(var, location); |
(...skipping 25 matching lines...) Expand all Loading... |
2516 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2515 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
2517 // Assignment to a property, using a keyed store IC. | 2516 // Assignment to a property, using a keyed store IC. |
2518 // eax : value | 2517 // eax : value |
2519 // esp[0] : key | 2518 // esp[0] : key |
2520 // esp[kPointerSize] : receiver | 2519 // esp[kPointerSize] : receiver |
2521 | 2520 |
2522 __ pop(ecx); // Key. | 2521 __ pop(ecx); // Key. |
2523 __ pop(edx); | 2522 __ pop(edx); |
2524 // Record source code position before IC call. | 2523 // Record source code position before IC call. |
2525 SetSourcePosition(expr->position()); | 2524 SetSourcePosition(expr->position()); |
2526 Handle<Code> ic = is_sloppy_mode() | 2525 Handle<Code> ic = strict_mode() == SLOPPY |
2527 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2526 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2528 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2527 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2529 CallIC(ic, expr->AssignmentFeedbackId()); | 2528 CallIC(ic, expr->AssignmentFeedbackId()); |
2530 | 2529 |
2531 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2530 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
2532 context()->Plug(eax); | 2531 context()->Plug(eax); |
2533 } | 2532 } |
2534 | 2533 |
2535 | 2534 |
2536 void FullCodeGenerator::VisitProperty(Property* expr) { | 2535 void FullCodeGenerator::VisitProperty(Property* expr) { |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2690 // Push copy of the first argument or undefined if it doesn't exist. | 2689 // Push copy of the first argument or undefined if it doesn't exist. |
2691 if (arg_count > 0) { | 2690 if (arg_count > 0) { |
2692 __ push(Operand(esp, arg_count * kPointerSize)); | 2691 __ push(Operand(esp, arg_count * kPointerSize)); |
2693 } else { | 2692 } else { |
2694 __ push(Immediate(isolate()->factory()->undefined_value())); | 2693 __ push(Immediate(isolate()->factory()->undefined_value())); |
2695 } | 2694 } |
2696 | 2695 |
2697 // Push the receiver of the enclosing function. | 2696 // Push the receiver of the enclosing function. |
2698 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); | 2697 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); |
2699 // Push the language mode. | 2698 // Push the language mode. |
2700 __ push(Immediate(Smi::FromInt(language_mode()))); | 2699 __ push(Immediate(Smi::FromInt(strict_mode()))); |
2701 | 2700 |
2702 // Push the start position of the scope the calls resides in. | 2701 // Push the start position of the scope the calls resides in. |
2703 __ push(Immediate(Smi::FromInt(scope()->start_position()))); | 2702 __ push(Immediate(Smi::FromInt(scope()->start_position()))); |
2704 | 2703 |
2705 // Do the runtime call. | 2704 // Do the runtime call. |
2706 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); | 2705 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); |
2707 } | 2706 } |
2708 | 2707 |
2709 | 2708 |
2710 void FullCodeGenerator::VisitCall(Call* expr) { | 2709 void FullCodeGenerator::VisitCall(Call* expr) { |
(...skipping 1464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4175 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4174 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
4176 switch (expr->op()) { | 4175 switch (expr->op()) { |
4177 case Token::DELETE: { | 4176 case Token::DELETE: { |
4178 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4177 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
4179 Property* property = expr->expression()->AsProperty(); | 4178 Property* property = expr->expression()->AsProperty(); |
4180 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4179 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
4181 | 4180 |
4182 if (property != NULL) { | 4181 if (property != NULL) { |
4183 VisitForStackValue(property->obj()); | 4182 VisitForStackValue(property->obj()); |
4184 VisitForStackValue(property->key()); | 4183 VisitForStackValue(property->key()); |
4185 StrictModeFlag strict_mode_flag = (language_mode() == SLOPPY_MODE) | 4184 __ push(Immediate(Smi::FromInt(strict_mode()))); |
4186 ? kSloppyMode : kStrictMode; | |
4187 __ push(Immediate(Smi::FromInt(strict_mode_flag))); | |
4188 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4185 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
4189 context()->Plug(eax); | 4186 context()->Plug(eax); |
4190 } else if (proxy != NULL) { | 4187 } else if (proxy != NULL) { |
4191 Variable* var = proxy->var(); | 4188 Variable* var = proxy->var(); |
4192 // Delete of an unqualified identifier is disallowed in strict mode | 4189 // Delete of an unqualified identifier is disallowed in strict mode |
4193 // but "delete this" is allowed. | 4190 // but "delete this" is allowed. |
4194 ASSERT(language_mode() == SLOPPY_MODE || var->is_this()); | 4191 ASSERT(strict_mode() == SLOPPY || var->is_this()); |
4195 if (var->IsUnallocated()) { | 4192 if (var->IsUnallocated()) { |
4196 __ push(GlobalObjectOperand()); | 4193 __ push(GlobalObjectOperand()); |
4197 __ push(Immediate(var->name())); | 4194 __ push(Immediate(var->name())); |
4198 __ push(Immediate(Smi::FromInt(kSloppyMode))); | 4195 __ push(Immediate(Smi::FromInt(SLOPPY))); |
4199 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4196 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
4200 context()->Plug(eax); | 4197 context()->Plug(eax); |
4201 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 4198 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
4202 // Result of deleting non-global variables is false. 'this' is | 4199 // Result of deleting non-global variables is false. 'this' is |
4203 // not really a variable, though we implement it as one. The | 4200 // not really a variable, though we implement it as one. The |
4204 // subexpression does not have side effects. | 4201 // subexpression does not have side effects. |
4205 context()->Plug(var->is_this()); | 4202 context()->Plug(var->is_this()); |
4206 } else { | 4203 } else { |
4207 // Non-global variable. Call the runtime to try to delete from the | 4204 // Non-global variable. Call the runtime to try to delete from the |
4208 // context where the variable was introduced. | 4205 // context where the variable was introduced. |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4455 context()->PlugTOS(); | 4452 context()->PlugTOS(); |
4456 } | 4453 } |
4457 } else { | 4454 } else { |
4458 context()->Plug(eax); | 4455 context()->Plug(eax); |
4459 } | 4456 } |
4460 break; | 4457 break; |
4461 } | 4458 } |
4462 case KEYED_PROPERTY: { | 4459 case KEYED_PROPERTY: { |
4463 __ pop(ecx); | 4460 __ pop(ecx); |
4464 __ pop(edx); | 4461 __ pop(edx); |
4465 Handle<Code> ic = is_sloppy_mode() | 4462 Handle<Code> ic = strict_mode() == SLOPPY |
4466 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4463 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
4467 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4464 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
4468 CallIC(ic, expr->CountStoreFeedbackId()); | 4465 CallIC(ic, expr->CountStoreFeedbackId()); |
4469 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4466 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
4470 if (expr->is_postfix()) { | 4467 if (expr->is_postfix()) { |
4471 // Result is on the stack | 4468 // Result is on the stack |
4472 if (!context()->IsEffect()) { | 4469 if (!context()->IsEffect()) { |
4473 context()->PlugTOS(); | 4470 context()->PlugTOS(); |
4474 } | 4471 } |
4475 } else { | 4472 } else { |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4912 | 4909 |
4913 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), | 4910 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), |
4914 Assembler::target_address_at(call_target_address)); | 4911 Assembler::target_address_at(call_target_address)); |
4915 return OSR_AFTER_STACK_CHECK; | 4912 return OSR_AFTER_STACK_CHECK; |
4916 } | 4913 } |
4917 | 4914 |
4918 | 4915 |
4919 } } // namespace v8::internal | 4916 } } // namespace v8::internal |
4920 | 4917 |
4921 #endif // V8_TARGET_ARCH_IA32 | 4918 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |