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 |