Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(525)

Side by Side Diff: src/x64/fast-codegen-x64.cc

Issue 496009: Added pre- and postfix count operations to top-level compiler.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/fast-codegen-ia32.cc ('k') | test/mjsunit/compiler/countoperation.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 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 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 TestAndBranch(source, &discard, false_label_); 229 TestAndBranch(source, &discard, false_label_);
230 __ bind(&discard); 230 __ bind(&discard);
231 __ addq(rsp, Immediate(kPointerSize)); 231 __ addq(rsp, Immediate(kPointerSize));
232 __ jmp(true_label_); 232 __ jmp(true_label_);
233 break; 233 break;
234 } 234 }
235 } 235 }
236 } 236 }
237 237
238 238
239 void FastCodeGenerator::MoveTOS(Expression::Context context) {
240 switch (context) {
241 case Expression::kUninitialized:
242 UNREACHABLE();
243 case Expression::kEffect:
244 __ Drop(1);
245 break;
246 case Expression::kValue:
247 break;
248 case Expression::kTest:
249 __ pop(rax);
250 TestAndBranch(rax, true_label_, false_label_);
251 break;
252 case Expression::kValueTest: {
253 Label discard;
254 __ movq(rax, Operand(rsp, 0));
255 TestAndBranch(rax, true_label_, &discard);
256 __ bind(&discard);
257 __ Drop(1);
258 __ jmp(false_label_);
259 break;
260 }
261 case Expression::kTestValue: {
262 Label discard;
263 __ movq(rax, Operand(rsp, 0));
264 TestAndBranch(rax, &discard, false_label_);
265 __ bind(&discard);
266 __ Drop(1);
267 __ jmp(true_label_);
268 }
269 }
270 }
271
272
239 template <> 273 template <>
240 Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, 274 Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
241 Register scratch) { 275 Register scratch) {
242 switch (source->type()) { 276 switch (source->type()) {
243 case Slot::PARAMETER: 277 case Slot::PARAMETER:
244 case Slot::LOCAL: 278 case Slot::LOCAL:
245 return Operand(rbp, SlotOffset(source)); 279 return Operand(rbp, SlotOffset(source));
246 case Slot::CONTEXT: { 280 case Slot::CONTEXT: {
247 int context_chain_length = 281 int context_chain_length =
248 function_->scope()->ContextChainLength(source->var()->scope()); 282 function_->scope()->ContextChainLength(source->var()->scope());
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after
830 __ addq(rsp, Immediate(kPointerSize)); 864 __ addq(rsp, Immediate(kPointerSize));
831 __ jmp(true_label_); 865 __ jmp(true_label_);
832 break; 866 break;
833 } 867 }
834 } 868 }
835 } 869 }
836 870
837 871
838 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, 872 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
839 Expression::Context context) { 873 Expression::Context context) {
874 SetSourcePosition(prop->position());
840 Literal* key = prop->key()->AsLiteral(); 875 Literal* key = prop->key()->AsLiteral();
841 __ Move(rcx, key->handle()); 876 __ Move(rcx, key->handle());
842 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 877 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
843 __ Call(ic, RelocInfo::CODE_TARGET); 878 __ Call(ic, RelocInfo::CODE_TARGET);
844 Move(context, rax); 879 Move(context, rax);
845 } 880 }
846 881
847 882
848 void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { 883 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
884 Expression::Context context) {
885 SetSourcePosition(prop->position());
849 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 886 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
850 __ Call(ic, RelocInfo::CODE_TARGET); 887 __ Call(ic, RelocInfo::CODE_TARGET);
851 Move(context, rax); 888 Move(context, rax);
852 } 889 }
853 890
854 891
855 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, 892 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
856 Expression::Context context) { 893 Expression::Context context) {
857 GenericBinaryOpStub stub(op, 894 GenericBinaryOpStub stub(op,
858 NO_OVERWRITE, 895 NO_OVERWRITE,
859 NO_GENERIC_BINARY_FLAGS); 896 NO_GENERIC_BINARY_FLAGS);
860 __ CallStub(&stub); 897 __ CallStub(&stub);
861 Move(context, rax); 898 Move(context, rax);
862 } 899 }
863 900
864 901
865 void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { 902 void FastCodeGenerator::EmitVariableAssignment(Variable* var,
866 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); 903 Expression::Context context) {
867 ASSERT(var != NULL); 904 ASSERT(var != NULL);
868 ASSERT(var->is_global() || var->slot() != NULL); 905 ASSERT(var->is_global() || var->slot() != NULL);
869 if (var->is_global()) { 906 if (var->is_global()) {
870 // Assignment to a global variable. Use inline caching for the 907 // Assignment to a global variable. Use inline caching for the
871 // assignment. Right-hand-side value is passed in rax, variable name in 908 // assignment. Right-hand-side value is passed in rax, variable name in
872 // rcx, and the global object on the stack. 909 // rcx, and the global object on the stack.
873 __ pop(rax); 910 __ pop(rax);
874 __ Move(rcx, var->name()); 911 __ Move(rcx, var->name());
875 __ push(CodeGenerator::GlobalObject()); 912 __ push(CodeGenerator::GlobalObject());
876 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 913 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
877 __ Call(ic, RelocInfo::CODE_TARGET); 914 __ Call(ic, RelocInfo::CODE_TARGET);
878 // Overwrite the global object on the stack with the result if needed. 915 // Overwrite the global object on the stack with the result if needed.
879 DropAndMove(expr->context(), rax); 916 DropAndMove(context, rax);
880 917
881 } else if (var->slot()) { 918 } else if (var->slot()) {
882 Slot* slot = var->slot(); 919 Slot* slot = var->slot();
883 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. 920 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
884 switch (slot->type()) { 921 switch (slot->type()) {
885 case Slot::LOCAL: 922 case Slot::LOCAL:
886 case Slot::PARAMETER: { 923 case Slot::PARAMETER: {
887 switch (expr->context()) { 924 switch (context) {
888 case Expression::kUninitialized: 925 case Expression::kUninitialized:
889 UNREACHABLE(); 926 UNREACHABLE();
890 case Expression::kEffect: 927 case Expression::kEffect:
891 // Perform assignment and discard value. 928 // Perform assignment and discard value.
892 __ pop(Operand(rbp, SlotOffset(var->slot()))); 929 __ pop(Operand(rbp, SlotOffset(var->slot())));
893 break; 930 break;
894 case Expression::kValue: 931 case Expression::kValue:
895 // Perform assignment and preserve value. 932 // Perform assignment and preserve value.
896 __ movq(rax, Operand(rsp, 0)); 933 __ movq(rax, Operand(rsp, 0));
897 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); 934 __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 } 982 }
946 if (FLAG_debug_code) { 983 if (FLAG_debug_code) {
947 __ cmpq(rax, 984 __ cmpq(rax,
948 Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX))); 985 Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
949 __ Check(equal, "Context Slot chain length wrong."); 986 __ Check(equal, "Context Slot chain length wrong.");
950 } 987 }
951 __ pop(rcx); 988 __ pop(rcx);
952 __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx); 989 __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx);
953 990
954 // RecordWrite may destroy all its register arguments. 991 // RecordWrite may destroy all its register arguments.
955 if (expr->context() == Expression::kValue) { 992 if (context == Expression::kValue) {
956 __ push(rcx); 993 __ push(rcx);
957 } else if (expr->context() != Expression::kEffect) { 994 } else if (context != Expression::kEffect) {
958 __ movq(rdx, rcx); 995 __ movq(rdx, rcx);
959 } 996 }
960 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 997 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
961 __ RecordWrite(rax, offset, rcx, rbx); 998 __ RecordWrite(rax, offset, rcx, rbx);
962 if (expr->context() != Expression::kEffect && 999 if (context != Expression::kEffect &&
963 expr->context() != Expression::kValue) { 1000 context != Expression::kValue) {
964 Move(expr->context(), rdx); 1001 Move(context, rdx);
965 } 1002 }
966 break; 1003 break;
967 } 1004 }
968 1005
969 case Slot::LOOKUP: 1006 case Slot::LOOKUP:
970 UNREACHABLE(); 1007 UNREACHABLE();
971 break; 1008 break;
972 } 1009 }
973 } 1010 }
974 } 1011 }
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
1256 // Restore context register. 1293 // Restore context register.
1257 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1294 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1258 // Discard the function left on TOS. 1295 // Discard the function left on TOS.
1259 DropAndMove(expr->context(), rax); 1296 DropAndMove(expr->context(), rax);
1260 } else { 1297 } else {
1261 __ CallRuntime(expr->function(), arg_count); 1298 __ CallRuntime(expr->function(), arg_count);
1262 Move(expr->context(), rax); 1299 Move(expr->context(), rax);
1263 } 1300 }
1264 } 1301 }
1265 1302
1266 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
1267 Comment cmnt(masm_, "[ CountOperation");
1268 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1269 ASSERT(proxy->AsVariable() != NULL);
1270 ASSERT(proxy->AsVariable()->is_global());
1271
1272 Visit(proxy);
1273 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
1274
1275 switch (expr->context()) {
1276 case Expression::kUninitialized:
1277 UNREACHABLE();
1278 case Expression::kValue: // Fall through
1279 case Expression::kTest: // Fall through
1280 case Expression::kTestValue: // Fall through
1281 case Expression::kValueTest:
1282 // Duplicate the result on the stack.
1283 __ push(rax);
1284 break;
1285 case Expression::kEffect:
1286 // Do not save result.
1287 break;
1288 }
1289 // Call runtime for +1/-1.
1290 __ push(rax);
1291 __ Push(Smi::FromInt(1));
1292 if (expr->op() == Token::INC) {
1293 __ CallRuntime(Runtime::kNumberAdd, 2);
1294 } else {
1295 __ CallRuntime(Runtime::kNumberSub, 2);
1296 }
1297 // Call Store IC.
1298 __ Move(rcx, proxy->AsVariable()->name());
1299 __ push(CodeGenerator::GlobalObject());
1300 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1301 __ call(ic, RelocInfo::CODE_TARGET);
1302 // Restore up stack after store IC
1303 __ addq(rsp, Immediate(kPointerSize));
1304
1305 switch (expr->context()) {
1306 case Expression::kUninitialized:
1307 UNREACHABLE();
1308 case Expression::kEffect: // Fall through
1309 case Expression::kValue:
1310 // Do nothing. Result in either on the stack for value context
1311 // or discarded for effect context.
1312 break;
1313 case Expression::kTest:
1314 __ pop(rax);
1315 TestAndBranch(rax, true_label_, false_label_);
1316 break;
1317 case Expression::kValueTest: {
1318 Label discard;
1319 __ movq(rax, Operand(rsp, 0));
1320 TestAndBranch(rax, true_label_, &discard);
1321 __ bind(&discard);
1322 __ addq(rsp, Immediate(kPointerSize));
1323 __ jmp(false_label_);
1324 break;
1325 }
1326 case Expression::kTestValue: {
1327 Label discard;
1328 __ movq(rax, Operand(rsp, 0));
1329 TestAndBranch(rax, &discard, false_label_);
1330 __ bind(&discard);
1331 __ addq(rsp, Immediate(kPointerSize));
1332 __ jmp(true_label_);
1333 break;
1334 }
1335 }
1336 }
1337
1338 1303
1339 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 1304 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1340 switch (expr->op()) { 1305 switch (expr->op()) {
1341 case Token::VOID: { 1306 case Token::VOID: {
1342 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 1307 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1343 Visit(expr->expression()); 1308 Visit(expr->expression());
1344 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); 1309 ASSERT_EQ(Expression::kEffect, expr->expression()->context());
1345 switch (expr->context()) { 1310 switch (expr->context()) {
1346 case Expression::kUninitialized: 1311 case Expression::kUninitialized:
1347 UNREACHABLE(); 1312 UNREACHABLE();
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
1457 Move(expr->context(), rax); 1422 Move(expr->context(), rax);
1458 break; 1423 break;
1459 } 1424 }
1460 1425
1461 default: 1426 default:
1462 UNREACHABLE(); 1427 UNREACHABLE();
1463 } 1428 }
1464 } 1429 }
1465 1430
1466 1431
1432 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
1433 Comment cmnt(masm_, "[ CountOperation");
1434
1435 // Expression can only be a property, a global or a (parameter or local)
1436 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1437 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1438 LhsKind assign_type = VARIABLE;
1439 Property* prop = expr->expression()->AsProperty();
1440 // In case of a property we use the uninitialized expression context
1441 // of the key to detect a named property.
1442 if (prop != NULL) {
1443 assign_type = (prop->key()->context() == Expression::kUninitialized)
1444 ? NAMED_PROPERTY
1445 : KEYED_PROPERTY;
1446 }
1447
1448 // Evaluate expression and get value.
1449 if (assign_type == VARIABLE) {
1450 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1451 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1452 Expression::kValue);
1453 } else {
1454 // Reserve space for result of postfix operation.
1455 if (expr->is_postfix() && expr->context() != Expression::kEffect) {
1456 ASSERT(expr->context() != Expression::kUninitialized);
1457 __ Push(Smi::FromInt(0));
1458 }
1459 Visit(prop->obj());
1460 ASSERT_EQ(Expression::kValue, prop->obj()->context());
1461 if (assign_type == NAMED_PROPERTY) {
1462 EmitNamedPropertyLoad(prop, Expression::kValue);
1463 } else {
1464 Visit(prop->key());
1465 ASSERT_EQ(Expression::kValue, prop->key()->context());
1466 EmitKeyedPropertyLoad(prop, Expression::kValue);
1467 }
1468 }
1469
1470 // Convert to number.
1471 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
1472
1473 // Save result for postfix expressions.
1474 if (expr->is_postfix()) {
1475 switch (expr->context()) {
1476 case Expression::kUninitialized:
1477 UNREACHABLE();
1478 case Expression::kEffect:
1479 // Do not save result.
1480 break;
1481 case Expression::kValue: // Fall through
1482 case Expression::kTest: // Fall through
1483 case Expression::kTestValue: // Fall through
1484 case Expression::kValueTest:
1485 // Save the result on the stack. If we have a named or keyed property
1486 // we store the result under the receiver that is currently on top
1487 // of the stack.
1488 switch (assign_type) {
1489 case VARIABLE:
1490 __ push(rax);
1491 break;
1492 case NAMED_PROPERTY:
1493 __ movq(Operand(rsp, kPointerSize), rax);
1494 break;
1495 case KEYED_PROPERTY:
1496 __ movq(Operand(rsp, 2 * kPointerSize), rax);
1497 break;
1498 }
1499 break;
1500 }
1501 }
1502
1503 // Call runtime for +1/-1.
1504 __ push(rax);
1505 __ Push(Smi::FromInt(1));
1506 if (expr->op() == Token::INC) {
1507 __ CallRuntime(Runtime::kNumberAdd, 2);
1508 } else {
1509 __ CallRuntime(Runtime::kNumberSub, 2);
1510 }
1511
1512 // Store the value returned in rax.
1513 switch (assign_type) {
1514 case VARIABLE:
1515 __ push(rax);
1516 if (expr->is_postfix()) {
1517 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1518 Expression::kEffect);
1519 // For all contexts except kEffect: We have the result on
1520 // top of the stack.
1521 if (expr->context() != Expression::kEffect) {
1522 MoveTOS(expr->context());
1523 }
1524 } else {
1525 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1526 expr->context());
1527 }
1528 break;
1529 case NAMED_PROPERTY: {
1530 __ Move(rcx, prop->key()->AsLiteral()->handle());
1531 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1532 __ call(ic, RelocInfo::CODE_TARGET);
1533 // This nop signals to the IC that there is no inlined code at the call
1534 // site for it to patch.
1535 __ nop();
1536 if (expr->is_postfix()) {
1537 __ Drop(1); // Result is on the stack under the receiver.
1538 if (expr->context() != Expression::kEffect) {
1539 MoveTOS(expr->context());
1540 }
1541 } else {
1542 DropAndMove(expr->context(), rax);
1543 }
1544 break;
1545 }
1546 case KEYED_PROPERTY: {
1547 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1548 __ call(ic, RelocInfo::CODE_TARGET);
1549 // This nop signals to the IC that there is no inlined code at the call
1550 // site for it to patch.
1551 __ nop();
1552 if (expr->is_postfix()) {
1553 __ Drop(2); // Result is on the stack under the key and the receiver.
1554 if (expr->context() != Expression::kEffect) {
1555 MoveTOS(expr->context());
1556 }
1557 } else {
1558 DropAndMove(expr->context(), rax, 2);
1559 }
1560 break;
1561 }
1562 }
1563 }
1564
1467 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { 1565 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
1468 Comment cmnt(masm_, "[ BinaryOperation"); 1566 Comment cmnt(masm_, "[ BinaryOperation");
1469 switch (expr->op()) { 1567 switch (expr->op()) {
1470 case Token::COMMA: 1568 case Token::COMMA:
1471 ASSERT_EQ(Expression::kEffect, expr->left()->context()); 1569 ASSERT_EQ(Expression::kEffect, expr->left()->context());
1472 ASSERT_EQ(expr->context(), expr->right()->context()); 1570 ASSERT_EQ(expr->context(), expr->right()->context());
1473 Visit(expr->left()); 1571 Visit(expr->left());
1474 Visit(expr->right()); 1572 Visit(expr->right());
1475 break; 1573 break;
1476 1574
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
1719 __ movq(Operand(rsp, 0), rdx); 1817 __ movq(Operand(rsp, 0), rdx);
1720 // And return. 1818 // And return.
1721 __ ret(0); 1819 __ ret(0);
1722 } 1820 }
1723 1821
1724 1822
1725 #undef __ 1823 #undef __
1726 1824
1727 1825
1728 } } // namespace v8::internal 1826 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ia32/fast-codegen-ia32.cc ('k') | test/mjsunit/compiler/countoperation.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698