Commit 8f1f1cb1 authored by neis's avatar neis Committed by Commit bot

Move catch prediction into frontend and make it aware of rethrows.

This solves an issue with throws inside for-of always being marked as caught.

BUG=v8:5183

Review-Url: https://codereview.chromium.org/2146493002
Cr-Commit-Position: refs/heads/master@{#37686}
parent ea90556a
...@@ -20,7 +20,8 @@ class AstNumberingVisitor final : public AstVisitor { ...@@ -20,7 +20,8 @@ class AstNumberingVisitor final : public AstVisitor {
yield_count_(0), yield_count_(0),
properties_(zone), properties_(zone),
slot_cache_(zone), slot_cache_(zone),
dont_optimize_reason_(kNoReason) { dont_optimize_reason_(kNoReason),
catch_predicted_(false) {
InitializeAstVisitor(isolate); InitializeAstVisitor(isolate);
} }
...@@ -80,6 +81,7 @@ class AstNumberingVisitor final : public AstVisitor { ...@@ -80,6 +81,7 @@ class AstNumberingVisitor final : public AstVisitor {
// The slot cache allows us to reuse certain feedback vector slots. // The slot cache allows us to reuse certain feedback vector slots.
FeedbackVectorSlotCache slot_cache_; FeedbackVectorSlotCache slot_cache_;
BailoutReason dont_optimize_reason_; BailoutReason dont_optimize_reason_;
bool catch_predicted_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor); DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor);
...@@ -297,7 +299,17 @@ void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) { ...@@ -297,7 +299,17 @@ void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) {
void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) { void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
IncrementNodeCount(); IncrementNodeCount();
DisableCrankshaft(kTryCatchStatement); DisableCrankshaft(kTryCatchStatement);
Visit(node->try_block()); {
const bool old_catch_predicted = catch_predicted_;
// If the node's clear_pending_message flag is unset, we assume that the
// catch block is a ReThrow and hence predict uncaught (unless caught by
// outer handlers). Otherwise, we predict caught.
const bool not_rethrow = node->clear_pending_message();
catch_predicted_ = catch_predicted_ || not_rethrow;
node->set_catch_predicted(catch_predicted_);
Visit(node->try_block());
catch_predicted_ = old_catch_predicted;
}
Visit(node->catch_block()); Visit(node->catch_block());
} }
...@@ -305,6 +317,9 @@ void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) { ...@@ -305,6 +317,9 @@ void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) { void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) {
IncrementNodeCount(); IncrementNodeCount();
DisableCrankshaft(kTryFinallyStatement); DisableCrankshaft(kTryFinallyStatement);
// We can't know whether the finally block will override ("catch") an
// exception thrown in the try block, so we just adopt the outer prediction.
node->set_catch_predicted(catch_predicted_);
Visit(node->try_block()); Visit(node->try_block());
Visit(node->finally_block()); Visit(node->finally_block());
} }
......
...@@ -15,7 +15,7 @@ class Zone; ...@@ -15,7 +15,7 @@ class Zone;
namespace AstNumbering { namespace AstNumbering {
// Assign type feedback IDs, bailout IDs, and generator yield IDs to an AST node // Assign type feedback IDs, bailout IDs, and generator yield IDs to an AST node
// tree. // tree; perform catch prediction for TryStatements.
bool Renumber(Isolate* isolate, Zone* zone, FunctionLiteral* function); bool Renumber(Isolate* isolate, Zone* zone, FunctionLiteral* function);
} }
......
...@@ -1140,12 +1140,26 @@ class TryStatement : public Statement { ...@@ -1140,12 +1140,26 @@ class TryStatement : public Statement {
Block* try_block() const { return try_block_; } Block* try_block() const { return try_block_; }
void set_try_block(Block* b) { try_block_ = b; } void set_try_block(Block* b) { try_block_ = b; }
// Prediction of whether exceptions thrown into the handler for this try block
// will be caught.
//
// This is set in ast-numbering and later compiled into the code's handler
// table. The runtime uses this information to implement a feature that
// notifies the debugger when an uncaught exception is thrown, _before_ the
// exception propagates to the top.
//
// Since it's generally undecidable whether an exception will be caught, our
// prediction is only an approximation.
bool catch_predicted() const { return catch_predicted_; }
void set_catch_predicted(bool b) { catch_predicted_ = b; }
protected: protected:
TryStatement(Zone* zone, Block* try_block, int pos) TryStatement(Zone* zone, Block* try_block, int pos)
: Statement(zone, pos), try_block_(try_block) {} : Statement(zone, pos), try_block_(try_block), catch_predicted_(false) {}
private: private:
Block* try_block_; Block* try_block_;
bool catch_predicted_;
}; };
......
...@@ -1431,7 +1431,7 @@ void AstPrinter::VisitForOfStatement(ForOfStatement* node) { ...@@ -1431,7 +1431,7 @@ void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
IndentedScope indent(this, "TRY CATCH", node->position()); IndentedScope indent(this, "TRY CATCH", node->position());
PrintIndentedVisit("TRY", node->try_block()); PrintTryStatement(node);
PrintLiteralWithModeIndented("CATCHVAR", PrintLiteralWithModeIndented("CATCHVAR",
node->variable(), node->variable(),
node->variable()->name()); node->variable()->name());
...@@ -1441,10 +1441,15 @@ void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { ...@@ -1441,10 +1441,15 @@ void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
IndentedScope indent(this, "TRY FINALLY", node->position()); IndentedScope indent(this, "TRY FINALLY", node->position());
PrintIndentedVisit("TRY", node->try_block()); PrintTryStatement(node);
PrintIndentedVisit("FINALLY", node->finally_block()); PrintIndentedVisit("FINALLY", node->finally_block());
} }
void AstPrinter::PrintTryStatement(TryStatement* node) {
PrintIndentedVisit("TRY", node->try_block());
PrintIndented("CATCH PREDICTED");
Print(" %d\n", node->catch_predicted());
}
void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) { void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
IndentedScope indent(this, "DEBUGGER", node->position()); IndentedScope indent(this, "DEBUGGER", node->position());
......
...@@ -131,6 +131,7 @@ class AstPrinter: public PrettyPrinter { ...@@ -131,6 +131,7 @@ class AstPrinter: public PrettyPrinter {
Handle<Object> value); Handle<Object> value);
void PrintLabelsIndented(ZoneList<const AstRawString*>* labels); void PrintLabelsIndented(ZoneList<const AstRawString*>* labels);
void PrintProperties(ZoneList<ObjectLiteral::Property*>* properties); void PrintProperties(ZoneList<ObjectLiteral::Property*>* properties);
void PrintTryStatement(TryStatement* try_statement);
void inc_indent() { indent_++; } void inc_indent() { indent_++; }
void dec_indent() { indent_--; } void dec_indent() { indent_--; }
......
...@@ -124,9 +124,9 @@ void FullCodeGenerator::PopulateHandlerTable(Handle<Code> code) { ...@@ -124,9 +124,9 @@ void FullCodeGenerator::PopulateHandlerTable(Handle<Code> code) {
Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray( Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
HandlerTable::LengthForRange(handler_table_size), TENURED)); HandlerTable::LengthForRange(handler_table_size), TENURED));
for (int i = 0; i < handler_table_size; ++i) { for (int i = 0; i < handler_table_size; ++i) {
HandlerTable::CatchPrediction prediction = HandlerTable::CatchPrediction prediction = handler_table_[i].catch_predicted
handler_table_[i].try_catch_depth > 0 ? HandlerTable::CAUGHT ? HandlerTable::CAUGHT
: HandlerTable::UNCAUGHT; : HandlerTable::UNCAUGHT;
table->SetRangeStart(i, handler_table_[i].range_start); table->SetRangeStart(i, handler_table_[i].range_start);
table->SetRangeEnd(i, handler_table_[i].range_end); table->SetRangeEnd(i, handler_table_[i].range_end);
table->SetRangeHandler(i, handler_table_[i].handler_offset, prediction); table->SetRangeHandler(i, handler_table_[i].handler_offset, prediction);
...@@ -1316,15 +1316,13 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { ...@@ -1316,15 +1316,13 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
// Try block code. Sets up the exception handler chain. // Try block code. Sets up the exception handler chain.
__ bind(&try_entry); __ bind(&try_entry);
try_catch_depth_++;
int handler_index = NewHandlerTableEntry(); int handler_index = NewHandlerTableEntry();
EnterTryBlock(handler_index, &handler_entry); EnterTryBlock(handler_index, &handler_entry, stmt->catch_predicted());
{ {
Comment cmnt_try(masm(), "[ Try block"); Comment cmnt_try(masm(), "[ Try block");
Visit(stmt->try_block()); Visit(stmt->try_block());
} }
ExitTryBlock(handler_index); ExitTryBlock(handler_index);
try_catch_depth_--;
__ bind(&exit); __ bind(&exit);
} }
...@@ -1368,7 +1366,7 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { ...@@ -1368,7 +1366,7 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// Set up try handler. // Set up try handler.
__ bind(&try_entry); __ bind(&try_entry);
int handler_index = NewHandlerTableEntry(); int handler_index = NewHandlerTableEntry();
EnterTryBlock(handler_index, &handler_entry); EnterTryBlock(handler_index, &handler_entry, stmt->catch_predicted());
{ {
Comment cmnt_try(masm(), "[ Try block"); Comment cmnt_try(masm(), "[ Try block");
TryFinally try_body(this, &deferred); TryFinally try_body(this, &deferred);
...@@ -1551,13 +1549,13 @@ void FullCodeGenerator::VisitThrow(Throw* expr) { ...@@ -1551,13 +1549,13 @@ void FullCodeGenerator::VisitThrow(Throw* expr) {
if (context()->IsStackValue()) OperandStackDepthIncrement(1); if (context()->IsStackValue()) OperandStackDepthIncrement(1);
} }
void FullCodeGenerator::EnterTryBlock(int handler_index, Label* handler,
void FullCodeGenerator::EnterTryBlock(int handler_index, Label* handler) { bool catch_predicted) {
HandlerTableEntry* entry = &handler_table_[handler_index]; HandlerTableEntry* entry = &handler_table_[handler_index];
entry->range_start = masm()->pc_offset(); entry->range_start = masm()->pc_offset();
entry->handler_offset = handler->pos(); entry->handler_offset = handler->pos();
entry->try_catch_depth = try_catch_depth_;
entry->stack_depth = operand_stack_depth_; entry->stack_depth = operand_stack_depth_;
entry->catch_predicted = catch_predicted;
// We are using the operand stack depth, check for accuracy. // We are using the operand stack depth, check for accuracy.
EmitOperandStackDepthCheck(); EmitOperandStackDepthCheck();
......
...@@ -37,7 +37,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -37,7 +37,6 @@ class FullCodeGenerator: public AstVisitor {
scope_(info->scope()), scope_(info->scope()),
nesting_stack_(NULL), nesting_stack_(NULL),
loop_depth_(0), loop_depth_(0),
try_catch_depth_(0),
operand_stack_depth_(0), operand_stack_depth_(0),
globals_(NULL), globals_(NULL),
context_(NULL), context_(NULL),
...@@ -687,7 +686,7 @@ class FullCodeGenerator: public AstVisitor { ...@@ -687,7 +686,7 @@ class FullCodeGenerator: public AstVisitor {
void RecordPosition(int pos); void RecordPosition(int pos);
// Non-local control flow support. // Non-local control flow support.
void EnterTryBlock(int handler_index, Label* handler); void EnterTryBlock(int handler_index, Label* handler, bool catch_predicted);
void ExitTryBlock(int handler_index); void ExitTryBlock(int handler_index);
void EnterFinallyBlock(); void EnterFinallyBlock();
void ExitFinallyBlock(); void ExitFinallyBlock();
...@@ -774,7 +773,7 @@ class FullCodeGenerator: public AstVisitor { ...@@ -774,7 +773,7 @@ class FullCodeGenerator: public AstVisitor {
unsigned range_end; unsigned range_end;
unsigned handler_offset; unsigned handler_offset;
int stack_depth; int stack_depth;
int try_catch_depth; bool catch_predicted;
}; };
class ExpressionContext BASE_EMBEDDED { class ExpressionContext BASE_EMBEDDED {
...@@ -969,7 +968,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -969,7 +968,6 @@ class FullCodeGenerator: public AstVisitor {
Label return_label_; Label return_label_;
NestedStatement* nesting_stack_; NestedStatement* nesting_stack_;
int loop_depth_; int loop_depth_;
int try_catch_depth_;
int operand_stack_depth_; int operand_stack_depth_;
ZoneList<Handle<Object> >* globals_; ZoneList<Handle<Object> >* globals_;
const ExpressionContext* context_; const ExpressionContext* context_;
......
...@@ -295,12 +295,7 @@ class BytecodeGenerator::ControlScopeForTryCatch final ...@@ -295,12 +295,7 @@ class BytecodeGenerator::ControlScopeForTryCatch final
public: public:
ControlScopeForTryCatch(BytecodeGenerator* generator, ControlScopeForTryCatch(BytecodeGenerator* generator,
TryCatchBuilder* try_catch_builder) TryCatchBuilder* try_catch_builder)
: ControlScope(generator) { : ControlScope(generator) {}
generator->try_catch_nesting_level_++;
}
virtual ~ControlScopeForTryCatch() {
generator()->try_catch_nesting_level_--;
}
protected: protected:
bool Execute(Command command, Statement* statement) override { bool Execute(Command command, Statement* statement) override {
...@@ -326,12 +321,7 @@ class BytecodeGenerator::ControlScopeForTryFinally final ...@@ -326,12 +321,7 @@ class BytecodeGenerator::ControlScopeForTryFinally final
DeferredCommands* commands) DeferredCommands* commands)
: ControlScope(generator), : ControlScope(generator),
try_finally_builder_(try_finally_builder), try_finally_builder_(try_finally_builder),
commands_(commands) { commands_(commands) {}
generator->try_finally_nesting_level_++;
}
virtual ~ControlScopeForTryFinally() {
generator()->try_finally_nesting_level_--;
}
protected: protected:
bool Execute(Command command, Statement* statement) override { bool Execute(Command command, Statement* statement) override {
...@@ -557,9 +547,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) ...@@ -557,9 +547,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
execution_result_(nullptr), execution_result_(nullptr),
register_allocator_(nullptr), register_allocator_(nullptr),
generator_resume_points_(info->literal()->yield_count(), info->zone()), generator_resume_points_(info->literal()->yield_count(), info->zone()),
generator_state_(), generator_state_() {
try_catch_nesting_level_(0),
try_finally_nesting_level_(0) {
InitializeAstVisitor(isolate()); InitializeAstVisitor(isolate());
} }
...@@ -1189,7 +1177,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { ...@@ -1189,7 +1177,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
} }
void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
TryCatchBuilder try_control_builder(builder()); TryCatchBuilder try_control_builder(builder(), stmt->catch_predicted());
Register no_reg; Register no_reg;
// Preserve the context in a dedicated register, so that it can be restored // Preserve the context in a dedicated register, so that it can be restored
...@@ -1225,7 +1213,7 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { ...@@ -1225,7 +1213,7 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
} }
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
TryFinallyBuilder try_control_builder(builder(), IsInsideTryCatch()); TryFinallyBuilder try_control_builder(builder(), stmt->catch_predicted());
Register no_reg; Register no_reg;
// We keep a record of all paths that enter the finally-block to be able to // We keep a record of all paths that enter the finally-block to be able to
......
...@@ -165,10 +165,6 @@ class BytecodeGenerator final : public AstVisitor { ...@@ -165,10 +165,6 @@ class BytecodeGenerator final : public AstVisitor {
void RecordStoreToRegister(Register reg); void RecordStoreToRegister(Register reg);
Register LoadFromAliasedRegister(Register reg); Register LoadFromAliasedRegister(Register reg);
// Methods for tracking try-block nesting.
bool IsInsideTryCatch() const { return try_catch_nesting_level_ > 0; }
bool IsInsideTryFinally() const { return try_finally_nesting_level_ > 0; }
// Initialize an array of temporary registers with consecutive registers. // Initialize an array of temporary registers with consecutive registers.
template <size_t N> template <size_t N>
void InitializeWithConsecutiveRegisters(Register (&registers)[N]); void InitializeWithConsecutiveRegisters(Register (&registers)[N]);
...@@ -215,8 +211,6 @@ class BytecodeGenerator final : public AstVisitor { ...@@ -215,8 +211,6 @@ class BytecodeGenerator final : public AstVisitor {
RegisterAllocationScope* register_allocator_; RegisterAllocationScope* register_allocator_;
ZoneVector<BytecodeLabel> generator_resume_points_; ZoneVector<BytecodeLabel> generator_resume_points_;
Register generator_state_; Register generator_state_;
int try_catch_nesting_level_;
int try_finally_nesting_level_;
}; };
} // namespace interpreter } // namespace interpreter
......
...@@ -142,7 +142,7 @@ void TryCatchBuilder::EndTry() { ...@@ -142,7 +142,7 @@ void TryCatchBuilder::EndTry() {
builder()->MarkTryEnd(handler_id_); builder()->MarkTryEnd(handler_id_);
builder()->Jump(&exit_); builder()->Jump(&exit_);
builder()->Bind(&handler_); builder()->Bind(&handler_);
builder()->MarkHandler(handler_id_, true); builder()->MarkHandler(handler_id_, catch_predicted_);
} }
...@@ -167,7 +167,7 @@ void TryFinallyBuilder::EndTry() { ...@@ -167,7 +167,7 @@ void TryFinallyBuilder::EndTry() {
void TryFinallyBuilder::BeginHandler() { void TryFinallyBuilder::BeginHandler() {
builder()->Bind(&handler_); builder()->Bind(&handler_);
builder()->MarkHandler(handler_id_, will_catch_); builder()->MarkHandler(handler_id_, catch_predicted_);
} }
......
...@@ -144,8 +144,10 @@ class SwitchBuilder final : public BreakableControlFlowBuilder { ...@@ -144,8 +144,10 @@ class SwitchBuilder final : public BreakableControlFlowBuilder {
// A class to help with co-ordinating control flow in try-catch statements. // A class to help with co-ordinating control flow in try-catch statements.
class TryCatchBuilder final : public ControlFlowBuilder { class TryCatchBuilder final : public ControlFlowBuilder {
public: public:
explicit TryCatchBuilder(BytecodeArrayBuilder* builder) explicit TryCatchBuilder(BytecodeArrayBuilder* builder, bool catch_predicted)
: ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {} : ControlFlowBuilder(builder),
handler_id_(builder->NewHandlerEntry()),
catch_predicted_(catch_predicted) {}
void BeginTry(Register context); void BeginTry(Register context);
void EndTry(); void EndTry();
...@@ -153,6 +155,7 @@ class TryCatchBuilder final : public ControlFlowBuilder { ...@@ -153,6 +155,7 @@ class TryCatchBuilder final : public ControlFlowBuilder {
private: private:
int handler_id_; int handler_id_;
bool catch_predicted_;
BytecodeLabel handler_; BytecodeLabel handler_;
BytecodeLabel exit_; BytecodeLabel exit_;
}; };
...@@ -161,11 +164,12 @@ class TryCatchBuilder final : public ControlFlowBuilder { ...@@ -161,11 +164,12 @@ class TryCatchBuilder final : public ControlFlowBuilder {
// A class to help with co-ordinating control flow in try-finally statements. // A class to help with co-ordinating control flow in try-finally statements.
class TryFinallyBuilder final : public ControlFlowBuilder { class TryFinallyBuilder final : public ControlFlowBuilder {
public: public:
explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, bool will_catch) explicit TryFinallyBuilder(BytecodeArrayBuilder* builder,
bool catch_predicted)
: ControlFlowBuilder(builder), : ControlFlowBuilder(builder),
handler_id_(builder->NewHandlerEntry()), handler_id_(builder->NewHandlerEntry()),
finalization_sites_(builder->zone()), catch_predicted_(catch_predicted),
will_catch_(will_catch) {} finalization_sites_(builder->zone()) {}
void BeginTry(Register context); void BeginTry(Register context);
void LeaveTry(); void LeaveTry();
...@@ -176,15 +180,11 @@ class TryFinallyBuilder final : public ControlFlowBuilder { ...@@ -176,15 +180,11 @@ class TryFinallyBuilder final : public ControlFlowBuilder {
private: private:
int handler_id_; int handler_id_;
bool catch_predicted_;
BytecodeLabel handler_; BytecodeLabel handler_;
// Unbound labels that identify jumps to the finally block in the code. // Unbound labels that identify jumps to the finally block in the code.
ZoneVector<BytecodeLabel> finalization_sites_; ZoneVector<BytecodeLabel> finalization_sites_;
// Conservative prediction of whether exceptions thrown into the handler for
// this finally block will be caught. Note that such a prediction depends on
// whether this try-finally is nested inside a surrounding try-catch.
bool will_catch_;
}; };
} // namespace interpreter } // namespace interpreter
......
...@@ -734,8 +734,7 @@ class Isolate { ...@@ -734,8 +734,7 @@ class Isolate {
// Tries to predict whether an exception will be caught. Note that this can // Tries to predict whether an exception will be caught. Note that this can
// only produce an estimate, because it is undecidable whether a finally // only produce an estimate, because it is undecidable whether a finally
// clause will consume or re-throw an exception. We conservatively assume any // clause will consume or re-throw an exception.
// finally clause will behave as if the exception were consumed.
enum CatchType { NOT_CAUGHT, CAUGHT_BY_JAVASCRIPT, CAUGHT_BY_EXTERNAL }; enum CatchType { NOT_CAUGHT, CAUGHT_BY_JAVASCRIPT, CAUGHT_BY_EXTERNAL };
CatchType PredictExceptionCatcher(); CatchType PredictExceptionCatcher();
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
Debug = debug.Debug
let error = false;
let uncaught;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Exception) return;
try {
uncaught = event_data.uncaught();
} catch (e) {
error = true;
}
}
Debug.setBreakOnException();
Debug.setListener(listener);
function assertCaught(f) {
try {f()} finally {
assertFalse(uncaught);
return;
}
}
function assertUncaught(f) {
try {f()} finally {
assertTrue(uncaught);
return;
}
}
assertUncaught(() => {
for (var a of [1, 2, 3]) {
throw a
}
});
assertUncaught(() => {
for (var a of [1, 2, 3]) {
try {throw a} finally {}
}
});
assertCaught(() => {
for (var a of [1, 2, 3]) {
try {
try {throw a} finally {}
} catch(_) {}
}
});
assertCaught(() => {
try {
for (var a of [1, 2, 3]) {
try {throw a} finally {}
}
} catch(_) {}
});
assertFalse(error);
...@@ -92,6 +92,9 @@ ...@@ -92,6 +92,9 @@
'debug-set-variable-value': [PASS, NO_VARIANTS], 'debug-set-variable-value': [PASS, NO_VARIANTS],
'es6/debug-evaluate-blockscopes': [PASS, NO_VARIANTS], 'es6/debug-evaluate-blockscopes': [PASS, NO_VARIANTS],
# TODO(mstarzinger): Use frontend's catch prediction in Turbofan.
'debug-exceptions': [PASS, NO_VARIANTS],
# Assumptions about optimization need investigation in TurboFan. # Assumptions about optimization need investigation in TurboFan.
'regress-sync-optimized-lists': [PASS, NO_VARIANTS], 'regress-sync-optimized-lists': [PASS, NO_VARIANTS],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment