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