| 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 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 } | 640 } |
| 641 } | 641 } |
| 642 | 642 |
| 643 | 643 |
| 644 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 644 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 645 Variable::Mode mode, | 645 Variable::Mode mode, |
| 646 FunctionLiteral* function) { | 646 FunctionLiteral* function) { |
| 647 Comment cmnt(masm_, "[ Declaration"); | 647 Comment cmnt(masm_, "[ Declaration"); |
| 648 ASSERT(variable != NULL); // Must have been resolved. | 648 ASSERT(variable != NULL); // Must have been resolved. |
| 649 Slot* slot = variable->AsSlot(); | 649 Slot* slot = variable->AsSlot(); |
| 650 Property* prop = variable->AsProperty(); | |
| 651 | 650 |
| 652 if (slot != NULL) { | 651 if (slot != NULL) { |
| 653 switch (slot->type()) { | 652 switch (slot->type()) { |
| 654 case Slot::PARAMETER: | 653 case Slot::PARAMETER: |
| 655 case Slot::LOCAL: | 654 case Slot::LOCAL: |
| 656 if (mode == Variable::CONST) { | 655 if (mode == Variable::CONST) { |
| 657 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 656 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 658 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); | 657 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); |
| 659 } else if (function != NULL) { | 658 } else if (function != NULL) { |
| 660 VisitForAccumulatorValue(function); | 659 VisitForAccumulatorValue(function); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 __ PushRoot(Heap::kTheHoleValueRootIndex); | 701 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 703 } else if (function != NULL) { | 702 } else if (function != NULL) { |
| 704 VisitForStackValue(function); | 703 VisitForStackValue(function); |
| 705 } else { | 704 } else { |
| 706 __ Push(Smi::FromInt(0)); // no initial value! | 705 __ Push(Smi::FromInt(0)); // no initial value! |
| 707 } | 706 } |
| 708 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 707 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 709 break; | 708 break; |
| 710 } | 709 } |
| 711 } | 710 } |
| 712 | |
| 713 } else if (prop != NULL) { | |
| 714 if (function != NULL || mode == Variable::CONST) { | |
| 715 // We are declaring a function or constant that rewrites to a | |
| 716 // property. Use (keyed) IC to set the initial value. We | |
| 717 // cannot visit the rewrite because it's shared and we risk | |
| 718 // recording duplicate AST IDs for bailouts from optimized code. | |
| 719 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 720 { AccumulatorValueContext for_object(this); | |
| 721 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 722 } | |
| 723 if (function != NULL) { | |
| 724 __ push(rax); | |
| 725 VisitForAccumulatorValue(function); | |
| 726 __ pop(rdx); | |
| 727 } else { | |
| 728 __ movq(rdx, rax); | |
| 729 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); | |
| 730 } | |
| 731 ASSERT(prop->key()->AsLiteral() != NULL && | |
| 732 prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 733 __ Move(rcx, prop->key()->AsLiteral()->handle()); | |
| 734 | |
| 735 Handle<Code> ic(Builtins::builtin( | |
| 736 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | |
| 737 : Builtins::KeyedStoreIC_Initialize)); | |
| 738 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 739 } | |
| 740 } | 711 } |
| 741 } | 712 } |
| 742 | 713 |
| 743 | 714 |
| 744 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 715 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 745 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 716 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 746 } | 717 } |
| 747 | 718 |
| 748 | 719 |
| 749 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 720 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1159 // Generate fast-case code for variables that might be shadowed by | 1130 // Generate fast-case code for variables that might be shadowed by |
| 1160 // eval-introduced variables. Eval is used a lot without | 1131 // eval-introduced variables. Eval is used a lot without |
| 1161 // introducing variables. In those cases, we do not want to | 1132 // introducing variables. In those cases, we do not want to |
| 1162 // perform a runtime call for all variables in the scope | 1133 // perform a runtime call for all variables in the scope |
| 1163 // containing the eval. | 1134 // containing the eval. |
| 1164 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 1135 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 1165 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); | 1136 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 1166 __ jmp(done); | 1137 __ jmp(done); |
| 1167 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 1138 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 1168 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); | 1139 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); |
| 1169 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | |
| 1170 if (potential_slot != NULL) { | 1140 if (potential_slot != NULL) { |
| 1171 // Generate fast case for locals that rewrite to slots. | 1141 // Generate fast case for locals that rewrite to slots. |
| 1172 __ movq(rax, | 1142 __ movq(rax, |
| 1173 ContextSlotOperandCheckExtensions(potential_slot, slow)); | 1143 ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1174 if (potential_slot->var()->mode() == Variable::CONST) { | 1144 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1175 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1145 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1176 __ j(not_equal, done); | 1146 __ j(not_equal, done); |
| 1177 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1147 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1178 } | 1148 } |
| 1179 __ jmp(done); | 1149 __ jmp(done); |
| 1180 } else if (rewrite != NULL) { | |
| 1181 // Generate fast case for calls of an argument function. | |
| 1182 Property* property = rewrite->AsProperty(); | |
| 1183 if (property != NULL) { | |
| 1184 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
| 1185 Literal* key_literal = property->key()->AsLiteral(); | |
| 1186 if (obj_proxy != NULL && | |
| 1187 key_literal != NULL && | |
| 1188 obj_proxy->IsArguments() && | |
| 1189 key_literal->handle()->IsSmi()) { | |
| 1190 // Load arguments object if there are no eval-introduced | |
| 1191 // variables. Then load the argument from the arguments | |
| 1192 // object using keyed load. | |
| 1193 __ movq(rdx, | |
| 1194 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | |
| 1195 slow)); | |
| 1196 __ Move(rax, key_literal->handle()); | |
| 1197 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1198 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 1199 __ jmp(done); | |
| 1200 } | |
| 1201 } | |
| 1202 } | 1150 } |
| 1203 } | 1151 } |
| 1204 } | 1152 } |
| 1205 | 1153 |
| 1206 | 1154 |
| 1207 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1155 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1208 // Four cases: non-this global variables, lookup slots, all other | 1156 // Three cases: non-this global variables, lookup slots, and all other |
| 1209 // types of slots, and parameters that rewrite to explicit property | 1157 // types of slots. |
| 1210 // accesses on the arguments object. | |
| 1211 Slot* slot = var->AsSlot(); | 1158 Slot* slot = var->AsSlot(); |
| 1212 Property* property = var->AsProperty(); | 1159 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); |
| 1213 | 1160 |
| 1214 if (var->is_global() && !var->is_this()) { | 1161 if (slot == NULL) { |
| 1215 Comment cmnt(masm_, "Global variable"); | 1162 Comment cmnt(masm_, "Global variable"); |
| 1216 // Use inline caching. Variable name is passed in rcx and the global | 1163 // Use inline caching. Variable name is passed in rcx and the global |
| 1217 // object on the stack. | 1164 // object on the stack. |
| 1218 __ Move(rcx, var->name()); | 1165 __ Move(rcx, var->name()); |
| 1219 __ movq(rax, GlobalObjectOperand()); | 1166 __ movq(rax, GlobalObjectOperand()); |
| 1220 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1167 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1221 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1168 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1222 context()->Plug(rax); | 1169 context()->Plug(rax); |
| 1223 | 1170 |
| 1224 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1171 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1225 Label done, slow; | 1172 Label done, slow; |
| 1226 | 1173 |
| 1227 // Generate code for loading from variables potentially shadowed | 1174 // Generate code for loading from variables potentially shadowed |
| 1228 // by eval-introduced variables. | 1175 // by eval-introduced variables. |
| 1229 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1176 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1230 | 1177 |
| 1231 __ bind(&slow); | 1178 __ bind(&slow); |
| 1232 Comment cmnt(masm_, "Lookup slot"); | 1179 Comment cmnt(masm_, "Lookup slot"); |
| 1233 __ push(rsi); // Context. | 1180 __ push(rsi); // Context. |
| 1234 __ Push(var->name()); | 1181 __ Push(var->name()); |
| 1235 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1182 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1236 __ bind(&done); | 1183 __ bind(&done); |
| 1237 | 1184 |
| 1238 context()->Plug(rax); | 1185 context()->Plug(rax); |
| 1239 | 1186 |
| 1240 } else if (slot != NULL) { | 1187 } else { |
| 1241 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1188 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1242 ? "Context slot" | 1189 ? "Context slot" |
| 1243 : "Stack slot"); | 1190 : "Stack slot"); |
| 1244 if (var->mode() == Variable::CONST) { | 1191 if (var->mode() == Variable::CONST) { |
| 1245 // Constants may be the hole value if they have not been initialized. | 1192 // Constants may be the hole value if they have not been initialized. |
| 1246 // Unhole them. | 1193 // Unhole them. |
| 1247 NearLabel done; | 1194 NearLabel done; |
| 1248 MemOperand slot_operand = EmitSlotSearch(slot, rax); | 1195 MemOperand slot_operand = EmitSlotSearch(slot, rax); |
| 1249 __ movq(rax, slot_operand); | 1196 __ movq(rax, slot_operand); |
| 1250 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1197 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1251 __ j(not_equal, &done); | 1198 __ j(not_equal, &done); |
| 1252 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1199 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1253 __ bind(&done); | 1200 __ bind(&done); |
| 1254 context()->Plug(rax); | 1201 context()->Plug(rax); |
| 1255 } else { | 1202 } else { |
| 1256 context()->Plug(slot); | 1203 context()->Plug(slot); |
| 1257 } | 1204 } |
| 1258 | |
| 1259 } else { | |
| 1260 Comment cmnt(masm_, "Rewritten parameter"); | |
| 1261 ASSERT_NOT_NULL(property); | |
| 1262 // Rewritten parameter accesses are of the form "slot[literal]". | |
| 1263 | |
| 1264 // Assert that the object is in a slot. | |
| 1265 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | |
| 1266 ASSERT_NOT_NULL(object_var); | |
| 1267 Slot* object_slot = object_var->AsSlot(); | |
| 1268 ASSERT_NOT_NULL(object_slot); | |
| 1269 | |
| 1270 // Load the object. | |
| 1271 MemOperand object_loc = EmitSlotSearch(object_slot, rax); | |
| 1272 __ movq(rdx, object_loc); | |
| 1273 | |
| 1274 // Assert that the key is a smi. | |
| 1275 Literal* key_literal = property->key()->AsLiteral(); | |
| 1276 ASSERT_NOT_NULL(key_literal); | |
| 1277 ASSERT(key_literal->handle()->IsSmi()); | |
| 1278 | |
| 1279 // Load the key. | |
| 1280 __ Move(rax, key_literal->handle()); | |
| 1281 | |
| 1282 // Do a keyed property load. | |
| 1283 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 1284 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 1285 context()->Plug(rax); | |
| 1286 } | 1205 } |
| 1287 } | 1206 } |
| 1288 | 1207 |
| 1289 | 1208 |
| 1290 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1209 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1291 Comment cmnt(masm_, "[ RegExpLiteral"); | 1210 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1292 Label materialized; | 1211 Label materialized; |
| 1293 // Registers will be used as follows: | 1212 // Registers will be used as follows: |
| 1294 // rdi = JS function. | 1213 // rdi = JS function. |
| 1295 // rcx = literals array. | 1214 // rcx = literals array. |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1410 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1492 Comment cmnt(masm_, "[ Assignment"); | 1411 Comment cmnt(masm_, "[ Assignment"); |
| 1493 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1412 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1494 // on the left-hand side. | 1413 // on the left-hand side. |
| 1495 if (!expr->target()->IsValidLeftHandSide()) { | 1414 if (!expr->target()->IsValidLeftHandSide()) { |
| 1496 VisitForEffect(expr->target()); | 1415 VisitForEffect(expr->target()); |
| 1497 return; | 1416 return; |
| 1498 } | 1417 } |
| 1499 | 1418 |
| 1500 // Left-hand side can only be a property, a global or a (parameter or local) | 1419 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1501 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1420 // slot. |
| 1502 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1421 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1503 LhsKind assign_type = VARIABLE; | 1422 LhsKind assign_type = VARIABLE; |
| 1504 Property* property = expr->target()->AsProperty(); | 1423 Property* property = expr->target()->AsProperty(); |
| 1505 if (property != NULL) { | 1424 if (property != NULL) { |
| 1506 assign_type = (property->key()->IsPropertyName()) | 1425 assign_type = (property->key()->IsPropertyName()) |
| 1507 ? NAMED_PROPERTY | 1426 ? NAMED_PROPERTY |
| 1508 : KEYED_PROPERTY; | 1427 : KEYED_PROPERTY; |
| 1509 } | 1428 } |
| 1510 | 1429 |
| 1511 // Evaluate LHS expression. | 1430 // Evaluate LHS expression. |
| 1512 switch (assign_type) { | 1431 switch (assign_type) { |
| 1513 case VARIABLE: | 1432 case VARIABLE: |
| 1514 // Nothing to do here. | 1433 // Nothing to do here. |
| 1515 break; | 1434 break; |
| 1516 case NAMED_PROPERTY: | 1435 case NAMED_PROPERTY: |
| 1517 if (expr->is_compound()) { | 1436 if (expr->is_compound()) { |
| 1518 // We need the receiver both on the stack and in the accumulator. | 1437 // We need the receiver both on the stack and in the accumulator. |
| 1519 VisitForAccumulatorValue(property->obj()); | 1438 VisitForAccumulatorValue(property->obj()); |
| 1520 __ push(result_register()); | 1439 __ push(result_register()); |
| 1521 } else { | 1440 } else { |
| 1522 VisitForStackValue(property->obj()); | 1441 VisitForStackValue(property->obj()); |
| 1523 } | 1442 } |
| 1524 break; | 1443 break; |
| 1525 case KEYED_PROPERTY: { | 1444 case KEYED_PROPERTY: { |
| 1526 if (expr->is_compound()) { | 1445 if (expr->is_compound()) { |
| 1527 if (property->is_arguments_access()) { | 1446 VisitForStackValue(property->obj()); |
| 1528 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1447 VisitForAccumulatorValue(property->key()); |
| 1529 MemOperand slot_operand = | |
| 1530 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); | |
| 1531 __ push(slot_operand); | |
| 1532 __ Move(rax, property->key()->AsLiteral()->handle()); | |
| 1533 } else { | |
| 1534 VisitForStackValue(property->obj()); | |
| 1535 VisitForAccumulatorValue(property->key()); | |
| 1536 } | |
| 1537 __ movq(rdx, Operand(rsp, 0)); | 1448 __ movq(rdx, Operand(rsp, 0)); |
| 1538 __ push(rax); | 1449 __ push(rax); |
| 1539 } else { | 1450 } else { |
| 1540 if (property->is_arguments_access()) { | 1451 VisitForStackValue(property->obj()); |
| 1541 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1452 VisitForStackValue(property->key()); |
| 1542 MemOperand slot_operand = | |
| 1543 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); | |
| 1544 __ push(slot_operand); | |
| 1545 __ Push(property->key()->AsLiteral()->handle()); | |
| 1546 } else { | |
| 1547 VisitForStackValue(property->obj()); | |
| 1548 VisitForStackValue(property->key()); | |
| 1549 } | |
| 1550 } | 1453 } |
| 1551 break; | 1454 break; |
| 1552 } | 1455 } |
| 1553 } | 1456 } |
| 1554 | 1457 |
| 1555 // For compound assignments we need another deoptimization point after the | 1458 // For compound assignments we need another deoptimization point after the |
| 1556 // variable/property load. | 1459 // variable/property load. |
| 1557 if (expr->is_compound()) { | 1460 if (expr->is_compound()) { |
| 1558 { AccumulatorValueContext context(this); | 1461 { AccumulatorValueContext context(this); |
| 1559 switch (assign_type) { | 1462 switch (assign_type) { |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1704 | 1607 |
| 1705 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1608 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1706 // Invalid left-hand sides are rewritten to have a 'throw | 1609 // Invalid left-hand sides are rewritten to have a 'throw |
| 1707 // ReferenceError' on the left-hand side. | 1610 // ReferenceError' on the left-hand side. |
| 1708 if (!expr->IsValidLeftHandSide()) { | 1611 if (!expr->IsValidLeftHandSide()) { |
| 1709 VisitForEffect(expr); | 1612 VisitForEffect(expr); |
| 1710 return; | 1613 return; |
| 1711 } | 1614 } |
| 1712 | 1615 |
| 1713 // Left-hand side can only be a property, a global or a (parameter or local) | 1616 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1714 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1617 // slot. |
| 1715 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1618 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1716 LhsKind assign_type = VARIABLE; | 1619 LhsKind assign_type = VARIABLE; |
| 1717 Property* prop = expr->AsProperty(); | 1620 Property* prop = expr->AsProperty(); |
| 1718 if (prop != NULL) { | 1621 if (prop != NULL) { |
| 1719 assign_type = (prop->key()->IsPropertyName()) | 1622 assign_type = (prop->key()->IsPropertyName()) |
| 1720 ? NAMED_PROPERTY | 1623 ? NAMED_PROPERTY |
| 1721 : KEYED_PROPERTY; | 1624 : KEYED_PROPERTY; |
| 1722 } | 1625 } |
| 1723 | 1626 |
| 1724 switch (assign_type) { | 1627 switch (assign_type) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1735 __ pop(rax); // Restore value. | 1638 __ pop(rax); // Restore value. |
| 1736 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1639 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1737 Handle<Code> ic(Builtins::builtin( | 1640 Handle<Code> ic(Builtins::builtin( |
| 1738 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1641 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1739 : Builtins::StoreIC_Initialize)); | 1642 : Builtins::StoreIC_Initialize)); |
| 1740 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1643 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1741 break; | 1644 break; |
| 1742 } | 1645 } |
| 1743 case KEYED_PROPERTY: { | 1646 case KEYED_PROPERTY: { |
| 1744 __ push(rax); // Preserve value. | 1647 __ push(rax); // Preserve value. |
| 1745 if (prop->is_synthetic()) { | 1648 VisitForStackValue(prop->obj()); |
| 1746 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1649 VisitForAccumulatorValue(prop->key()); |
| 1747 ASSERT(prop->key()->AsLiteral() != NULL); | 1650 __ movq(rcx, rax); |
| 1748 { AccumulatorValueContext for_object(this); | 1651 __ pop(rdx); |
| 1749 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 1750 } | |
| 1751 __ movq(rdx, rax); | |
| 1752 __ Move(rcx, prop->key()->AsLiteral()->handle()); | |
| 1753 } else { | |
| 1754 VisitForStackValue(prop->obj()); | |
| 1755 VisitForAccumulatorValue(prop->key()); | |
| 1756 __ movq(rcx, rax); | |
| 1757 __ pop(rdx); | |
| 1758 } | |
| 1759 __ pop(rax); // Restore value. | 1652 __ pop(rax); // Restore value. |
| 1760 Handle<Code> ic(Builtins::builtin( | 1653 Handle<Code> ic(Builtins::builtin( |
| 1761 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 1654 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1762 : Builtins::KeyedStoreIC_Initialize)); | 1655 : Builtins::KeyedStoreIC_Initialize)); |
| 1763 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1656 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1764 break; | 1657 break; |
| 1765 } | 1658 } |
| 1766 } | 1659 } |
| 1767 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1660 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1768 context()->Plug(rax); | 1661 context()->Plug(rax); |
| 1769 } | 1662 } |
| 1770 | 1663 |
| 1771 | 1664 |
| 1772 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1665 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1773 Token::Value op) { | 1666 Token::Value op) { |
| 1774 // Left-hand sides that rewrite to explicit property accesses do not reach | |
| 1775 // here. | |
| 1776 ASSERT(var != NULL); | 1667 ASSERT(var != NULL); |
| 1777 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1668 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1778 | 1669 |
| 1779 if (var->is_global()) { | 1670 if (var->is_global()) { |
| 1780 ASSERT(!var->is_this()); | 1671 ASSERT(!var->is_this()); |
| 1781 // Assignment to a global variable. Use inline caching for the | 1672 // Assignment to a global variable. Use inline caching for the |
| 1782 // assignment. Right-hand-side value is passed in rax, variable name in | 1673 // assignment. Right-hand-side value is passed in rax, variable name in |
| 1783 // rcx, and the global object on the stack. | 1674 // rcx, and the global object on the stack. |
| 1784 __ Move(rcx, var->name()); | 1675 __ Move(rcx, var->name()); |
| 1785 __ movq(rdx, GlobalObjectOperand()); | 1676 __ movq(rdx, GlobalObjectOperand()); |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2180 Property* prop = fun->AsProperty(); | 2071 Property* prop = fun->AsProperty(); |
| 2181 Literal* key = prop->key()->AsLiteral(); | 2072 Literal* key = prop->key()->AsLiteral(); |
| 2182 if (key != NULL && key->handle()->IsSymbol()) { | 2073 if (key != NULL && key->handle()->IsSymbol()) { |
| 2183 // Call to a named property, use call IC. | 2074 // Call to a named property, use call IC. |
| 2184 { PreservePositionScope scope(masm()->positions_recorder()); | 2075 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2185 VisitForStackValue(prop->obj()); | 2076 VisitForStackValue(prop->obj()); |
| 2186 } | 2077 } |
| 2187 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2078 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2188 } else { | 2079 } else { |
| 2189 // Call to a keyed property. | 2080 // Call to a keyed property. |
| 2190 // For a synthetic property use keyed load IC followed by function call, | 2081 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2191 // for a regular property use keyed EmitCallIC. | 2082 VisitForStackValue(prop->obj()); |
| 2192 if (prop->is_synthetic()) { | |
| 2193 // Do not visit the object and key subexpressions (they are shared | |
| 2194 // by all occurrences of the same rewritten parameter). | |
| 2195 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 2196 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | |
| 2197 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | |
| 2198 MemOperand operand = EmitSlotSearch(slot, rdx); | |
| 2199 __ movq(rdx, operand); | |
| 2200 | |
| 2201 ASSERT(prop->key()->AsLiteral() != NULL); | |
| 2202 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 2203 __ Move(rax, prop->key()->AsLiteral()->handle()); | |
| 2204 | |
| 2205 // Record source code position for IC call. | |
| 2206 SetSourcePosition(prop->position()); | |
| 2207 | |
| 2208 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
| 2209 EmitCallIC(ic, RelocInfo::CODE_TARGET); | |
| 2210 // Push result (function). | |
| 2211 __ push(rax); | |
| 2212 // Push Global receiver. | |
| 2213 __ movq(rcx, GlobalObjectOperand()); | |
| 2214 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); | |
| 2215 EmitCallWithStub(expr); | |
| 2216 } else { | |
| 2217 { PreservePositionScope scope(masm()->positions_recorder()); | |
| 2218 VisitForStackValue(prop->obj()); | |
| 2219 } | |
| 2220 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | |
| 2221 } | 2083 } |
| 2084 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 2222 } | 2085 } |
| 2223 } else { | 2086 } else { |
| 2224 // Call to some other expression. If the expression is an anonymous | 2087 // Call to some other expression. If the expression is an anonymous |
| 2225 // function literal not called in a loop, mark it as one that should | 2088 // function literal not called in a loop, mark it as one that should |
| 2226 // also use the full code generator. | 2089 // also use the full code generator. |
| 2227 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2090 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 2228 if (lit != NULL && | 2091 if (lit != NULL && |
| 2229 lit->name()->Equals(Heap::empty_string()) && | 2092 lit->name()->Equals(Heap::empty_string()) && |
| 2230 loop_depth() == 0) { | 2093 loop_depth() == 0) { |
| 2231 lit->set_try_full_codegen(true); | 2094 lit->set_try_full_codegen(true); |
| (...skipping 1007 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3239 | 3102 |
| 3240 | 3103 |
| 3241 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3104 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 3242 switch (expr->op()) { | 3105 switch (expr->op()) { |
| 3243 case Token::DELETE: { | 3106 case Token::DELETE: { |
| 3244 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3107 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 3245 Property* prop = expr->expression()->AsProperty(); | 3108 Property* prop = expr->expression()->AsProperty(); |
| 3246 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3109 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 3247 | 3110 |
| 3248 if (prop != NULL) { | 3111 if (prop != NULL) { |
| 3249 if (prop->is_synthetic()) { | 3112 VisitForStackValue(prop->obj()); |
| 3250 // Result of deleting parameters is false, even when they rewrite | 3113 VisitForStackValue(prop->key()); |
| 3251 // to accesses on the arguments object. | 3114 __ Push(Smi::FromInt(strict_mode_flag())); |
| 3252 context()->Plug(false); | 3115 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3253 } else { | 3116 context()->Plug(rax); |
| 3254 VisitForStackValue(prop->obj()); | |
| 3255 VisitForStackValue(prop->key()); | |
| 3256 __ Push(Smi::FromInt(strict_mode_flag())); | |
| 3257 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
| 3258 context()->Plug(rax); | |
| 3259 } | |
| 3260 } else if (var != NULL) { | 3117 } else if (var != NULL) { |
| 3261 // Delete of an unqualified identifier is disallowed in strict mode | 3118 // Delete of an unqualified identifier is disallowed in strict mode |
| 3262 // but "delete this" is. | 3119 // but "delete this" is. |
| 3263 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3120 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3264 if (var->is_global()) { | 3121 if (var->is_global()) { |
| 3265 __ push(GlobalObjectOperand()); | 3122 __ push(GlobalObjectOperand()); |
| 3266 __ Push(var->name()); | 3123 __ Push(var->name()); |
| 3267 __ Push(Smi::FromInt(kNonStrictMode)); | 3124 __ Push(Smi::FromInt(kNonStrictMode)); |
| 3268 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3125 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3269 context()->Plug(rax); | 3126 context()->Plug(rax); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3392 SetSourcePosition(expr->position()); | 3249 SetSourcePosition(expr->position()); |
| 3393 | 3250 |
| 3394 // Invalid left-hand-sides are rewritten to have a 'throw | 3251 // Invalid left-hand-sides are rewritten to have a 'throw |
| 3395 // ReferenceError' as the left-hand side. | 3252 // ReferenceError' as the left-hand side. |
| 3396 if (!expr->expression()->IsValidLeftHandSide()) { | 3253 if (!expr->expression()->IsValidLeftHandSide()) { |
| 3397 VisitForEffect(expr->expression()); | 3254 VisitForEffect(expr->expression()); |
| 3398 return; | 3255 return; |
| 3399 } | 3256 } |
| 3400 | 3257 |
| 3401 // Expression can only be a property, a global or a (parameter or local) | 3258 // Expression can only be a property, a global or a (parameter or local) |
| 3402 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 3259 // slot. |
| 3403 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3260 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 3404 LhsKind assign_type = VARIABLE; | 3261 LhsKind assign_type = VARIABLE; |
| 3405 Property* prop = expr->expression()->AsProperty(); | 3262 Property* prop = expr->expression()->AsProperty(); |
| 3406 // In case of a property we use the uninitialized expression context | 3263 // In case of a property we use the uninitialized expression context |
| 3407 // of the key to detect a named property. | 3264 // of the key to detect a named property. |
| 3408 if (prop != NULL) { | 3265 if (prop != NULL) { |
| 3409 assign_type = | 3266 assign_type = |
| 3410 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3267 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3411 } | 3268 } |
| 3412 | 3269 |
| 3413 // Evaluate expression and get value. | 3270 // Evaluate expression and get value. |
| 3414 if (assign_type == VARIABLE) { | 3271 if (assign_type == VARIABLE) { |
| 3415 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3272 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3416 AccumulatorValueContext context(this); | 3273 AccumulatorValueContext context(this); |
| 3417 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3274 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3418 } else { | 3275 } else { |
| 3419 // Reserve space for result of postfix operation. | 3276 // Reserve space for result of postfix operation. |
| 3420 if (expr->is_postfix() && !context()->IsEffect()) { | 3277 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3421 __ Push(Smi::FromInt(0)); | 3278 __ Push(Smi::FromInt(0)); |
| 3422 } | 3279 } |
| 3423 if (assign_type == NAMED_PROPERTY) { | 3280 if (assign_type == NAMED_PROPERTY) { |
| 3424 VisitForAccumulatorValue(prop->obj()); | 3281 VisitForAccumulatorValue(prop->obj()); |
| 3425 __ push(rax); // Copy of receiver, needed for later store. | 3282 __ push(rax); // Copy of receiver, needed for later store. |
| 3426 EmitNamedPropertyLoad(prop); | 3283 EmitNamedPropertyLoad(prop); |
| 3427 } else { | 3284 } else { |
| 3428 if (prop->is_arguments_access()) { | 3285 VisitForStackValue(prop->obj()); |
| 3429 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3286 VisitForAccumulatorValue(prop->key()); |
| 3430 MemOperand slot_operand = | |
| 3431 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); | |
| 3432 __ push(slot_operand); | |
| 3433 __ Move(rax, prop->key()->AsLiteral()->handle()); | |
| 3434 } else { | |
| 3435 VisitForStackValue(prop->obj()); | |
| 3436 VisitForAccumulatorValue(prop->key()); | |
| 3437 } | |
| 3438 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3287 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
| 3439 __ push(rax); // Copy of key, needed for later store. | 3288 __ push(rax); // Copy of key, needed for later store. |
| 3440 EmitKeyedPropertyLoad(prop); | 3289 EmitKeyedPropertyLoad(prop); |
| 3441 } | 3290 } |
| 3442 } | 3291 } |
| 3443 | 3292 |
| 3444 // We need a second deoptimization point after loading the value | 3293 // We need a second deoptimization point after loading the value |
| 3445 // in case evaluating the property load my have a side effect. | 3294 // in case evaluating the property load my have a side effect. |
| 3446 if (assign_type == VARIABLE) { | 3295 if (assign_type == VARIABLE) { |
| 3447 PrepareForBailout(expr->expression(), TOS_REG); | 3296 PrepareForBailout(expr->expression(), TOS_REG); |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3963 __ ret(0); | 3812 __ ret(0); |
| 3964 } | 3813 } |
| 3965 | 3814 |
| 3966 | 3815 |
| 3967 #undef __ | 3816 #undef __ |
| 3968 | 3817 |
| 3969 | 3818 |
| 3970 } } // namespace v8::internal | 3819 } } // namespace v8::internal |
| 3971 | 3820 |
| 3972 #endif // V8_TARGET_ARCH_X64 | 3821 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |