| 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 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 } | 628 } |
| 629 } | 629 } |
| 630 | 630 |
| 631 | 631 |
| 632 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 632 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 633 Variable::Mode mode, | 633 Variable::Mode mode, |
| 634 FunctionLiteral* function) { | 634 FunctionLiteral* function) { |
| 635 Comment cmnt(masm_, "[ Declaration"); | 635 Comment cmnt(masm_, "[ Declaration"); |
| 636 ASSERT(variable != NULL); // Must have been resolved. | 636 ASSERT(variable != NULL); // Must have been resolved. |
| 637 Slot* slot = variable->AsSlot(); | 637 Slot* slot = variable->AsSlot(); |
| 638 Property* prop = variable->AsProperty(); | |
| 639 | 638 |
| 640 if (slot != NULL) { | 639 if (slot != NULL) { |
| 641 switch (slot->type()) { | 640 switch (slot->type()) { |
| 642 case Slot::PARAMETER: | 641 case Slot::PARAMETER: |
| 643 case Slot::LOCAL: | 642 case Slot::LOCAL: |
| 644 if (mode == Variable::CONST) { | 643 if (mode == Variable::CONST) { |
| 645 __ mov(Operand(ebp, SlotOffset(slot)), | 644 __ mov(Operand(ebp, SlotOffset(slot)), |
| 646 Immediate(Factory::the_hole_value())); | 645 Immediate(Factory::the_hole_value())); |
| 647 } else if (function != NULL) { | 646 } else if (function != NULL) { |
| 648 VisitForAccumulatorValue(function); | 647 VisitForAccumulatorValue(function); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 __ push(Immediate(Factory::the_hole_value())); | 690 __ push(Immediate(Factory::the_hole_value())); |
| 692 } else if (function != NULL) { | 691 } else if (function != NULL) { |
| 693 VisitForStackValue(function); | 692 VisitForStackValue(function); |
| 694 } else { | 693 } else { |
| 695 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 694 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
| 696 } | 695 } |
| 697 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 696 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 698 break; | 697 break; |
| 699 } | 698 } |
| 700 } | 699 } |
| 701 | |
| 702 } else if (prop != NULL) { | |
| 703 if (function != NULL || mode == Variable::CONST) { | |
| 704 // We are declaring a function or constant that rewrites to a | |
| 705 // property. Use (keyed) IC to set the initial value. We cannot | |
| 706 // visit the rewrite because it's shared and we risk recording | |
| 707 // duplicate AST IDs for bailouts from optimized code. | |
| 708 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 709 { AccumulatorValueContext for_object(this); | |
| 710 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 711 } | |
| 712 | |
| 713 if (function != NULL) { | |
| 714 __ push(eax); | |
| 715 VisitForAccumulatorValue(function); | |
| 716 __ pop(edx); | |
| 717 } else { | |
| 718 __ mov(edx, eax); | |
| 719 __ mov(eax, Factory::the_hole_value()); | |
| 720 } | |
| 721 ASSERT(prop->key()->AsLiteral() != NULL && | |
| 722 prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 723 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | |
| 724 | |
| 725 Handle<Code> ic(Builtins::builtin( | |
| 726 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | |
| 727 : Builtins::KeyedStoreIC_Initialize)); | |
| 728 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 729 } | |
| 730 } | 700 } |
| 731 } | 701 } |
| 732 | 702 |
| 733 | 703 |
| 734 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 704 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 735 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 705 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 736 } | 706 } |
| 737 | 707 |
| 738 | 708 |
| 739 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 709 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 // Generate fast-case code for variables that might be shadowed by | 1109 // Generate fast-case code for variables that might be shadowed by |
| 1140 // eval-introduced variables. Eval is used a lot without | 1110 // eval-introduced variables. Eval is used a lot without |
| 1141 // introducing variables. In those cases, we do not want to | 1111 // introducing variables. In those cases, we do not want to |
| 1142 // perform a runtime call for all variables in the scope | 1112 // perform a runtime call for all variables in the scope |
| 1143 // containing the eval. | 1113 // containing the eval. |
| 1144 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 1114 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 1145 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); | 1115 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 1146 __ jmp(done); | 1116 __ jmp(done); |
| 1147 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 1117 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 1148 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); | 1118 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); |
| 1149 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | |
| 1150 if (potential_slot != NULL) { | 1119 if (potential_slot != NULL) { |
| 1151 // Generate fast case for locals that rewrite to slots. | 1120 // Generate fast case for locals that rewrite to slots. |
| 1152 __ mov(eax, | 1121 __ mov(eax, |
| 1153 ContextSlotOperandCheckExtensions(potential_slot, slow)); | 1122 ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1154 if (potential_slot->var()->mode() == Variable::CONST) { | 1123 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1155 __ cmp(eax, Factory::the_hole_value()); | 1124 __ cmp(eax, Factory::the_hole_value()); |
| 1156 __ j(not_equal, done); | 1125 __ j(not_equal, done); |
| 1157 __ mov(eax, Factory::undefined_value()); | 1126 __ mov(eax, Factory::undefined_value()); |
| 1158 } | 1127 } |
| 1159 __ jmp(done); | 1128 __ jmp(done); |
| 1160 } else if (rewrite != NULL) { | |
| 1161 // Generate fast case for calls of an argument function. | |
| 1162 Property* property = rewrite->AsProperty(); | |
| 1163 if (property != NULL) { | |
| 1164 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
| 1165 Literal* key_literal = property->key()->AsLiteral(); | |
| 1166 if (obj_proxy != NULL && | |
| 1167 key_literal != NULL && | |
| 1168 obj_proxy->IsArguments() && | |
| 1169 key_literal->handle()->IsSmi()) { | |
| 1170 // Load arguments object if there are no eval-introduced | |
| 1171 // variables. Then load the argument from the arguments | |
| 1172 // object using keyed load. | |
| 1173 __ mov(edx, | |
| 1174 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | |
| 1175 slow)); | |
| 1176 __ mov(eax, Immediate(key_literal->handle())); | |
| 1177 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1178 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 1179 __ jmp(done); | |
| 1180 } | |
| 1181 } | |
| 1182 } | 1129 } |
| 1183 } | 1130 } |
| 1184 } | 1131 } |
| 1185 | 1132 |
| 1186 | 1133 |
| 1187 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1134 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1188 // Four cases: non-this global variables, lookup slots, all other | 1135 // Three cases: non-this global variables, lookup slots, and all other |
| 1189 // types of slots, and parameters that rewrite to explicit property | 1136 // types of slots. |
| 1190 // accesses on the arguments object. | |
| 1191 Slot* slot = var->AsSlot(); | 1137 Slot* slot = var->AsSlot(); |
| 1192 Property* property = var->AsProperty(); | 1138 ASSERT((var->is_global() && !var->is_this()) == (slot != NULL)); |
| 1193 | 1139 |
| 1194 if (var->is_global() && !var->is_this()) { | 1140 if (slot == NULL) { |
| 1195 Comment cmnt(masm_, "Global variable"); | 1141 Comment cmnt(masm_, "Global variable"); |
| 1196 // Use inline caching. Variable name is passed in ecx and the global | 1142 // Use inline caching. Variable name is passed in ecx and the global |
| 1197 // object on the stack. | 1143 // object on the stack. |
| 1198 __ mov(eax, GlobalObjectOperand()); | 1144 __ mov(eax, GlobalObjectOperand()); |
| 1199 __ mov(ecx, var->name()); | 1145 __ mov(ecx, var->name()); |
| 1200 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1146 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1201 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1147 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1202 context()->Plug(eax); | 1148 context()->Plug(eax); |
| 1203 | 1149 |
| 1204 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1150 } else if (slot->type() == Slot::LOOKUP) { |
| 1205 Label done, slow; | 1151 Label done, slow; |
| 1206 | 1152 |
| 1207 // Generate code for loading from variables potentially shadowed | 1153 // Generate code for loading from variables potentially shadowed |
| 1208 // by eval-introduced variables. | 1154 // by eval-introduced variables. |
| 1209 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1155 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1210 | 1156 |
| 1211 __ bind(&slow); | 1157 __ bind(&slow); |
| 1212 Comment cmnt(masm_, "Lookup slot"); | 1158 Comment cmnt(masm_, "Lookup slot"); |
| 1213 __ push(esi); // Context. | 1159 __ push(esi); // Context. |
| 1214 __ push(Immediate(var->name())); | 1160 __ push(Immediate(var->name())); |
| 1215 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1161 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1216 __ bind(&done); | 1162 __ bind(&done); |
| 1217 | 1163 |
| 1218 context()->Plug(eax); | 1164 context()->Plug(eax); |
| 1219 | 1165 |
| 1220 } else if (slot != NULL) { | 1166 } else { |
| 1221 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1167 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1222 ? "Context slot" | 1168 ? "Context slot" |
| 1223 : "Stack slot"); | 1169 : "Stack slot"); |
| 1224 if (var->mode() == Variable::CONST) { | 1170 if (var->mode() == Variable::CONST) { |
| 1225 // Constants may be the hole value if they have not been initialized. | 1171 // Constants may be the hole value if they have not been initialized. |
| 1226 // Unhole them. | 1172 // Unhole them. |
| 1227 NearLabel done; | 1173 NearLabel done; |
| 1228 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1174 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1229 __ mov(eax, slot_operand); | 1175 __ mov(eax, slot_operand); |
| 1230 __ cmp(eax, Factory::the_hole_value()); | 1176 __ cmp(eax, Factory::the_hole_value()); |
| 1231 __ j(not_equal, &done); | 1177 __ j(not_equal, &done); |
| 1232 __ mov(eax, Factory::undefined_value()); | 1178 __ mov(eax, Factory::undefined_value()); |
| 1233 __ bind(&done); | 1179 __ bind(&done); |
| 1234 context()->Plug(eax); | 1180 context()->Plug(eax); |
| 1235 } else { | 1181 } else { |
| 1236 context()->Plug(slot); | 1182 context()->Plug(slot); |
| 1237 } | 1183 } |
| 1238 | |
| 1239 } else { | |
| 1240 Comment cmnt(masm_, "Rewritten parameter"); | |
| 1241 ASSERT_NOT_NULL(property); | |
| 1242 // Rewritten parameter accesses are of the form "slot[literal]". | |
| 1243 | |
| 1244 // Assert that the object is in a slot. | |
| 1245 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | |
| 1246 ASSERT_NOT_NULL(object_var); | |
| 1247 Slot* object_slot = object_var->AsSlot(); | |
| 1248 ASSERT_NOT_NULL(object_slot); | |
| 1249 | |
| 1250 // Load the object. | |
| 1251 MemOperand object_loc = EmitSlotSearch(object_slot, eax); | |
| 1252 __ mov(edx, object_loc); | |
| 1253 | |
| 1254 // Assert that the key is a smi. | |
| 1255 Literal* key_literal = property->key()->AsLiteral(); | |
| 1256 ASSERT_NOT_NULL(key_literal); | |
| 1257 ASSERT(key_literal->handle()->IsSmi()); | |
| 1258 | |
| 1259 // Load the key. | |
| 1260 __ mov(eax, Immediate(key_literal->handle())); | |
| 1261 | |
| 1262 // Do a keyed property load. | |
| 1263 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1264 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 1265 | |
| 1266 // Drop key and object left on the stack by IC. | |
| 1267 context()->Plug(eax); | |
| 1268 } | 1184 } |
| 1269 } | 1185 } |
| 1270 | 1186 |
| 1271 | 1187 |
| 1272 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1188 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1273 Comment cmnt(masm_, "[ RegExpLiteral"); | 1189 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1274 NearLabel materialized; | 1190 NearLabel materialized; |
| 1275 // Registers will be used as follows: | 1191 // Registers will be used as follows: |
| 1276 // edi = JS function. | 1192 // edi = JS function. |
| 1277 // ecx = literals array. | 1193 // ecx = literals array. |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1477 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1393 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1478 Comment cmnt(masm_, "[ Assignment"); | 1394 Comment cmnt(masm_, "[ Assignment"); |
| 1479 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1395 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1480 // on the left-hand side. | 1396 // on the left-hand side. |
| 1481 if (!expr->target()->IsValidLeftHandSide()) { | 1397 if (!expr->target()->IsValidLeftHandSide()) { |
| 1482 VisitForEffect(expr->target()); | 1398 VisitForEffect(expr->target()); |
| 1483 return; | 1399 return; |
| 1484 } | 1400 } |
| 1485 | 1401 |
| 1486 // Left-hand side can only be a property, a global or a (parameter or local) | 1402 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1487 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1403 // slot. |
| 1488 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1404 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1489 LhsKind assign_type = VARIABLE; | 1405 LhsKind assign_type = VARIABLE; |
| 1490 Property* property = expr->target()->AsProperty(); | 1406 Property* property = expr->target()->AsProperty(); |
| 1491 if (property != NULL) { | 1407 if (property != NULL) { |
| 1492 assign_type = (property->key()->IsPropertyName()) | 1408 assign_type = (property->key()->IsPropertyName()) |
| 1493 ? NAMED_PROPERTY | 1409 ? NAMED_PROPERTY |
| 1494 : KEYED_PROPERTY; | 1410 : KEYED_PROPERTY; |
| 1495 } | 1411 } |
| 1496 | 1412 |
| 1497 // Evaluate LHS expression. | 1413 // Evaluate LHS expression. |
| 1498 switch (assign_type) { | 1414 switch (assign_type) { |
| 1499 case VARIABLE: | 1415 case VARIABLE: |
| 1500 // Nothing to do here. | 1416 // Nothing to do here. |
| 1501 break; | 1417 break; |
| 1502 case NAMED_PROPERTY: | 1418 case NAMED_PROPERTY: |
| 1503 if (expr->is_compound()) { | 1419 if (expr->is_compound()) { |
| 1504 // We need the receiver both on the stack and in the accumulator. | 1420 // We need the receiver both on the stack and in the accumulator. |
| 1505 VisitForAccumulatorValue(property->obj()); | 1421 VisitForAccumulatorValue(property->obj()); |
| 1506 __ push(result_register()); | 1422 __ push(result_register()); |
| 1507 } else { | 1423 } else { |
| 1508 VisitForStackValue(property->obj()); | 1424 VisitForStackValue(property->obj()); |
| 1509 } | 1425 } |
| 1510 break; | 1426 break; |
| 1511 case KEYED_PROPERTY: { | 1427 case KEYED_PROPERTY: { |
| 1512 if (expr->is_compound()) { | 1428 if (expr->is_compound()) { |
| 1513 if (property->is_arguments_access()) { | 1429 VisitForStackValue(property->obj()); |
| 1514 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1430 VisitForAccumulatorValue(property->key()); |
| 1515 MemOperand slot_operand = | |
| 1516 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | |
| 1517 __ push(slot_operand); | |
| 1518 __ mov(eax, Immediate(property->key()->AsLiteral()->handle())); | |
| 1519 } else { | |
| 1520 VisitForStackValue(property->obj()); | |
| 1521 VisitForAccumulatorValue(property->key()); | |
| 1522 } | |
| 1523 __ mov(edx, Operand(esp, 0)); | 1431 __ mov(edx, Operand(esp, 0)); |
| 1524 __ push(eax); | 1432 __ push(eax); |
| 1525 } else { | 1433 } else { |
| 1526 if (property->is_arguments_access()) { | 1434 VisitForStackValue(property->obj()); |
| 1527 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1435 VisitForStackValue(property->key()); |
| 1528 MemOperand slot_operand = | |
| 1529 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | |
| 1530 __ push(slot_operand); | |
| 1531 __ push(Immediate(property->key()->AsLiteral()->handle())); | |
| 1532 } else { | |
| 1533 VisitForStackValue(property->obj()); | |
| 1534 VisitForStackValue(property->key()); | |
| 1535 } | |
| 1536 } | 1436 } |
| 1537 break; | 1437 break; |
| 1538 } | 1438 } |
| 1539 } | 1439 } |
| 1540 | 1440 |
| 1541 // For compound assignments we need another deoptimization point after the | 1441 // For compound assignments we need another deoptimization point after the |
| 1542 // variable/property load. | 1442 // variable/property load. |
| 1543 if (expr->is_compound()) { | 1443 if (expr->is_compound()) { |
| 1544 { AccumulatorValueContext context(this); | 1444 { AccumulatorValueContext context(this); |
| 1545 switch (assign_type) { | 1445 switch (assign_type) { |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1726 | 1626 |
| 1727 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1627 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1728 // Invalid left-hand sides are rewritten to have a 'throw | 1628 // Invalid left-hand sides are rewritten to have a 'throw |
| 1729 // ReferenceError' on the left-hand side. | 1629 // ReferenceError' on the left-hand side. |
| 1730 if (!expr->IsValidLeftHandSide()) { | 1630 if (!expr->IsValidLeftHandSide()) { |
| 1731 VisitForEffect(expr); | 1631 VisitForEffect(expr); |
| 1732 return; | 1632 return; |
| 1733 } | 1633 } |
| 1734 | 1634 |
| 1735 // Left-hand side can only be a property, a global or a (parameter or local) | 1635 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1736 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1636 // slot. |
| 1737 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1637 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1738 LhsKind assign_type = VARIABLE; | 1638 LhsKind assign_type = VARIABLE; |
| 1739 Property* prop = expr->AsProperty(); | 1639 Property* prop = expr->AsProperty(); |
| 1740 if (prop != NULL) { | 1640 if (prop != NULL) { |
| 1741 assign_type = (prop->key()->IsPropertyName()) | 1641 assign_type = (prop->key()->IsPropertyName()) |
| 1742 ? NAMED_PROPERTY | 1642 ? NAMED_PROPERTY |
| 1743 : KEYED_PROPERTY; | 1643 : KEYED_PROPERTY; |
| 1744 } | 1644 } |
| 1745 | 1645 |
| 1746 switch (assign_type) { | 1646 switch (assign_type) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1757 __ pop(eax); // Restore value. | 1657 __ pop(eax); // Restore value. |
| 1758 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1658 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1759 Handle<Code> ic(Builtins::builtin( | 1659 Handle<Code> ic(Builtins::builtin( |
| 1760 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1660 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1761 : Builtins::StoreIC_Initialize)); | 1661 : Builtins::StoreIC_Initialize)); |
| 1762 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1662 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1763 break; | 1663 break; |
| 1764 } | 1664 } |
| 1765 case KEYED_PROPERTY: { | 1665 case KEYED_PROPERTY: { |
| 1766 __ push(eax); // Preserve value. | 1666 __ push(eax); // Preserve value. |
| 1767 if (prop->is_synthetic()) { | 1667 VisitForStackValue(prop->obj()); |
| 1768 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1668 VisitForAccumulatorValue(prop->key()); |
| 1769 ASSERT(prop->key()->AsLiteral() != NULL); | 1669 __ mov(ecx, eax); |
| 1770 { AccumulatorValueContext for_object(this); | 1670 __ pop(edx); |
| 1771 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 1772 } | |
| 1773 __ mov(edx, eax); | |
| 1774 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | |
| 1775 } else { | |
| 1776 VisitForStackValue(prop->obj()); | |
| 1777 VisitForAccumulatorValue(prop->key()); | |
| 1778 __ mov(ecx, eax); | |
| 1779 __ pop(edx); | |
| 1780 } | |
| 1781 __ pop(eax); // Restore value. | 1671 __ pop(eax); // Restore value. |
| 1782 Handle<Code> ic(Builtins::builtin( | 1672 Handle<Code> ic(Builtins::builtin( |
| 1783 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 1673 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1784 : Builtins::KeyedStoreIC_Initialize)); | 1674 : Builtins::KeyedStoreIC_Initialize)); |
| 1785 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1675 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1786 break; | 1676 break; |
| 1787 } | 1677 } |
| 1788 } | 1678 } |
| 1789 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1679 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1790 context()->Plug(eax); | 1680 context()->Plug(eax); |
| 1791 } | 1681 } |
| 1792 | 1682 |
| 1793 | 1683 |
| 1794 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1684 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1795 Token::Value op) { | 1685 Token::Value op) { |
| 1796 // Left-hand sides that rewrite to explicit property accesses do not reach | |
| 1797 // here. | |
| 1798 ASSERT(var != NULL); | 1686 ASSERT(var != NULL); |
| 1799 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1687 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1800 | 1688 |
| 1801 if (var->is_global()) { | 1689 if (var->is_global()) { |
| 1802 ASSERT(!var->is_this()); | 1690 ASSERT(!var->is_this()); |
| 1803 // Assignment to a global variable. Use inline caching for the | 1691 // Assignment to a global variable. Use inline caching for the |
| 1804 // assignment. Right-hand-side value is passed in eax, variable name in | 1692 // assignment. Right-hand-side value is passed in eax, variable name in |
| 1805 // ecx, and the global object on the stack. | 1693 // ecx, and the global object on the stack. |
| 1806 __ mov(ecx, var->name()); | 1694 __ mov(ecx, var->name()); |
| 1807 __ mov(edx, GlobalObjectOperand()); | 1695 __ mov(edx, GlobalObjectOperand()); |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2199 Property* prop = fun->AsProperty(); | 2087 Property* prop = fun->AsProperty(); |
| 2200 Literal* key = prop->key()->AsLiteral(); | 2088 Literal* key = prop->key()->AsLiteral(); |
| 2201 if (key != NULL && key->handle()->IsSymbol()) { | 2089 if (key != NULL && key->handle()->IsSymbol()) { |
| 2202 // Call to a named property, use call IC. | 2090 // Call to a named property, use call IC. |
| 2203 { PreservePositionScope scope(masm()->positions_recorder()); | 2091 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2204 VisitForStackValue(prop->obj()); | 2092 VisitForStackValue(prop->obj()); |
| 2205 } | 2093 } |
| 2206 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2094 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2207 } else { | 2095 } else { |
| 2208 // Call to a keyed property. | 2096 // Call to a keyed property. |
| 2209 // For a synthetic property use keyed load IC followed by function call, | 2097 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2210 // for a regular property use keyed EmitCallIC. | 2098 VisitForStackValue(prop->obj()); |
| 2211 if (prop->is_synthetic()) { | |
| 2212 // Do not visit the object and key subexpressions (they are shared | |
| 2213 // by all occurrences of the same rewritten parameter). | |
| 2214 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 2215 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | |
| 2216 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | |
| 2217 MemOperand operand = EmitSlotSearch(slot, edx); | |
| 2218 __ mov(edx, operand); | |
| 2219 | |
| 2220 ASSERT(prop->key()->AsLiteral() != NULL); | |
| 2221 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 2222 __ mov(eax, prop->key()->AsLiteral()->handle()); | |
| 2223 | |
| 2224 // Record source code position for IC call. | |
| 2225 SetSourcePosition(prop->position()); | |
| 2226 | |
| 2227 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 2228 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 2229 // Push result (function). | |
| 2230 __ push(eax); | |
| 2231 // Push Global receiver. | |
| 2232 __ mov(ecx, GlobalObjectOperand()); | |
| 2233 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | |
| 2234 EmitCallWithStub(expr); | |
| 2235 } else { | |
| 2236 { PreservePositionScope scope(masm()->positions_recorder()); | |
| 2237 VisitForStackValue(prop->obj()); | |
| 2238 } | |
| 2239 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | |
| 2240 } | 2099 } |
| 2100 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 2241 } | 2101 } |
| 2242 } else { | 2102 } else { |
| 2243 // Call to some other expression. If the expression is an anonymous | 2103 // Call to some other expression. If the expression is an anonymous |
| 2244 // function literal not called in a loop, mark it as one that should | 2104 // function literal not called in a loop, mark it as one that should |
| 2245 // also use the full code generator. | 2105 // also use the full code generator. |
| 2246 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2106 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 2247 if (lit != NULL && | 2107 if (lit != NULL && |
| 2248 lit->name()->Equals(Heap::empty_string()) && | 2108 lit->name()->Equals(Heap::empty_string()) && |
| 2249 loop_depth() == 0) { | 2109 loop_depth() == 0) { |
| 2250 lit->set_try_full_codegen(true); | 2110 lit->set_try_full_codegen(true); |
| (...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3534 | 3394 |
| 3535 | 3395 |
| 3536 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3396 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 3537 switch (expr->op()) { | 3397 switch (expr->op()) { |
| 3538 case Token::DELETE: { | 3398 case Token::DELETE: { |
| 3539 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3399 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 3540 Property* prop = expr->expression()->AsProperty(); | 3400 Property* prop = expr->expression()->AsProperty(); |
| 3541 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3401 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 3542 | 3402 |
| 3543 if (prop != NULL) { | 3403 if (prop != NULL) { |
| 3544 if (prop->is_synthetic()) { | 3404 VisitForStackValue(prop->obj()); |
| 3545 // Result of deleting parameters is false, even when they rewrite | 3405 VisitForStackValue(prop->key()); |
| 3546 // to accesses on the arguments object. | 3406 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 3547 context()->Plug(false); | 3407 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3548 } else { | 3408 context()->Plug(eax); |
| 3549 VisitForStackValue(prop->obj()); | |
| 3550 VisitForStackValue(prop->key()); | |
| 3551 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | |
| 3552 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
| 3553 context()->Plug(eax); | |
| 3554 } | |
| 3555 } else if (var != NULL) { | 3409 } else if (var != NULL) { |
| 3556 // Delete of an unqualified identifier is disallowed in strict mode | 3410 // Delete of an unqualified identifier is disallowed in strict mode |
| 3557 // but "delete this" is. | 3411 // but "delete this" is. |
| 3558 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3412 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3559 if (var->is_global()) { | 3413 if (var->is_global()) { |
| 3560 __ push(GlobalObjectOperand()); | 3414 __ push(GlobalObjectOperand()); |
| 3561 __ push(Immediate(var->name())); | 3415 __ push(Immediate(var->name())); |
| 3562 __ push(Immediate(Smi::FromInt(kNonStrictMode))); | 3416 __ push(Immediate(Smi::FromInt(kNonStrictMode))); |
| 3563 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3417 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3564 context()->Plug(eax); | 3418 context()->Plug(eax); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3690 SetSourcePosition(expr->position()); | 3544 SetSourcePosition(expr->position()); |
| 3691 | 3545 |
| 3692 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 3546 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 3693 // as the left-hand side. | 3547 // as the left-hand side. |
| 3694 if (!expr->expression()->IsValidLeftHandSide()) { | 3548 if (!expr->expression()->IsValidLeftHandSide()) { |
| 3695 VisitForEffect(expr->expression()); | 3549 VisitForEffect(expr->expression()); |
| 3696 return; | 3550 return; |
| 3697 } | 3551 } |
| 3698 | 3552 |
| 3699 // Expression can only be a property, a global or a (parameter or local) | 3553 // Expression can only be a property, a global or a (parameter or local) |
| 3700 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 3554 // slot. |
| 3701 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3555 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 3702 LhsKind assign_type = VARIABLE; | 3556 LhsKind assign_type = VARIABLE; |
| 3703 Property* prop = expr->expression()->AsProperty(); | 3557 Property* prop = expr->expression()->AsProperty(); |
| 3704 // In case of a property we use the uninitialized expression context | 3558 // In case of a property we use the uninitialized expression context |
| 3705 // of the key to detect a named property. | 3559 // of the key to detect a named property. |
| 3706 if (prop != NULL) { | 3560 if (prop != NULL) { |
| 3707 assign_type = | 3561 assign_type = |
| 3708 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3562 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3709 } | 3563 } |
| 3710 | 3564 |
| 3711 // Evaluate expression and get value. | 3565 // Evaluate expression and get value. |
| 3712 if (assign_type == VARIABLE) { | 3566 if (assign_type == VARIABLE) { |
| 3713 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3567 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3714 AccumulatorValueContext context(this); | 3568 AccumulatorValueContext context(this); |
| 3715 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3569 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3716 } else { | 3570 } else { |
| 3717 // Reserve space for result of postfix operation. | 3571 // Reserve space for result of postfix operation. |
| 3718 if (expr->is_postfix() && !context()->IsEffect()) { | 3572 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3719 __ push(Immediate(Smi::FromInt(0))); | 3573 __ push(Immediate(Smi::FromInt(0))); |
| 3720 } | 3574 } |
| 3721 if (assign_type == NAMED_PROPERTY) { | 3575 if (assign_type == NAMED_PROPERTY) { |
| 3722 // Put the object both on the stack and in the accumulator. | 3576 // Put the object both on the stack and in the accumulator. |
| 3723 VisitForAccumulatorValue(prop->obj()); | 3577 VisitForAccumulatorValue(prop->obj()); |
| 3724 __ push(eax); | 3578 __ push(eax); |
| 3725 EmitNamedPropertyLoad(prop); | 3579 EmitNamedPropertyLoad(prop); |
| 3726 } else { | 3580 } else { |
| 3727 if (prop->is_arguments_access()) { | 3581 VisitForStackValue(prop->obj()); |
| 3728 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3582 VisitForAccumulatorValue(prop->key()); |
| 3729 MemOperand slot_operand = | |
| 3730 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | |
| 3731 __ push(slot_operand); | |
| 3732 __ mov(eax, Immediate(prop->key()->AsLiteral()->handle())); | |
| 3733 } else { | |
| 3734 VisitForStackValue(prop->obj()); | |
| 3735 VisitForAccumulatorValue(prop->key()); | |
| 3736 } | |
| 3737 __ mov(edx, Operand(esp, 0)); | 3583 __ mov(edx, Operand(esp, 0)); |
| 3738 __ push(eax); | 3584 __ push(eax); |
| 3739 EmitKeyedPropertyLoad(prop); | 3585 EmitKeyedPropertyLoad(prop); |
| 3740 } | 3586 } |
| 3741 } | 3587 } |
| 3742 | 3588 |
| 3743 // We need a second deoptimization point after loading the value | 3589 // We need a second deoptimization point after loading the value |
| 3744 // in case evaluating the property load my have a side effect. | 3590 // in case evaluating the property load my have a side effect. |
| 3745 if (assign_type == VARIABLE) { | 3591 if (assign_type == VARIABLE) { |
| 3746 PrepareForBailout(expr->expression(), TOS_REG); | 3592 PrepareForBailout(expr->expression(), TOS_REG); |
| (...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4257 // And return. | 4103 // And return. |
| 4258 __ ret(0); | 4104 __ ret(0); |
| 4259 } | 4105 } |
| 4260 | 4106 |
| 4261 | 4107 |
| 4262 #undef __ | 4108 #undef __ |
| 4263 | 4109 |
| 4264 } } // namespace v8::internal | 4110 } } // namespace v8::internal |
| 4265 | 4111 |
| 4266 #endif // V8_TARGET_ARCH_IA32 | 4112 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |