Commit 1382879f authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Implement throwing exceptions into TurboFan code.

This extends the stack unwinding logic to respect optimized frames
and perform a lookup in the handler table to find handlers. It also
contains fixes to the API call stubs to allow a stack walk while
promoting scheduled exceptions.

R=jarin@chromium.org
TEST=cctest/test-run-jsexceptions

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

Cr-Commit-Position: refs/heads/master@{#27016}
parent 62d860f1
...@@ -4813,7 +4813,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4813,7 +4813,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
} }
Label promote_scheduled_exception; Label promote_scheduled_exception;
Label exception_handled;
Label delete_allocated_handles; Label delete_allocated_handles;
Label leave_exit_frame; Label leave_exit_frame;
Label return_value_loaded; Label return_value_loaded;
...@@ -4835,15 +4834,8 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4835,15 +4834,8 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ cmp(r5, ip); __ cmp(r5, ip);
__ b(ne, &delete_allocated_handles); __ b(ne, &delete_allocated_handles);
// Check if the function scheduled an exception. // Leave the API exit frame.
__ bind(&leave_exit_frame); __ bind(&leave_exit_frame);
__ LoadRoot(r4, Heap::kTheHoleValueRootIndex);
__ mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate)));
__ ldr(r5, MemOperand(ip));
__ cmp(r4, r5);
__ b(ne, &promote_scheduled_exception);
__ bind(&exception_handled);
bool restore_context = context_restore_operand != NULL; bool restore_context = context_restore_operand != NULL;
if (restore_context) { if (restore_context) {
__ ldr(cp, *context_restore_operand); __ ldr(cp, *context_restore_operand);
...@@ -4855,15 +4847,19 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4855,15 +4847,19 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ mov(r4, Operand(stack_space)); __ mov(r4, Operand(stack_space));
} }
__ LeaveExitFrame(false, r4, !restore_context, stack_space_operand != NULL); __ LeaveExitFrame(false, r4, !restore_context, stack_space_operand != NULL);
// Check if the function scheduled an exception.
__ LoadRoot(r4, Heap::kTheHoleValueRootIndex);
__ mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate)));
__ ldr(r5, MemOperand(ip));
__ cmp(r4, r5);
__ b(ne, &promote_scheduled_exception);
__ mov(pc, lr); __ mov(pc, lr);
// Re-throw by promoting a scheduled exception.
__ bind(&promote_scheduled_exception); __ bind(&promote_scheduled_exception);
{ __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
FrameScope frame(masm, StackFrame::INTERNAL);
__ CallExternalReference(
ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
}
__ jmp(&exception_handled);
// HandleScope limit has changed. Delete allocated extensions. // HandleScope limit has changed. Delete allocated extensions.
__ bind(&delete_allocated_handles); __ bind(&delete_allocated_handles);
......
...@@ -5266,7 +5266,6 @@ static void CallApiFunctionAndReturn( ...@@ -5266,7 +5266,6 @@ static void CallApiFunctionAndReturn(
} }
Label promote_scheduled_exception; Label promote_scheduled_exception;
Label exception_handled;
Label delete_allocated_handles; Label delete_allocated_handles;
Label leave_exit_frame; Label leave_exit_frame;
Label return_value_loaded; Label return_value_loaded;
...@@ -5288,6 +5287,7 @@ static void CallApiFunctionAndReturn( ...@@ -5288,6 +5287,7 @@ static void CallApiFunctionAndReturn(
__ Cmp(limit_reg, x1); __ Cmp(limit_reg, x1);
__ B(ne, &delete_allocated_handles); __ B(ne, &delete_allocated_handles);
// Leave the API exit frame.
__ Bind(&leave_exit_frame); __ Bind(&leave_exit_frame);
// Restore callee-saved registers. // Restore callee-saved registers.
__ Peek(x19, (spill_offset + 0) * kXRegSize); __ Peek(x19, (spill_offset + 0) * kXRegSize);
...@@ -5295,13 +5295,6 @@ static void CallApiFunctionAndReturn( ...@@ -5295,13 +5295,6 @@ static void CallApiFunctionAndReturn(
__ Peek(x21, (spill_offset + 2) * kXRegSize); __ Peek(x21, (spill_offset + 2) * kXRegSize);
__ Peek(x22, (spill_offset + 3) * kXRegSize); __ Peek(x22, (spill_offset + 3) * kXRegSize);
// Check if the function scheduled an exception.
__ Mov(x5, ExternalReference::scheduled_exception_address(isolate));
__ Ldr(x5, MemOperand(x5));
__ JumpIfNotRoot(x5, Heap::kTheHoleValueRootIndex,
&promote_scheduled_exception);
__ Bind(&exception_handled);
bool restore_context = context_restore_operand != NULL; bool restore_context = context_restore_operand != NULL;
if (restore_context) { if (restore_context) {
__ Ldr(cp, *context_restore_operand); __ Ldr(cp, *context_restore_operand);
...@@ -5312,6 +5305,13 @@ static void CallApiFunctionAndReturn( ...@@ -5312,6 +5305,13 @@ static void CallApiFunctionAndReturn(
} }
__ LeaveExitFrame(false, x1, !restore_context); __ LeaveExitFrame(false, x1, !restore_context);
// Check if the function scheduled an exception.
__ Mov(x5, ExternalReference::scheduled_exception_address(isolate));
__ Ldr(x5, MemOperand(x5));
__ JumpIfNotRoot(x5, Heap::kTheHoleValueRootIndex,
&promote_scheduled_exception);
if (stack_space_operand != NULL) { if (stack_space_operand != NULL) {
__ Drop(x2, 1); __ Drop(x2, 1);
} else { } else {
...@@ -5319,13 +5319,9 @@ static void CallApiFunctionAndReturn( ...@@ -5319,13 +5319,9 @@ static void CallApiFunctionAndReturn(
} }
__ Ret(); __ Ret();
// Re-throw by promoting a scheduled exception.
__ Bind(&promote_scheduled_exception); __ Bind(&promote_scheduled_exception);
{ __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
FrameScope frame(masm, StackFrame::INTERNAL);
__ CallExternalReference(
ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
}
__ B(&exception_handled);
// HandleScope limit has changed. Delete allocated extensions. // HandleScope limit has changed. Delete allocated extensions.
__ Bind(&delete_allocated_handles); __ Bind(&delete_allocated_handles);
......
...@@ -1870,16 +1870,8 @@ void AstGraphBuilder::VisitYield(Yield* expr) { ...@@ -1870,16 +1870,8 @@ void AstGraphBuilder::VisitYield(Yield* expr) {
void AstGraphBuilder::VisitThrow(Throw* expr) { void AstGraphBuilder::VisitThrow(Throw* expr) {
VisitForValue(expr->exception()); VisitForValue(expr->exception());
Node* exception = environment()->Pop(); Node* exception = environment()->Pop();
if (FLAG_turbo_exceptions) { Node* value = BuildThrowError(exception, expr->id());
execution_control()->ThrowValue(exception); ast_context()->ProduceValue(value);
ast_context()->ProduceValue(exception);
} else {
// TODO(mstarzinger): Temporary workaround for bailout-id for debugger.
const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
Node* value = NewNode(op, exception);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
}
} }
...@@ -2859,9 +2851,16 @@ Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object, ...@@ -2859,9 +2851,16 @@ Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
} }
Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) {
const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
Node* call = NewNode(op, exception);
PrepareFrameState(call, bailout_id);
return call;
}
Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable, Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
BailoutId bailout_id) { BailoutId bailout_id) {
// TODO(mstarzinger): Should be unified with the VisitThrow implementation.
Node* variable_name = jsgraph()->Constant(variable->name()); Node* variable_name = jsgraph()->Constant(variable->name());
const Operator* op = const Operator* op =
javascript()->CallRuntime(Runtime::kThrowReferenceError, 1); javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
...@@ -2872,7 +2871,6 @@ Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable, ...@@ -2872,7 +2871,6 @@ Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) {
// TODO(mstarzinger): Should be unified with the VisitThrow implementation.
const Operator* op = const Operator* op =
javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0); javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0);
Node* call = NewNode(op); Node* call = NewNode(op);
......
...@@ -240,6 +240,7 @@ class AstGraphBuilder : public AstVisitor { ...@@ -240,6 +240,7 @@ class AstGraphBuilder : public AstVisitor {
Node* BuildSetHomeObject(Node* value, Node* home_object, Expression* expr); Node* BuildSetHomeObject(Node* value, Node* home_object, Expression* expr);
// Builders for error reporting at runtime. // Builders for error reporting at runtime.
Node* BuildThrowError(Node* exception, BailoutId bailout_id);
Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id); Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id);
Node* BuildThrowConstAssignError(BailoutId bailout_id); Node* BuildThrowConstAssignError(BailoutId bailout_id);
......
...@@ -278,6 +278,9 @@ class StackFrame BASE_EMBEDDED { ...@@ -278,6 +278,9 @@ class StackFrame BASE_EMBEDDED {
// Checks if this frame includes any stack handlers. // Checks if this frame includes any stack handlers.
bool HasHandler() const; bool HasHandler() const;
// Get the top handler from the current stack iterator.
inline StackHandler* top_handler() const;
// Get the type of this frame. // Get the type of this frame.
virtual Type type() const = 0; virtual Type type() const = 0;
...@@ -311,7 +314,6 @@ class StackFrame BASE_EMBEDDED { ...@@ -311,7 +314,6 @@ class StackFrame BASE_EMBEDDED {
// Resolves pc_address through the resolution address function if one is set. // Resolves pc_address through the resolution address function if one is set.
static inline Address* ResolveReturnAddressLocation(Address* pc_address); static inline Address* ResolveReturnAddressLocation(Address* pc_address);
// Printing support. // Printing support.
enum PrintMode { OVERVIEW, DETAILS }; enum PrintMode { OVERVIEW, DETAILS };
virtual void Print(StringStream* accumulator, virtual void Print(StringStream* accumulator,
...@@ -332,9 +334,6 @@ class StackFrame BASE_EMBEDDED { ...@@ -332,9 +334,6 @@ class StackFrame BASE_EMBEDDED {
PrintMode mode, PrintMode mode,
int index); int index);
// Get the top handler from the current stack iterator.
inline StackHandler* top_handler() const;
// Compute the stack frame type for the given state. // Compute the stack frame type for the given state.
static Type ComputeType(const StackFrameIteratorBase* iterator, State* state); static Type ComputeType(const StackFrameIteratorBase* iterator, State* state);
......
...@@ -4893,7 +4893,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4893,7 +4893,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ mov(eax, return_value_operand); __ mov(eax, return_value_operand);
Label promote_scheduled_exception; Label promote_scheduled_exception;
Label exception_handled;
Label delete_allocated_handles; Label delete_allocated_handles;
Label leave_exit_frame; Label leave_exit_frame;
...@@ -4905,7 +4904,17 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4905,7 +4904,17 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ Assert(above_equal, kInvalidHandleScopeLevel); __ Assert(above_equal, kInvalidHandleScopeLevel);
__ cmp(edi, Operand::StaticVariable(limit_address)); __ cmp(edi, Operand::StaticVariable(limit_address));
__ j(not_equal, &delete_allocated_handles); __ j(not_equal, &delete_allocated_handles);
// Leave the API exit frame.
__ bind(&leave_exit_frame); __ bind(&leave_exit_frame);
bool restore_context = context_restore_operand != NULL;
if (restore_context) {
__ mov(esi, *context_restore_operand);
}
if (stack_space_operand != nullptr) {
__ mov(ebx, *stack_space_operand);
}
__ LeaveApiExitFrame(!restore_context);
// Check if the function scheduled an exception. // Check if the function scheduled an exception.
ExternalReference scheduled_exception_address = ExternalReference scheduled_exception_address =
...@@ -4913,7 +4922,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4913,7 +4922,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ cmp(Operand::StaticVariable(scheduled_exception_address), __ cmp(Operand::StaticVariable(scheduled_exception_address),
Immediate(isolate->factory()->the_hole_value())); Immediate(isolate->factory()->the_hole_value()));
__ j(not_equal, &promote_scheduled_exception); __ j(not_equal, &promote_scheduled_exception);
__ bind(&exception_handled);
#if DEBUG #if DEBUG
// Check if the function returned a valid JavaScript value. // Check if the function returned a valid JavaScript value.
...@@ -4950,14 +4958,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4950,14 +4958,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ bind(&ok); __ bind(&ok);
#endif #endif
bool restore_context = context_restore_operand != NULL;
if (restore_context) {
__ mov(esi, *context_restore_operand);
}
if (stack_space_operand != nullptr) {
__ mov(ebx, *stack_space_operand);
}
__ LeaveApiExitFrame(!restore_context);
if (stack_space_operand != nullptr) { if (stack_space_operand != nullptr) {
DCHECK_EQ(0, stack_space); DCHECK_EQ(0, stack_space);
__ pop(ecx); __ pop(ecx);
...@@ -4967,12 +4967,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4967,12 +4967,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ ret(stack_space * kPointerSize); __ ret(stack_space * kPointerSize);
} }
// Re-throw by promoting a scheduled exception.
__ bind(&promote_scheduled_exception); __ bind(&promote_scheduled_exception);
{ __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
FrameScope frame(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kPromoteScheduledException, 0);
}
__ jmp(&exception_handled);
// HandleScope limit has changed. Delete allocated extensions. // HandleScope limit has changed. Delete allocated extensions.
ExternalReference delete_extensions = ExternalReference delete_extensions =
......
...@@ -1031,29 +1031,94 @@ Object* Isolate::ReThrow(Object* exception) { ...@@ -1031,29 +1031,94 @@ Object* Isolate::ReThrow(Object* exception) {
} }
// TODO(turbofan): Make sure table is sorted and use binary search.
static int LookupInHandlerTable(Code* code, int pc_offset) {
FixedArray* handler_table = code->handler_table();
for (int i = 0; i < handler_table->length(); i += 2) {
int return_offset = Smi::cast(handler_table->get(i))->value();
int handler_offset = Smi::cast(handler_table->get(i + 1))->value();
if (pc_offset == return_offset) return handler_offset;
}
return -1;
}
Object* Isolate::FindHandler() { Object* Isolate::FindHandler() {
Object* exception = pending_exception(); Object* exception = pending_exception();
// Determine target stack handler. Special handling of termination exceptions Code* code = nullptr;
// which are uncatchable by JavaScript code, we unwind the handlers until the Context* context = nullptr;
// top ENTRY handler is found. intptr_t offset = 0;
StackHandler* handler = Address handler_sp = nullptr;
StackHandler::FromAddress(Isolate::handler(thread_local_top())); Address handler_fp = nullptr;
if (!is_catchable_by_javascript(exception)) {
while (!handler->is_js_entry()) handler = handler->next(); // Special handling of termination exceptions, uncatchable by JavaScript code,
} // we unwind the handlers until the top ENTRY handler is found.
bool catchable_by_js = is_catchable_by_javascript(exception);
// Compute handler and stack unwinding information by performing a full walk
// over the stack and dispatching according to the frame type.
for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
StackFrame* frame = iter.frame();
// For JSEntryStub frames we always have a handler.
if (frame->is_entry() || frame->is_entry_construct()) {
StackHandler* handler = frame->top_handler();
DCHECK_EQ(StackHandler::JS_ENTRY, handler->kind());
DCHECK_EQ(0, handler->index());
// Restore the next handler.
thread_local_top()->handler_ = handler->next()->address();
// Gather information from the handler.
code = handler->code();
handler_sp = handler->address() + StackHandlerConstants::kSize;
offset = Smi::cast(code->handler_table()->get(0))->value();
break;
}
// For JavaScript frames which have a handler, we use the handler.
if (frame->is_java_script() && catchable_by_js && frame->HasHandler()) {
StackHandler* handler = frame->top_handler();
DCHECK_NE(StackHandler::JS_ENTRY, handler->kind());
// Restore the next handler.
thread_local_top()->handler_ = handler->next()->address();
// Gather information from the handler.
code = handler->code();
context = handler->context();
offset = Smi::cast(code->handler_table()->get(handler->index()))->value();
handler_sp = handler->address() + StackHandlerConstants::kSize;
handler_fp = handler->frame_pointer();
break;
}
// Restore the next handler. // For optimized frames we perform a lookup in the handler table.
thread_local_top()->handler_ = handler->next()->address(); if (frame->is_optimized() && catchable_by_js) {
Code* frame_code = frame->LookupCode();
DCHECK(frame_code->is_optimized_code());
int pc_offset = static_cast<int>(frame->pc() - frame_code->entry());
int handler_offset = LookupInHandlerTable(frame_code, pc_offset);
if (handler_offset < 0) continue;
// Compute the stack pointer from the frame pointer. This ensures that
// argument slots on the stack are dropped as returning would.
Address return_sp = frame->fp() -
StandardFrameConstants::kFixedFrameSizeFromFp -
frame_code->stack_slots() * kPointerSize;
// Gather information from the frame.
code = frame_code;
offset = handler_offset;
handler_sp = return_sp;
handler_fp = frame->fp();
break;
}
}
// Compute handler and stack unwinding information. // Handler must exist.
// TODO(mstarzinger): Extend this to perform actual stack-walk and take into CHECK(code != nullptr);
// account that TurboFan code can contain handlers as well.
Code* code = handler->code();
Context* context = handler->is_js_entry() ? nullptr : handler->context();
int offset = Smi::cast(code->handler_table()->get(handler->index()))->value();
Address handler_sp = handler->address() + StackHandlerConstants::kSize;
Address handler_fp = handler->frame_pointer();
// Store information to be consumed by the CEntryStub. // Store information to be consumed by the CEntryStub.
thread_local_top()->pending_handler_context_ = context; thread_local_top()->pending_handler_context_ = context;
......
...@@ -4782,7 +4782,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4782,7 +4782,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
Operand* context_restore_operand) { Operand* context_restore_operand) {
Label prologue; Label prologue;
Label promote_scheduled_exception; Label promote_scheduled_exception;
Label exception_handled;
Label delete_allocated_handles; Label delete_allocated_handles;
Label leave_exit_frame; Label leave_exit_frame;
Label write_back; Label write_back;
...@@ -4859,13 +4858,22 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4859,13 +4858,22 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ movp(Operand(base_reg, kNextOffset), prev_next_address_reg); __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg);
__ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset)); __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset));
__ j(not_equal, &delete_allocated_handles); __ j(not_equal, &delete_allocated_handles);
// Leave the API exit frame.
__ bind(&leave_exit_frame); __ bind(&leave_exit_frame);
bool restore_context = context_restore_operand != NULL;
if (restore_context) {
__ movp(rsi, *context_restore_operand);
}
if (stack_space_operand != nullptr) {
__ movp(rbx, *stack_space_operand);
}
__ LeaveApiExitFrame(!restore_context);
// Check if the function scheduled an exception. // Check if the function scheduled an exception.
__ Move(rsi, scheduled_exception_address); __ Move(rdi, scheduled_exception_address);
__ Cmp(Operand(rsi, 0), factory->the_hole_value()); __ Cmp(Operand(rdi, 0), factory->the_hole_value());
__ j(not_equal, &promote_scheduled_exception); __ j(not_equal, &promote_scheduled_exception);
__ bind(&exception_handled);
#if DEBUG #if DEBUG
// Check if the function returned a valid JavaScript value. // Check if the function returned a valid JavaScript value.
...@@ -4902,14 +4910,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4902,14 +4910,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ bind(&ok); __ bind(&ok);
#endif #endif
bool restore_context = context_restore_operand != NULL;
if (restore_context) {
__ movp(rsi, *context_restore_operand);
}
if (stack_space_operand != nullptr) {
__ movp(rbx, *stack_space_operand);
}
__ LeaveApiExitFrame(!restore_context);
if (stack_space_operand != nullptr) { if (stack_space_operand != nullptr) {
DCHECK_EQ(stack_space, 0); DCHECK_EQ(stack_space, 0);
__ PopReturnAddressTo(rcx); __ PopReturnAddressTo(rcx);
...@@ -4919,12 +4919,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, ...@@ -4919,12 +4919,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
__ ret(stack_space * kPointerSize); __ ret(stack_space * kPointerSize);
} }
// Re-throw by promoting a scheduled exception.
__ bind(&promote_scheduled_exception); __ bind(&promote_scheduled_exception);
{ __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
FrameScope frame(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kPromoteScheduledException, 0);
}
__ jmp(&exception_handled);
// HandleScope limit has changed. Delete allocated extensions. // HandleScope limit has changed. Delete allocated extensions.
__ bind(&delete_allocated_handles); __ bind(&delete_allocated_handles);
......
...@@ -19,6 +19,7 @@ TEST(Throw) { ...@@ -19,6 +19,7 @@ TEST(Throw) {
TEST(ThrowSourcePosition) { TEST(ThrowSourcePosition) {
i::FLAG_turbo_exceptions = true;
static const char* src = static const char* src =
"(function(a, b) { \n" "(function(a, b) { \n"
" if (a == 1) throw 1; \n" " if (a == 1) throw 1; \n"
...@@ -134,9 +135,7 @@ TEST(CatchCall) { ...@@ -134,9 +135,7 @@ TEST(CatchCall) {
FunctionTester T(src); FunctionTester T(src);
CompileRun("function thrower() { throw 'T-'; }"); CompileRun("function thrower() { throw 'T-'; }");
#if 0 // TODO(mstarzinger): Enable once we have exception handlers.
T.CheckCall(T.Val("-A-T-"), T.NewFunction("thrower")); T.CheckCall(T.Val("-A-T-"), T.NewFunction("thrower"));
#endif
CompileRun("function returner() { return 'R-'; }"); CompileRun("function returner() { return 'R-'; }");
T.CheckCall(T.Val("-A-B-R-"), T.NewFunction("returner")); T.CheckCall(T.Val("-A-B-R-"), T.NewFunction("returner"));
} }
......
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