| 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 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 } | 674 } |
| 675 } | 675 } |
| 676 | 676 |
| 677 | 677 |
| 678 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 678 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 679 Variable::Mode mode, | 679 Variable::Mode mode, |
| 680 FunctionLiteral* function) { | 680 FunctionLiteral* function) { |
| 681 Comment cmnt(masm_, "[ Declaration"); | 681 Comment cmnt(masm_, "[ Declaration"); |
| 682 ASSERT(variable != NULL); // Must have been resolved. | 682 ASSERT(variable != NULL); // Must have been resolved. |
| 683 Slot* slot = variable->AsSlot(); | 683 Slot* slot = variable->AsSlot(); |
| 684 Property* prop = variable->AsProperty(); | |
| 685 | 684 |
| 686 if (slot != NULL) { | 685 if (slot != NULL) { |
| 687 switch (slot->type()) { | 686 switch (slot->type()) { |
| 688 case Slot::PARAMETER: | 687 case Slot::PARAMETER: |
| 689 case Slot::LOCAL: | 688 case Slot::LOCAL: |
| 690 if (mode == Variable::CONST) { | 689 if (mode == Variable::CONST) { |
| 691 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 690 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 692 __ str(ip, MemOperand(fp, SlotOffset(slot))); | 691 __ str(ip, MemOperand(fp, SlotOffset(slot))); |
| 693 } else if (function != NULL) { | 692 } else if (function != NULL) { |
| 694 VisitForAccumulatorValue(function); | 693 VisitForAccumulatorValue(function); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 // Push initial value for function declaration. | 742 // Push initial value for function declaration. |
| 744 VisitForStackValue(function); | 743 VisitForStackValue(function); |
| 745 } else { | 744 } else { |
| 746 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! | 745 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! |
| 747 __ Push(cp, r2, r1, r0); | 746 __ Push(cp, r2, r1, r0); |
| 748 } | 747 } |
| 749 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 748 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 750 break; | 749 break; |
| 751 } | 750 } |
| 752 } | 751 } |
| 753 | |
| 754 } else if (prop != NULL) { | |
| 755 if (function != NULL || mode == Variable::CONST) { | |
| 756 // We are declaring a function or constant that rewrites to a | |
| 757 // property. Use (keyed) IC to set the initial value. We | |
| 758 // cannot visit the rewrite because it's shared and we risk | |
| 759 // recording duplicate AST IDs for bailouts from optimized code. | |
| 760 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 761 { AccumulatorValueContext for_object(this); | |
| 762 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 763 } | |
| 764 if (function != NULL) { | |
| 765 __ push(r0); | |
| 766 VisitForAccumulatorValue(function); | |
| 767 __ pop(r2); | |
| 768 } else { | |
| 769 __ mov(r2, r0); | |
| 770 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | |
| 771 } | |
| 772 ASSERT(prop->key()->AsLiteral() != NULL && | |
| 773 prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 774 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); | |
| 775 | |
| 776 Handle<Code> ic(Builtins::builtin( | |
| 777 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | |
| 778 : Builtins::KeyedStoreIC_Initialize)); | |
| 779 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 780 // Value in r0 is ignored (declarations are statements). | |
| 781 } | |
| 782 } | 752 } |
| 783 } | 753 } |
| 784 | 754 |
| 785 | 755 |
| 786 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 756 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 787 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 757 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 788 } | 758 } |
| 789 | 759 |
| 790 | 760 |
| 791 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 761 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1144 // Generate fast-case code for variables that might be shadowed by | 1114 // Generate fast-case code for variables that might be shadowed by |
| 1145 // eval-introduced variables. Eval is used a lot without | 1115 // eval-introduced variables. Eval is used a lot without |
| 1146 // introducing variables. In those cases, we do not want to | 1116 // introducing variables. In those cases, we do not want to |
| 1147 // perform a runtime call for all variables in the scope | 1117 // perform a runtime call for all variables in the scope |
| 1148 // containing the eval. | 1118 // containing the eval. |
| 1149 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 1119 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 1150 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); | 1120 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 1151 __ jmp(done); | 1121 __ jmp(done); |
| 1152 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 1122 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 1153 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); | 1123 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); |
| 1154 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | |
| 1155 if (potential_slot != NULL) { | 1124 if (potential_slot != NULL) { |
| 1156 // Generate fast case for locals that rewrite to slots. | 1125 // Generate fast case for locals that rewrite to slots. |
| 1157 __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow)); | 1126 __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1158 if (potential_slot->var()->mode() == Variable::CONST) { | 1127 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1159 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 1128 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 1160 __ cmp(r0, ip); | 1129 __ cmp(r0, ip); |
| 1161 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1130 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
| 1162 } | 1131 } |
| 1163 __ jmp(done); | 1132 __ jmp(done); |
| 1164 } else if (rewrite != NULL) { | |
| 1165 // Generate fast case for calls of an argument function. | |
| 1166 Property* property = rewrite->AsProperty(); | |
| 1167 if (property != NULL) { | |
| 1168 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
| 1169 Literal* key_literal = property->key()->AsLiteral(); | |
| 1170 if (obj_proxy != NULL && | |
| 1171 key_literal != NULL && | |
| 1172 obj_proxy->IsArguments() && | |
| 1173 key_literal->handle()->IsSmi()) { | |
| 1174 // Load arguments object if there are no eval-introduced | |
| 1175 // variables. Then load the argument from the arguments | |
| 1176 // object using keyed load. | |
| 1177 __ ldr(r1, | |
| 1178 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | |
| 1179 slow)); | |
| 1180 __ mov(r0, Operand(key_literal->handle())); | |
| 1181 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1182 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 1183 __ jmp(done); | |
| 1184 } | |
| 1185 } | |
| 1186 } | 1133 } |
| 1187 } | 1134 } |
| 1188 } | 1135 } |
| 1189 | 1136 |
| 1190 | 1137 |
| 1191 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( | 1138 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( |
| 1192 Slot* slot, | 1139 Slot* slot, |
| 1193 TypeofState typeof_state, | 1140 TypeofState typeof_state, |
| 1194 Label* slow) { | 1141 Label* slow) { |
| 1195 Register current = cp; | 1142 Register current = cp; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1243 __ mov(r2, Operand(slot->var()->name())); | 1190 __ mov(r2, Operand(slot->var()->name())); |
| 1244 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1191 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 1245 ? RelocInfo::CODE_TARGET | 1192 ? RelocInfo::CODE_TARGET |
| 1246 : RelocInfo::CODE_TARGET_CONTEXT; | 1193 : RelocInfo::CODE_TARGET_CONTEXT; |
| 1247 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1194 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1248 EmitCallIC(ic, mode); | 1195 EmitCallIC(ic, mode); |
| 1249 } | 1196 } |
| 1250 | 1197 |
| 1251 | 1198 |
| 1252 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1199 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1253 // Four cases: non-this global variables, lookup slots, all other | 1200 // Three cases: non-this global variables, lookup slots, and all other |
| 1254 // types of slots, and parameters that rewrite to explicit property | 1201 // types of slots. |
| 1255 // accesses on the arguments object. | |
| 1256 Slot* slot = var->AsSlot(); | 1202 Slot* slot = var->AsSlot(); |
| 1257 Property* property = var->AsProperty(); | 1203 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); |
| 1258 | 1204 |
| 1259 if (var->is_global() && !var->is_this()) { | 1205 if (slot == NULL) { |
| 1260 Comment cmnt(masm_, "Global variable"); | 1206 Comment cmnt(masm_, "Global variable"); |
| 1261 // Use inline caching. Variable name is passed in r2 and the global | 1207 // Use inline caching. Variable name is passed in r2 and the global |
| 1262 // object (receiver) in r0. | 1208 // object (receiver) in r0. |
| 1263 __ ldr(r0, GlobalObjectOperand()); | 1209 __ ldr(r0, GlobalObjectOperand()); |
| 1264 __ mov(r2, Operand(var->name())); | 1210 __ mov(r2, Operand(var->name())); |
| 1265 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1211 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1266 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1212 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1267 context()->Plug(r0); | 1213 context()->Plug(r0); |
| 1268 | 1214 |
| 1269 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1215 } else if (slot->type() == Slot::LOOKUP) { |
| 1270 Label done, slow; | 1216 Label done, slow; |
| 1271 | 1217 |
| 1272 // Generate code for loading from variables potentially shadowed | 1218 // Generate code for loading from variables potentially shadowed |
| 1273 // by eval-introduced variables. | 1219 // by eval-introduced variables. |
| 1274 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1220 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1275 | 1221 |
| 1276 __ bind(&slow); | 1222 __ bind(&slow); |
| 1277 Comment cmnt(masm_, "Lookup slot"); | 1223 Comment cmnt(masm_, "Lookup slot"); |
| 1278 __ mov(r1, Operand(var->name())); | 1224 __ mov(r1, Operand(var->name())); |
| 1279 __ Push(cp, r1); // Context and name. | 1225 __ Push(cp, r1); // Context and name. |
| 1280 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1226 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1281 __ bind(&done); | 1227 __ bind(&done); |
| 1282 | 1228 |
| 1283 context()->Plug(r0); | 1229 context()->Plug(r0); |
| 1284 | 1230 |
| 1285 } else if (slot != NULL) { | 1231 } else { |
| 1286 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1232 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1287 ? "Context slot" | 1233 ? "Context slot" |
| 1288 : "Stack slot"); | 1234 : "Stack slot"); |
| 1289 if (var->mode() == Variable::CONST) { | 1235 if (var->mode() == Variable::CONST) { |
| 1290 // Constants may be the hole value if they have not been initialized. | 1236 // Constants may be the hole value if they have not been initialized. |
| 1291 // Unhole them. | 1237 // Unhole them. |
| 1292 MemOperand slot_operand = EmitSlotSearch(slot, r0); | 1238 MemOperand slot_operand = EmitSlotSearch(slot, r0); |
| 1293 __ ldr(r0, slot_operand); | 1239 __ ldr(r0, slot_operand); |
| 1294 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 1240 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 1295 __ cmp(r0, ip); | 1241 __ cmp(r0, ip); |
| 1296 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1242 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
| 1297 context()->Plug(r0); | 1243 context()->Plug(r0); |
| 1298 } else { | 1244 } else { |
| 1299 context()->Plug(slot); | 1245 context()->Plug(slot); |
| 1300 } | 1246 } |
| 1301 } else { | |
| 1302 Comment cmnt(masm_, "Rewritten parameter"); | |
| 1303 ASSERT_NOT_NULL(property); | |
| 1304 // Rewritten parameter accesses are of the form "slot[literal]". | |
| 1305 | |
| 1306 // Assert that the object is in a slot. | |
| 1307 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | |
| 1308 ASSERT_NOT_NULL(object_var); | |
| 1309 Slot* object_slot = object_var->AsSlot(); | |
| 1310 ASSERT_NOT_NULL(object_slot); | |
| 1311 | |
| 1312 // Load the object. | |
| 1313 Move(r1, object_slot); | |
| 1314 | |
| 1315 // Assert that the key is a smi. | |
| 1316 Literal* key_literal = property->key()->AsLiteral(); | |
| 1317 ASSERT_NOT_NULL(key_literal); | |
| 1318 ASSERT(key_literal->handle()->IsSmi()); | |
| 1319 | |
| 1320 // Load the key. | |
| 1321 __ mov(r0, Operand(key_literal->handle())); | |
| 1322 | |
| 1323 // Call keyed load IC. It has arguments key and receiver in r0 and r1. | |
| 1324 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1325 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 1326 context()->Plug(r0); | |
| 1327 } | 1247 } |
| 1328 } | 1248 } |
| 1329 | 1249 |
| 1330 | 1250 |
| 1331 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1251 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1332 Comment cmnt(masm_, "[ RegExpLiteral"); | 1252 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1333 Label materialized; | 1253 Label materialized; |
| 1334 // Registers will be used as follows: | 1254 // Registers will be used as follows: |
| 1335 // r5 = materialized value (RegExp literal) | 1255 // r5 = materialized value (RegExp literal) |
| 1336 // r4 = JS function, literals array | 1256 // r4 = JS function, literals array |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1460 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1541 Comment cmnt(masm_, "[ Assignment"); | 1461 Comment cmnt(masm_, "[ Assignment"); |
| 1542 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1462 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1543 // on the left-hand side. | 1463 // on the left-hand side. |
| 1544 if (!expr->target()->IsValidLeftHandSide()) { | 1464 if (!expr->target()->IsValidLeftHandSide()) { |
| 1545 VisitForEffect(expr->target()); | 1465 VisitForEffect(expr->target()); |
| 1546 return; | 1466 return; |
| 1547 } | 1467 } |
| 1548 | 1468 |
| 1549 // Left-hand side can only be a property, a global or a (parameter or local) | 1469 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1550 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1470 // slot. |
| 1551 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1471 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1552 LhsKind assign_type = VARIABLE; | 1472 LhsKind assign_type = VARIABLE; |
| 1553 Property* property = expr->target()->AsProperty(); | 1473 Property* property = expr->target()->AsProperty(); |
| 1554 if (property != NULL) { | 1474 if (property != NULL) { |
| 1555 assign_type = (property->key()->IsPropertyName()) | 1475 assign_type = (property->key()->IsPropertyName()) |
| 1556 ? NAMED_PROPERTY | 1476 ? NAMED_PROPERTY |
| 1557 : KEYED_PROPERTY; | 1477 : KEYED_PROPERTY; |
| 1558 } | 1478 } |
| 1559 | 1479 |
| 1560 // Evaluate LHS expression. | 1480 // Evaluate LHS expression. |
| 1561 switch (assign_type) { | 1481 switch (assign_type) { |
| 1562 case VARIABLE: | 1482 case VARIABLE: |
| 1563 // Nothing to do here. | 1483 // Nothing to do here. |
| 1564 break; | 1484 break; |
| 1565 case NAMED_PROPERTY: | 1485 case NAMED_PROPERTY: |
| 1566 if (expr->is_compound()) { | 1486 if (expr->is_compound()) { |
| 1567 // We need the receiver both on the stack and in the accumulator. | 1487 // We need the receiver both on the stack and in the accumulator. |
| 1568 VisitForAccumulatorValue(property->obj()); | 1488 VisitForAccumulatorValue(property->obj()); |
| 1569 __ push(result_register()); | 1489 __ push(result_register()); |
| 1570 } else { | 1490 } else { |
| 1571 VisitForStackValue(property->obj()); | 1491 VisitForStackValue(property->obj()); |
| 1572 } | 1492 } |
| 1573 break; | 1493 break; |
| 1574 case KEYED_PROPERTY: | 1494 case KEYED_PROPERTY: |
| 1575 if (expr->is_compound()) { | 1495 if (expr->is_compound()) { |
| 1576 if (property->is_arguments_access()) { | 1496 VisitForStackValue(property->obj()); |
| 1577 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1497 VisitForAccumulatorValue(property->key()); |
| 1578 __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); | |
| 1579 __ push(r0); | |
| 1580 __ mov(r0, Operand(property->key()->AsLiteral()->handle())); | |
| 1581 } else { | |
| 1582 VisitForStackValue(property->obj()); | |
| 1583 VisitForAccumulatorValue(property->key()); | |
| 1584 } | |
| 1585 __ ldr(r1, MemOperand(sp, 0)); | 1498 __ ldr(r1, MemOperand(sp, 0)); |
| 1586 __ push(r0); | 1499 __ push(r0); |
| 1587 } else { | 1500 } else { |
| 1588 if (property->is_arguments_access()) { | 1501 VisitForStackValue(property->obj()); |
| 1589 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1502 VisitForStackValue(property->key()); |
| 1590 __ ldr(r1, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); | |
| 1591 __ mov(r0, Operand(property->key()->AsLiteral()->handle())); | |
| 1592 __ Push(r1, r0); | |
| 1593 } else { | |
| 1594 VisitForStackValue(property->obj()); | |
| 1595 VisitForStackValue(property->key()); | |
| 1596 } | |
| 1597 } | 1503 } |
| 1598 break; | 1504 break; |
| 1599 } | 1505 } |
| 1600 | 1506 |
| 1601 // For compound assignments we need another deoptimization point after the | 1507 // For compound assignments we need another deoptimization point after the |
| 1602 // variable/property load. | 1508 // variable/property load. |
| 1603 if (expr->is_compound()) { | 1509 if (expr->is_compound()) { |
| 1604 { AccumulatorValueContext context(this); | 1510 { AccumulatorValueContext context(this); |
| 1605 switch (assign_type) { | 1511 switch (assign_type) { |
| 1606 case VARIABLE: | 1512 case VARIABLE: |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1792 | 1698 |
| 1793 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1699 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1794 // Invalid left-hand sides are rewritten to have a 'throw | 1700 // Invalid left-hand sides are rewritten to have a 'throw |
| 1795 // ReferenceError' on the left-hand side. | 1701 // ReferenceError' on the left-hand side. |
| 1796 if (!expr->IsValidLeftHandSide()) { | 1702 if (!expr->IsValidLeftHandSide()) { |
| 1797 VisitForEffect(expr); | 1703 VisitForEffect(expr); |
| 1798 return; | 1704 return; |
| 1799 } | 1705 } |
| 1800 | 1706 |
| 1801 // Left-hand side can only be a property, a global or a (parameter or local) | 1707 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1802 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1708 // slot. |
| 1803 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1709 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1804 LhsKind assign_type = VARIABLE; | 1710 LhsKind assign_type = VARIABLE; |
| 1805 Property* prop = expr->AsProperty(); | 1711 Property* prop = expr->AsProperty(); |
| 1806 if (prop != NULL) { | 1712 if (prop != NULL) { |
| 1807 assign_type = (prop->key()->IsPropertyName()) | 1713 assign_type = (prop->key()->IsPropertyName()) |
| 1808 ? NAMED_PROPERTY | 1714 ? NAMED_PROPERTY |
| 1809 : KEYED_PROPERTY; | 1715 : KEYED_PROPERTY; |
| 1810 } | 1716 } |
| 1811 | 1717 |
| 1812 switch (assign_type) { | 1718 switch (assign_type) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1823 __ pop(r0); // Restore value. | 1729 __ pop(r0); // Restore value. |
| 1824 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); | 1730 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); |
| 1825 Handle<Code> ic(Builtins::builtin( | 1731 Handle<Code> ic(Builtins::builtin( |
| 1826 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1732 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1827 : Builtins::StoreIC_Initialize)); | 1733 : Builtins::StoreIC_Initialize)); |
| 1828 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1734 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1829 break; | 1735 break; |
| 1830 } | 1736 } |
| 1831 case KEYED_PROPERTY: { | 1737 case KEYED_PROPERTY: { |
| 1832 __ push(r0); // Preserve value. | 1738 __ push(r0); // Preserve value. |
| 1833 if (prop->is_synthetic()) { | 1739 VisitForStackValue(prop->obj()); |
| 1834 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1740 VisitForAccumulatorValue(prop->key()); |
| 1835 ASSERT(prop->key()->AsLiteral() != NULL); | 1741 __ mov(r1, r0); |
| 1836 { AccumulatorValueContext for_object(this); | 1742 __ pop(r2); |
| 1837 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 1838 } | |
| 1839 __ mov(r2, r0); | |
| 1840 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); | |
| 1841 } else { | |
| 1842 VisitForStackValue(prop->obj()); | |
| 1843 VisitForAccumulatorValue(prop->key()); | |
| 1844 __ mov(r1, r0); | |
| 1845 __ pop(r2); | |
| 1846 } | |
| 1847 __ pop(r0); // Restore value. | 1743 __ pop(r0); // Restore value. |
| 1848 Handle<Code> ic(Builtins::builtin( | 1744 Handle<Code> ic(Builtins::builtin( |
| 1849 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 1745 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1850 : Builtins::KeyedStoreIC_Initialize)); | 1746 : Builtins::KeyedStoreIC_Initialize)); |
| 1851 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1747 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1852 break; | 1748 break; |
| 1853 } | 1749 } |
| 1854 } | 1750 } |
| 1855 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1751 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1856 context()->Plug(r0); | 1752 context()->Plug(r0); |
| 1857 } | 1753 } |
| 1858 | 1754 |
| 1859 | 1755 |
| 1860 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1756 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1861 Token::Value op) { | 1757 Token::Value op) { |
| 1862 // Left-hand sides that rewrite to explicit property accesses do not reach | |
| 1863 // here. | |
| 1864 ASSERT(var != NULL); | 1758 ASSERT(var != NULL); |
| 1865 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1759 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1866 | 1760 |
| 1867 if (var->is_global()) { | 1761 if (var->is_global()) { |
| 1868 ASSERT(!var->is_this()); | 1762 ASSERT(!var->is_this()); |
| 1869 // Assignment to a global variable. Use inline caching for the | 1763 // Assignment to a global variable. Use inline caching for the |
| 1870 // assignment. Right-hand-side value is passed in r0, variable name in | 1764 // assignment. Right-hand-side value is passed in r0, variable name in |
| 1871 // r2, and the global object in r1. | 1765 // r2, and the global object in r1. |
| 1872 __ mov(r2, Operand(var->name())); | 1766 __ mov(r2, Operand(var->name())); |
| 1873 __ ldr(r1, GlobalObjectOperand()); | 1767 __ ldr(r1, GlobalObjectOperand()); |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2286 Property* prop = fun->AsProperty(); | 2180 Property* prop = fun->AsProperty(); |
| 2287 Literal* key = prop->key()->AsLiteral(); | 2181 Literal* key = prop->key()->AsLiteral(); |
| 2288 if (key != NULL && key->handle()->IsSymbol()) { | 2182 if (key != NULL && key->handle()->IsSymbol()) { |
| 2289 // Call to a named property, use call IC. | 2183 // Call to a named property, use call IC. |
| 2290 { PreservePositionScope scope(masm()->positions_recorder()); | 2184 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2291 VisitForStackValue(prop->obj()); | 2185 VisitForStackValue(prop->obj()); |
| 2292 } | 2186 } |
| 2293 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2187 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2294 } else { | 2188 } else { |
| 2295 // Call to a keyed property. | 2189 // Call to a keyed property. |
| 2296 // For a synthetic property use keyed load IC followed by function call, | 2190 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2297 // for a regular property use keyed CallIC. | 2191 VisitForStackValue(prop->obj()); |
| 2298 if (prop->is_synthetic()) { | |
| 2299 // Do not visit the object and key subexpressions (they are shared | |
| 2300 // by all occurrences of the same rewritten parameter). | |
| 2301 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 2302 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | |
| 2303 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | |
| 2304 MemOperand operand = EmitSlotSearch(slot, r1); | |
| 2305 __ ldr(r1, operand); | |
| 2306 | |
| 2307 ASSERT(prop->key()->AsLiteral() != NULL); | |
| 2308 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 2309 __ mov(r0, Operand(prop->key()->AsLiteral()->handle())); | |
| 2310 | |
| 2311 // Record source code position for IC call. | |
| 2312 SetSourcePosition(prop->position()); | |
| 2313 | |
| 2314 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 2315 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 2316 __ ldr(r1, GlobalObjectOperand()); | |
| 2317 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | |
| 2318 __ Push(r0, r1); // Function, receiver. | |
| 2319 EmitCallWithStub(expr); | |
| 2320 } else { | |
| 2321 { PreservePositionScope scope(masm()->positions_recorder()); | |
| 2322 VisitForStackValue(prop->obj()); | |
| 2323 } | |
| 2324 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | |
| 2325 } | 2192 } |
| 2193 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 2326 } | 2194 } |
| 2327 } else { | 2195 } else { |
| 2328 // Call to some other expression. If the expression is an anonymous | 2196 // Call to some other expression. If the expression is an anonymous |
| 2329 // function literal not called in a loop, mark it as one that should | 2197 // function literal not called in a loop, mark it as one that should |
| 2330 // also use the fast code generator. | 2198 // also use the fast code generator. |
| 2331 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2199 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 2332 if (lit != NULL && | 2200 if (lit != NULL && |
| 2333 lit->name()->Equals(Heap::empty_string()) && | 2201 lit->name()->Equals(Heap::empty_string()) && |
| 2334 loop_depth() == 0) { | 2202 loop_depth() == 0) { |
| 2335 lit->set_try_full_codegen(true); | 2203 lit->set_try_full_codegen(true); |
| (...skipping 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3587 | 3455 |
| 3588 | 3456 |
| 3589 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3457 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 3590 switch (expr->op()) { | 3458 switch (expr->op()) { |
| 3591 case Token::DELETE: { | 3459 case Token::DELETE: { |
| 3592 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3460 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 3593 Property* prop = expr->expression()->AsProperty(); | 3461 Property* prop = expr->expression()->AsProperty(); |
| 3594 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3462 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 3595 | 3463 |
| 3596 if (prop != NULL) { | 3464 if (prop != NULL) { |
| 3597 if (prop->is_synthetic()) { | 3465 VisitForStackValue(prop->obj()); |
| 3598 // Result of deleting parameters is false, even when they rewrite | 3466 VisitForStackValue(prop->key()); |
| 3599 // to accesses on the arguments object. | 3467 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); |
| 3600 context()->Plug(false); | 3468 __ push(r1); |
| 3601 } else { | 3469 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| 3602 VisitForStackValue(prop->obj()); | 3470 context()->Plug(r0); |
| 3603 VisitForStackValue(prop->key()); | |
| 3604 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); | |
| 3605 __ push(r1); | |
| 3606 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); | |
| 3607 context()->Plug(r0); | |
| 3608 } | |
| 3609 } else if (var != NULL) { | 3471 } else if (var != NULL) { |
| 3610 // Delete of an unqualified identifier is disallowed in strict mode | 3472 // Delete of an unqualified identifier is disallowed in strict mode |
| 3611 // but "delete this" is. | 3473 // but "delete this" is. |
| 3612 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3474 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3613 if (var->is_global()) { | 3475 if (var->is_global()) { |
| 3614 __ ldr(r2, GlobalObjectOperand()); | 3476 __ ldr(r2, GlobalObjectOperand()); |
| 3615 __ mov(r1, Operand(var->name())); | 3477 __ mov(r1, Operand(var->name())); |
| 3616 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); | 3478 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); |
| 3617 __ Push(r2, r1, r0); | 3479 __ Push(r2, r1, r0); |
| 3618 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); | 3480 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3746 SetSourcePosition(expr->position()); | 3608 SetSourcePosition(expr->position()); |
| 3747 | 3609 |
| 3748 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 3610 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 3749 // as the left-hand side. | 3611 // as the left-hand side. |
| 3750 if (!expr->expression()->IsValidLeftHandSide()) { | 3612 if (!expr->expression()->IsValidLeftHandSide()) { |
| 3751 VisitForEffect(expr->expression()); | 3613 VisitForEffect(expr->expression()); |
| 3752 return; | 3614 return; |
| 3753 } | 3615 } |
| 3754 | 3616 |
| 3755 // Expression can only be a property, a global or a (parameter or local) | 3617 // Expression can only be a property, a global or a (parameter or local) |
| 3756 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 3618 // slot. |
| 3757 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3619 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 3758 LhsKind assign_type = VARIABLE; | 3620 LhsKind assign_type = VARIABLE; |
| 3759 Property* prop = expr->expression()->AsProperty(); | 3621 Property* prop = expr->expression()->AsProperty(); |
| 3760 // In case of a property we use the uninitialized expression context | 3622 // In case of a property we use the uninitialized expression context |
| 3761 // of the key to detect a named property. | 3623 // of the key to detect a named property. |
| 3762 if (prop != NULL) { | 3624 if (prop != NULL) { |
| 3763 assign_type = | 3625 assign_type = |
| 3764 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3626 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3765 } | 3627 } |
| 3766 | 3628 |
| 3767 // Evaluate expression and get value. | 3629 // Evaluate expression and get value. |
| 3768 if (assign_type == VARIABLE) { | 3630 if (assign_type == VARIABLE) { |
| 3769 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3631 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3770 AccumulatorValueContext context(this); | 3632 AccumulatorValueContext context(this); |
| 3771 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3633 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3772 } else { | 3634 } else { |
| 3773 // Reserve space for result of postfix operation. | 3635 // Reserve space for result of postfix operation. |
| 3774 if (expr->is_postfix() && !context()->IsEffect()) { | 3636 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3775 __ mov(ip, Operand(Smi::FromInt(0))); | 3637 __ mov(ip, Operand(Smi::FromInt(0))); |
| 3776 __ push(ip); | 3638 __ push(ip); |
| 3777 } | 3639 } |
| 3778 if (assign_type == NAMED_PROPERTY) { | 3640 if (assign_type == NAMED_PROPERTY) { |
| 3779 // Put the object both on the stack and in the accumulator. | 3641 // Put the object both on the stack and in the accumulator. |
| 3780 VisitForAccumulatorValue(prop->obj()); | 3642 VisitForAccumulatorValue(prop->obj()); |
| 3781 __ push(r0); | 3643 __ push(r0); |
| 3782 EmitNamedPropertyLoad(prop); | 3644 EmitNamedPropertyLoad(prop); |
| 3783 } else { | 3645 } else { |
| 3784 if (prop->is_arguments_access()) { | 3646 VisitForStackValue(prop->obj()); |
| 3785 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3647 VisitForAccumulatorValue(prop->key()); |
| 3786 __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); | |
| 3787 __ push(r0); | |
| 3788 __ mov(r0, Operand(prop->key()->AsLiteral()->handle())); | |
| 3789 } else { | |
| 3790 VisitForStackValue(prop->obj()); | |
| 3791 VisitForAccumulatorValue(prop->key()); | |
| 3792 } | |
| 3793 __ ldr(r1, MemOperand(sp, 0)); | 3648 __ ldr(r1, MemOperand(sp, 0)); |
| 3794 __ push(r0); | 3649 __ push(r0); |
| 3795 EmitKeyedPropertyLoad(prop); | 3650 EmitKeyedPropertyLoad(prop); |
| 3796 } | 3651 } |
| 3797 } | 3652 } |
| 3798 | 3653 |
| 3799 // We need a second deoptimization point after loading the value | 3654 // We need a second deoptimization point after loading the value |
| 3800 // in case evaluating the property load my have a side effect. | 3655 // in case evaluating the property load my have a side effect. |
| 3801 if (assign_type == VARIABLE) { | 3656 if (assign_type == VARIABLE) { |
| 3802 PrepareForBailout(expr->expression(), TOS_REG); | 3657 PrepareForBailout(expr->expression(), TOS_REG); |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4279 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 4134 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
| 4280 __ add(pc, r1, Operand(masm_->CodeObject())); | 4135 __ add(pc, r1, Operand(masm_->CodeObject())); |
| 4281 } | 4136 } |
| 4282 | 4137 |
| 4283 | 4138 |
| 4284 #undef __ | 4139 #undef __ |
| 4285 | 4140 |
| 4286 } } // namespace v8::internal | 4141 } } // namespace v8::internal |
| 4287 | 4142 |
| 4288 #endif // V8_TARGET_ARCH_ARM | 4143 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |