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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 } | 67 } |
68 } | 68 } |
69 } | 69 } |
70 | 70 |
71 | 71 |
72 // ------------------------------------------------------------------------- | 72 // ------------------------------------------------------------------------- |
73 // CodeGenState implementation. | 73 // CodeGenState implementation. |
74 | 74 |
75 CodeGenState::CodeGenState(CodeGenerator* owner) | 75 CodeGenState::CodeGenState(CodeGenerator* owner) |
76 : owner_(owner), | 76 : owner_(owner), |
77 typeof_state_(NOT_INSIDE_TYPEOF), | |
78 destination_(NULL), | 77 destination_(NULL), |
79 previous_(NULL) { | 78 previous_(NULL) { |
80 owner_->set_state(this); | 79 owner_->set_state(this); |
81 } | 80 } |
82 | 81 |
83 | 82 |
84 CodeGenState::CodeGenState(CodeGenerator* owner, | 83 CodeGenState::CodeGenState(CodeGenerator* owner, |
85 TypeofState typeof_state, | |
86 ControlDestination* destination) | 84 ControlDestination* destination) |
87 : owner_(owner), | 85 : owner_(owner), |
88 typeof_state_(typeof_state), | |
89 destination_(destination), | 86 destination_(destination), |
90 previous_(owner->state()) { | 87 previous_(owner->state()) { |
91 owner_->set_state(this); | 88 owner_->set_state(this); |
92 } | 89 } |
93 | 90 |
94 | 91 |
95 CodeGenState::~CodeGenState() { | 92 CodeGenState::~CodeGenState() { |
96 ASSERT(owner_->state() == this); | 93 ASSERT(owner_->state() == this); |
97 owner_->set_state(previous_); | 94 owner_->set_state(previous_); |
98 } | 95 } |
(...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 VariableProxy* arguments, | 645 VariableProxy* arguments, |
649 int position) { | 646 int position) { |
650 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 647 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); |
651 ASSERT(arguments->IsArguments()); | 648 ASSERT(arguments->IsArguments()); |
652 | 649 |
653 JumpTarget slow, done; | 650 JumpTarget slow, done; |
654 | 651 |
655 // Load the apply function onto the stack. This will usually | 652 // Load the apply function onto the stack. This will usually |
656 // give us a megamorphic load site. Not super, but it works. | 653 // give us a megamorphic load site. Not super, but it works. |
657 Reference ref(this, apply); | 654 Reference ref(this, apply); |
658 ref.GetValue(NOT_INSIDE_TYPEOF); | 655 ref.GetValue(); |
659 ASSERT(ref.type() == Reference::NAMED); | 656 ASSERT(ref.type() == Reference::NAMED); |
660 | 657 |
661 // Load the receiver and the existing arguments object onto the | 658 // Load the receiver and the existing arguments object onto the |
662 // expression stack. Avoid allocating the arguments object here. | 659 // expression stack. Avoid allocating the arguments object here. |
663 Load(receiver); | 660 Load(receiver); |
664 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 661 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
665 | 662 |
666 // Emit the source position information after having loaded the | 663 // Emit the source position information after having loaded the |
667 // receiver and the arguments. | 664 // receiver and the arguments. |
668 CodeForSourcePosition(position); | 665 CodeForSourcePosition(position); |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
973 // are present or not. | 970 // are present or not. |
974 bool has_then_stm = node->HasThenStatement(); | 971 bool has_then_stm = node->HasThenStatement(); |
975 bool has_else_stm = node->HasElseStatement(); | 972 bool has_else_stm = node->HasElseStatement(); |
976 | 973 |
977 CodeForStatementPosition(node); | 974 CodeForStatementPosition(node); |
978 JumpTarget exit; | 975 JumpTarget exit; |
979 if (has_then_stm && has_else_stm) { | 976 if (has_then_stm && has_else_stm) { |
980 JumpTarget then; | 977 JumpTarget then; |
981 JumpTarget else_; | 978 JumpTarget else_; |
982 ControlDestination dest(&then, &else_, true); | 979 ControlDestination dest(&then, &else_, true); |
983 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 980 LoadCondition(node->condition(), &dest, true); |
984 | 981 |
985 if (dest.false_was_fall_through()) { | 982 if (dest.false_was_fall_through()) { |
986 // The else target was bound, so we compile the else part first. | 983 // The else target was bound, so we compile the else part first. |
987 Visit(node->else_statement()); | 984 Visit(node->else_statement()); |
988 | 985 |
989 // We may have dangling jumps to the then part. | 986 // We may have dangling jumps to the then part. |
990 if (then.is_linked()) { | 987 if (then.is_linked()) { |
991 if (has_valid_frame()) exit.Jump(); | 988 if (has_valid_frame()) exit.Jump(); |
992 then.Bind(); | 989 then.Bind(); |
993 Visit(node->then_statement()); | 990 Visit(node->then_statement()); |
994 } | 991 } |
995 } else { | 992 } else { |
996 // The then target was bound, so we compile the then part first. | 993 // The then target was bound, so we compile the then part first. |
997 Visit(node->then_statement()); | 994 Visit(node->then_statement()); |
998 | 995 |
999 if (else_.is_linked()) { | 996 if (else_.is_linked()) { |
1000 if (has_valid_frame()) exit.Jump(); | 997 if (has_valid_frame()) exit.Jump(); |
1001 else_.Bind(); | 998 else_.Bind(); |
1002 Visit(node->else_statement()); | 999 Visit(node->else_statement()); |
1003 } | 1000 } |
1004 } | 1001 } |
1005 | 1002 |
1006 } else if (has_then_stm) { | 1003 } else if (has_then_stm) { |
1007 ASSERT(!has_else_stm); | 1004 ASSERT(!has_else_stm); |
1008 JumpTarget then; | 1005 JumpTarget then; |
1009 ControlDestination dest(&then, &exit, true); | 1006 ControlDestination dest(&then, &exit, true); |
1010 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 1007 LoadCondition(node->condition(), &dest, true); |
1011 | 1008 |
1012 if (dest.false_was_fall_through()) { | 1009 if (dest.false_was_fall_through()) { |
1013 // The exit label was bound. We may have dangling jumps to the | 1010 // The exit label was bound. We may have dangling jumps to the |
1014 // then part. | 1011 // then part. |
1015 if (then.is_linked()) { | 1012 if (then.is_linked()) { |
1016 exit.Unuse(); | 1013 exit.Unuse(); |
1017 exit.Jump(); | 1014 exit.Jump(); |
1018 then.Bind(); | 1015 then.Bind(); |
1019 Visit(node->then_statement()); | 1016 Visit(node->then_statement()); |
1020 } | 1017 } |
1021 } else { | 1018 } else { |
1022 // The then label was bound. | 1019 // The then label was bound. |
1023 Visit(node->then_statement()); | 1020 Visit(node->then_statement()); |
1024 } | 1021 } |
1025 | 1022 |
1026 } else if (has_else_stm) { | 1023 } else if (has_else_stm) { |
1027 ASSERT(!has_then_stm); | 1024 ASSERT(!has_then_stm); |
1028 JumpTarget else_; | 1025 JumpTarget else_; |
1029 ControlDestination dest(&exit, &else_, false); | 1026 ControlDestination dest(&exit, &else_, false); |
1030 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 1027 LoadCondition(node->condition(), &dest, true); |
1031 | 1028 |
1032 if (dest.true_was_fall_through()) { | 1029 if (dest.true_was_fall_through()) { |
1033 // The exit label was bound. We may have dangling jumps to the | 1030 // The exit label was bound. We may have dangling jumps to the |
1034 // else part. | 1031 // else part. |
1035 if (else_.is_linked()) { | 1032 if (else_.is_linked()) { |
1036 exit.Unuse(); | 1033 exit.Unuse(); |
1037 exit.Jump(); | 1034 exit.Jump(); |
1038 else_.Bind(); | 1035 else_.Bind(); |
1039 Visit(node->else_statement()); | 1036 Visit(node->else_statement()); |
1040 } | 1037 } |
1041 } else { | 1038 } else { |
1042 // The else label was bound. | 1039 // The else label was bound. |
1043 Visit(node->else_statement()); | 1040 Visit(node->else_statement()); |
1044 } | 1041 } |
1045 | 1042 |
1046 } else { | 1043 } else { |
1047 ASSERT(!has_then_stm && !has_else_stm); | 1044 ASSERT(!has_then_stm && !has_else_stm); |
1048 // We only care about the condition's side effects (not its value | 1045 // We only care about the condition's side effects (not its value |
1049 // or control flow effect). LoadCondition is called without | 1046 // or control flow effect). LoadCondition is called without |
1050 // forcing control flow. | 1047 // forcing control flow. |
1051 ControlDestination dest(&exit, &exit, true); | 1048 ControlDestination dest(&exit, &exit, true); |
1052 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, false); | 1049 LoadCondition(node->condition(), &dest, false); |
1053 if (!dest.is_used()) { | 1050 if (!dest.is_used()) { |
1054 // We got a value on the frame rather than (or in addition to) | 1051 // We got a value on the frame rather than (or in addition to) |
1055 // control flow. | 1052 // control flow. |
1056 frame_->Drop(); | 1053 frame_->Drop(); |
1057 } | 1054 } |
1058 } | 1055 } |
1059 | 1056 |
1060 if (exit.is_linked()) { | 1057 if (exit.is_linked()) { |
1061 exit.Bind(); | 1058 exit.Bind(); |
1062 } | 1059 } |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1314 } | 1311 } |
1315 break; | 1312 break; |
1316 case DONT_KNOW: | 1313 case DONT_KNOW: |
1317 // We have to compile the test expression if it can be reached by | 1314 // We have to compile the test expression if it can be reached by |
1318 // control flow falling out of the body or via continue. | 1315 // control flow falling out of the body or via continue. |
1319 if (node->continue_target()->is_linked()) { | 1316 if (node->continue_target()->is_linked()) { |
1320 node->continue_target()->Bind(); | 1317 node->continue_target()->Bind(); |
1321 } | 1318 } |
1322 if (has_valid_frame()) { | 1319 if (has_valid_frame()) { |
1323 ControlDestination dest(&body, node->break_target(), false); | 1320 ControlDestination dest(&body, node->break_target(), false); |
1324 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 1321 LoadCondition(node->cond(), &dest, true); |
1325 } | 1322 } |
1326 if (node->break_target()->is_linked()) { | 1323 if (node->break_target()->is_linked()) { |
1327 node->break_target()->Bind(); | 1324 node->break_target()->Bind(); |
1328 } | 1325 } |
1329 break; | 1326 break; |
1330 } | 1327 } |
1331 | 1328 |
1332 DecrementLoopNesting(); | 1329 DecrementLoopNesting(); |
1333 node->continue_target()->Unuse(); | 1330 node->continue_target()->Unuse(); |
1334 node->break_target()->Unuse(); | 1331 node->break_target()->Unuse(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1371 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1368 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1372 } else { | 1369 } else { |
1373 // Label the test at the top as the continue target. The body | 1370 // Label the test at the top as the continue target. The body |
1374 // is a forward-only target. | 1371 // is a forward-only target. |
1375 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); | 1372 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
1376 node->continue_target()->Bind(); | 1373 node->continue_target()->Bind(); |
1377 } | 1374 } |
1378 // Compile the test with the body as the true target and preferred | 1375 // Compile the test with the body as the true target and preferred |
1379 // fall-through and with the break target as the false target. | 1376 // fall-through and with the break target as the false target. |
1380 ControlDestination dest(&body, node->break_target(), true); | 1377 ControlDestination dest(&body, node->break_target(), true); |
1381 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 1378 LoadCondition(node->cond(), &dest, true); |
1382 | 1379 |
1383 if (dest.false_was_fall_through()) { | 1380 if (dest.false_was_fall_through()) { |
1384 // If we got the break target as fall-through, the test may have | 1381 // If we got the break target as fall-through, the test may have |
1385 // been unconditionally false (if there are no jumps to the | 1382 // been unconditionally false (if there are no jumps to the |
1386 // body). | 1383 // body). |
1387 if (!body.is_linked()) { | 1384 if (!body.is_linked()) { |
1388 DecrementLoopNesting(); | 1385 DecrementLoopNesting(); |
1389 return; | 1386 return; |
1390 } | 1387 } |
1391 | 1388 |
(...skipping 26 matching lines...) Expand all Loading... |
1418 if (test_at_bottom) { | 1415 if (test_at_bottom) { |
1419 // If we have chosen to recompile the test at the bottom, | 1416 // If we have chosen to recompile the test at the bottom, |
1420 // then it is the continue target. | 1417 // then it is the continue target. |
1421 if (node->continue_target()->is_linked()) { | 1418 if (node->continue_target()->is_linked()) { |
1422 node->continue_target()->Bind(); | 1419 node->continue_target()->Bind(); |
1423 } | 1420 } |
1424 if (has_valid_frame()) { | 1421 if (has_valid_frame()) { |
1425 // The break target is the fall-through (body is a backward | 1422 // The break target is the fall-through (body is a backward |
1426 // jump from here and thus an invalid fall-through). | 1423 // jump from here and thus an invalid fall-through). |
1427 ControlDestination dest(&body, node->break_target(), false); | 1424 ControlDestination dest(&body, node->break_target(), false); |
1428 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 1425 LoadCondition(node->cond(), &dest, true); |
1429 } | 1426 } |
1430 } else { | 1427 } else { |
1431 // If we have chosen not to recompile the test at the | 1428 // If we have chosen not to recompile the test at the |
1432 // bottom, jump back to the one at the top. | 1429 // bottom, jump back to the one at the top. |
1433 if (has_valid_frame()) { | 1430 if (has_valid_frame()) { |
1434 node->continue_target()->Jump(); | 1431 node->continue_target()->Jump(); |
1435 } | 1432 } |
1436 } | 1433 } |
1437 break; | 1434 break; |
1438 case ALWAYS_FALSE: | 1435 case ALWAYS_FALSE: |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1510 } else { | 1507 } else { |
1511 // We are not recompiling the test at the bottom and there is an | 1508 // We are not recompiling the test at the bottom and there is an |
1512 // update expression. | 1509 // update expression. |
1513 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1510 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1514 loop.Bind(); | 1511 loop.Bind(); |
1515 } | 1512 } |
1516 | 1513 |
1517 // Compile the test with the body as the true target and preferred | 1514 // Compile the test with the body as the true target and preferred |
1518 // fall-through and with the break target as the false target. | 1515 // fall-through and with the break target as the false target. |
1519 ControlDestination dest(&body, node->break_target(), true); | 1516 ControlDestination dest(&body, node->break_target(), true); |
1520 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 1517 LoadCondition(node->cond(), &dest, true); |
1521 | 1518 |
1522 if (dest.false_was_fall_through()) { | 1519 if (dest.false_was_fall_through()) { |
1523 // If we got the break target as fall-through, the test may have | 1520 // If we got the break target as fall-through, the test may have |
1524 // been unconditionally false (if there are no jumps to the | 1521 // been unconditionally false (if there are no jumps to the |
1525 // body). | 1522 // body). |
1526 if (!body.is_linked()) { | 1523 if (!body.is_linked()) { |
1527 DecrementLoopNesting(); | 1524 DecrementLoopNesting(); |
1528 return; | 1525 return; |
1529 } | 1526 } |
1530 | 1527 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 // was no update expression. | 1577 // was no update expression. |
1581 node->continue_target()->Bind(); | 1578 node->continue_target()->Bind(); |
1582 } | 1579 } |
1583 // Control can reach the test at the bottom by falling out of | 1580 // Control can reach the test at the bottom by falling out of |
1584 // the body, by a continue in the body, or from the update | 1581 // the body, by a continue in the body, or from the update |
1585 // expression. | 1582 // expression. |
1586 if (has_valid_frame()) { | 1583 if (has_valid_frame()) { |
1587 // The break target is the fall-through (body is a backward | 1584 // The break target is the fall-through (body is a backward |
1588 // jump from here). | 1585 // jump from here). |
1589 ControlDestination dest(&body, node->break_target(), false); | 1586 ControlDestination dest(&body, node->break_target(), false); |
1590 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 1587 LoadCondition(node->cond(), &dest, true); |
1591 } | 1588 } |
1592 } else { | 1589 } else { |
1593 // Otherwise, jump back to the test at the top. | 1590 // Otherwise, jump back to the test at the top. |
1594 if (has_valid_frame()) { | 1591 if (has_valid_frame()) { |
1595 if (node->next() == NULL) { | 1592 if (node->next() == NULL) { |
1596 node->continue_target()->Jump(); | 1593 node->continue_target()->Jump(); |
1597 } else { | 1594 } else { |
1598 loop.Jump(); | 1595 loop.Jump(); |
1599 } | 1596 } |
1600 } | 1597 } |
(...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2180 InstantiateBoilerplate(node->boilerplate()); | 2177 InstantiateBoilerplate(node->boilerplate()); |
2181 } | 2178 } |
2182 | 2179 |
2183 | 2180 |
2184 void CodeGenerator::VisitConditional(Conditional* node) { | 2181 void CodeGenerator::VisitConditional(Conditional* node) { |
2185 Comment cmnt(masm_, "[ Conditional"); | 2182 Comment cmnt(masm_, "[ Conditional"); |
2186 JumpTarget then; | 2183 JumpTarget then; |
2187 JumpTarget else_; | 2184 JumpTarget else_; |
2188 JumpTarget exit; | 2185 JumpTarget exit; |
2189 ControlDestination dest(&then, &else_, true); | 2186 ControlDestination dest(&then, &else_, true); |
2190 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 2187 LoadCondition(node->condition(), &dest, true); |
2191 | 2188 |
2192 if (dest.false_was_fall_through()) { | 2189 if (dest.false_was_fall_through()) { |
2193 // The else target was bound, so we compile the else part first. | 2190 // The else target was bound, so we compile the else part first. |
2194 Load(node->else_expression(), typeof_state()); | 2191 Load(node->else_expression()); |
2195 | 2192 |
2196 if (then.is_linked()) { | 2193 if (then.is_linked()) { |
2197 exit.Jump(); | 2194 exit.Jump(); |
2198 then.Bind(); | 2195 then.Bind(); |
2199 Load(node->then_expression(), typeof_state()); | 2196 Load(node->then_expression()); |
2200 } | 2197 } |
2201 } else { | 2198 } else { |
2202 // The then target was bound, so we compile the then part first. | 2199 // The then target was bound, so we compile the then part first. |
2203 Load(node->then_expression(), typeof_state()); | 2200 Load(node->then_expression()); |
2204 | 2201 |
2205 if (else_.is_linked()) { | 2202 if (else_.is_linked()) { |
2206 exit.Jump(); | 2203 exit.Jump(); |
2207 else_.Bind(); | 2204 else_.Bind(); |
2208 Load(node->else_expression(), typeof_state()); | 2205 Load(node->else_expression()); |
2209 } | 2206 } |
2210 } | 2207 } |
2211 | 2208 |
2212 exit.Bind(); | 2209 exit.Bind(); |
2213 } | 2210 } |
2214 | 2211 |
2215 | 2212 |
2216 void CodeGenerator::VisitSlot(Slot* node) { | 2213 void CodeGenerator::VisitSlot(Slot* node) { |
2217 Comment cmnt(masm_, "[ Slot"); | 2214 Comment cmnt(masm_, "[ Slot"); |
2218 LoadFromSlotCheckForArguments(node, typeof_state()); | 2215 LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); |
2219 } | 2216 } |
2220 | 2217 |
2221 | 2218 |
2222 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2219 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
2223 Comment cmnt(masm_, "[ VariableProxy"); | 2220 Comment cmnt(masm_, "[ VariableProxy"); |
2224 Variable* var = node->var(); | 2221 Variable* var = node->var(); |
2225 Expression* expr = var->rewrite(); | 2222 Expression* expr = var->rewrite(); |
2226 if (expr != NULL) { | 2223 if (expr != NULL) { |
2227 Visit(expr); | 2224 Visit(expr); |
2228 } else { | 2225 } else { |
2229 ASSERT(var->is_global()); | 2226 ASSERT(var->is_global()); |
2230 Reference ref(this, node); | 2227 Reference ref(this, node); |
2231 ref.GetValue(typeof_state()); | 2228 ref.GetValue(); |
2232 } | 2229 } |
2233 } | 2230 } |
2234 | 2231 |
2235 | 2232 |
2236 void CodeGenerator::VisitLiteral(Literal* node) { | 2233 void CodeGenerator::VisitLiteral(Literal* node) { |
2237 Comment cmnt(masm_, "[ Literal"); | 2234 Comment cmnt(masm_, "[ Literal"); |
2238 frame_->Push(node->handle()); | 2235 frame_->Push(node->handle()); |
2239 } | 2236 } |
2240 | 2237 |
2241 | 2238 |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2612 bool overwrite_value = | 2609 bool overwrite_value = |
2613 (node->value()->AsBinaryOperation() != NULL && | 2610 (node->value()->AsBinaryOperation() != NULL && |
2614 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 2611 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
2615 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); | 2612 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); |
2616 // There are two cases where the target is not read in the right hand | 2613 // There are two cases where the target is not read in the right hand |
2617 // side, that are easy to test for: the right hand side is a literal, | 2614 // side, that are easy to test for: the right hand side is a literal, |
2618 // or the right hand side is a different variable. TakeValue invalidates | 2615 // or the right hand side is a different variable. TakeValue invalidates |
2619 // the target, with an implicit promise that it will be written to again | 2616 // the target, with an implicit promise that it will be written to again |
2620 // before it is read. | 2617 // before it is read. |
2621 if (literal != NULL || (right_var != NULL && right_var != var)) { | 2618 if (literal != NULL || (right_var != NULL && right_var != var)) { |
2622 target.TakeValue(NOT_INSIDE_TYPEOF); | 2619 target.TakeValue(); |
2623 } else { | 2620 } else { |
2624 target.GetValue(NOT_INSIDE_TYPEOF); | 2621 target.GetValue(); |
2625 } | 2622 } |
2626 Load(node->value()); | 2623 Load(node->value()); |
2627 GenericBinaryOperation(node->binary_op(), | 2624 GenericBinaryOperation(node->binary_op(), |
2628 node->type(), | 2625 node->type(), |
2629 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 2626 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
2630 } | 2627 } |
2631 | 2628 |
2632 if (var != NULL && | 2629 if (var != NULL && |
2633 var->mode() == Variable::CONST && | 2630 var->mode() == Variable::CONST && |
2634 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 2631 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
(...skipping 27 matching lines...) Expand all Loading... |
2662 Comment cmnt(masm_, "[ Throw"); | 2659 Comment cmnt(masm_, "[ Throw"); |
2663 Load(node->exception()); | 2660 Load(node->exception()); |
2664 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 2661 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
2665 frame_->Push(&result); | 2662 frame_->Push(&result); |
2666 } | 2663 } |
2667 | 2664 |
2668 | 2665 |
2669 void CodeGenerator::VisitProperty(Property* node) { | 2666 void CodeGenerator::VisitProperty(Property* node) { |
2670 Comment cmnt(masm_, "[ Property"); | 2667 Comment cmnt(masm_, "[ Property"); |
2671 Reference property(this, node); | 2668 Reference property(this, node); |
2672 property.GetValue(typeof_state()); | 2669 property.GetValue(); |
2673 } | 2670 } |
2674 | 2671 |
2675 | 2672 |
2676 void CodeGenerator::VisitCall(Call* node) { | 2673 void CodeGenerator::VisitCall(Call* node) { |
2677 Comment cmnt(masm_, "[ Call"); | 2674 Comment cmnt(masm_, "[ Call"); |
2678 | 2675 |
2679 ZoneList<Expression*>* args = node->arguments(); | 2676 ZoneList<Expression*>* args = node->arguments(); |
2680 | 2677 |
2681 // Check if the function is a variable or a property. | 2678 // Check if the function is a variable or a property. |
2682 Expression* function = node->expression(); | 2679 Expression* function = node->expression(); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2848 frame_->SetElementAt(0, &result); | 2845 frame_->SetElementAt(0, &result); |
2849 } | 2846 } |
2850 | 2847 |
2851 } else { | 2848 } else { |
2852 // ------------------------------------------- | 2849 // ------------------------------------------- |
2853 // JavaScript example: 'array[index](1, 2, 3)' | 2850 // JavaScript example: 'array[index](1, 2, 3)' |
2854 // ------------------------------------------- | 2851 // ------------------------------------------- |
2855 | 2852 |
2856 // Load the function to call from the property through a reference. | 2853 // Load the function to call from the property through a reference. |
2857 Reference ref(this, property); | 2854 Reference ref(this, property); |
2858 ref.GetValue(NOT_INSIDE_TYPEOF); | 2855 ref.GetValue(); |
2859 | 2856 |
2860 // Pass receiver to called function. | 2857 // Pass receiver to called function. |
2861 if (property->is_synthetic()) { | 2858 if (property->is_synthetic()) { |
2862 // Use global object as receiver. | 2859 // Use global object as receiver. |
2863 LoadGlobalReceiver(); | 2860 LoadGlobalReceiver(); |
2864 } else { | 2861 } else { |
2865 // The reference's size is non-negative. | 2862 // The reference's size is non-negative. |
2866 frame_->PushElementAt(ref.size()); | 2863 frame_->PushElementAt(ref.size()); |
2867 } | 2864 } |
2868 | 2865 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2954 frame_->SetElementAt(0, &answer); | 2951 frame_->SetElementAt(0, &answer); |
2955 } else { | 2952 } else { |
2956 // Call the C runtime function. | 2953 // Call the C runtime function. |
2957 Result answer = frame_->CallRuntime(function, arg_count); | 2954 Result answer = frame_->CallRuntime(function, arg_count); |
2958 frame_->Push(&answer); | 2955 frame_->Push(&answer); |
2959 } | 2956 } |
2960 } | 2957 } |
2961 | 2958 |
2962 | 2959 |
2963 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2960 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
2964 // Note that because of NOT and an optimization in comparison of a typeof | |
2965 // expression to a literal string, this function can fail to leave a value | |
2966 // on top of the frame or in the cc register. | |
2967 Comment cmnt(masm_, "[ UnaryOperation"); | 2961 Comment cmnt(masm_, "[ UnaryOperation"); |
2968 | 2962 |
2969 Token::Value op = node->op(); | 2963 Token::Value op = node->op(); |
2970 | 2964 |
2971 if (op == Token::NOT) { | 2965 if (op == Token::NOT) { |
2972 // Swap the true and false targets but keep the same actual label | 2966 // Swap the true and false targets but keep the same actual label |
2973 // as the fall through. | 2967 // as the fall through. |
2974 destination()->Invert(); | 2968 destination()->Invert(); |
2975 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, destination(), true); | 2969 LoadCondition(node->expression(), destination(), true); |
2976 // Swap the labels back. | 2970 // Swap the labels back. |
2977 destination()->Invert(); | 2971 destination()->Invert(); |
2978 | 2972 |
2979 } else if (op == Token::DELETE) { | 2973 } else if (op == Token::DELETE) { |
2980 Property* property = node->expression()->AsProperty(); | 2974 Property* property = node->expression()->AsProperty(); |
2981 if (property != NULL) { | 2975 if (property != NULL) { |
2982 Load(property->obj()); | 2976 Load(property->obj()); |
2983 Load(property->key()); | 2977 Load(property->key()); |
2984 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 2978 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
2985 frame_->Push(&answer); | 2979 frame_->Push(&answer); |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3205 // value will be in the frame to be spilled. | 3199 // value will be in the frame to be spilled. |
3206 if (is_postfix) frame_->Push(Smi::FromInt(0)); | 3200 if (is_postfix) frame_->Push(Smi::FromInt(0)); |
3207 | 3201 |
3208 { Reference target(this, node->expression()); | 3202 { Reference target(this, node->expression()); |
3209 if (target.is_illegal()) { | 3203 if (target.is_illegal()) { |
3210 // Spoof the virtual frame to have the expected height (one higher | 3204 // Spoof the virtual frame to have the expected height (one higher |
3211 // than on entry). | 3205 // than on entry). |
3212 if (!is_postfix) frame_->Push(Smi::FromInt(0)); | 3206 if (!is_postfix) frame_->Push(Smi::FromInt(0)); |
3213 return; | 3207 return; |
3214 } | 3208 } |
3215 target.TakeValue(NOT_INSIDE_TYPEOF); | 3209 target.TakeValue(); |
3216 | 3210 |
3217 Result new_value = frame_->Pop(); | 3211 Result new_value = frame_->Pop(); |
3218 new_value.ToRegister(); | 3212 new_value.ToRegister(); |
3219 | 3213 |
3220 Result old_value; // Only allocated in the postfix case. | 3214 Result old_value; // Only allocated in the postfix case. |
3221 if (is_postfix) { | 3215 if (is_postfix) { |
3222 // Allocate a temporary to preserve the old value. | 3216 // Allocate a temporary to preserve the old value. |
3223 old_value = allocator_->Allocate(); | 3217 old_value = allocator_->Allocate(); |
3224 ASSERT(old_value.is_valid()); | 3218 ASSERT(old_value.is_valid()); |
3225 __ movq(old_value.reg(), new_value.reg()); | 3219 __ movq(old_value.reg(), new_value.reg()); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3263 | 3257 |
3264 // Postfix: drop the new value and use the old. | 3258 // Postfix: drop the new value and use the old. |
3265 if (is_postfix) frame_->Drop(); | 3259 if (is_postfix) frame_->Drop(); |
3266 } | 3260 } |
3267 | 3261 |
3268 | 3262 |
3269 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3263 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
3270 // TODO(X64): This code was copied verbatim from codegen-ia32. | 3264 // TODO(X64): This code was copied verbatim from codegen-ia32. |
3271 // Either find a reason to change it or move it to a shared location. | 3265 // Either find a reason to change it or move it to a shared location. |
3272 | 3266 |
3273 // Note that due to an optimization in comparison operations (typeof | |
3274 // compared to a string literal), we can evaluate a binary expression such | |
3275 // as AND or OR and not leave a value on the frame or in the cc register. | |
3276 Comment cmnt(masm_, "[ BinaryOperation"); | 3267 Comment cmnt(masm_, "[ BinaryOperation"); |
3277 Token::Value op = node->op(); | 3268 Token::Value op = node->op(); |
3278 | 3269 |
3279 // According to ECMA-262 section 11.11, page 58, the binary logical | 3270 // According to ECMA-262 section 11.11, page 58, the binary logical |
3280 // operators must yield the result of one of the two expressions | 3271 // operators must yield the result of one of the two expressions |
3281 // before any ToBoolean() conversions. This means that the value | 3272 // before any ToBoolean() conversions. This means that the value |
3282 // produced by a && or || operator is not necessarily a boolean. | 3273 // produced by a && or || operator is not necessarily a boolean. |
3283 | 3274 |
3284 // NOTE: If the left hand side produces a materialized value (not | 3275 // NOTE: If the left hand side produces a materialized value (not |
3285 // control flow), we force the right hand side to do the same. This | 3276 // control flow), we force the right hand side to do the same. This |
3286 // is necessary because we assume that if we get control flow on the | 3277 // is necessary because we assume that if we get control flow on the |
3287 // last path out of an expression we got it on all paths. | 3278 // last path out of an expression we got it on all paths. |
3288 if (op == Token::AND) { | 3279 if (op == Token::AND) { |
3289 JumpTarget is_true; | 3280 JumpTarget is_true; |
3290 ControlDestination dest(&is_true, destination()->false_target(), true); | 3281 ControlDestination dest(&is_true, destination()->false_target(), true); |
3291 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); | 3282 LoadCondition(node->left(), &dest, false); |
3292 | 3283 |
3293 if (dest.false_was_fall_through()) { | 3284 if (dest.false_was_fall_through()) { |
3294 // The current false target was used as the fall-through. If | 3285 // The current false target was used as the fall-through. If |
3295 // there are no dangling jumps to is_true then the left | 3286 // there are no dangling jumps to is_true then the left |
3296 // subexpression was unconditionally false. Otherwise we have | 3287 // subexpression was unconditionally false. Otherwise we have |
3297 // paths where we do have to evaluate the right subexpression. | 3288 // paths where we do have to evaluate the right subexpression. |
3298 if (is_true.is_linked()) { | 3289 if (is_true.is_linked()) { |
3299 // We need to compile the right subexpression. If the jump to | 3290 // We need to compile the right subexpression. If the jump to |
3300 // the current false target was a forward jump then we have a | 3291 // the current false target was a forward jump then we have a |
3301 // valid frame, we have just bound the false target, and we | 3292 // valid frame, we have just bound the false target, and we |
3302 // have to jump around the code for the right subexpression. | 3293 // have to jump around the code for the right subexpression. |
3303 if (has_valid_frame()) { | 3294 if (has_valid_frame()) { |
3304 destination()->false_target()->Unuse(); | 3295 destination()->false_target()->Unuse(); |
3305 destination()->false_target()->Jump(); | 3296 destination()->false_target()->Jump(); |
3306 } | 3297 } |
3307 is_true.Bind(); | 3298 is_true.Bind(); |
3308 // The left subexpression compiled to control flow, so the | 3299 // The left subexpression compiled to control flow, so the |
3309 // right one is free to do so as well. | 3300 // right one is free to do so as well. |
3310 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 3301 LoadCondition(node->right(), destination(), false); |
3311 } else { | 3302 } else { |
3312 // We have actually just jumped to or bound the current false | 3303 // We have actually just jumped to or bound the current false |
3313 // target but the current control destination is not marked as | 3304 // target but the current control destination is not marked as |
3314 // used. | 3305 // used. |
3315 destination()->Use(false); | 3306 destination()->Use(false); |
3316 } | 3307 } |
3317 | 3308 |
3318 } else if (dest.is_used()) { | 3309 } else if (dest.is_used()) { |
3319 // The left subexpression compiled to control flow (and is_true | 3310 // The left subexpression compiled to control flow (and is_true |
3320 // was just bound), so the right is free to do so as well. | 3311 // was just bound), so the right is free to do so as well. |
3321 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 3312 LoadCondition(node->right(), destination(), false); |
3322 | 3313 |
3323 } else { | 3314 } else { |
3324 // We have a materialized value on the frame, so we exit with | 3315 // We have a materialized value on the frame, so we exit with |
3325 // one on all paths. There are possibly also jumps to is_true | 3316 // one on all paths. There are possibly also jumps to is_true |
3326 // from nested subexpressions. | 3317 // from nested subexpressions. |
3327 JumpTarget pop_and_continue; | 3318 JumpTarget pop_and_continue; |
3328 JumpTarget exit; | 3319 JumpTarget exit; |
3329 | 3320 |
3330 // Avoid popping the result if it converts to 'false' using the | 3321 // Avoid popping the result if it converts to 'false' using the |
3331 // standard ToBoolean() conversion as described in ECMA-262, | 3322 // standard ToBoolean() conversion as described in ECMA-262, |
(...skipping 12 matching lines...) Expand all Loading... |
3344 is_true.Bind(); | 3335 is_true.Bind(); |
3345 Load(node->right()); | 3336 Load(node->right()); |
3346 | 3337 |
3347 // Exit (always with a materialized value). | 3338 // Exit (always with a materialized value). |
3348 exit.Bind(); | 3339 exit.Bind(); |
3349 } | 3340 } |
3350 | 3341 |
3351 } else if (op == Token::OR) { | 3342 } else if (op == Token::OR) { |
3352 JumpTarget is_false; | 3343 JumpTarget is_false; |
3353 ControlDestination dest(destination()->true_target(), &is_false, false); | 3344 ControlDestination dest(destination()->true_target(), &is_false, false); |
3354 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); | 3345 LoadCondition(node->left(), &dest, false); |
3355 | 3346 |
3356 if (dest.true_was_fall_through()) { | 3347 if (dest.true_was_fall_through()) { |
3357 // The current true target was used as the fall-through. If | 3348 // The current true target was used as the fall-through. If |
3358 // there are no dangling jumps to is_false then the left | 3349 // there are no dangling jumps to is_false then the left |
3359 // subexpression was unconditionally true. Otherwise we have | 3350 // subexpression was unconditionally true. Otherwise we have |
3360 // paths where we do have to evaluate the right subexpression. | 3351 // paths where we do have to evaluate the right subexpression. |
3361 if (is_false.is_linked()) { | 3352 if (is_false.is_linked()) { |
3362 // We need to compile the right subexpression. If the jump to | 3353 // We need to compile the right subexpression. If the jump to |
3363 // the current true target was a forward jump then we have a | 3354 // the current true target was a forward jump then we have a |
3364 // valid frame, we have just bound the true target, and we | 3355 // valid frame, we have just bound the true target, and we |
3365 // have to jump around the code for the right subexpression. | 3356 // have to jump around the code for the right subexpression. |
3366 if (has_valid_frame()) { | 3357 if (has_valid_frame()) { |
3367 destination()->true_target()->Unuse(); | 3358 destination()->true_target()->Unuse(); |
3368 destination()->true_target()->Jump(); | 3359 destination()->true_target()->Jump(); |
3369 } | 3360 } |
3370 is_false.Bind(); | 3361 is_false.Bind(); |
3371 // The left subexpression compiled to control flow, so the | 3362 // The left subexpression compiled to control flow, so the |
3372 // right one is free to do so as well. | 3363 // right one is free to do so as well. |
3373 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 3364 LoadCondition(node->right(), destination(), false); |
3374 } else { | 3365 } else { |
3375 // We have just jumped to or bound the current true target but | 3366 // We have just jumped to or bound the current true target but |
3376 // the current control destination is not marked as used. | 3367 // the current control destination is not marked as used. |
3377 destination()->Use(true); | 3368 destination()->Use(true); |
3378 } | 3369 } |
3379 | 3370 |
3380 } else if (dest.is_used()) { | 3371 } else if (dest.is_used()) { |
3381 // The left subexpression compiled to control flow (and is_false | 3372 // The left subexpression compiled to control flow (and is_false |
3382 // was just bound), so the right is free to do so as well. | 3373 // was just bound), so the right is free to do so as well. |
3383 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 3374 LoadCondition(node->right(), destination(), false); |
3384 | 3375 |
3385 } else { | 3376 } else { |
3386 // We have a materialized value on the frame, so we exit with | 3377 // We have a materialized value on the frame, so we exit with |
3387 // one on all paths. There are possibly also jumps to is_false | 3378 // one on all paths. There are possibly also jumps to is_false |
3388 // from nested subexpressions. | 3379 // from nested subexpressions. |
3389 JumpTarget pop_and_continue; | 3380 JumpTarget pop_and_continue; |
3390 JumpTarget exit; | 3381 JumpTarget exit; |
3391 | 3382 |
3392 // Avoid popping the result if it converts to 'true' using the | 3383 // Avoid popping the result if it converts to 'true' using the |
3393 // standard ToBoolean() conversion as described in ECMA-262, | 3384 // standard ToBoolean() conversion as described in ECMA-262, |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4094 __ movq(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset)); | 4085 __ movq(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset)); |
4095 object.Unuse(); | 4086 object.Unuse(); |
4096 frame_->SetElementAt(0, &temp); | 4087 frame_->SetElementAt(0, &temp); |
4097 leave.Bind(); | 4088 leave.Bind(); |
4098 } | 4089 } |
4099 | 4090 |
4100 | 4091 |
4101 // ----------------------------------------------------------------------------- | 4092 // ----------------------------------------------------------------------------- |
4102 // CodeGenerator implementation of Expressions | 4093 // CodeGenerator implementation of Expressions |
4103 | 4094 |
4104 void CodeGenerator::LoadAndSpill(Expression* expression, | 4095 void CodeGenerator::LoadAndSpill(Expression* expression) { |
4105 TypeofState typeof_state) { | |
4106 // TODO(x64): No architecture specific code. Move to shared location. | 4096 // TODO(x64): No architecture specific code. Move to shared location. |
4107 ASSERT(in_spilled_code()); | 4097 ASSERT(in_spilled_code()); |
4108 set_in_spilled_code(false); | 4098 set_in_spilled_code(false); |
4109 Load(expression, typeof_state); | 4099 Load(expression); |
4110 frame_->SpillAll(); | 4100 frame_->SpillAll(); |
4111 set_in_spilled_code(true); | 4101 set_in_spilled_code(true); |
4112 } | 4102 } |
4113 | 4103 |
4114 | 4104 |
4115 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 4105 void CodeGenerator::Load(Expression* expr) { |
4116 #ifdef DEBUG | 4106 #ifdef DEBUG |
4117 int original_height = frame_->height(); | 4107 int original_height = frame_->height(); |
4118 #endif | 4108 #endif |
4119 ASSERT(!in_spilled_code()); | 4109 ASSERT(!in_spilled_code()); |
4120 JumpTarget true_target; | 4110 JumpTarget true_target; |
4121 JumpTarget false_target; | 4111 JumpTarget false_target; |
4122 ControlDestination dest(&true_target, &false_target, true); | 4112 ControlDestination dest(&true_target, &false_target, true); |
4123 LoadCondition(x, typeof_state, &dest, false); | 4113 LoadCondition(expr, &dest, false); |
4124 | 4114 |
4125 if (dest.false_was_fall_through()) { | 4115 if (dest.false_was_fall_through()) { |
4126 // The false target was just bound. | 4116 // The false target was just bound. |
4127 JumpTarget loaded; | 4117 JumpTarget loaded; |
4128 frame_->Push(Factory::false_value()); | 4118 frame_->Push(Factory::false_value()); |
4129 // There may be dangling jumps to the true target. | 4119 // There may be dangling jumps to the true target. |
4130 if (true_target.is_linked()) { | 4120 if (true_target.is_linked()) { |
4131 loaded.Jump(); | 4121 loaded.Jump(); |
4132 true_target.Bind(); | 4122 true_target.Bind(); |
4133 frame_->Push(Factory::true_value()); | 4123 frame_->Push(Factory::true_value()); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4173 ASSERT(has_valid_frame()); | 4163 ASSERT(has_valid_frame()); |
4174 ASSERT(frame_->height() == original_height + 1); | 4164 ASSERT(frame_->height() == original_height + 1); |
4175 } | 4165 } |
4176 | 4166 |
4177 | 4167 |
4178 // Emit code to load the value of an expression to the top of the | 4168 // Emit code to load the value of an expression to the top of the |
4179 // frame. If the expression is boolean-valued it may be compiled (or | 4169 // frame. If the expression is boolean-valued it may be compiled (or |
4180 // partially compiled) into control flow to the control destination. | 4170 // partially compiled) into control flow to the control destination. |
4181 // If force_control is true, control flow is forced. | 4171 // If force_control is true, control flow is forced. |
4182 void CodeGenerator::LoadCondition(Expression* x, | 4172 void CodeGenerator::LoadCondition(Expression* x, |
4183 TypeofState typeof_state, | |
4184 ControlDestination* dest, | 4173 ControlDestination* dest, |
4185 bool force_control) { | 4174 bool force_control) { |
4186 ASSERT(!in_spilled_code()); | 4175 ASSERT(!in_spilled_code()); |
4187 int original_height = frame_->height(); | 4176 int original_height = frame_->height(); |
4188 | 4177 |
4189 { CodeGenState new_state(this, typeof_state, dest); | 4178 { CodeGenState new_state(this, dest); |
4190 Visit(x); | 4179 Visit(x); |
4191 | 4180 |
4192 // If we hit a stack overflow, we may not have actually visited | 4181 // If we hit a stack overflow, we may not have actually visited |
4193 // the expression. In that case, we ensure that we have a | 4182 // the expression. In that case, we ensure that we have a |
4194 // valid-looking frame state because we will continue to generate | 4183 // valid-looking frame state because we will continue to generate |
4195 // code as we unwind the C++ stack. | 4184 // code as we unwind the C++ stack. |
4196 // | 4185 // |
4197 // It's possible to have both a stack overflow and a valid frame | 4186 // It's possible to have both a stack overflow and a valid frame |
4198 // state (eg, a subexpression overflowed, visiting it returned | 4187 // state (eg, a subexpression overflowed, visiting it returned |
4199 // with a dummied frame state, and visiting this expression | 4188 // with a dummied frame state, and visiting this expression |
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4807 if (!skip_arguments) { | 4796 if (!skip_arguments) { |
4808 arguments_ref.SetValue(NOT_CONST_INIT); | 4797 arguments_ref.SetValue(NOT_CONST_INIT); |
4809 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 4798 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
4810 } | 4799 } |
4811 shadow_ref.SetValue(NOT_CONST_INIT); | 4800 shadow_ref.SetValue(NOT_CONST_INIT); |
4812 } | 4801 } |
4813 return frame_->Pop(); | 4802 return frame_->Pop(); |
4814 } | 4803 } |
4815 | 4804 |
4816 | 4805 |
4817 // TODO(1241834): Get rid of this function in favor of just using Load, now | 4806 void CodeGenerator::LoadTypeofExpression(Expression* expr) { |
4818 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 4807 // Special handling of identifiers as subexpressions of typeof. |
4819 // variables w/o reference errors elsewhere. | 4808 Variable* variable = expr->AsVariableProxy()->AsVariable(); |
4820 void CodeGenerator::LoadTypeofExpression(Expression* x) { | |
4821 Variable* variable = x->AsVariableProxy()->AsVariable(); | |
4822 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 4809 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
4823 // NOTE: This is somewhat nasty. We force the compiler to load | 4810 // For a global variable we build the property reference |
4824 // the variable as if through '<global>.<variable>' to make sure we | 4811 // <global>.<variable> and perform a (regular non-contextual) property |
4825 // do not get reference errors. | 4812 // load to make sure we do not get reference errors. |
4826 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 4813 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
4827 Literal key(variable->name()); | 4814 Literal key(variable->name()); |
4828 // TODO(1241834): Fetch the position from the variable instead of using | 4815 // TODO(1241834): Fetch the position from the variable instead of using |
4829 // no position. | 4816 // no position. |
4830 Property property(&global, &key, RelocInfo::kNoPosition); | 4817 Property property(&global, &key, RelocInfo::kNoPosition); |
4831 Load(&property); | 4818 Reference ref(this, &property); |
| 4819 ref.GetValue(); |
| 4820 } else if (variable != NULL && variable->slot() != NULL) { |
| 4821 // For a variable that rewrites to a slot, we signal it is the immediate |
| 4822 // subexpression of a typeof. |
| 4823 LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF); |
4832 } else { | 4824 } else { |
4833 Load(x, INSIDE_TYPEOF); | 4825 // Anything else can be handled normally. |
| 4826 Load(expr); |
4834 } | 4827 } |
4835 } | 4828 } |
4836 | 4829 |
4837 | 4830 |
4838 void CodeGenerator::Comparison(Condition cc, | 4831 void CodeGenerator::Comparison(Condition cc, |
4839 bool strict, | 4832 bool strict, |
4840 ControlDestination* dest) { | 4833 ControlDestination* dest) { |
4841 // Strict only makes sense for equality comparisons. | 4834 // Strict only makes sense for equality comparisons. |
4842 ASSERT(!strict || cc == equal); | 4835 ASSERT(!strict || cc == equal); |
4843 | 4836 |
(...skipping 874 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5718 ASSERT(proxy->AsVariable()->is_global()); | 5711 ASSERT(proxy->AsVariable()->is_global()); |
5719 return proxy->name(); | 5712 return proxy->name(); |
5720 } else { | 5713 } else { |
5721 Literal* raw_name = property->key()->AsLiteral(); | 5714 Literal* raw_name = property->key()->AsLiteral(); |
5722 ASSERT(raw_name != NULL); | 5715 ASSERT(raw_name != NULL); |
5723 return Handle<String>(String::cast(*raw_name->handle())); | 5716 return Handle<String>(String::cast(*raw_name->handle())); |
5724 } | 5717 } |
5725 } | 5718 } |
5726 | 5719 |
5727 | 5720 |
5728 void Reference::GetValue(TypeofState typeof_state) { | 5721 void Reference::GetValue() { |
5729 ASSERT(!cgen_->in_spilled_code()); | 5722 ASSERT(!cgen_->in_spilled_code()); |
5730 ASSERT(cgen_->HasValidEntryRegisters()); | 5723 ASSERT(cgen_->HasValidEntryRegisters()); |
5731 ASSERT(!is_illegal()); | 5724 ASSERT(!is_illegal()); |
5732 MacroAssembler* masm = cgen_->masm(); | 5725 MacroAssembler* masm = cgen_->masm(); |
5733 | 5726 |
5734 // Record the source position for the property load. | 5727 // Record the source position for the property load. |
5735 Property* property = expression_->AsProperty(); | 5728 Property* property = expression_->AsProperty(); |
5736 if (property != NULL) { | 5729 if (property != NULL) { |
5737 cgen_->CodeForSourcePosition(property->position()); | 5730 cgen_->CodeForSourcePosition(property->position()); |
5738 } | 5731 } |
5739 | 5732 |
5740 switch (type_) { | 5733 switch (type_) { |
5741 case SLOT: { | 5734 case SLOT: { |
5742 Comment cmnt(masm, "[ Load from Slot"); | 5735 Comment cmnt(masm, "[ Load from Slot"); |
5743 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 5736 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
5744 ASSERT(slot != NULL); | 5737 ASSERT(slot != NULL); |
5745 cgen_->LoadFromSlotCheckForArguments(slot, typeof_state); | 5738 cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
5746 break; | 5739 break; |
5747 } | 5740 } |
5748 | 5741 |
5749 case NAMED: { | 5742 case NAMED: { |
5750 // TODO(1241834): Make sure that it is safe to ignore the | |
5751 // distinction between expressions in a typeof and not in a | |
5752 // typeof. If there is a chance that reference errors can be | |
5753 // thrown below, we must distinguish between the two kinds of | |
5754 // loads (typeof expression loads must not throw a reference | |
5755 // error). | |
5756 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 5743 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
5757 bool is_global = var != NULL; | 5744 bool is_global = var != NULL; |
5758 ASSERT(!is_global || var->is_global()); | 5745 ASSERT(!is_global || var->is_global()); |
5759 | 5746 |
5760 // Do not inline the inobject property case for loads from the global | 5747 // Do not inline the inobject property case for loads from the global |
5761 // object. Also do not inline for unoptimized code. This saves time | 5748 // object. Also do not inline for unoptimized code. This saves time |
5762 // in the code generator. Unoptimized code is toplevel code or code | 5749 // in the code generator. Unoptimized code is toplevel code or code |
5763 // that is not in a loop. | 5750 // that is not in a loop. |
5764 if (is_global || | 5751 if (is_global || |
5765 cgen_->scope()->is_global_scope() || | 5752 cgen_->scope()->is_global_scope() || |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5827 | 5814 |
5828 __ IncrementCounter(&Counters::named_load_inline, 1); | 5815 __ IncrementCounter(&Counters::named_load_inline, 1); |
5829 deferred->BindExit(); | 5816 deferred->BindExit(); |
5830 cgen_->frame()->Push(&receiver); | 5817 cgen_->frame()->Push(&receiver); |
5831 cgen_->frame()->Push(&value); | 5818 cgen_->frame()->Push(&value); |
5832 } | 5819 } |
5833 break; | 5820 break; |
5834 } | 5821 } |
5835 | 5822 |
5836 case KEYED: { | 5823 case KEYED: { |
5837 // TODO(1241834): Make sure that this it is safe to ignore the | |
5838 // distinction between expressions in a typeof and not in a typeof. | |
5839 Comment cmnt(masm, "[ Load from keyed Property"); | 5824 Comment cmnt(masm, "[ Load from keyed Property"); |
5840 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 5825 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
5841 bool is_global = var != NULL; | 5826 bool is_global = var != NULL; |
5842 ASSERT(!is_global || var->is_global()); | 5827 ASSERT(!is_global || var->is_global()); |
5843 | 5828 |
5844 // Inline array load code if inside of a loop. We do not know | 5829 // Inline array load code if inside of a loop. We do not know |
5845 // the receiver map yet, so we initially generate the code with | 5830 // the receiver map yet, so we initially generate the code with |
5846 // a check against an invalid map. In the inline cache code, we | 5831 // a check against an invalid map. In the inline cache code, we |
5847 // patch the map check if appropriate. | 5832 // patch the map check if appropriate. |
5848 if (cgen_->loop_nesting() > 0) { | 5833 if (cgen_->loop_nesting() > 0) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5950 } | 5935 } |
5951 break; | 5936 break; |
5952 } | 5937 } |
5953 | 5938 |
5954 default: | 5939 default: |
5955 UNREACHABLE(); | 5940 UNREACHABLE(); |
5956 } | 5941 } |
5957 } | 5942 } |
5958 | 5943 |
5959 | 5944 |
5960 void Reference::TakeValue(TypeofState typeof_state) { | 5945 void Reference::TakeValue() { |
5961 // TODO(X64): This function is completely architecture independent. Move | 5946 // TODO(X64): This function is completely architecture independent. Move |
5962 // it somewhere shared. | 5947 // it somewhere shared. |
5963 | 5948 |
5964 // For non-constant frame-allocated slots, we invalidate the value in the | 5949 // For non-constant frame-allocated slots, we invalidate the value in the |
5965 // slot. For all others, we fall back on GetValue. | 5950 // slot. For all others, we fall back on GetValue. |
5966 ASSERT(!cgen_->in_spilled_code()); | 5951 ASSERT(!cgen_->in_spilled_code()); |
5967 ASSERT(!is_illegal()); | 5952 ASSERT(!is_illegal()); |
5968 if (type_ != SLOT) { | 5953 if (type_ != SLOT) { |
5969 GetValue(typeof_state); | 5954 GetValue(); |
5970 return; | 5955 return; |
5971 } | 5956 } |
5972 | 5957 |
5973 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 5958 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
5974 ASSERT(slot != NULL); | 5959 ASSERT(slot != NULL); |
5975 if (slot->type() == Slot::LOOKUP || | 5960 if (slot->type() == Slot::LOOKUP || |
5976 slot->type() == Slot::CONTEXT || | 5961 slot->type() == Slot::CONTEXT || |
5977 slot->var()->mode() == Variable::CONST || | 5962 slot->var()->mode() == Variable::CONST || |
5978 slot->is_arguments()) { | 5963 slot->is_arguments()) { |
5979 GetValue(typeof_state); | 5964 GetValue(); |
5980 return; | 5965 return; |
5981 } | 5966 } |
5982 | 5967 |
5983 // Only non-constant, frame-allocated parameters and locals can reach | 5968 // Only non-constant, frame-allocated parameters and locals can reach |
5984 // here. Be careful not to use the optimizations for arguments | 5969 // here. Be careful not to use the optimizations for arguments |
5985 // object access since it may not have been initialized yet. | 5970 // object access since it may not have been initialized yet. |
5986 ASSERT(!slot->is_arguments()); | 5971 ASSERT(!slot->is_arguments()); |
5987 if (slot->type() == Slot::PARAMETER) { | 5972 if (slot->type() == Slot::PARAMETER) { |
5988 cgen_->frame()->TakeParameterAt(slot->index()); | 5973 cgen_->frame()->TakeParameterAt(slot->index()); |
5989 } else { | 5974 } else { |
(...skipping 1862 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7852 masm.GetCode(&desc); | 7837 masm.GetCode(&desc); |
7853 // Call the function from C++. | 7838 // Call the function from C++. |
7854 return FUNCTION_CAST<ModuloFunction>(buffer); | 7839 return FUNCTION_CAST<ModuloFunction>(buffer); |
7855 } | 7840 } |
7856 | 7841 |
7857 #endif | 7842 #endif |
7858 | 7843 |
7859 #undef __ | 7844 #undef __ |
7860 | 7845 |
7861 } } // namespace v8::internal | 7846 } } // namespace v8::internal |
OLD | NEW |