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