| 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-numbering.h" | 7 #include "src/ast/ast-numbering.h" |
| 8 #include "src/ast/ast.h" | 8 #include "src/ast/ast.h" |
| 9 #include "src/ast/prettyprinter.h" | 9 #include "src/ast/prettyprinter.h" |
| 10 #include "src/ast/scopes.h" | 10 #include "src/ast/scopes.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 nesting_stack_(NULL), | 55 nesting_stack_(NULL), |
| 56 loop_depth_(0), | 56 loop_depth_(0), |
| 57 operand_stack_depth_(0), | 57 operand_stack_depth_(0), |
| 58 globals_(NULL), | 58 globals_(NULL), |
| 59 context_(NULL), | 59 context_(NULL), |
| 60 bailout_entries_(info->HasDeoptimizationSupport() | 60 bailout_entries_(info->HasDeoptimizationSupport() |
| 61 ? info->literal()->ast_node_count() | 61 ? info->literal()->ast_node_count() |
| 62 : 0, | 62 : 0, |
| 63 info->zone()), | 63 info->zone()), |
| 64 back_edges_(2, info->zone()), | 64 back_edges_(2, info->zone()), |
| 65 handler_table_(info->zone()), | |
| 66 source_position_table_builder_(info->zone(), | 65 source_position_table_builder_(info->zone(), |
| 67 info->SourcePositionRecordingMode()), | 66 info->SourcePositionRecordingMode()), |
| 68 ic_total_count_(0) { | 67 ic_total_count_(0) { |
| 69 DCHECK(!info->IsStub()); | 68 DCHECK(!info->IsStub()); |
| 70 Initialize(stack_limit); | 69 Initialize(stack_limit); |
| 71 } | 70 } |
| 72 | 71 |
| 73 // static | 72 // static |
| 74 CompilationJob* FullCodeGenerator::NewCompilationJob(CompilationInfo* info) { | 73 CompilationJob* FullCodeGenerator::NewCompilationJob(CompilationInfo* info) { |
| 75 return new FullCodegenCompilationJob(info); | 74 return new FullCodegenCompilationJob(info); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 if (cgen.HasStackOverflow()) { | 107 if (cgen.HasStackOverflow()) { |
| 109 DCHECK(!isolate->has_pending_exception()); | 108 DCHECK(!isolate->has_pending_exception()); |
| 110 return false; | 109 return false; |
| 111 } | 110 } |
| 112 unsigned table_offset = cgen.EmitBackEdgeTable(); | 111 unsigned table_offset = cgen.EmitBackEdgeTable(); |
| 113 | 112 |
| 114 Handle<Code> code = | 113 Handle<Code> code = |
| 115 CodeGenerator::MakeCodeEpilogue(&masm, nullptr, info, masm.CodeObject()); | 114 CodeGenerator::MakeCodeEpilogue(&masm, nullptr, info, masm.CodeObject()); |
| 116 cgen.PopulateDeoptimizationData(code); | 115 cgen.PopulateDeoptimizationData(code); |
| 117 cgen.PopulateTypeFeedbackInfo(code); | 116 cgen.PopulateTypeFeedbackInfo(code); |
| 118 cgen.PopulateHandlerTable(code); | |
| 119 code->set_has_deoptimization_support(info->HasDeoptimizationSupport()); | 117 code->set_has_deoptimization_support(info->HasDeoptimizationSupport()); |
| 120 code->set_has_reloc_info_for_serialization(info->will_serialize()); | 118 code->set_has_reloc_info_for_serialization(info->will_serialize()); |
| 121 code->set_allow_osr_at_loop_nesting_level(0); | 119 code->set_allow_osr_at_loop_nesting_level(0); |
| 122 code->set_profiler_ticks(0); | 120 code->set_profiler_ticks(0); |
| 123 code->set_back_edge_table_offset(table_offset); | 121 code->set_back_edge_table_offset(table_offset); |
| 124 Handle<ByteArray> source_positions = | 122 Handle<ByteArray> source_positions = |
| 125 cgen.source_position_table_builder_.ToSourcePositionTable( | 123 cgen.source_position_table_builder_.ToSourcePositionTable( |
| 126 isolate, Handle<AbstractCode>::cast(code)); | 124 isolate, Handle<AbstractCode>::cast(code)); |
| 127 code->set_source_position_table(*source_positions); | 125 code->set_source_position_table(*source_positions); |
| 128 CodeGenerator::PrintCode(code, info); | 126 CodeGenerator::PrintCode(code, info); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 | 167 |
| 170 | 168 |
| 171 void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) { | 169 void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) { |
| 172 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo(); | 170 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo(); |
| 173 info->set_ic_total_count(ic_total_count_); | 171 info->set_ic_total_count(ic_total_count_); |
| 174 DCHECK(!isolate()->heap()->InNewSpace(*info)); | 172 DCHECK(!isolate()->heap()->InNewSpace(*info)); |
| 175 code->set_type_feedback_info(*info); | 173 code->set_type_feedback_info(*info); |
| 176 } | 174 } |
| 177 | 175 |
| 178 | 176 |
| 179 void FullCodeGenerator::PopulateHandlerTable(Handle<Code> code) { | |
| 180 int handler_table_size = static_cast<int>(handler_table_.size()); | |
| 181 Handle<HandlerTable> table = | |
| 182 Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray( | |
| 183 HandlerTable::LengthForRange(handler_table_size), TENURED)); | |
| 184 for (int i = 0; i < handler_table_size; ++i) { | |
| 185 table->SetRangeStart(i, handler_table_[i].range_start); | |
| 186 table->SetRangeEnd(i, handler_table_[i].range_end); | |
| 187 table->SetRangeHandler(i, handler_table_[i].handler_offset, | |
| 188 handler_table_[i].catch_prediction); | |
| 189 table->SetRangeData(i, handler_table_[i].stack_depth); | |
| 190 } | |
| 191 code->set_handler_table(*table); | |
| 192 } | |
| 193 | |
| 194 | |
| 195 int FullCodeGenerator::NewHandlerTableEntry() { | |
| 196 int index = static_cast<int>(handler_table_.size()); | |
| 197 HandlerTableEntry entry = {0, 0, 0, 0, HandlerTable::UNCAUGHT}; | |
| 198 handler_table_.push_back(entry); | |
| 199 return index; | |
| 200 } | |
| 201 | |
| 202 | |
| 203 bool FullCodeGenerator::MustCreateObjectLiteralWithRuntime( | 177 bool FullCodeGenerator::MustCreateObjectLiteralWithRuntime( |
| 204 ObjectLiteral* expr) const { | 178 ObjectLiteral* expr) const { |
| 205 return masm()->serializer_enabled() || | 179 return masm()->serializer_enabled() || |
| 206 !FastCloneShallowObjectStub::IsSupported(expr); | 180 !FastCloneShallowObjectStub::IsSupported(expr); |
| 207 } | 181 } |
| 208 | 182 |
| 209 | 183 |
| 210 bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime( | 184 bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime( |
| 211 ArrayLiteral* expr) const { | 185 ArrayLiteral* expr) const { |
| 212 return expr->depth() > 1 || | 186 return expr->depth() > 1 || |
| (...skipping 769 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 PrepareForBailoutForId(stmt->ElseId(), BailoutState::NO_REGISTERS); | 956 PrepareForBailoutForId(stmt->ElseId(), BailoutState::NO_REGISTERS); |
| 983 } | 957 } |
| 984 __ bind(&done); | 958 __ bind(&done); |
| 985 PrepareForBailoutForId(stmt->IfId(), BailoutState::NO_REGISTERS); | 959 PrepareForBailoutForId(stmt->IfId(), BailoutState::NO_REGISTERS); |
| 986 } | 960 } |
| 987 | 961 |
| 988 void FullCodeGenerator::EmitContinue(Statement* target) { | 962 void FullCodeGenerator::EmitContinue(Statement* target) { |
| 989 NestedStatement* current = nesting_stack_; | 963 NestedStatement* current = nesting_stack_; |
| 990 int context_length = 0; | 964 int context_length = 0; |
| 991 // When continuing, we clobber the unpredictable value in the accumulator | 965 // When continuing, we clobber the unpredictable value in the accumulator |
| 992 // with one that's safe for GC. If we hit an exit from the try block of | 966 // with one that's safe for GC. |
| 993 // try...finally on our way out, we will unconditionally preserve the | |
| 994 // accumulator on the stack. | |
| 995 ClearAccumulator(); | 967 ClearAccumulator(); |
| 996 while (!current->IsContinueTarget(target)) { | 968 while (!current->IsContinueTarget(target)) { |
| 997 if (HasStackOverflow()) return; | 969 if (HasStackOverflow()) return; |
| 998 if (current->IsTryFinally()) { | |
| 999 Comment cmnt(masm(), "[ Deferred continue through finally"); | |
| 1000 current->Exit(&context_length); | |
| 1001 DCHECK_EQ(-1, context_length); | |
| 1002 current->AsTryFinally()->deferred_commands()->RecordContinue(target); | |
| 1003 return; | |
| 1004 } | |
| 1005 current = current->Exit(&context_length); | 970 current = current->Exit(&context_length); |
| 1006 } | 971 } |
| 1007 int stack_depth = current->GetStackDepthAtTarget(); | 972 int stack_depth = current->GetStackDepthAtTarget(); |
| 1008 int stack_drop = operand_stack_depth_ - stack_depth; | 973 int stack_drop = operand_stack_depth_ - stack_depth; |
| 1009 DCHECK_GE(stack_drop, 0); | 974 DCHECK_GE(stack_drop, 0); |
| 1010 __ Drop(stack_drop); | 975 __ Drop(stack_drop); |
| 1011 if (context_length > 0) { | 976 if (context_length > 0) { |
| 1012 while (context_length > 0) { | 977 while (context_length > 0) { |
| 1013 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 978 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 1014 --context_length; | 979 --context_length; |
| 1015 } | 980 } |
| 1016 StoreToFrameField(StandardFrameConstants::kContextOffset, | 981 StoreToFrameField(StandardFrameConstants::kContextOffset, |
| 1017 context_register()); | 982 context_register()); |
| 1018 } | 983 } |
| 1019 | 984 |
| 1020 __ jmp(current->AsIteration()->continue_label()); | 985 __ jmp(current->AsIteration()->continue_label()); |
| 1021 } | 986 } |
| 1022 | 987 |
| 1023 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | 988 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
| 1024 Comment cmnt(masm_, "[ ContinueStatement"); | 989 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1025 SetStatementPosition(stmt); | 990 SetStatementPosition(stmt); |
| 1026 EmitContinue(stmt->target()); | 991 EmitContinue(stmt->target()); |
| 1027 } | 992 } |
| 1028 | 993 |
| 1029 void FullCodeGenerator::EmitBreak(Statement* target) { | 994 void FullCodeGenerator::EmitBreak(Statement* target) { |
| 1030 NestedStatement* current = nesting_stack_; | 995 NestedStatement* current = nesting_stack_; |
| 1031 int context_length = 0; | 996 int context_length = 0; |
| 1032 // When breaking, we clobber the unpredictable value in the accumulator | 997 // When breaking, we clobber the unpredictable value in the accumulator |
| 1033 // with one that's safe for GC. If we hit an exit from the try block of | 998 // with one that's safe for GC. |
| 1034 // try...finally on our way out, we will unconditionally preserve the | |
| 1035 // accumulator on the stack. | |
| 1036 ClearAccumulator(); | 999 ClearAccumulator(); |
| 1037 while (!current->IsBreakTarget(target)) { | 1000 while (!current->IsBreakTarget(target)) { |
| 1038 if (HasStackOverflow()) return; | 1001 if (HasStackOverflow()) return; |
| 1039 if (current->IsTryFinally()) { | |
| 1040 Comment cmnt(masm(), "[ Deferred break through finally"); | |
| 1041 current->Exit(&context_length); | |
| 1042 DCHECK_EQ(-1, context_length); | |
| 1043 current->AsTryFinally()->deferred_commands()->RecordBreak(target); | |
| 1044 return; | |
| 1045 } | |
| 1046 current = current->Exit(&context_length); | 1002 current = current->Exit(&context_length); |
| 1047 } | 1003 } |
| 1048 int stack_depth = current->GetStackDepthAtTarget(); | 1004 int stack_depth = current->GetStackDepthAtTarget(); |
| 1049 int stack_drop = operand_stack_depth_ - stack_depth; | 1005 int stack_drop = operand_stack_depth_ - stack_depth; |
| 1050 DCHECK_GE(stack_drop, 0); | 1006 DCHECK_GE(stack_drop, 0); |
| 1051 __ Drop(stack_drop); | 1007 __ Drop(stack_drop); |
| 1052 if (context_length > 0) { | 1008 if (context_length > 0) { |
| 1053 while (context_length > 0) { | 1009 while (context_length > 0) { |
| 1054 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 1010 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 1055 --context_length; | 1011 --context_length; |
| 1056 } | 1012 } |
| 1057 StoreToFrameField(StandardFrameConstants::kContextOffset, | 1013 StoreToFrameField(StandardFrameConstants::kContextOffset, |
| 1058 context_register()); | 1014 context_register()); |
| 1059 } | 1015 } |
| 1060 | 1016 |
| 1061 __ jmp(current->AsBreakable()->break_label()); | 1017 __ jmp(current->AsBreakable()->break_label()); |
| 1062 } | 1018 } |
| 1063 | 1019 |
| 1064 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 1020 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
| 1065 Comment cmnt(masm_, "[ BreakStatement"); | 1021 Comment cmnt(masm_, "[ BreakStatement"); |
| 1066 SetStatementPosition(stmt); | 1022 SetStatementPosition(stmt); |
| 1067 EmitBreak(stmt->target()); | 1023 EmitBreak(stmt->target()); |
| 1068 } | 1024 } |
| 1069 | 1025 |
| 1070 void FullCodeGenerator::EmitUnwindAndReturn() { | 1026 void FullCodeGenerator::EmitUnwindAndReturn() { |
| 1071 NestedStatement* current = nesting_stack_; | 1027 NestedStatement* current = nesting_stack_; |
| 1072 int context_length = 0; | 1028 int context_length = 0; |
| 1073 while (current != NULL) { | 1029 while (current != NULL) { |
| 1074 if (HasStackOverflow()) return; | 1030 if (HasStackOverflow()) return; |
| 1075 if (current->IsTryFinally()) { | |
| 1076 Comment cmnt(masm(), "[ Deferred return through finally"); | |
| 1077 current->Exit(&context_length); | |
| 1078 DCHECK_EQ(-1, context_length); | |
| 1079 current->AsTryFinally()->deferred_commands()->RecordReturn(); | |
| 1080 return; | |
| 1081 } | |
| 1082 current = current->Exit(&context_length); | 1031 current = current->Exit(&context_length); |
| 1083 } | 1032 } |
| 1084 EmitReturnSequence(); | 1033 EmitReturnSequence(); |
| 1085 } | 1034 } |
| 1086 | 1035 |
| 1087 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, | 1036 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, |
| 1088 bool pretenure) { | 1037 bool pretenure) { |
| 1089 // If we're running with the --always-opt or the --prepare-always-opt | 1038 // If we're running with the --always-opt or the --prepare-always-opt |
| 1090 // flag, we need to use the runtime function so that the new function | 1039 // flag, we need to use the runtime function so that the new function |
| 1091 // we are creating here gets a chance to have its code optimized and | 1040 // we are creating here gets a chance to have its code optimized and |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1353 decrement_loop_depth(); | 1302 decrement_loop_depth(); |
| 1354 } | 1303 } |
| 1355 | 1304 |
| 1356 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 1305 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 1357 LoadFromFrameField(JavaScriptFrameConstants::kFunctionOffset, | 1306 LoadFromFrameField(JavaScriptFrameConstants::kFunctionOffset, |
| 1358 result_register()); | 1307 result_register()); |
| 1359 context()->Plug(result_register()); | 1308 context()->Plug(result_register()); |
| 1360 } | 1309 } |
| 1361 | 1310 |
| 1362 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1311 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 1363 Comment cmnt(masm_, "[ TryCatchStatement"); | 1312 // Exception handling is not supported. |
| 1364 SetStatementPosition(stmt, SKIP_BREAK); | 1313 UNREACHABLE(); |
| 1365 | |
| 1366 // The try block adds a handler to the exception handler chain before | |
| 1367 // entering, and removes it again when exiting normally. If an exception | |
| 1368 // is thrown during execution of the try block, the handler is consumed | |
| 1369 // and control is passed to the catch block with the exception in the | |
| 1370 // result register. | |
| 1371 | |
| 1372 Label try_entry, handler_entry, exit; | |
| 1373 __ jmp(&try_entry); | |
| 1374 __ bind(&handler_entry); | |
| 1375 if (stmt->clear_pending_message()) ClearPendingMessage(); | |
| 1376 | |
| 1377 // Exception handler code, the exception is in the result register. | |
| 1378 // Extend the context before executing the catch block. | |
| 1379 { Comment cmnt(masm_, "[ Extend catch context"); | |
| 1380 PushOperand(stmt->variable()->name()); | |
| 1381 PushOperand(result_register()); | |
| 1382 PushOperand(stmt->scope()->scope_info()); | |
| 1383 PushFunctionArgumentForContextAllocation(); | |
| 1384 CallRuntimeWithOperands(Runtime::kPushCatchContext); | |
| 1385 StoreToFrameField(StandardFrameConstants::kContextOffset, | |
| 1386 context_register()); | |
| 1387 } | |
| 1388 | |
| 1389 Scope* saved_scope = scope(); | |
| 1390 scope_ = stmt->scope(); | |
| 1391 DCHECK(scope_->declarations()->is_empty()); | |
| 1392 { WithOrCatch catch_body(this); | |
| 1393 Visit(stmt->catch_block()); | |
| 1394 } | |
| 1395 // Restore the context. | |
| 1396 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | |
| 1397 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); | |
| 1398 scope_ = saved_scope; | |
| 1399 __ jmp(&exit); | |
| 1400 | |
| 1401 // Try block code. Sets up the exception handler chain. | |
| 1402 __ bind(&try_entry); | |
| 1403 | |
| 1404 int handler_index = NewHandlerTableEntry(); | |
| 1405 EnterTryBlock(handler_index, &handler_entry, stmt->catch_prediction()); | |
| 1406 { | |
| 1407 Comment cmnt_try(masm(), "[ Try block"); | |
| 1408 Visit(stmt->try_block()); | |
| 1409 } | |
| 1410 ExitTryBlock(handler_index); | |
| 1411 __ bind(&exit); | |
| 1412 } | 1314 } |
| 1413 | 1315 |
| 1414 | 1316 |
| 1415 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1317 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 1416 Comment cmnt(masm_, "[ TryFinallyStatement"); | 1318 // Exception handling is not supported. |
| 1417 SetStatementPosition(stmt, SKIP_BREAK); | 1319 UNREACHABLE(); |
| 1418 | |
| 1419 // Try finally is compiled by setting up a try-handler on the stack while | |
| 1420 // executing the try body, and removing it again afterwards. | |
| 1421 // | |
| 1422 // The try-finally construct can enter the finally block in three ways: | |
| 1423 // 1. By exiting the try-block normally. This exits the try block, | |
| 1424 // pushes the continuation token and falls through to the finally | |
| 1425 // block. | |
| 1426 // 2. By exiting the try-block with a function-local control flow transfer | |
| 1427 // (break/continue/return). The site of the, e.g., break exits the | |
| 1428 // try block, pushes the continuation token and jumps to the | |
| 1429 // finally block. After the finally block executes, the execution | |
| 1430 // continues based on the continuation token to a block that | |
| 1431 // continues with the control flow transfer. | |
| 1432 // 3. By exiting the try-block with a thrown exception. In the handler, | |
| 1433 // we push the exception and continuation token and jump to the | |
| 1434 // finally block (which will again dispatch based on the token once | |
| 1435 // it is finished). | |
| 1436 | |
| 1437 Label try_entry, handler_entry, finally_entry; | |
| 1438 DeferredCommands deferred(this, &finally_entry); | |
| 1439 | |
| 1440 // Jump to try-handler setup and try-block code. | |
| 1441 __ jmp(&try_entry); | |
| 1442 __ bind(&handler_entry); | |
| 1443 | |
| 1444 // Exception handler code. This code is only executed when an exception | |
| 1445 // is thrown. Record the continuation and jump to the finally block. | |
| 1446 { | |
| 1447 Comment cmnt_handler(masm(), "[ Finally handler"); | |
| 1448 deferred.RecordThrow(); | |
| 1449 } | |
| 1450 | |
| 1451 // Set up try handler. | |
| 1452 __ bind(&try_entry); | |
| 1453 int handler_index = NewHandlerTableEntry(); | |
| 1454 EnterTryBlock(handler_index, &handler_entry, stmt->catch_prediction()); | |
| 1455 { | |
| 1456 Comment cmnt_try(masm(), "[ Try block"); | |
| 1457 TryFinally try_body(this, &deferred); | |
| 1458 Visit(stmt->try_block()); | |
| 1459 } | |
| 1460 ExitTryBlock(handler_index); | |
| 1461 // Execute the finally block on the way out. Clobber the unpredictable | |
| 1462 // value in the result register with one that's safe for GC because the | |
| 1463 // finally block will unconditionally preserve the result register on the | |
| 1464 // stack. | |
| 1465 ClearAccumulator(); | |
| 1466 deferred.EmitFallThrough(); | |
| 1467 // Fall through to the finally block. | |
| 1468 | |
| 1469 // Finally block implementation. | |
| 1470 __ bind(&finally_entry); | |
| 1471 { | |
| 1472 Comment cmnt_finally(masm(), "[ Finally block"); | |
| 1473 OperandStackDepthIncrement(2); // Token and accumulator are on stack. | |
| 1474 EnterFinallyBlock(); | |
| 1475 Visit(stmt->finally_block()); | |
| 1476 ExitFinallyBlock(); | |
| 1477 OperandStackDepthDecrement(2); // Token and accumulator were on stack. | |
| 1478 } | |
| 1479 | |
| 1480 { | |
| 1481 Comment cmnt_deferred(masm(), "[ Post-finally dispatch"); | |
| 1482 deferred.EmitCommands(); // Return to the calling code. | |
| 1483 } | |
| 1484 } | 1320 } |
| 1485 | 1321 |
| 1486 | 1322 |
| 1487 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1323 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 1488 Comment cmnt(masm_, "[ DebuggerStatement"); | 1324 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 1489 SetStatementPosition(stmt); | 1325 SetStatementPosition(stmt); |
| 1490 | 1326 |
| 1491 __ DebugBreak(); | 1327 __ DebugBreak(); |
| 1492 // Ignore the return value. | 1328 // Ignore the return value. |
| 1493 | 1329 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1623 VisitForStackValue(expr->exception()); | 1459 VisitForStackValue(expr->exception()); |
| 1624 SetExpressionPosition(expr); | 1460 SetExpressionPosition(expr); |
| 1625 CallRuntimeWithOperands(Runtime::kThrow); | 1461 CallRuntimeWithOperands(Runtime::kThrow); |
| 1626 // Never returns here. | 1462 // Never returns here. |
| 1627 | 1463 |
| 1628 // Even though this expression doesn't produce a value, we need to simulate | 1464 // Even though this expression doesn't produce a value, we need to simulate |
| 1629 // plugging of the value context to ensure stack depth tracking is in sync. | 1465 // plugging of the value context to ensure stack depth tracking is in sync. |
| 1630 if (context()->IsStackValue()) OperandStackDepthIncrement(1); | 1466 if (context()->IsStackValue()) OperandStackDepthIncrement(1); |
| 1631 } | 1467 } |
| 1632 | 1468 |
| 1633 void FullCodeGenerator::EnterTryBlock( | |
| 1634 int handler_index, Label* handler, | |
| 1635 HandlerTable::CatchPrediction catch_prediction) { | |
| 1636 HandlerTableEntry* entry = &handler_table_[handler_index]; | |
| 1637 entry->range_start = masm()->pc_offset(); | |
| 1638 entry->handler_offset = handler->pos(); | |
| 1639 entry->stack_depth = operand_stack_depth_; | |
| 1640 entry->catch_prediction = catch_prediction; | |
| 1641 | |
| 1642 // We are using the operand stack depth, check for accuracy. | |
| 1643 EmitOperandStackDepthCheck(); | |
| 1644 | |
| 1645 // Push context onto operand stack. | |
| 1646 STATIC_ASSERT(TryBlockConstant::kElementCount == 1); | |
| 1647 PushOperand(context_register()); | |
| 1648 } | |
| 1649 | |
| 1650 | |
| 1651 void FullCodeGenerator::ExitTryBlock(int handler_index) { | |
| 1652 HandlerTableEntry* entry = &handler_table_[handler_index]; | |
| 1653 entry->range_end = masm()->pc_offset(); | |
| 1654 | |
| 1655 // Drop context from operand stack. | |
| 1656 DropOperands(TryBlockConstant::kElementCount); | |
| 1657 } | |
| 1658 | |
| 1659 | 1469 |
| 1660 void FullCodeGenerator::VisitCall(Call* expr) { | 1470 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1661 #ifdef DEBUG | 1471 #ifdef DEBUG |
| 1662 // We want to verify that RecordJSReturnSite gets called on all paths | 1472 // We want to verify that RecordJSReturnSite gets called on all paths |
| 1663 // through this function. Avoid early returns. | 1473 // through this function. Avoid early returns. |
| 1664 expr->return_is_recorded_ = false; | 1474 expr->return_is_recorded_ = false; |
| 1665 #endif | 1475 #endif |
| 1666 | 1476 |
| 1667 Comment cmnt(masm_, (expr->tail_call_mode() == TailCallMode::kAllow) | 1477 Comment cmnt(masm_, (expr->tail_call_mode() == TailCallMode::kAllow) |
| 1668 ? "[ TailCall" | 1478 ? "[ TailCall" |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1769 | 1579 |
| 1770 void FullCodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { | 1580 void FullCodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { |
| 1771 UNREACHABLE(); | 1581 UNREACHABLE(); |
| 1772 } | 1582 } |
| 1773 | 1583 |
| 1774 | 1584 |
| 1775 void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { | 1585 void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { |
| 1776 Visit(expr->expression()); | 1586 Visit(expr->expression()); |
| 1777 } | 1587 } |
| 1778 | 1588 |
| 1779 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( | |
| 1780 int* context_length) { | |
| 1781 // The macros used here must preserve the result register. | |
| 1782 | |
| 1783 // Calculate how many operands to drop to get down to handler block. | |
| 1784 int stack_drop = codegen_->operand_stack_depth_ - GetStackDepthAtTarget(); | |
| 1785 DCHECK_GE(stack_drop, 0); | |
| 1786 | |
| 1787 // Because the handler block contains the context of the finally | |
| 1788 // code, we can restore it directly from there for the finally code | |
| 1789 // rather than iteratively unwinding contexts via their previous | |
| 1790 // links. | |
| 1791 if (*context_length > 0) { | |
| 1792 __ Drop(stack_drop); // Down to the handler block. | |
| 1793 // Restore the context to its dedicated register and the stack. | |
| 1794 STATIC_ASSERT(TryBlockConstant::kElementCount == 1); | |
| 1795 __ Pop(codegen_->context_register()); | |
| 1796 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, | |
| 1797 codegen_->context_register()); | |
| 1798 } else { | |
| 1799 // Down to the handler block and also drop context. | |
| 1800 __ Drop(stack_drop + TryBlockConstant::kElementCount); | |
| 1801 } | |
| 1802 | |
| 1803 // The caller will ignore outputs. | |
| 1804 *context_length = -1; | |
| 1805 return previous_; | |
| 1806 } | |
| 1807 | |
| 1808 void FullCodeGenerator::DeferredCommands::RecordBreak(Statement* target) { | |
| 1809 TokenId token = dispenser_.GetBreakContinueToken(); | |
| 1810 commands_.push_back({kBreak, token, target}); | |
| 1811 EmitJumpToFinally(token); | |
| 1812 } | |
| 1813 | |
| 1814 void FullCodeGenerator::DeferredCommands::RecordContinue(Statement* target) { | |
| 1815 TokenId token = dispenser_.GetBreakContinueToken(); | |
| 1816 commands_.push_back({kContinue, token, target}); | |
| 1817 EmitJumpToFinally(token); | |
| 1818 } | |
| 1819 | |
| 1820 void FullCodeGenerator::DeferredCommands::RecordReturn() { | |
| 1821 if (return_token_ == TokenDispenserForFinally::kInvalidToken) { | |
| 1822 return_token_ = TokenDispenserForFinally::kReturnToken; | |
| 1823 commands_.push_back({kReturn, return_token_, nullptr}); | |
| 1824 } | |
| 1825 EmitJumpToFinally(return_token_); | |
| 1826 } | |
| 1827 | |
| 1828 void FullCodeGenerator::DeferredCommands::RecordThrow() { | |
| 1829 if (throw_token_ == TokenDispenserForFinally::kInvalidToken) { | |
| 1830 throw_token_ = TokenDispenserForFinally::kThrowToken; | |
| 1831 commands_.push_back({kThrow, throw_token_, nullptr}); | |
| 1832 } | |
| 1833 EmitJumpToFinally(throw_token_); | |
| 1834 } | |
| 1835 | |
| 1836 void FullCodeGenerator::DeferredCommands::EmitFallThrough() { | |
| 1837 __ Push(Smi::FromInt(TokenDispenserForFinally::kFallThroughToken)); | |
| 1838 __ Push(result_register()); | |
| 1839 } | |
| 1840 | |
| 1841 void FullCodeGenerator::DeferredCommands::EmitJumpToFinally(TokenId token) { | |
| 1842 __ Push(Smi::FromInt(token)); | |
| 1843 __ Push(result_register()); | |
| 1844 __ jmp(finally_entry_); | |
| 1845 } | |
| 1846 | 1589 |
| 1847 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { | 1590 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { |
| 1848 Expression* sub_expr; | 1591 Expression* sub_expr; |
| 1849 Handle<String> check; | 1592 Handle<String> check; |
| 1850 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { | 1593 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
| 1851 SetExpressionPosition(expr); | 1594 SetExpressionPosition(expr); |
| 1852 EmitLiteralCompareTypeof(expr, sub_expr, check); | 1595 EmitLiteralCompareTypeof(expr, sub_expr, check); |
| 1853 return true; | 1596 return true; |
| 1854 } | 1597 } |
| 1855 | 1598 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1995 return info_->has_simple_parameters(); | 1738 return info_->has_simple_parameters(); |
| 1996 } | 1739 } |
| 1997 | 1740 |
| 1998 FunctionLiteral* FullCodeGenerator::literal() const { return info_->literal(); } | 1741 FunctionLiteral* FullCodeGenerator::literal() const { return info_->literal(); } |
| 1999 | 1742 |
| 2000 #undef __ | 1743 #undef __ |
| 2001 | 1744 |
| 2002 | 1745 |
| 2003 } // namespace internal | 1746 } // namespace internal |
| 2004 } // namespace v8 | 1747 } // namespace v8 |
| OLD | NEW |