Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: src/full-codegen/full-codegen.cc

Issue 1663323003: [fullcode] Change fullcode to compile finally using the token approach. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: More rebase fixes Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698