OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/full-codegen/full-codegen.h" | 5 #include "src/full-codegen/full-codegen.h" |
6 | 6 |
7 #include "src/ast/ast.h" | 7 #include "src/ast/ast.h" |
8 #include "src/ast/ast-numbering.h" | 8 #include "src/ast/ast-numbering.h" |
9 #include "src/ast/prettyprinter.h" | 9 #include "src/ast/prettyprinter.h" |
10 #include "src/ast/scopeinfo.h" | 10 #include "src/ast/scopeinfo.h" |
(...skipping 835 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); | 846 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); |
847 __ bind(&then_part); | 847 __ bind(&then_part); |
848 Visit(stmt->then_statement()); | 848 Visit(stmt->then_statement()); |
849 | 849 |
850 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); | 850 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); |
851 } | 851 } |
852 __ bind(&done); | 852 __ bind(&done); |
853 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS); | 853 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS); |
854 } | 854 } |
855 | 855 |
856 | 856 void FullCodeGenerator::EmitContinue(Statement* target) { |
857 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | |
858 Comment cmnt(masm_, "[ ContinueStatement"); | |
859 SetStatementPosition(stmt); | |
860 NestedStatement* current = nesting_stack_; | 857 NestedStatement* current = nesting_stack_; |
861 int stack_depth = 0; | 858 int stack_depth = 0; |
862 int context_length = 0; | 859 int context_length = 0; |
863 // When continuing, we clobber the unpredictable value in the accumulator | 860 // When continuing, we clobber the unpredictable value in the accumulator |
864 // with one that's safe for GC. If we hit an exit from the try block of | 861 // with one that's safe for GC. If we hit an exit from the try block of |
865 // try...finally on our way out, we will unconditionally preserve the | 862 // try...finally on our way out, we will unconditionally preserve the |
866 // accumulator on the stack. | 863 // accumulator on the stack. |
867 ClearAccumulator(); | 864 ClearAccumulator(); |
868 while (!current->IsContinueTarget(stmt->target())) { | 865 while (!current->IsContinueTarget(target)) { |
| 866 if (current->IsTryFinally()) { |
| 867 Comment cmnt(masm(), "[ Deferred continue through finally"); |
| 868 current->Exit(&stack_depth, &context_length); |
| 869 DCHECK_EQ(0, stack_depth); |
| 870 DCHECK_EQ(0, context_length); |
| 871 current->AsTryFinally()->deferred_commands()->RecordContinue(target); |
| 872 return; |
| 873 } |
869 current = current->Exit(&stack_depth, &context_length); | 874 current = current->Exit(&stack_depth, &context_length); |
870 } | 875 } |
871 __ Drop(stack_depth); | 876 __ Drop(stack_depth); |
872 if (context_length > 0) { | 877 if (context_length > 0) { |
873 while (context_length > 0) { | 878 while (context_length > 0) { |
874 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 879 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
875 --context_length; | 880 --context_length; |
876 } | 881 } |
877 StoreToFrameField(StandardFrameConstants::kContextOffset, | 882 StoreToFrameField(StandardFrameConstants::kContextOffset, |
878 context_register()); | 883 context_register()); |
879 } | 884 } |
880 | 885 |
881 __ jmp(current->AsIteration()->continue_label()); | 886 __ jmp(current->AsIteration()->continue_label()); |
882 } | 887 } |
883 | 888 |
| 889 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
| 890 Comment cmnt(masm_, "[ ContinueStatement"); |
| 891 SetStatementPosition(stmt); |
| 892 EmitContinue(stmt->target()); |
| 893 } |
884 | 894 |
885 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 895 void FullCodeGenerator::EmitBreak(Statement* target) { |
886 Comment cmnt(masm_, "[ BreakStatement"); | |
887 SetStatementPosition(stmt); | |
888 NestedStatement* current = nesting_stack_; | 896 NestedStatement* current = nesting_stack_; |
889 int stack_depth = 0; | 897 int stack_depth = 0; |
890 int context_length = 0; | 898 int context_length = 0; |
891 // When breaking, we clobber the unpredictable value in the accumulator | 899 // When breaking, we clobber the unpredictable value in the accumulator |
892 // with one that's safe for GC. If we hit an exit from the try block of | 900 // with one that's safe for GC. If we hit an exit from the try block of |
893 // try...finally on our way out, we will unconditionally preserve the | 901 // try...finally on our way out, we will unconditionally preserve the |
894 // accumulator on the stack. | 902 // accumulator on the stack. |
895 ClearAccumulator(); | 903 ClearAccumulator(); |
896 while (!current->IsBreakTarget(stmt->target())) { | 904 while (!current->IsBreakTarget(target)) { |
| 905 if (current->IsTryFinally()) { |
| 906 Comment cmnt(masm(), "[ Deferred break through finally"); |
| 907 current->Exit(&stack_depth, &context_length); |
| 908 DCHECK_EQ(0, stack_depth); |
| 909 DCHECK_EQ(0, context_length); |
| 910 current->AsTryFinally()->deferred_commands()->RecordBreak(target); |
| 911 return; |
| 912 } |
897 current = current->Exit(&stack_depth, &context_length); | 913 current = current->Exit(&stack_depth, &context_length); |
898 } | 914 } |
899 __ Drop(stack_depth); | 915 __ Drop(stack_depth); |
900 if (context_length > 0) { | 916 if (context_length > 0) { |
901 while (context_length > 0) { | 917 while (context_length > 0) { |
902 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 918 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
903 --context_length; | 919 --context_length; |
904 } | 920 } |
905 StoreToFrameField(StandardFrameConstants::kContextOffset, | 921 StoreToFrameField(StandardFrameConstants::kContextOffset, |
906 context_register()); | 922 context_register()); |
907 } | 923 } |
908 | 924 |
909 __ jmp(current->AsBreakable()->break_label()); | 925 __ jmp(current->AsBreakable()->break_label()); |
910 } | 926 } |
911 | 927 |
| 928 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
| 929 Comment cmnt(masm_, "[ BreakStatement"); |
| 930 SetStatementPosition(stmt); |
| 931 EmitBreak(stmt->target()); |
| 932 } |
912 | 933 |
913 void FullCodeGenerator::EmitUnwindBeforeReturn() { | 934 void FullCodeGenerator::EmitUnwindAndReturn() { |
914 NestedStatement* current = nesting_stack_; | 935 NestedStatement* current = nesting_stack_; |
915 int stack_depth = 0; | 936 int stack_depth = 0; |
916 int context_length = 0; | 937 int context_length = 0; |
917 while (current != NULL) { | 938 while (current != NULL) { |
| 939 if (current->IsTryFinally()) { |
| 940 Comment cmnt(masm(), "[ Deferred return through finally"); |
| 941 current->Exit(&stack_depth, &context_length); |
| 942 DCHECK_EQ(0, stack_depth); |
| 943 DCHECK_EQ(0, context_length); |
| 944 current->AsTryFinally()->deferred_commands()->RecordReturn(); |
| 945 return; |
| 946 } |
918 current = current->Exit(&stack_depth, &context_length); | 947 current = current->Exit(&stack_depth, &context_length); |
919 } | 948 } |
920 __ Drop(stack_depth); | 949 __ Drop(stack_depth); |
| 950 EmitReturnSequence(); |
921 } | 951 } |
922 | 952 |
923 | 953 |
924 void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property, | 954 void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property, |
925 BailoutId bailout_id) { | 955 BailoutId bailout_id) { |
926 VisitForStackValue(property->key()); | 956 VisitForStackValue(property->key()); |
927 __ CallRuntime(Runtime::kToName); | 957 __ CallRuntime(Runtime::kToName); |
928 PrepareForBailoutForId(bailout_id, NO_REGISTERS); | 958 PrepareForBailoutForId(bailout_id, NO_REGISTERS); |
929 __ Push(result_register()); | 959 __ Push(result_register()); |
930 } | 960 } |
931 | 961 |
932 | 962 |
933 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 963 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
934 Comment cmnt(masm_, "[ ReturnStatement"); | 964 Comment cmnt(masm_, "[ ReturnStatement"); |
935 SetStatementPosition(stmt); | 965 SetStatementPosition(stmt); |
936 Expression* expr = stmt->expression(); | 966 Expression* expr = stmt->expression(); |
937 VisitForAccumulatorValue(expr); | 967 VisitForAccumulatorValue(expr); |
938 EmitUnwindBeforeReturn(); | 968 EmitUnwindAndReturn(); |
939 EmitReturnSequence(); | |
940 } | 969 } |
941 | 970 |
942 | 971 |
943 void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) { | 972 void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) { |
944 Comment cmnt(masm_, "[ WithStatement"); | 973 Comment cmnt(masm_, "[ WithStatement"); |
945 SetStatementPosition(stmt); | 974 SetStatementPosition(stmt); |
946 | 975 |
947 VisitForAccumulatorValue(stmt->expression()); | 976 VisitForAccumulatorValue(stmt->expression()); |
948 Callable callable = CodeFactory::ToObject(isolate()); | 977 Callable callable = CodeFactory::ToObject(isolate()); |
949 __ Move(callable.descriptor().GetRegisterParameter(0), result_register()); | 978 __ Move(callable.descriptor().GetRegisterParameter(0), result_register()); |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1181 | 1210 |
1182 | 1211 |
1183 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1212 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
1184 Comment cmnt(masm_, "[ TryFinallyStatement"); | 1213 Comment cmnt(masm_, "[ TryFinallyStatement"); |
1185 SetStatementPosition(stmt, SKIP_BREAK); | 1214 SetStatementPosition(stmt, SKIP_BREAK); |
1186 | 1215 |
1187 // Try finally is compiled by setting up a try-handler on the stack while | 1216 // Try finally is compiled by setting up a try-handler on the stack while |
1188 // executing the try body, and removing it again afterwards. | 1217 // executing the try body, and removing it again afterwards. |
1189 // | 1218 // |
1190 // The try-finally construct can enter the finally block in three ways: | 1219 // The try-finally construct can enter the finally block in three ways: |
1191 // 1. By exiting the try-block normally. This removes the try-handler and | 1220 // 1. By exiting the try-block normally. This exits the try block, |
1192 // calls the finally block code before continuing. | 1221 // pushes the continuation token and falls through to the finally |
| 1222 // block. |
1193 // 2. By exiting the try-block with a function-local control flow transfer | 1223 // 2. By exiting the try-block with a function-local control flow transfer |
1194 // (break/continue/return). The site of the, e.g., break removes the | 1224 // (break/continue/return). The site of the, e.g., break exits the |
1195 // try handler and calls the finally block code before continuing | 1225 // try block, pushes the continuation token and jumps to the |
1196 // its outward control transfer. | 1226 // finally block. After the finally block executes, the execution |
1197 // 3. By exiting the try-block with a thrown exception. | 1227 // continues based on the continuation token to a block that |
1198 // This can happen in nested function calls. It traverses the try-handler | 1228 // continues with the control flow transfer. |
1199 // chain and consumes the try-handler entry before jumping to the | 1229 // 3. By exiting the try-block with a thrown exception. In the handler, |
1200 // handler code. The handler code then calls the finally-block before | 1230 // we push the exception and continuation token and jump to the |
1201 // rethrowing the exception. | 1231 // finally block (which will again dispatch based on the token once |
1202 // | 1232 // it is finished). |
1203 // The finally block must assume a return address on top of the stack | 1233 |
1204 // (or in the link register on ARM chips) and a value (return value or | |
1205 // exception) in the result register (rax/eax/r0), both of which must | |
1206 // be preserved. The return address isn't GC-safe, so it should be | |
1207 // cooked before GC. | |
1208 Label try_entry, handler_entry, finally_entry; | 1234 Label try_entry, handler_entry, finally_entry; |
| 1235 DeferredCommands deferred(this, &finally_entry); |
1209 | 1236 |
1210 // Jump to try-handler setup and try-block code. | 1237 // Jump to try-handler setup and try-block code. |
1211 __ jmp(&try_entry); | 1238 __ jmp(&try_entry); |
1212 __ bind(&handler_entry); | 1239 __ bind(&handler_entry); |
1213 PrepareForBailoutForId(stmt->HandlerId(), NO_REGISTERS); | 1240 PrepareForBailoutForId(stmt->HandlerId(), NO_REGISTERS); |
1214 | 1241 |
1215 // Exception handler code. This code is only executed when an exception | 1242 // Exception handler code. This code is only executed when an exception |
1216 // is thrown. The exception is in the result register, and must be | 1243 // is thrown. Record the continuation and jump to the finally block. |
1217 // preserved by the finally block. Call the finally block and then | 1244 { |
1218 // rethrow the exception if it returns. | 1245 Comment cmt_handler(masm(), "[ Finally handler"); |
1219 __ Call(&finally_entry); | 1246 deferred.RecordThrow(); |
1220 __ Push(result_register()); | |
1221 __ CallRuntime(Runtime::kReThrow); | |
1222 | |
1223 // Finally block implementation. | |
1224 __ bind(&finally_entry); | |
1225 EnterFinallyBlock(); | |
1226 { Finally finally_body(this); | |
1227 Visit(stmt->finally_block()); | |
1228 } | 1247 } |
1229 ExitFinallyBlock(); // Return to the calling code. | |
1230 | 1248 |
1231 // Set up try handler. | 1249 // Set up try handler. |
1232 __ bind(&try_entry); | 1250 __ bind(&try_entry); |
1233 int handler_index = NewHandlerTableEntry(); | 1251 int handler_index = NewHandlerTableEntry(); |
1234 EnterTryBlock(handler_index, &handler_entry); | 1252 EnterTryBlock(handler_index, &handler_entry); |
1235 { TryFinally try_body(this, &finally_entry); | 1253 { |
| 1254 TryFinally try_body(this, &deferred); |
1236 Visit(stmt->try_block()); | 1255 Visit(stmt->try_block()); |
1237 } | 1256 } |
1238 ExitTryBlock(handler_index); | 1257 ExitTryBlock(handler_index); |
1239 // Execute the finally block on the way out. Clobber the unpredictable | 1258 // Execute the finally block on the way out. Clobber the unpredictable |
1240 // value in the result register with one that's safe for GC because the | 1259 // value in the result register with one that's safe for GC because the |
1241 // finally block will unconditionally preserve the result register on the | 1260 // finally block will unconditionally preserve the result register on the |
1242 // stack. | 1261 // stack. |
1243 ClearAccumulator(); | 1262 ClearAccumulator(); |
1244 __ Call(&finally_entry); | 1263 deferred.EmitFallThrough(); |
| 1264 // Fall through to the finally block. |
| 1265 |
| 1266 // Finally block implementation. |
| 1267 __ bind(&finally_entry); |
| 1268 Comment cmnt_finally(masm(), "[ Finally block"); |
| 1269 EnterFinallyBlock(); |
| 1270 { |
| 1271 Finally finally_body(this); |
| 1272 Visit(stmt->finally_block()); |
| 1273 } |
| 1274 ExitFinallyBlock(); // Return to the calling code. |
| 1275 |
| 1276 { |
| 1277 Comment cmnt_deferred(masm(), "[ Post-finally dispatch"); |
| 1278 deferred.EmitCommands(); |
| 1279 } |
1245 } | 1280 } |
1246 | 1281 |
1247 | 1282 |
1248 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1283 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
1249 Comment cmnt(masm_, "[ DebuggerStatement"); | 1284 Comment cmnt(masm_, "[ DebuggerStatement"); |
1250 SetStatementPosition(stmt); | 1285 SetStatementPosition(stmt); |
1251 | 1286 |
1252 __ DebugBreak(); | 1287 __ DebugBreak(); |
1253 // Ignore the return value. | 1288 // Ignore the return value. |
1254 | 1289 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1478 __ Drop(*stack_depth); // Down to the handler block. | 1513 __ Drop(*stack_depth); // Down to the handler block. |
1479 // Restore the context to its dedicated register and the stack. | 1514 // Restore the context to its dedicated register and the stack. |
1480 STATIC_ASSERT(TryFinally::kElementCount == 1); | 1515 STATIC_ASSERT(TryFinally::kElementCount == 1); |
1481 __ Pop(codegen_->context_register()); | 1516 __ Pop(codegen_->context_register()); |
1482 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, | 1517 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, |
1483 codegen_->context_register()); | 1518 codegen_->context_register()); |
1484 } else { | 1519 } else { |
1485 // Down to the handler block and also drop context. | 1520 // Down to the handler block and also drop context. |
1486 __ Drop(*stack_depth + kElementCount); | 1521 __ Drop(*stack_depth + kElementCount); |
1487 } | 1522 } |
1488 __ Call(finally_entry_); | |
1489 | |
1490 *stack_depth = 0; | 1523 *stack_depth = 0; |
1491 *context_length = 0; | 1524 *context_length = 0; |
1492 return previous_; | 1525 return previous_; |
1493 } | 1526 } |
1494 | 1527 |
| 1528 void FullCodeGenerator::DeferredCommands::RecordBreak(Statement* target) { |
| 1529 TokenId token = dispenser_.GetBreakContinueToken(); |
| 1530 commands_.push_back({kBreak, token, target}); |
| 1531 EmitJumpToFinally(token); |
| 1532 } |
| 1533 |
| 1534 void FullCodeGenerator::DeferredCommands::RecordContinue(Statement* target) { |
| 1535 TokenId token = dispenser_.GetBreakContinueToken(); |
| 1536 commands_.push_back({kContinue, token, target}); |
| 1537 EmitJumpToFinally(token); |
| 1538 } |
| 1539 |
| 1540 void FullCodeGenerator::DeferredCommands::RecordReturn() { |
| 1541 if (return_token_ == TokenDispenserForFinally::kInvalidToken) { |
| 1542 return_token_ = TokenDispenserForFinally::kReturnToken; |
| 1543 commands_.push_back({kReturn, return_token_, nullptr}); |
| 1544 } |
| 1545 EmitJumpToFinally(return_token_); |
| 1546 } |
| 1547 |
| 1548 void FullCodeGenerator::DeferredCommands::RecordThrow() { |
| 1549 if (throw_token_ == TokenDispenserForFinally::kInvalidToken) { |
| 1550 throw_token_ = TokenDispenserForFinally::kThrowToken; |
| 1551 commands_.push_back({kThrow, throw_token_, nullptr}); |
| 1552 } |
| 1553 EmitJumpToFinally(throw_token_); |
| 1554 } |
| 1555 |
| 1556 void FullCodeGenerator::DeferredCommands::EmitFallThrough() { |
| 1557 __ Push(Smi::FromInt(TokenDispenserForFinally::kFallThroughToken)); |
| 1558 __ Push(result_register()); |
| 1559 } |
| 1560 |
| 1561 void FullCodeGenerator::DeferredCommands::EmitJumpToFinally(TokenId token) { |
| 1562 __ Push(Smi::FromInt(token)); |
| 1563 __ Push(result_register()); |
| 1564 __ jmp(finally_entry_); |
| 1565 } |
1495 | 1566 |
1496 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { | 1567 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { |
1497 Expression* sub_expr; | 1568 Expression* sub_expr; |
1498 Handle<String> check; | 1569 Handle<String> check; |
1499 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { | 1570 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
1500 EmitLiteralCompareTypeof(expr, sub_expr, check); | 1571 EmitLiteralCompareTypeof(expr, sub_expr, check); |
1501 return true; | 1572 return true; |
1502 } | 1573 } |
1503 | 1574 |
1504 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { | 1575 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1709 return var->mode() == CONST_LEGACY || var->scope()->is_nonlinear() || | 1780 return var->mode() == CONST_LEGACY || var->scope()->is_nonlinear() || |
1710 var->initializer_position() >= proxy->position(); | 1781 var->initializer_position() >= proxy->position(); |
1711 } | 1782 } |
1712 | 1783 |
1713 | 1784 |
1714 #undef __ | 1785 #undef __ |
1715 | 1786 |
1716 | 1787 |
1717 } // namespace internal | 1788 } // namespace internal |
1718 } // namespace v8 | 1789 } // namespace v8 |
OLD | NEW |