| OLD | NEW |
| 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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 __ push(source); | 220 __ push(source); |
| 221 TestAndBranch(source, &discard, false_label_); | 221 TestAndBranch(source, &discard, false_label_); |
| 222 __ bind(&discard); | 222 __ bind(&discard); |
| 223 __ add(Operand(esp), Immediate(kPointerSize)); | 223 __ add(Operand(esp), Immediate(kPointerSize)); |
| 224 __ jmp(true_label_); | 224 __ jmp(true_label_); |
| 225 } | 225 } |
| 226 } | 226 } |
| 227 } | 227 } |
| 228 | 228 |
| 229 | 229 |
| 230 void FastCodeGenerator::MoveTOS(Expression::Context context) { |
| 231 switch (context) { |
| 232 case Expression::kUninitialized: |
| 233 UNREACHABLE(); |
| 234 case Expression::kEffect: |
| 235 __ Drop(1); |
| 236 break; |
| 237 case Expression::kValue: |
| 238 break; |
| 239 case Expression::kTest: |
| 240 __ pop(eax); |
| 241 TestAndBranch(eax, true_label_, false_label_); |
| 242 break; |
| 243 case Expression::kValueTest: { |
| 244 Label discard; |
| 245 __ mov(eax, Operand(esp, 0)); |
| 246 TestAndBranch(eax, true_label_, &discard); |
| 247 __ bind(&discard); |
| 248 __ Drop(1); |
| 249 __ jmp(false_label_); |
| 250 break; |
| 251 } |
| 252 case Expression::kTestValue: { |
| 253 Label discard; |
| 254 __ mov(eax, Operand(esp, 0)); |
| 255 TestAndBranch(eax, &discard, false_label_); |
| 256 __ bind(&discard); |
| 257 __ Drop(1); |
| 258 __ jmp(true_label_); |
| 259 } |
| 260 } |
| 261 } |
| 262 |
| 263 |
| 230 template <> | 264 template <> |
| 231 Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, | 265 Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, |
| 232 Register scratch) { | 266 Register scratch) { |
| 233 switch (source->type()) { | 267 switch (source->type()) { |
| 234 case Slot::PARAMETER: | 268 case Slot::PARAMETER: |
| 235 case Slot::LOCAL: | 269 case Slot::LOCAL: |
| 236 return Operand(ebp, SlotOffset(source)); | 270 return Operand(ebp, SlotOffset(source)); |
| 237 case Slot::CONTEXT: { | 271 case Slot::CONTEXT: { |
| 238 int context_chain_length = | 272 int context_chain_length = |
| 239 function_->scope()->ContextChainLength(source->var()->scope()); | 273 function_->scope()->ContextChainLength(source->var()->scope()); |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 __ add(Operand(esp), Immediate(kPointerSize)); | 855 __ add(Operand(esp), Immediate(kPointerSize)); |
| 822 __ jmp(true_label_); | 856 __ jmp(true_label_); |
| 823 break; | 857 break; |
| 824 } | 858 } |
| 825 } | 859 } |
| 826 } | 860 } |
| 827 | 861 |
| 828 | 862 |
| 829 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, | 863 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, |
| 830 Expression::Context context) { | 864 Expression::Context context) { |
| 865 SetSourcePosition(prop->position()); |
| 831 Literal* key = prop->key()->AsLiteral(); | 866 Literal* key = prop->key()->AsLiteral(); |
| 832 __ mov(ecx, Immediate(key->handle())); | 867 __ mov(ecx, Immediate(key->handle())); |
| 833 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 868 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 834 __ call(ic, RelocInfo::CODE_TARGET); | 869 __ call(ic, RelocInfo::CODE_TARGET); |
| 835 Move(context, eax); | 870 Move(context, eax); |
| 836 } | 871 } |
| 837 | 872 |
| 838 | 873 |
| 839 void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { | 874 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop, |
| 875 Expression::Context context) { |
| 876 SetSourcePosition(prop->position()); |
| 840 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 877 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 841 __ call(ic, RelocInfo::CODE_TARGET); | 878 __ call(ic, RelocInfo::CODE_TARGET); |
| 842 Move(context, eax); | 879 Move(context, eax); |
| 843 } | 880 } |
| 844 | 881 |
| 845 | 882 |
| 846 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, | 883 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, |
| 847 Expression::Context context) { | 884 Expression::Context context) { |
| 848 GenericBinaryOpStub stub(op, | 885 GenericBinaryOpStub stub(op, |
| 849 NO_OVERWRITE, | 886 NO_OVERWRITE, |
| 850 NO_GENERIC_BINARY_FLAGS); | 887 NO_GENERIC_BINARY_FLAGS); |
| 851 __ CallStub(&stub); | 888 __ CallStub(&stub); |
| 852 Move(context, eax); | 889 Move(context, eax); |
| 853 } | 890 } |
| 854 | 891 |
| 855 | 892 |
| 856 void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { | 893 void FastCodeGenerator::EmitVariableAssignment(Variable* var, |
| 857 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 894 Expression::Context context) { |
| 858 ASSERT(var != NULL); | 895 ASSERT(var != NULL); |
| 859 ASSERT(var->is_global() || var->slot() != NULL); | 896 ASSERT(var->is_global() || var->slot() != NULL); |
| 860 if (var->is_global()) { | 897 if (var->is_global()) { |
| 861 // Assignment to a global variable. Use inline caching for the | 898 // Assignment to a global variable. Use inline caching for the |
| 862 // assignment. Right-hand-side value is passed in eax, variable name in | 899 // assignment. Right-hand-side value is passed in eax, variable name in |
| 863 // ecx, and the global object on the stack. | 900 // ecx, and the global object on the stack. |
| 864 __ pop(eax); | 901 __ pop(eax); |
| 865 __ mov(ecx, var->name()); | 902 __ mov(ecx, var->name()); |
| 866 __ push(CodeGenerator::GlobalObject()); | 903 __ push(CodeGenerator::GlobalObject()); |
| 867 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 904 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 868 __ call(ic, RelocInfo::CODE_TARGET); | 905 __ call(ic, RelocInfo::CODE_TARGET); |
| 869 // Overwrite the receiver on the stack with the result if needed. | 906 // Overwrite the receiver on the stack with the result if needed. |
| 870 DropAndMove(expr->context(), eax); | 907 DropAndMove(context, eax); |
| 871 | 908 |
| 872 } else if (var->slot() != NULL) { | 909 } else if (var->slot() != NULL) { |
| 873 Slot* slot = var->slot(); | 910 Slot* slot = var->slot(); |
| 874 switch (slot->type()) { | 911 switch (slot->type()) { |
| 875 case Slot::LOCAL: | 912 case Slot::LOCAL: |
| 876 case Slot::PARAMETER: { | 913 case Slot::PARAMETER: { |
| 877 Operand target = Operand(ebp, SlotOffset(var->slot())); | 914 Operand target = Operand(ebp, SlotOffset(var->slot())); |
| 878 switch (expr->context()) { | 915 switch (context) { |
| 879 case Expression::kUninitialized: | 916 case Expression::kUninitialized: |
| 880 UNREACHABLE(); | 917 UNREACHABLE(); |
| 881 case Expression::kEffect: | 918 case Expression::kEffect: |
| 882 // Perform assignment and discard value. | 919 // Perform assignment and discard value. |
| 883 __ pop(target); | 920 __ pop(target); |
| 884 break; | 921 break; |
| 885 case Expression::kValue: | 922 case Expression::kValue: |
| 886 // Perform assignment and preserve value. | 923 // Perform assignment and preserve value. |
| 887 __ mov(eax, Operand(esp, 0)); | 924 __ mov(eax, Operand(esp, 0)); |
| 888 __ mov(target, eax); | 925 __ mov(target, eax); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 } | 973 } |
| 937 if (FLAG_debug_code) { | 974 if (FLAG_debug_code) { |
| 938 __ cmp(eax, | 975 __ cmp(eax, |
| 939 Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 976 Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX))); |
| 940 __ Check(equal, "Context Slot chain length wrong."); | 977 __ Check(equal, "Context Slot chain length wrong."); |
| 941 } | 978 } |
| 942 __ pop(ecx); | 979 __ pop(ecx); |
| 943 __ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx); | 980 __ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx); |
| 944 | 981 |
| 945 // RecordWrite may destroy all its register arguments. | 982 // RecordWrite may destroy all its register arguments. |
| 946 if (expr->context() == Expression::kValue) { | 983 if (context == Expression::kValue) { |
| 947 __ push(ecx); | 984 __ push(ecx); |
| 948 } else if (expr->context() != Expression::kEffect) { | 985 } else if (context != Expression::kEffect) { |
| 949 __ mov(edx, ecx); | 986 __ mov(edx, ecx); |
| 950 } | 987 } |
| 951 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 988 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 952 __ RecordWrite(eax, offset, ecx, ebx); | 989 __ RecordWrite(eax, offset, ecx, ebx); |
| 953 if (expr->context() != Expression::kEffect && | 990 if (context != Expression::kEffect && |
| 954 expr->context() != Expression::kValue) { | 991 context != Expression::kValue) { |
| 955 Move(expr->context(), edx); | 992 Move(context, edx); |
| 956 } | 993 } |
| 957 break; | 994 break; |
| 958 } | 995 } |
| 959 | 996 |
| 960 case Slot::LOOKUP: | 997 case Slot::LOOKUP: |
| 961 UNREACHABLE(); | 998 UNREACHABLE(); |
| 962 break; | 999 break; |
| 963 } | 1000 } |
| 964 } | 1001 } |
| 965 } | 1002 } |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1370 } | 1407 } |
| 1371 | 1408 |
| 1372 default: | 1409 default: |
| 1373 UNREACHABLE(); | 1410 UNREACHABLE(); |
| 1374 } | 1411 } |
| 1375 } | 1412 } |
| 1376 | 1413 |
| 1377 | 1414 |
| 1378 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { | 1415 void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { |
| 1379 Comment cmnt(masm_, "[ CountOperation"); | 1416 Comment cmnt(masm_, "[ CountOperation"); |
| 1380 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | |
| 1381 ASSERT(proxy->AsVariable() != NULL); | |
| 1382 ASSERT(proxy->AsVariable()->is_global()); | |
| 1383 | 1417 |
| 1384 Visit(proxy); | 1418 // Expression can only be a property, a global or a (parameter or local) |
| 1419 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1420 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1421 LhsKind assign_type = VARIABLE; |
| 1422 Property* prop = expr->expression()->AsProperty(); |
| 1423 // In case of a property we use the uninitialized expression context |
| 1424 // of the key to detect a named property. |
| 1425 if (prop != NULL) { |
| 1426 assign_type = (prop->key()->context() == Expression::kUninitialized) |
| 1427 ? NAMED_PROPERTY |
| 1428 : KEYED_PROPERTY; |
| 1429 } |
| 1430 |
| 1431 // Evaluate expression and get value. |
| 1432 if (assign_type == VARIABLE) { |
| 1433 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 1434 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
| 1435 Expression::kValue); |
| 1436 } else { |
| 1437 // Reserve space for result of postfix operation. |
| 1438 if (expr->is_postfix() && expr->context() != Expression::kEffect) { |
| 1439 ASSERT(expr->context() != Expression::kUninitialized); |
| 1440 __ push(Immediate(Smi::FromInt(0))); |
| 1441 } |
| 1442 Visit(prop->obj()); |
| 1443 ASSERT_EQ(Expression::kValue, prop->obj()->context()); |
| 1444 if (assign_type == NAMED_PROPERTY) { |
| 1445 EmitNamedPropertyLoad(prop, Expression::kValue); |
| 1446 } else { |
| 1447 Visit(prop->key()); |
| 1448 ASSERT_EQ(Expression::kValue, prop->key()->context()); |
| 1449 EmitKeyedPropertyLoad(prop, Expression::kValue); |
| 1450 } |
| 1451 } |
| 1452 |
| 1453 // Convert to number. |
| 1385 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 1454 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 1386 | 1455 |
| 1387 switch (expr->context()) { | 1456 // Save result for postfix expressions. |
| 1388 case Expression::kUninitialized: | 1457 if (expr->is_postfix()) { |
| 1389 UNREACHABLE(); | 1458 switch (expr->context()) { |
| 1390 case Expression::kValue: // Fall through | 1459 case Expression::kUninitialized: |
| 1391 case Expression::kTest: // Fall through | 1460 UNREACHABLE(); |
| 1392 case Expression::kTestValue: // Fall through | 1461 case Expression::kEffect: |
| 1393 case Expression::kValueTest: | 1462 // Do not save result. |
| 1394 // Duplicate the result on the stack. | 1463 break; |
| 1395 __ push(eax); | 1464 case Expression::kValue: // Fall through |
| 1396 break; | 1465 case Expression::kTest: // Fall through |
| 1397 case Expression::kEffect: | 1466 case Expression::kTestValue: // Fall through |
| 1398 // Do not save result. | 1467 case Expression::kValueTest: |
| 1399 break; | 1468 // Save the result on the stack. If we have a named or keyed property |
| 1469 // we store the result under the receiver that is currently on top |
| 1470 // of the stack. |
| 1471 switch (assign_type) { |
| 1472 case VARIABLE: |
| 1473 __ push(eax); |
| 1474 break; |
| 1475 case NAMED_PROPERTY: |
| 1476 __ mov(Operand(esp, kPointerSize), eax); |
| 1477 break; |
| 1478 case KEYED_PROPERTY: |
| 1479 __ mov(Operand(esp, 2 * kPointerSize), eax); |
| 1480 break; |
| 1481 } |
| 1482 break; |
| 1483 } |
| 1400 } | 1484 } |
| 1485 |
| 1401 // Call runtime for +1/-1. | 1486 // Call runtime for +1/-1. |
| 1402 __ push(eax); | 1487 __ push(eax); |
| 1403 __ push(Immediate(Smi::FromInt(1))); | 1488 __ push(Immediate(Smi::FromInt(1))); |
| 1404 if (expr->op() == Token::INC) { | 1489 if (expr->op() == Token::INC) { |
| 1405 __ CallRuntime(Runtime::kNumberAdd, 2); | 1490 __ CallRuntime(Runtime::kNumberAdd, 2); |
| 1406 } else { | 1491 } else { |
| 1407 __ CallRuntime(Runtime::kNumberSub, 2); | 1492 __ CallRuntime(Runtime::kNumberSub, 2); |
| 1408 } | 1493 } |
| 1409 // Call Store IC. | |
| 1410 __ mov(ecx, proxy->AsVariable()->name()); | |
| 1411 __ push(CodeGenerator::GlobalObject()); | |
| 1412 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
| 1413 __ call(ic, RelocInfo::CODE_TARGET); | |
| 1414 // Restore up stack after store IC. | |
| 1415 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 1416 | 1494 |
| 1417 switch (expr->context()) { | 1495 // Store the value returned in eax. |
| 1418 case Expression::kUninitialized: | 1496 switch (assign_type) { |
| 1419 UNREACHABLE(); | 1497 case VARIABLE: |
| 1420 case Expression::kEffect: // Fall through | 1498 __ push(eax); |
| 1421 case Expression::kValue: | 1499 if (expr->is_postfix()) { |
| 1422 // Do nothing. Result in either on the stack for value context | 1500 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1423 // or discarded for effect context. | 1501 Expression::kEffect); |
| 1502 // For all contexts except kEffect: We have the result on |
| 1503 // top of the stack. |
| 1504 if (expr->context() != Expression::kEffect) { |
| 1505 MoveTOS(expr->context()); |
| 1506 } |
| 1507 } else { |
| 1508 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1509 expr->context()); |
| 1510 } |
| 1424 break; | 1511 break; |
| 1425 case Expression::kTest: | 1512 case NAMED_PROPERTY: { |
| 1426 __ pop(eax); | 1513 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1427 TestAndBranch(eax, true_label_, false_label_); | 1514 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1428 break; | 1515 __ call(ic, RelocInfo::CODE_TARGET); |
| 1429 case Expression::kValueTest: { | 1516 // This nop signals to the IC that there is no inlined code at the call |
| 1430 Label discard; | 1517 // site for it to patch. |
| 1431 __ mov(eax, Operand(esp, 0)); | 1518 __ nop(); |
| 1432 TestAndBranch(eax, true_label_, &discard); | 1519 if (expr->is_postfix()) { |
| 1433 __ bind(&discard); | 1520 __ Drop(1); // Result is on the stack under the receiver. |
| 1434 __ add(Operand(esp), Immediate(kPointerSize)); | 1521 if (expr->context() != Expression::kEffect) { |
| 1435 __ jmp(false_label_); | 1522 MoveTOS(expr->context()); |
| 1523 } |
| 1524 } else { |
| 1525 DropAndMove(expr->context(), eax); |
| 1526 } |
| 1436 break; | 1527 break; |
| 1437 } | 1528 } |
| 1438 case Expression::kTestValue: { | 1529 case KEYED_PROPERTY: { |
| 1439 Label discard; | 1530 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 1440 __ mov(eax, Operand(esp, 0)); | 1531 __ call(ic, RelocInfo::CODE_TARGET); |
| 1441 TestAndBranch(eax, &discard, false_label_); | 1532 // This nop signals to the IC that there is no inlined code at the call |
| 1442 __ bind(&discard); | 1533 // site for it to patch. |
| 1443 __ add(Operand(esp), Immediate(kPointerSize)); | 1534 __ nop(); |
| 1444 __ jmp(true_label_); | 1535 if (expr->is_postfix()) { |
| 1536 __ Drop(2); // Result is on the stack under the key and the receiver. |
| 1537 if (expr->context() != Expression::kEffect) { |
| 1538 MoveTOS(expr->context()); |
| 1539 } |
| 1540 } else { |
| 1541 DropAndMove(expr->context(), eax, 2); |
| 1542 } |
| 1445 break; | 1543 break; |
| 1446 } | 1544 } |
| 1447 } | 1545 } |
| 1448 } | 1546 } |
| 1449 | 1547 |
| 1450 | 1548 |
| 1451 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 1549 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 1452 Comment cmnt(masm_, "[ BinaryOperation"); | 1550 Comment cmnt(masm_, "[ BinaryOperation"); |
| 1453 switch (expr->op()) { | 1551 switch (expr->op()) { |
| 1454 case Token::COMMA: | 1552 case Token::COMMA: |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1702 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 1800 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
| 1703 __ mov(Operand(esp, 0), edx); | 1801 __ mov(Operand(esp, 0), edx); |
| 1704 // And return. | 1802 // And return. |
| 1705 __ ret(0); | 1803 __ ret(0); |
| 1706 } | 1804 } |
| 1707 | 1805 |
| 1708 | 1806 |
| 1709 #undef __ | 1807 #undef __ |
| 1710 | 1808 |
| 1711 } } // namespace v8::internal | 1809 } } // namespace v8::internal |
| OLD | NEW |