Commit 82716f1c authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[interpreter] Implement exception handler table building.

This implements a first version of exception handler table construction
within the interpreter. Note that the local control flow for try-catch
and try-finally statements is still off, and also stack unwinding does
not yet respect interpreter frames. But generated handler tables should
be populated correctly already.

R=oth@chromium.org
BUG=v8:4674
LOG=n

Review URL: https://codereview.chromium.org/1607433005

Cr-Commit-Position: refs/heads/master@{#33400}
parent 98cd565f
...@@ -1104,6 +1104,8 @@ source_set("v8_base") { ...@@ -1104,6 +1104,8 @@ source_set("v8_base") {
"src/interpreter/constant-array-builder.h", "src/interpreter/constant-array-builder.h",
"src/interpreter/control-flow-builders.cc", "src/interpreter/control-flow-builders.cc",
"src/interpreter/control-flow-builders.h", "src/interpreter/control-flow-builders.h",
"src/interpreter/handler-table-builder.cc",
"src/interpreter/handler-table-builder.h",
"src/interpreter/interpreter.cc", "src/interpreter/interpreter.cc",
"src/interpreter/interpreter.h", "src/interpreter/interpreter.h",
"src/isolate-inl.h", "src/isolate-inl.h",
......
...@@ -70,6 +70,7 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) ...@@ -70,6 +70,7 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
bytecodes_(zone), bytecodes_(zone),
bytecode_generated_(false), bytecode_generated_(false),
constant_array_builder_(isolate, zone), constant_array_builder_(isolate, zone),
handler_table_builder_(isolate, zone),
last_block_end_(0), last_block_end_(0),
last_bytecode_start_(~0), last_bytecode_start_(~0),
exit_seen_in_block_(false), exit_seen_in_block_(false),
...@@ -152,9 +153,11 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { ...@@ -152,9 +153,11 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
Factory* factory = isolate_->factory(); Factory* factory = isolate_->factory();
Handle<FixedArray> constant_pool = Handle<FixedArray> constant_pool =
constant_array_builder()->ToFixedArray(factory); constant_array_builder()->ToFixedArray(factory);
Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable();
Handle<BytecodeArray> output = Handle<BytecodeArray> output =
factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
parameter_count(), constant_pool); parameter_count(), constant_pool);
output->set_handler_table(*handler_table);
bytecode_generated_ = true; bytecode_generated_ = true;
return output; return output;
} }
...@@ -1010,6 +1013,28 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { ...@@ -1010,6 +1013,28 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(int handler_id,
bool will_catch) {
handler_table_builder()->SetHandlerTarget(handler_id, bytecodes()->size());
handler_table_builder()->SetPrediction(handler_id, will_catch);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
Register context) {
handler_table_builder()->SetTryRegionStart(handler_id, bytecodes()->size());
handler_table_builder()->SetContextRegister(handler_id, context);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
handler_table_builder()->SetTryRegionEnd(handler_id, bytecodes()->size());
return *this;
}
void BytecodeArrayBuilder::LeaveBasicBlock() { void BytecodeArrayBuilder::LeaveBasicBlock() {
last_block_end_ = bytecodes()->size(); last_block_end_ = bytecodes()->size();
exit_seen_in_block_ = false; exit_seen_in_block_ = false;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#include "src/interpreter/constant-array-builder.h" #include "src/interpreter/constant-array-builder.h"
#include "src/interpreter/handler-table-builder.h"
#include "src/zone-containers.h" #include "src/zone-containers.h"
namespace v8 { namespace v8 {
...@@ -225,6 +226,15 @@ class BytecodeArrayBuilder final { ...@@ -225,6 +226,15 @@ class BytecodeArrayBuilder final {
Register cache_type_array_pair); Register cache_type_array_pair);
BytecodeArrayBuilder& ForInStep(Register index); BytecodeArrayBuilder& ForInStep(Register index);
// Exception handling.
BytecodeArrayBuilder& MarkHandler(int handler_id, bool will_catch);
BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
BytecodeArrayBuilder& MarkTryEnd(int handler_id);
// Creates a new handler table entry and returns a {hander_id} identifying the
// entry, so that it can be referenced by above exception handling support.
int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
// Accessors // Accessors
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
...@@ -315,12 +325,16 @@ class BytecodeArrayBuilder final { ...@@ -315,12 +325,16 @@ class BytecodeArrayBuilder final {
const ConstantArrayBuilder* constant_array_builder() const { const ConstantArrayBuilder* constant_array_builder() const {
return &constant_array_builder_; return &constant_array_builder_;
} }
HandlerTableBuilder* handler_table_builder() {
return &handler_table_builder_;
}
Isolate* isolate_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
ZoneVector<uint8_t> bytecodes_; ZoneVector<uint8_t> bytecodes_;
bool bytecode_generated_; bool bytecode_generated_;
ConstantArrayBuilder constant_array_builder_; ConstantArrayBuilder constant_array_builder_;
HandlerTableBuilder handler_table_builder_;
size_t last_block_end_; size_t last_block_end_;
size_t last_bytecode_start_; size_t last_bytecode_start_;
bool exit_seen_in_block_; bool exit_seen_in_block_;
......
...@@ -899,21 +899,65 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { ...@@ -899,21 +899,65 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
if (FLAG_ignition_fake_try_catch) { TryCatchBuilder try_control_builder(builder());
Visit(stmt->try_block()); if (!FLAG_ignition_fake_try_catch) UNIMPLEMENTED();
return;
} // Preserve the context in a dedicated register, so that it can be restored
UNIMPLEMENTED(); // when the handler is entered by the stack-unwinding machinery.
// TODO(mstarzinger): Be smarter about register allocation.
Register context = register_allocator()->NewRegister();
// Evaluate the try-block inside a control scope. This simulates a handler
// that is intercepting 'throw' control commands.
try_control_builder.BeginTry(context);
// TODO(mstarzinger): Control scope is missing!
Visit(stmt->try_block());
try_control_builder.EndTry();
// Clear message object as we enter the catch block.
// TODO(mstarzinger): Implement this!
// Create a catch scope that binds the exception.
register_allocator()->PrepareForConsecutiveAllocations(3);
Register name = register_allocator()->NextConsecutiveRegister();
Register exception = register_allocator()->NextConsecutiveRegister();
Register closure = register_allocator()->NextConsecutiveRegister();
builder()
->StoreAccumulatorInRegister(exception)
.LoadLiteral(stmt->variable()->name())
.StoreAccumulatorInRegister(name);
VisitFunctionClosureForContext();
builder()->StoreAccumulatorInRegister(closure).CallRuntime(
Runtime::kPushCatchContext, name, 3);
// Evaluate the catch-block.
Visit(stmt->catch_block());
try_control_builder.EndCatch();
} }
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
if (FLAG_ignition_fake_try_catch) { TryFinallyBuilder try_control_builder(builder());
Visit(stmt->try_block()); if (!FLAG_ignition_fake_try_catch) UNIMPLEMENTED();
Visit(stmt->finally_block());
return; // Preserve the context in a dedicated register, so that it can be restored
} // when the handler is entered by the stack-unwinding machinery.
UNIMPLEMENTED(); // TODO(mstarzinger): Be smarter about register allocation.
Register context = register_allocator()->NewRegister();
// Evaluate the try-block inside a control scope. This simulates a handler
// that is intercepting all control commands.
try_control_builder.BeginTry(context);
// TODO(mstarzinger): Control scope is missing!
Visit(stmt->try_block());
try_control_builder.EndTry();
// Clear message object as we enter the finally block.
// TODO(mstarzinger): Implement this!
// Evaluate the finally-block.
Visit(stmt->finally_block());
try_control_builder.EndFinally();
} }
......
...@@ -137,6 +137,39 @@ void SwitchBuilder::SetCaseTarget(int index) { ...@@ -137,6 +137,39 @@ void SwitchBuilder::SetCaseTarget(int index) {
builder()->Bind(&site); builder()->Bind(&site);
} }
void TryCatchBuilder::BeginTry(Register context) {
builder()->MarkTryBegin(handler_id_, context);
}
void TryCatchBuilder::EndTry() {
builder()->MarkTryEnd(handler_id_);
builder()->Jump(&exit_);
builder()->Bind(&handler_);
builder()->MarkHandler(handler_id_, true);
}
void TryCatchBuilder::EndCatch() { builder()->Bind(&exit_); }
void TryFinallyBuilder::BeginTry(Register context) {
builder()->MarkTryBegin(handler_id_, context);
}
void TryFinallyBuilder::EndTry() {
builder()->MarkTryEnd(handler_id_);
builder()->Bind(&handler_);
builder()->MarkHandler(handler_id_, false);
}
void TryFinallyBuilder::EndFinally() {
// Nothing to be done here.
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -144,6 +144,39 @@ class SwitchBuilder final : public BreakableControlFlowBuilder { ...@@ -144,6 +144,39 @@ class SwitchBuilder final : public BreakableControlFlowBuilder {
ZoneVector<BytecodeLabel> case_sites_; ZoneVector<BytecodeLabel> case_sites_;
}; };
// A class to help with co-ordinating control flow in try-catch statements.
class TryCatchBuilder final : public ControlFlowBuilder {
public:
explicit TryCatchBuilder(BytecodeArrayBuilder* builder)
: ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
void BeginTry(Register context);
void EndTry();
void EndCatch();
private:
int handler_id_;
BytecodeLabel handler_;
BytecodeLabel exit_;
};
// A class to help with co-ordinating control flow in try-finally statements.
class TryFinallyBuilder final : public ControlFlowBuilder {
public:
explicit TryFinallyBuilder(BytecodeArrayBuilder* builder)
: ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
void BeginTry(Register context);
void EndTry();
void EndFinally();
private:
int handler_id_;
BytecodeLabel handler_;
};
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
// 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.
#include "src/interpreter/handler-table-builder.h"
#include "src/factory.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
namespace interpreter {
HandlerTableBuilder::HandlerTableBuilder(Isolate* isolate, Zone* zone)
: isolate_(isolate), entries_(zone) {}
Handle<HandlerTable> HandlerTableBuilder::ToHandlerTable() {
int handler_table_size = static_cast<int>(entries_.size());
Handle<HandlerTable> table =
Handle<HandlerTable>::cast(isolate_->factory()->NewFixedArray(
HandlerTable::LengthForRange(handler_table_size), TENURED));
for (int i = 0; i < handler_table_size; ++i) {
Entry& entry = entries_[i];
HandlerTable::CatchPrediction pred =
entry.will_catch ? HandlerTable::CAUGHT : HandlerTable::UNCAUGHT;
table->SetRangeStart(i, static_cast<int>(entry.offset_start));
table->SetRangeEnd(i, static_cast<int>(entry.offset_end));
table->SetRangeHandler(i, static_cast<int>(entry.offset_target), pred);
table->SetRangeDepth(i, entry.context.index());
}
return table;
}
int HandlerTableBuilder::NewHandlerEntry() {
int handler_id = static_cast<int>(entries_.size());
Entry entry = {0, 0, 0, Register(), false};
entries_.push_back(entry);
return handler_id;
}
void HandlerTableBuilder::SetTryRegionStart(int handler_id, size_t offset) {
DCHECK(Smi::IsValid(offset)); // Encoding of handler table requires this.
entries_[handler_id].offset_start = offset;
}
void HandlerTableBuilder::SetTryRegionEnd(int handler_id, size_t offset) {
DCHECK(Smi::IsValid(offset)); // Encoding of handler table requires this.
entries_[handler_id].offset_end = offset;
}
void HandlerTableBuilder::SetHandlerTarget(int handler_id, size_t offset) {
DCHECK(Smi::IsValid(offset)); // Encoding of handler table requires this.
entries_[handler_id].offset_target = offset;
}
void HandlerTableBuilder::SetPrediction(int handler_id, bool will_catch) {
entries_[handler_id].will_catch = will_catch;
}
void HandlerTableBuilder::SetContextRegister(int handler_id, Register reg) {
entries_[handler_id].context = reg;
}
} // namespace interpreter
} // namespace internal
} // namespace v8
// 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.
#ifndef V8_INTERPRETER_HANDLER_TABLE_BUILDER_H_
#define V8_INTERPRETER_HANDLER_TABLE_BUILDER_H_
#include "src/handles.h"
#include "src/interpreter/bytecodes.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
class HandlerTable;
class Isolate;
namespace interpreter {
// A helper class for constructing exception handler tables for the interpreter.
class HandlerTableBuilder final BASE_EMBEDDED {
public:
HandlerTableBuilder(Isolate* isolate, Zone* zone);
// Builds the actual handler table by copying the current values into a heap
// object. Any further mutations to the builder won't be reflected.
Handle<HandlerTable> ToHandlerTable();
// Creates a new handler table entry and returns a {hander_id} identifying the
// entry, so that it can be referenced by below setter functions.
int NewHandlerEntry();
// Setter functions that modify certain values within the handler table entry
// being referenced by the given {handler_id}. All values will be encoded by
// the resulting {HandlerTable} class when copied into the heap.
void SetTryRegionStart(int handler_id, size_t offset);
void SetTryRegionEnd(int handler_id, size_t offset);
void SetHandlerTarget(int handler_id, size_t offset);
void SetPrediction(int handler_id, bool will_catch);
void SetContextRegister(int handler_id, Register reg);
private:
struct Entry {
size_t offset_start; // Bytecode offset starting try-region.
size_t offset_end; // Bytecode offset ending try-region.
size_t offset_target; // Bytecode offset of handler target.
Register context; // Register holding context for handler.
bool will_catch; // Optimistic prediction for handler.
};
Isolate* isolate_;
ZoneVector<Entry> entries_;
DISALLOW_COPY_AND_ASSIGN(HandlerTableBuilder);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_HANDLER_TABLE_BUILDER_H_
...@@ -15012,8 +15012,17 @@ void BytecodeArray::Disassemble(std::ostream& os) { ...@@ -15012,8 +15012,17 @@ void BytecodeArray::Disassemble(std::ostream& os) {
os << "\n"; os << "\n";
} }
os << "Constant pool (size = " << constant_pool()->length() << ")\n"; if (constant_pool()->length() > 0) {
constant_pool()->Print(); os << "Constant pool (size = " << constant_pool()->length() << ")\n";
constant_pool()->Print();
}
#ifdef ENABLE_DISASSEMBLER
if (handler_table()->length() > 0) {
os << "Handler Table (size = " << handler_table()->Size() << ")\n";
HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
}
#endif
} }
......
...@@ -4696,7 +4696,7 @@ class DeoptimizationOutputData: public FixedArray { ...@@ -4696,7 +4696,7 @@ class DeoptimizationOutputData: public FixedArray {
DECLARE_CAST(DeoptimizationOutputData) DECLARE_CAST(DeoptimizationOutputData)
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) #ifdef ENABLE_DISASSEMBLER
void DeoptimizationOutputDataPrint(std::ostream& os); // NOLINT void DeoptimizationOutputDataPrint(std::ostream& os); // NOLINT
#endif #endif
}; };
...@@ -4774,7 +4774,7 @@ class HandlerTable : public FixedArray { ...@@ -4774,7 +4774,7 @@ class HandlerTable : public FixedArray {
DECLARE_CAST(HandlerTable) DECLARE_CAST(HandlerTable)
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) #ifdef ENABLE_DISASSEMBLER
void HandlerTableRangePrint(std::ostream& os); // NOLINT void HandlerTableRangePrint(std::ostream& os); // NOLINT
void HandlerTableReturnPrint(std::ostream& os); // NOLINT void HandlerTableReturnPrint(std::ostream& os); // NOLINT
#endif #endif
......
...@@ -161,6 +161,12 @@ struct ExpectedSnippet { ...@@ -161,6 +161,12 @@ struct ExpectedSnippet {
const uint8_t bytecode[2048]; const uint8_t bytecode[2048];
int constant_count; int constant_count;
T constants[C]; T constants[C];
int handler_count;
struct {
int start;
int end;
int handler;
} handlers[C];
}; };
...@@ -205,6 +211,24 @@ static void CheckBytecodeArrayEqual(const ExpectedSnippet<T, C>& expected, ...@@ -205,6 +211,24 @@ static void CheckBytecodeArrayEqual(const ExpectedSnippet<T, C>& expected,
CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); CheckConstant(expected.constants[i], actual->constant_pool()->get(i));
} }
} }
if (expected.handler_count == 0) {
CHECK_EQ(CcTest::heap()->empty_fixed_array(), actual->handler_table());
} else {
static const int kHTSize = 4; // see HandlerTable::kRangeEntrySize
static const int kHTStart = 0; // see HandlerTable::kRangeStartIndex
static const int kHTEnd = 1; // see HandlerTable::kRangeEndIndex
static const int kHTHandler = 2; // see HandlerTable::kRangeHandlerIndex
HandlerTable* table = HandlerTable::cast(actual->handler_table());
CHECK_EQ(expected.handler_count * kHTSize, table->length());
for (int i = 0; i < expected.handler_count; i++) {
int start = Smi::cast(table->get(i * kHTSize + kHTStart))->value();
int end = Smi::cast(table->get(i * kHTSize + kHTEnd))->value();
int handler = Smi::cast(table->get(i * kHTSize + kHTHandler))->value();
CHECK_EQ(expected.handlers[i].start, start);
CHECK_EQ(expected.handlers[i].end, end);
CHECK_EQ(expected.handlers[i].handler, handler >> 1);
}
}
BytecodeArrayIterator iterator(actual); BytecodeArrayIterator iterator(actual);
int i = 0; int i = 0;
...@@ -4143,17 +4167,64 @@ TEST(TryCatch) { ...@@ -4143,17 +4167,64 @@ TEST(TryCatch) {
InitializedHandleScope handle_scope; InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper; BytecodeGeneratorHelper helper;
// TODO(rmcilroy): modify tests when we have real try catch support. int closure = Register::function_closure().index();
ExpectedSnippet<int> snippets[] = {
ExpectedSnippet<const char*> snippets[] = {
{"try { return 1; } catch(e) { return 2; }", {"try { return 1; } catch(e) { return 2; }",
kPointerSize, 5 * kPointerSize,
1, 1,
3, 23,
{ {
B(LdaSmi8), U8(1), // B(LdaSmi8), U8(1), //
B(Return), // B(Return), //
B(Star), R(3), //
B(LdaConstant), U8(0), //
B(Star), R(2), //
B(Ldar), R(closure), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(2), U8(3), //
B(LdaSmi8), U8(2), //
B(Return), //
// TODO(mstarzinger): Potential optimization, elide next bytes.
B(LdaUndefined), //
B(Return), //
}, },
0}, 1,
{"e"},
1,
{{0, 3, 3}}},
{"var a; try { a = 1 } catch(e1) {}; try { a = 2 } catch(e2) { a = 3 }",
6 * kPointerSize,
1,
48,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Jump), U8(17), //
B(Star), R(4), //
B(LdaConstant), U8(0), //
B(Star), R(3), //
B(Ldar), R(closure), //
B(Star), R(5), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(3), U8(3), //
B(LdaSmi8), U8(2), //
B(Star), R(0), //
B(Jump), U8(21), //
B(Star), R(4), //
B(LdaConstant), U8(1), //
B(Star), R(3), //
B(Ldar), R(closure), //
B(Star), R(5), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(3), U8(3), //
B(LdaSmi8), U8(3), //
B(Star), R(0), //
B(LdaUndefined), //
B(Return), //
},
2,
{"e1", "e2"},
2,
{{0, 4, 6}, {21, 25, 27}}},
}; };
for (size_t i = 0; i < arraysize(snippets); i++) { for (size_t i = 0; i < arraysize(snippets); i++) {
...@@ -4168,10 +4239,11 @@ TEST(TryFinally) { ...@@ -4168,10 +4239,11 @@ TEST(TryFinally) {
InitializedHandleScope handle_scope; InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper; BytecodeGeneratorHelper helper;
// TODO(rmcilroy): modify tests when we have real try finally support. int closure = Register::function_closure().index();
ExpectedSnippet<int> snippets[] = {
ExpectedSnippet<const char*> snippets[] = {
{"var a = 1; try { a = 2; } finally { a = 3; }", {"var a = 1; try { a = 2; } finally { a = 3; }",
kPointerSize, 2 * kPointerSize,
1, 1,
14, 14,
{ {
...@@ -4184,22 +4256,73 @@ TEST(TryFinally) { ...@@ -4184,22 +4256,73 @@ TEST(TryFinally) {
B(LdaUndefined), // B(LdaUndefined), //
B(Return), // B(Return), //
}, },
0}, 0,
{},
1,
{{4, 8, 8}}},
{"var a = 1; try { a = 2; } catch(e) { a = 20 } finally { a = 3; }", {"var a = 1; try { a = 2; } catch(e) { a = 20 } finally { a = 3; }",
2 * kPointerSize, 7 * kPointerSize,
1, 1,
14, 35,
{ {
B(LdaSmi8), U8(1), // B(LdaSmi8), U8(1), //
B(Star), R(0), // B(Star), R(0), //
B(LdaSmi8), U8(2), // B(LdaSmi8), U8(2), //
B(Star), R(0), // B(Star), R(0), //
B(LdaSmi8), U8(3), // B(Jump), U8(21), //
B(Star), R(0), // B(Star), R(5), //
B(LdaUndefined), // B(LdaConstant), U8(0), //
B(Return), // B(Star), R(4), //
B(Ldar), R(closure), //
B(Star), R(6), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(4), U8(3), //
B(LdaSmi8), U8(20), //
B(Star), R(0), //
B(LdaSmi8), U8(3), //
B(Star), R(0), //
B(LdaUndefined), //
B(Return), //
}, },
0}, 1,
{"e"},
2,
{{4, 29, 29}, {4, 8, 10}}},
{"var a; try {"
" try { a = 1 } catch(e) { a = 2 }"
"} catch(e) { a = 20 } finally { a = 3; }",
8 * kPointerSize,
1,
52,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Jump), U8(21), //
B(Star), R(6), //
B(LdaConstant), U8(0), //
B(Star), R(5), //
B(Ldar), R(closure), //
B(Star), R(7), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(5), U8(3), //
B(LdaSmi8), U8(2), //
B(Star), R(0), //
B(Jump), U8(21), //
B(Star), R(5), //
B(LdaConstant), U8(0), //
B(Star), R(4), //
B(Ldar), R(closure), //
B(Star), R(6), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(4), U8(3), //
B(LdaSmi8), U8(20), //
B(Star), R(0), //
B(LdaSmi8), U8(3), //
B(Star), R(0), //
B(LdaUndefined), //
B(Return), //
},
1,
{"e"},
3,
{{0, 46, 46}, {0, 25, 27}, {0, 4, 6}}},
}; };
for (size_t i = 0; i < arraysize(snippets); i++) { for (size_t i = 0; i < arraysize(snippets); i++) {
...@@ -4214,7 +4337,6 @@ TEST(Throw) { ...@@ -4214,7 +4337,6 @@ TEST(Throw) {
InitializedHandleScope handle_scope; InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper; BytecodeGeneratorHelper helper;
// TODO(rmcilroy): modify tests when we have real try catch support.
ExpectedSnippet<const char*> snippets[] = { ExpectedSnippet<const char*> snippets[] = {
{"throw 1;", {"throw 1;",
0, 0,
......
...@@ -872,6 +872,8 @@ ...@@ -872,6 +872,8 @@
'../../src/interpreter/constant-array-builder.h', '../../src/interpreter/constant-array-builder.h',
'../../src/interpreter/control-flow-builders.cc', '../../src/interpreter/control-flow-builders.cc',
'../../src/interpreter/control-flow-builders.h', '../../src/interpreter/control-flow-builders.h',
'../../src/interpreter/handler-table-builder.cc',
'../../src/interpreter/handler-table-builder.h',
'../../src/interpreter/interpreter.cc', '../../src/interpreter/interpreter.cc',
'../../src/interpreter/interpreter.h', '../../src/interpreter/interpreter.h',
'../../src/isolate-inl.h', '../../src/isolate-inl.h',
......
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