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