| 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 |