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 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 __ push(edi); | 211 __ push(edi); |
212 } else { | 212 } else { |
213 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 213 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
214 } | 214 } |
215 // Receiver is just before the parameters on the caller's stack. | 215 // Receiver is just before the parameters on the caller's stack. |
216 int offset = scope()->num_parameters() * kPointerSize; | 216 int offset = scope()->num_parameters() * kPointerSize; |
217 __ lea(edx, | 217 __ lea(edx, |
218 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); | 218 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); |
219 __ push(edx); | 219 __ push(edx); |
220 __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters()))); | 220 __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters()))); |
221 // Arguments to ArgumentsAccessStub and/or New...: | 221 // Arguments to ArgumentsAccessStub: |
222 // function, receiver address, parameter count. | 222 // function, receiver address, parameter count. |
223 // The stub will rewrite receiver and parameter count if the previous | 223 // The stub will rewrite receiver and parameter count if the previous |
224 // stack frame was an arguments adapter frame. | 224 // stack frame was an arguments adapter frame. |
225 ArgumentsAccessStub::Type type; | 225 ArgumentsAccessStub stub( |
226 if (is_strict_mode()) { | 226 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT |
227 type = ArgumentsAccessStub::NEW_STRICT; | 227 : ArgumentsAccessStub::NEW_NON_STRICT); |
228 } else if (function()->has_duplicate_parameters()) { | |
229 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; | |
230 } else { | |
231 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; | |
232 } | |
233 ArgumentsAccessStub stub(type); | |
234 __ CallStub(&stub); | 228 __ CallStub(&stub); |
235 | 229 |
| 230 Variable* arguments_shadow = scope()->arguments_shadow(); |
| 231 if (arguments_shadow != NULL) { |
| 232 __ mov(ecx, eax); // Duplicate result. |
| 233 Move(arguments_shadow->AsSlot(), ecx, ebx, edx); |
| 234 } |
236 Move(arguments->AsSlot(), eax, ebx, edx); | 235 Move(arguments->AsSlot(), eax, ebx, edx); |
237 } | 236 } |
238 | 237 |
239 if (FLAG_trace) { | 238 if (FLAG_trace) { |
240 __ CallRuntime(Runtime::kTraceEnter, 0); | 239 __ CallRuntime(Runtime::kTraceEnter, 0); |
241 } | 240 } |
242 | 241 |
243 // Visit the declarations and body unless there is an illegal | 242 // Visit the declarations and body unless there is an illegal |
244 // redeclaration. | 243 // redeclaration. |
245 if (scope()->HasIllegalRedeclaration()) { | 244 if (scope()->HasIllegalRedeclaration()) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 367 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
369 // Memory operands can be pushed directly. | 368 // Memory operands can be pushed directly. |
370 __ push(slot_operand); | 369 __ push(slot_operand); |
371 } | 370 } |
372 | 371 |
373 | 372 |
374 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 373 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
375 // For simplicity we always test the accumulator register. | 374 // For simplicity we always test the accumulator register. |
376 codegen()->Move(result_register(), slot); | 375 codegen()->Move(result_register(), slot); |
377 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 376 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
378 codegen()->DoTest(true_label_, false_label_, fall_through_); | 377 codegen()->DoTest(this); |
379 } | 378 } |
380 | 379 |
381 | 380 |
382 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 381 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
383 UNREACHABLE(); // Not used on IA32. | 382 UNREACHABLE(); // Not used on IA32. |
384 } | 383 } |
385 | 384 |
386 | 385 |
387 void FullCodeGenerator::AccumulatorValueContext::Plug( | 386 void FullCodeGenerator::AccumulatorValueContext::Plug( |
388 Heap::RootListIndex index) const { | 387 Heap::RootListIndex index) const { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 } | 441 } |
443 } else if (lit->IsSmi()) { | 442 } else if (lit->IsSmi()) { |
444 if (Smi::cast(*lit)->value() == 0) { | 443 if (Smi::cast(*lit)->value() == 0) { |
445 if (false_label_ != fall_through_) __ jmp(false_label_); | 444 if (false_label_ != fall_through_) __ jmp(false_label_); |
446 } else { | 445 } else { |
447 if (true_label_ != fall_through_) __ jmp(true_label_); | 446 if (true_label_ != fall_through_) __ jmp(true_label_); |
448 } | 447 } |
449 } else { | 448 } else { |
450 // For simplicity we always test the accumulator register. | 449 // For simplicity we always test the accumulator register. |
451 __ mov(result_register(), lit); | 450 __ mov(result_register(), lit); |
452 codegen()->DoTest(true_label_, false_label_, fall_through_); | 451 codegen()->DoTest(this); |
453 } | 452 } |
454 } | 453 } |
455 | 454 |
456 | 455 |
457 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 456 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
458 Register reg) const { | 457 Register reg) const { |
459 ASSERT(count > 0); | 458 ASSERT(count > 0); |
460 __ Drop(count); | 459 __ Drop(count); |
461 } | 460 } |
462 | 461 |
(...skipping 15 matching lines...) Expand all Loading... |
478 } | 477 } |
479 | 478 |
480 | 479 |
481 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 480 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
482 Register reg) const { | 481 Register reg) const { |
483 ASSERT(count > 0); | 482 ASSERT(count > 0); |
484 // For simplicity we always test the accumulator register. | 483 // For simplicity we always test the accumulator register. |
485 __ Drop(count); | 484 __ Drop(count); |
486 __ Move(result_register(), reg); | 485 __ Move(result_register(), reg); |
487 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 486 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
488 codegen()->DoTest(true_label_, false_label_, fall_through_); | 487 codegen()->DoTest(this); |
489 } | 488 } |
490 | 489 |
491 | 490 |
492 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 491 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
493 Label* materialize_false) const { | 492 Label* materialize_false) const { |
494 ASSERT(materialize_true == materialize_false); | 493 ASSERT(materialize_true == materialize_false); |
495 __ bind(materialize_true); | 494 __ bind(materialize_true); |
496 } | 495 } |
497 | 496 |
498 | 497 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 true_label_, | 554 true_label_, |
556 false_label_); | 555 false_label_); |
557 if (flag) { | 556 if (flag) { |
558 if (true_label_ != fall_through_) __ jmp(true_label_); | 557 if (true_label_ != fall_through_) __ jmp(true_label_); |
559 } else { | 558 } else { |
560 if (false_label_ != fall_through_) __ jmp(false_label_); | 559 if (false_label_ != fall_through_) __ jmp(false_label_); |
561 } | 560 } |
562 } | 561 } |
563 | 562 |
564 | 563 |
565 void FullCodeGenerator::DoTest(Label* if_true, | 564 void FullCodeGenerator::DoTest(Expression* condition, |
| 565 Label* if_true, |
566 Label* if_false, | 566 Label* if_false, |
567 Label* fall_through) { | 567 Label* fall_through) { |
568 ToBooleanStub stub; | 568 ToBooleanStub stub; |
569 __ push(result_register()); | 569 __ push(result_register()); |
570 __ CallStub(&stub); | 570 __ CallStub(&stub); |
571 __ test(eax, Operand(eax)); | 571 __ test(eax, Operand(eax)); |
572 // The stub returns nonzero for true. | 572 // The stub returns nonzero for true. |
573 Split(not_zero, if_true, if_false, fall_through); | 573 Split(not_zero, if_true, if_false, fall_through); |
574 } | 574 } |
575 | 575 |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1202 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1202 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
1203 __ jmp(done); | 1203 __ jmp(done); |
1204 } | 1204 } |
1205 } | 1205 } |
1206 } | 1206 } |
1207 } | 1207 } |
1208 } | 1208 } |
1209 | 1209 |
1210 | 1210 |
1211 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1211 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
1212 // Three cases: non-this global variables, lookup slots, and all other | 1212 // Four cases: non-this global variables, lookup slots, all other |
1213 // types of slots. | 1213 // types of slots, and parameters that rewrite to explicit property |
| 1214 // accesses on the arguments object. |
1214 Slot* slot = var->AsSlot(); | 1215 Slot* slot = var->AsSlot(); |
1215 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); | 1216 Property* property = var->AsProperty(); |
1216 | 1217 |
1217 if (slot == NULL) { | 1218 if (var->is_global() && !var->is_this()) { |
1218 Comment cmnt(masm_, "Global variable"); | 1219 Comment cmnt(masm_, "Global variable"); |
1219 // Use inline caching. Variable name is passed in ecx and the global | 1220 // Use inline caching. Variable name is passed in ecx and the global |
1220 // object on the stack. | 1221 // object on the stack. |
1221 __ mov(eax, GlobalObjectOperand()); | 1222 __ mov(eax, GlobalObjectOperand()); |
1222 __ mov(ecx, var->name()); | 1223 __ mov(ecx, var->name()); |
1223 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1224 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
1224 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1225 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); |
1225 context()->Plug(eax); | 1226 context()->Plug(eax); |
1226 | 1227 |
1227 } else if (slot->type() == Slot::LOOKUP) { | 1228 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1228 Label done, slow; | 1229 Label done, slow; |
1229 | 1230 |
1230 // Generate code for loading from variables potentially shadowed | 1231 // Generate code for loading from variables potentially shadowed |
1231 // by eval-introduced variables. | 1232 // by eval-introduced variables. |
1232 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1233 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
1233 | 1234 |
1234 __ bind(&slow); | 1235 __ bind(&slow); |
1235 Comment cmnt(masm_, "Lookup slot"); | 1236 Comment cmnt(masm_, "Lookup slot"); |
1236 __ push(esi); // Context. | 1237 __ push(esi); // Context. |
1237 __ push(Immediate(var->name())); | 1238 __ push(Immediate(var->name())); |
1238 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1239 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
1239 __ bind(&done); | 1240 __ bind(&done); |
1240 | 1241 |
1241 context()->Plug(eax); | 1242 context()->Plug(eax); |
1242 | 1243 |
1243 } else { | 1244 } else if (slot != NULL) { |
1244 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1245 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
1245 ? "Context slot" | 1246 ? "Context slot" |
1246 : "Stack slot"); | 1247 : "Stack slot"); |
1247 if (var->mode() == Variable::CONST) { | 1248 if (var->mode() == Variable::CONST) { |
1248 // Constants may be the hole value if they have not been initialized. | 1249 // Constants may be the hole value if they have not been initialized. |
1249 // Unhole them. | 1250 // Unhole them. |
1250 Label done; | 1251 Label done; |
1251 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1252 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
1252 __ mov(eax, slot_operand); | 1253 __ mov(eax, slot_operand); |
1253 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1254 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1254 __ j(not_equal, &done, Label::kNear); | 1255 __ j(not_equal, &done, Label::kNear); |
1255 __ mov(eax, isolate()->factory()->undefined_value()); | 1256 __ mov(eax, isolate()->factory()->undefined_value()); |
1256 __ bind(&done); | 1257 __ bind(&done); |
1257 context()->Plug(eax); | 1258 context()->Plug(eax); |
1258 } else { | 1259 } else { |
1259 context()->Plug(slot); | 1260 context()->Plug(slot); |
1260 } | 1261 } |
| 1262 |
| 1263 } else { |
| 1264 Comment cmnt(masm_, "Rewritten parameter"); |
| 1265 ASSERT_NOT_NULL(property); |
| 1266 // Rewritten parameter accesses are of the form "slot[literal]". |
| 1267 |
| 1268 // Assert that the object is in a slot. |
| 1269 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 1270 ASSERT_NOT_NULL(object_var); |
| 1271 Slot* object_slot = object_var->AsSlot(); |
| 1272 ASSERT_NOT_NULL(object_slot); |
| 1273 |
| 1274 // Load the object. |
| 1275 MemOperand object_loc = EmitSlotSearch(object_slot, eax); |
| 1276 __ mov(edx, object_loc); |
| 1277 |
| 1278 // Assert that the key is a smi. |
| 1279 Literal* key_literal = property->key()->AsLiteral(); |
| 1280 ASSERT_NOT_NULL(key_literal); |
| 1281 ASSERT(key_literal->handle()->IsSmi()); |
| 1282 |
| 1283 // Load the key. |
| 1284 __ SafeSet(eax, Immediate(key_literal->handle())); |
| 1285 |
| 1286 // Do a keyed property load. |
| 1287 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1288 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1289 |
| 1290 // Drop key and object left on the stack by IC. |
| 1291 context()->Plug(eax); |
1261 } | 1292 } |
1262 } | 1293 } |
1263 | 1294 |
1264 | 1295 |
1265 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1296 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
1266 Comment cmnt(masm_, "[ RegExpLiteral"); | 1297 Comment cmnt(masm_, "[ RegExpLiteral"); |
1267 Label materialized; | 1298 Label materialized; |
1268 // Registers will be used as follows: | 1299 // Registers will be used as follows: |
1269 // edi = JS function. | 1300 // edi = JS function. |
1270 // ecx = literals array. | 1301 // ecx = literals array. |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1483 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1514 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
1484 Comment cmnt(masm_, "[ Assignment"); | 1515 Comment cmnt(masm_, "[ Assignment"); |
1485 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1516 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
1486 // on the left-hand side. | 1517 // on the left-hand side. |
1487 if (!expr->target()->IsValidLeftHandSide()) { | 1518 if (!expr->target()->IsValidLeftHandSide()) { |
1488 VisitForEffect(expr->target()); | 1519 VisitForEffect(expr->target()); |
1489 return; | 1520 return; |
1490 } | 1521 } |
1491 | 1522 |
1492 // Left-hand side can only be a property, a global or a (parameter or local) | 1523 // Left-hand side can only be a property, a global or a (parameter or local) |
1493 // slot. | 1524 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1494 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1525 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1495 LhsKind assign_type = VARIABLE; | 1526 LhsKind assign_type = VARIABLE; |
1496 Property* property = expr->target()->AsProperty(); | 1527 Property* property = expr->target()->AsProperty(); |
1497 if (property != NULL) { | 1528 if (property != NULL) { |
1498 assign_type = (property->key()->IsPropertyName()) | 1529 assign_type = (property->key()->IsPropertyName()) |
1499 ? NAMED_PROPERTY | 1530 ? NAMED_PROPERTY |
1500 : KEYED_PROPERTY; | 1531 : KEYED_PROPERTY; |
1501 } | 1532 } |
1502 | 1533 |
1503 // Evaluate LHS expression. | 1534 // Evaluate LHS expression. |
1504 switch (assign_type) { | 1535 switch (assign_type) { |
1505 case VARIABLE: | 1536 case VARIABLE: |
1506 // Nothing to do here. | 1537 // Nothing to do here. |
1507 break; | 1538 break; |
1508 case NAMED_PROPERTY: | 1539 case NAMED_PROPERTY: |
1509 if (expr->is_compound()) { | 1540 if (expr->is_compound()) { |
1510 // We need the receiver both on the stack and in the accumulator. | 1541 // We need the receiver both on the stack and in the accumulator. |
1511 VisitForAccumulatorValue(property->obj()); | 1542 VisitForAccumulatorValue(property->obj()); |
1512 __ push(result_register()); | 1543 __ push(result_register()); |
1513 } else { | 1544 } else { |
1514 VisitForStackValue(property->obj()); | 1545 VisitForStackValue(property->obj()); |
1515 } | 1546 } |
1516 break; | 1547 break; |
1517 case KEYED_PROPERTY: { | 1548 case KEYED_PROPERTY: { |
1518 if (expr->is_compound()) { | 1549 if (expr->is_compound()) { |
1519 VisitForStackValue(property->obj()); | 1550 if (property->is_arguments_access()) { |
1520 VisitForAccumulatorValue(property->key()); | 1551 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1552 MemOperand slot_operand = |
| 1553 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); |
| 1554 __ push(slot_operand); |
| 1555 __ SafeSet(eax, Immediate(property->key()->AsLiteral()->handle())); |
| 1556 } else { |
| 1557 VisitForStackValue(property->obj()); |
| 1558 VisitForAccumulatorValue(property->key()); |
| 1559 } |
1521 __ mov(edx, Operand(esp, 0)); | 1560 __ mov(edx, Operand(esp, 0)); |
1522 __ push(eax); | 1561 __ push(eax); |
1523 } else { | 1562 } else { |
1524 VisitForStackValue(property->obj()); | 1563 if (property->is_arguments_access()) { |
1525 VisitForStackValue(property->key()); | 1564 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1565 MemOperand slot_operand = |
| 1566 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); |
| 1567 __ push(slot_operand); |
| 1568 __ SafePush(Immediate(property->key()->AsLiteral()->handle())); |
| 1569 } else { |
| 1570 VisitForStackValue(property->obj()); |
| 1571 VisitForStackValue(property->key()); |
| 1572 } |
1526 } | 1573 } |
1527 break; | 1574 break; |
1528 } | 1575 } |
1529 } | 1576 } |
1530 | 1577 |
1531 // For compound assignments we need another deoptimization point after the | 1578 // For compound assignments we need another deoptimization point after the |
1532 // variable/property load. | 1579 // variable/property load. |
1533 if (expr->is_compound()) { | 1580 if (expr->is_compound()) { |
1534 { AccumulatorValueContext context(this); | 1581 { AccumulatorValueContext context(this); |
1535 switch (assign_type) { | 1582 switch (assign_type) { |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1719 | 1766 |
1720 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1767 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
1721 // Invalid left-hand sides are rewritten to have a 'throw | 1768 // Invalid left-hand sides are rewritten to have a 'throw |
1722 // ReferenceError' on the left-hand side. | 1769 // ReferenceError' on the left-hand side. |
1723 if (!expr->IsValidLeftHandSide()) { | 1770 if (!expr->IsValidLeftHandSide()) { |
1724 VisitForEffect(expr); | 1771 VisitForEffect(expr); |
1725 return; | 1772 return; |
1726 } | 1773 } |
1727 | 1774 |
1728 // Left-hand side can only be a property, a global or a (parameter or local) | 1775 // Left-hand side can only be a property, a global or a (parameter or local) |
1729 // slot. | 1776 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1730 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1777 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1731 LhsKind assign_type = VARIABLE; | 1778 LhsKind assign_type = VARIABLE; |
1732 Property* prop = expr->AsProperty(); | 1779 Property* prop = expr->AsProperty(); |
1733 if (prop != NULL) { | 1780 if (prop != NULL) { |
1734 assign_type = (prop->key()->IsPropertyName()) | 1781 assign_type = (prop->key()->IsPropertyName()) |
1735 ? NAMED_PROPERTY | 1782 ? NAMED_PROPERTY |
1736 : KEYED_PROPERTY; | 1783 : KEYED_PROPERTY; |
1737 } | 1784 } |
1738 | 1785 |
1739 switch (assign_type) { | 1786 switch (assign_type) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1779 break; | 1826 break; |
1780 } | 1827 } |
1781 } | 1828 } |
1782 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1829 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
1783 context()->Plug(eax); | 1830 context()->Plug(eax); |
1784 } | 1831 } |
1785 | 1832 |
1786 | 1833 |
1787 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1834 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1788 Token::Value op) { | 1835 Token::Value op) { |
| 1836 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1837 // here. |
1789 ASSERT(var != NULL); | 1838 ASSERT(var != NULL); |
1790 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1839 ASSERT(var->is_global() || var->AsSlot() != NULL); |
1791 | 1840 |
1792 if (var->is_global()) { | 1841 if (var->is_global()) { |
1793 ASSERT(!var->is_this()); | 1842 ASSERT(!var->is_this()); |
1794 // Assignment to a global variable. Use inline caching for the | 1843 // Assignment to a global variable. Use inline caching for the |
1795 // assignment. Right-hand-side value is passed in eax, variable name in | 1844 // assignment. Right-hand-side value is passed in eax, variable name in |
1796 // ecx, and the global object on the stack. | 1845 // ecx, and the global object on the stack. |
1797 __ mov(ecx, var->name()); | 1846 __ mov(ecx, var->name()); |
1798 __ mov(edx, GlobalObjectOperand()); | 1847 __ mov(edx, GlobalObjectOperand()); |
(...skipping 1932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3731 SetSourcePosition(expr->position()); | 3780 SetSourcePosition(expr->position()); |
3732 | 3781 |
3733 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 3782 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
3734 // as the left-hand side. | 3783 // as the left-hand side. |
3735 if (!expr->expression()->IsValidLeftHandSide()) { | 3784 if (!expr->expression()->IsValidLeftHandSide()) { |
3736 VisitForEffect(expr->expression()); | 3785 VisitForEffect(expr->expression()); |
3737 return; | 3786 return; |
3738 } | 3787 } |
3739 | 3788 |
3740 // Expression can only be a property, a global or a (parameter or local) | 3789 // Expression can only be a property, a global or a (parameter or local) |
3741 // slot. | 3790 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
3742 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3791 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
3743 LhsKind assign_type = VARIABLE; | 3792 LhsKind assign_type = VARIABLE; |
3744 Property* prop = expr->expression()->AsProperty(); | 3793 Property* prop = expr->expression()->AsProperty(); |
3745 // In case of a property we use the uninitialized expression context | 3794 // In case of a property we use the uninitialized expression context |
3746 // of the key to detect a named property. | 3795 // of the key to detect a named property. |
3747 if (prop != NULL) { | 3796 if (prop != NULL) { |
3748 assign_type = | 3797 assign_type = |
3749 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3798 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
3750 } | 3799 } |
3751 | 3800 |
3752 // Evaluate expression and get value. | 3801 // Evaluate expression and get value. |
3753 if (assign_type == VARIABLE) { | 3802 if (assign_type == VARIABLE) { |
3754 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3803 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
3755 AccumulatorValueContext context(this); | 3804 AccumulatorValueContext context(this); |
3756 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3805 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
3757 } else { | 3806 } else { |
3758 // Reserve space for result of postfix operation. | 3807 // Reserve space for result of postfix operation. |
3759 if (expr->is_postfix() && !context()->IsEffect()) { | 3808 if (expr->is_postfix() && !context()->IsEffect()) { |
3760 __ push(Immediate(Smi::FromInt(0))); | 3809 __ push(Immediate(Smi::FromInt(0))); |
3761 } | 3810 } |
3762 if (assign_type == NAMED_PROPERTY) { | 3811 if (assign_type == NAMED_PROPERTY) { |
3763 // Put the object both on the stack and in the accumulator. | 3812 // Put the object both on the stack and in the accumulator. |
3764 VisitForAccumulatorValue(prop->obj()); | 3813 VisitForAccumulatorValue(prop->obj()); |
3765 __ push(eax); | 3814 __ push(eax); |
3766 EmitNamedPropertyLoad(prop); | 3815 EmitNamedPropertyLoad(prop); |
3767 } else { | 3816 } else { |
3768 VisitForStackValue(prop->obj()); | 3817 if (prop->is_arguments_access()) { |
3769 VisitForAccumulatorValue(prop->key()); | 3818 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3819 MemOperand slot_operand = |
| 3820 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); |
| 3821 __ push(slot_operand); |
| 3822 __ SafeSet(eax, Immediate(prop->key()->AsLiteral()->handle())); |
| 3823 } else { |
| 3824 VisitForStackValue(prop->obj()); |
| 3825 VisitForAccumulatorValue(prop->key()); |
| 3826 } |
3770 __ mov(edx, Operand(esp, 0)); | 3827 __ mov(edx, Operand(esp, 0)); |
3771 __ push(eax); | 3828 __ push(eax); |
3772 EmitKeyedPropertyLoad(prop); | 3829 EmitKeyedPropertyLoad(prop); |
3773 } | 3830 } |
3774 } | 3831 } |
3775 | 3832 |
3776 // We need a second deoptimization point after loading the value | 3833 // We need a second deoptimization point after loading the value |
3777 // in case evaluating the property load my have a side effect. | 3834 // in case evaluating the property load my have a side effect. |
3778 if (assign_type == VARIABLE) { | 3835 if (assign_type == VARIABLE) { |
3779 PrepareForBailout(expr->expression(), TOS_REG); | 3836 PrepareForBailout(expr->expression(), TOS_REG); |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4271 // And return. | 4328 // And return. |
4272 __ ret(0); | 4329 __ ret(0); |
4273 } | 4330 } |
4274 | 4331 |
4275 | 4332 |
4276 #undef __ | 4333 #undef __ |
4277 | 4334 |
4278 } } // namespace v8::internal | 4335 } } // namespace v8::internal |
4279 | 4336 |
4280 #endif // V8_TARGET_ARCH_IA32 | 4337 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |