Commit 0b3066b8 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[interpreter] First implementation of stack unwinding.

This implements a first prototype of stack unwinding for interpreted
frames. The unwinding machinery performs a range-based lookup in the
given handler table and potentially continues dispatching at the handler
offset. Note that this does not yet correctly restore the context to the
correct value when the handler is being entered.

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

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

Cr-Commit-Position: refs/heads/master@{#33414}
parent 7c54dc33
......@@ -1059,25 +1059,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ mov(r1, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(r1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
// Initialize register file register and dispatch table register.
__ add(kInterpreterRegisterFileRegister, fp,
Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
......@@ -1127,6 +1109,30 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ mov(r1, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(r1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
// Enter the bytecode dispatch.
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
......@@ -1142,6 +1148,11 @@ void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
}
void Builtins::Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm) {
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
......
......@@ -1018,25 +1018,7 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ Mov(x1, Operand(Smi::FromInt(static_cast<int>(type))));
__ Push(x1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
// Initialize register file register and dispatch table register.
__ Add(kInterpreterRegisterFileRegister, fp,
Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
......@@ -1086,6 +1068,30 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ Mov(x1, Operand(Smi::FromInt(static_cast<int>(type))));
__ Push(x1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
// Enter the bytecode dispatch.
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
......@@ -1101,6 +1107,11 @@ void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
}
void Builtins::Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm) {
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
......
......@@ -195,6 +195,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(InterpreterNotifyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterNotifySoftDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterNotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterEnterExceptionHandler, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(LoadIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \
......@@ -505,6 +506,7 @@ class Builtins {
static void Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm);
static void Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm);
static void Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm);
static void Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm);
#define DECLARE_CODE_AGE_BUILTIN_GENERATOR(C) \
static void Generate_Make##C##CodeYoungAgainEvenMarking( \
......
......@@ -1128,6 +1128,33 @@ Object* OptimizedFrame::StackSlotAt(int index) const {
}
int InterpretedFrame::LookupExceptionHandlerInTable(
int* stack_slots, HandlerTable::CatchPrediction* prediction) {
BytecodeArray* bytecode = function()->shared()->bytecode_array();
HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
int pc_offset = GetBytecodeOffset() + 1; // Point after current bytecode.
return table->LookupRange(pc_offset, stack_slots, prediction);
}
int InterpretedFrame::GetBytecodeOffset() const {
const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
DCHECK_EQ(InterpreterFrameConstants::kBytecodeOffsetFromFp,
StandardFrameConstants::kExpressionsOffset - index * kPointerSize);
int raw_offset = Smi::cast(GetExpression(index))->value();
return raw_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
}
void InterpretedFrame::PatchBytecodeOffset(int new_offset) {
const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
DCHECK_EQ(InterpreterFrameConstants::kBytecodeOffsetFromFp,
StandardFrameConstants::kExpressionsOffset - index * kPointerSize);
int raw_offset = new_offset + BytecodeArray::kHeaderSize - kHeapObjectTag;
SetExpression(index, Smi::FromInt(raw_offset));
}
int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
return Smi::cast(GetExpression(0))->value();
}
......
......@@ -183,9 +183,14 @@ class InterpreterFrameConstants : public AllStatic {
StandardFrameConstants::kFixedFrameSizeFromFp + 2 * kPointerSize;
// FP-relative.
static const int kBytecodeOffsetFromFp =
-StandardFrameConstants::kFixedFrameSizeFromFp - 2 * kPointerSize;
static const int kRegisterFilePointerFromFp =
-StandardFrameConstants::kFixedFrameSizeFromFp - 3 * kPointerSize;
// Expression index for {StandardFrame::GetExpressionAddress}.
static const int kBytecodeOffsetExpressionIndex = 1;
// Register file pointer relative.
static const int kLastParamFromRegisterPointer =
StandardFrameConstants::kFixedFrameSize + 3 * kPointerSize;
......@@ -249,6 +254,7 @@ class StackFrame BASE_EMBEDDED {
bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
bool is_exit() const { return type() == EXIT; }
bool is_optimized() const { return type() == OPTIMIZED; }
bool is_interpreted() const { return type() == INTERPRETED; }
bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
bool is_internal() const { return type() == INTERNAL; }
bool is_stub_failure_trampoline() const {
......@@ -711,8 +717,21 @@ class OptimizedFrame : public JavaScriptFrame {
class InterpretedFrame : public JavaScriptFrame {
public:
Type type() const override { return INTERPRETED; }
// Lookup exception handler for current {pc}, returns -1 if none found. Also
// returns the expected number of stack slots at the handler site.
int LookupExceptionHandlerInTable(
int* stack_slots, HandlerTable::CatchPrediction* prediction) override;
// Returns the current offset into the bytecode stream.
int GetBytecodeOffset() const;
// Updates the current offset into the bytecode stream, mainly used for stack
// unwinding to continue execution at a different bytecode offset.
void PatchBytecodeOffset(int new_offset);
protected:
inline explicit InterpretedFrame(StackFrameIteratorBase* iterator);
......
......@@ -758,22 +758,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ Push(Smi::FromInt(static_cast<int>(type)));
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
// Initialize register file register.
__ mov(kInterpreterRegisterFileRegister, ebp);
__ add(kInterpreterRegisterFileRegister,
......@@ -801,12 +786,13 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
__ SmiUntag(kInterpreterBytecodeOffsetRegister);
// Push dispatch table as a stack located parameter to the bytecode handler -
// overwrite the state slot (we don't use these for interpreter deopts).
// Push dispatch table as a stack located parameter to the bytecode handler.
__ LoadRoot(ebx, Heap::kInterpreterTableRootIndex);
__ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
__ mov(Operand(esp, kPointerSize), ebx);
__ Pop(esi);
__ Push(ebx);
__ Push(esi);
// Dispatch to the target bytecode.
__ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
......@@ -827,6 +813,34 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ Push(Smi::FromInt(static_cast<int>(type)));
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use these for interpreter deopts) and push PC at top
// of stack (to simulate initial call to bytecode handler in interpreter entry
// trampoline).
__ Pop(ebx);
__ Drop(1);
__ Push(ebx);
// Enter the bytecode dispatch.
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
......@@ -842,6 +856,11 @@ void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
}
void Builtins::Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm) {
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
......
......@@ -917,20 +917,10 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
// 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);
VisitNewLocalCatchContext(stmt->variable());
// Evaluate the catch-block.
Visit(stmt->catch_block());
VisitInScope(stmt->catch_block(), stmt->scope());
try_control_builder.EndCatch();
}
......@@ -2128,6 +2118,27 @@ void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
}
void BytecodeGenerator::VisitNewLocalCatchContext(Variable* variable) {
AccumulatorResultScope accumulator_execution_result(this);
DCHECK(variable->IsContextSlot());
// Allocate a new local block context.
register_allocator()->PrepareForConsecutiveAllocations(3);
Register name = register_allocator()->NextConsecutiveRegister();
Register exception = register_allocator()->NextConsecutiveRegister();
Register closure = register_allocator()->NextConsecutiveRegister();
builder()
->StoreAccumulatorInRegister(exception)
.LoadLiteral(variable->name())
.StoreAccumulatorInRegister(name);
VisitFunctionClosureForContext();
builder()->StoreAccumulatorInRegister(closure).CallRuntime(
Runtime::kPushCatchContext, name, 3);
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitObjectLiteralAccessor(
Register home_object, ObjectLiteralProperty* property, Register value_out) {
// TODO(rmcilroy): Replace value_out with VisitForRegister();
......@@ -2232,6 +2243,13 @@ Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
}
void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
ContextScope context_scope(this, scope);
DCHECK(scope->declarations()->is_empty());
Visit(stmt);
}
Register BytecodeGenerator::NextContextRegister() const {
if (execution_context() == nullptr) {
// Return the incoming function context for the outermost execution context.
......
......@@ -81,6 +81,7 @@ class BytecodeGenerator final : public AstVisitor {
void VisitBuildLocalActivationContext();
void VisitBlockDeclarationsAndStatements(Block* stmt);
void VisitNewLocalBlockContext(Scope* scope);
void VisitNewLocalCatchContext(Variable* variable);
void VisitFunctionClosureForContext();
void VisitSetHomeObject(Register value, Register home_object,
ObjectLiteralProperty* property, int slot_number = 0);
......@@ -89,6 +90,9 @@ class BytecodeGenerator final : public AstVisitor {
Register value_out);
void VisitForInAssignment(Expression* expr, FeedbackVectorSlot slot);
// Visit a statement and switch scopes, the context is in the accumulator.
void VisitInScope(Statement* stmt, Scope* scope);
// Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect.
void VisitForAccumulatorValue(Expression* expression);
......
......@@ -1116,6 +1116,26 @@ Object* Isolate::UnwindAndFindHandler() {
}
}
// For interpreted frame we perform a range lookup in the handler table.
if (frame->is_interpreted() && catchable_by_js) {
InterpretedFrame* js_frame = static_cast<InterpretedFrame*>(frame);
int stack_slots = 0; // Will contain stack slot count of frame.
offset = js_frame->LookupExceptionHandlerInTable(&stack_slots, NULL);
if (offset >= 0) {
// Patch the bytecode offset in the interpreted frame to reflect the
// position of the exception handler. The special builtin below will
// take care of continuing to dispatch at that position.
js_frame->PatchBytecodeOffset(static_cast<int>(offset));
offset = 0;
// Gather information from the frame.
code = *builtins()->InterpreterEnterExceptionHandler();
handler_sp = frame->sp();
handler_fp = frame->fp();
break;
}
}
// For JavaScript frames we perform a range lookup in the handler table.
if (frame->is_java_script() && catchable_by_js) {
JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame);
......
......@@ -1048,25 +1048,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ li(a1, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(a1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
// Initialize register file register and dispatch table register.
__ Addu(kInterpreterRegisterFileRegister, fp,
Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
......@@ -1118,6 +1100,30 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ li(a1, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(a1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
// Enter the bytecode dispatch.
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
......@@ -1133,6 +1139,11 @@ void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
}
void Builtins::Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm) {
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
......
......@@ -1046,25 +1046,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ li(a1, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(a1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
// Initialize register file register and dispatch table register.
__ Daddu(kInterpreterRegisterFileRegister, fp,
Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
......@@ -1117,6 +1099,30 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ li(a1, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(a1);
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use this for interpreter deopts).
__ Drop(1);
// Enter the bytecode dispatch.
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
......@@ -1132,6 +1138,11 @@ void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
}
void Builtins::Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm) {
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
......
......@@ -810,29 +810,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ Push(Smi::FromInt(static_cast<int>(type)));
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use these for interpreter deopts) and push PC at top
// of stack (to simulate initial call to bytecode handler in interpreter entry
// trampoline).
__ Pop(rbx);
__ Drop(1);
__ Push(rbx);
static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
// Initialize register file register and dispatch table register.
__ movp(kInterpreterRegisterFileRegister, rbp);
__ addp(kInterpreterRegisterFileRegister,
......@@ -883,6 +861,34 @@ static void Generate_InterpreterNotifyDeoptimizedHelper(
}
static void Generate_InterpreterNotifyDeoptimizedHelper(
MacroAssembler* masm, Deoptimizer::BailoutType type) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
// Pass the deoptimization type to the runtime system.
__ Push(Smi::FromInt(static_cast<int>(type)));
__ CallRuntime(Runtime::kNotifyDeoptimized);
__ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
// Tear down internal frame.
}
// Drop state (we don't use these for interpreter deopts) and push PC at top
// of stack (to simulate initial call to bytecode handler in interpreter entry
// trampoline).
__ Pop(rbx);
__ Drop(1);
__ Push(rbx);
// Enter the bytecode dispatch.
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
......@@ -898,6 +904,11 @@ void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
}
void Builtins::Generate_InterpreterEnterExceptionHandler(MacroAssembler* masm) {
Generate_EnterBytecodeDispatch(masm);
}
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
......
......@@ -580,6 +580,7 @@
'test-run-variables/StackLoadVariables': [SKIP],
'test-run-variables/StackStoreVariables': [SKIP],
'test-sampler-api/StackFramesConsistent': [SKIP],
'test-strings/OneByteArrayJoin': [SKIP],
'test-thread-termination/TerminateCancelTerminateFromThreadItself': [SKIP],
'test-thread-termination/TerminateFromOtherThreadWhileMicrotaskRunning': [SKIP],
'test-thread-termination/TerminateOnlyV8ThreadFromThreadItselfNoLoop': [SKIP],
......
......@@ -4167,12 +4167,13 @@ TEST(TryCatch) {
BytecodeGeneratorHelper helper;
int closure = Register::function_closure().index();
int context = Register::function_context().index();
ExpectedSnippet<const char*> snippets[] = {
{"try { return 1; } catch(e) { return 2; }",
5 * kPointerSize,
1,
23,
25,
{
B(LdaSmi8), U8(1), //
B(Return), //
......@@ -4182,6 +4183,7 @@ TEST(TryCatch) {
B(Ldar), R(closure), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kPushCatchContext), R(2), U8(3), //
B(PushContext), R(0), //
B(LdaSmi8), U8(2), //
B(Return), //
// TODO(mstarzinger): Potential optimization, elide next bytes.
......@@ -4195,35 +4197,39 @@ TEST(TryCatch) {
{"var a; try { a = 1 } catch(e1) {}; try { a = 2 } catch(e2) { a = 3 }",
6 * kPointerSize,
1,
48,
56,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Jump), U8(17), //
B(Jump), U8(21), //
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(PushContext), R(1), //
B(PopContext), R(context), //
B(LdaSmi8), U8(2), //
B(Star), R(0), //
B(Jump), U8(21), //
B(Jump), U8(25), //
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(PushContext), R(1), //
B(LdaSmi8), U8(3), //
B(Star), R(0), //
B(PopContext), R(context), //
B(LdaUndefined), //
B(Return), //
},
2,
{"e1", "e2"},
2,
{{0, 4, 6}, {21, 25, 27}}},
{{0, 4, 6}, {25, 29, 31}}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
......@@ -4239,6 +4245,7 @@ TEST(TryFinally) {
BytecodeGeneratorHelper helper;
int closure = Register::function_closure().index();
int context = Register::function_context().index();
ExpectedSnippet<const char*> snippets[] = {
{"var a = 1; try { a = 2; } finally { a = 3; }",
......@@ -4262,21 +4269,23 @@ TEST(TryFinally) {
{"var a = 1; try { a = 2; } catch(e) { a = 20 } finally { a = 3; }",
7 * kPointerSize,
1,
35,
39,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(LdaSmi8), U8(2), //
B(Star), R(0), //
B(Jump), U8(21), //
B(Jump), U8(25), //
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(PushContext), R(1), //
B(LdaSmi8), U8(20), //
B(Star), R(0), //
B(PopContext), R(context), //
B(LdaSmi8), U8(3), //
B(Star), R(0), //
B(LdaUndefined), //
......@@ -4285,34 +4294,38 @@ TEST(TryFinally) {
1,
{"e"},
2,
{{4, 29, 29}, {4, 8, 10}}},
{{4, 33, 33}, {4, 8, 10}}},
{"var a; try {"
" try { a = 1 } catch(e) { a = 2 }"
"} catch(e) { a = 20 } finally { a = 3; }",
8 * kPointerSize,
1,
52,
60,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Jump), U8(21), //
B(Jump), U8(25), //
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(PushContext), R(1), //
B(LdaSmi8), U8(2), //
B(Star), R(0), //
B(Jump), U8(21), //
B(PopContext), R(context), //
B(Jump), U8(25), //
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(PushContext), R(1), //
B(LdaSmi8), U8(20), //
B(Star), R(0), //
B(PopContext), R(context), //
B(LdaSmi8), U8(3), //
B(Star), R(0), //
B(LdaUndefined), //
......@@ -4321,7 +4334,7 @@ TEST(TryFinally) {
1,
{"e"},
3,
{{0, 46, 46}, {0, 25, 27}, {0, 4, 6}}},
{{0, 54, 54}, {0, 29, 31}, {0, 4, 6}}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
......
......@@ -2021,15 +2021,25 @@ TEST(InterpreterLogicalAnd) {
TEST(InterpreterTryCatch) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
// TODO(rmcilroy): modify tests when we have real try catch support.
std::string source(InterpreterTester::SourceForBody(
"var a = 1; try { a = a + 1; } catch(e) { a = a + 2; }; return a;"));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
std::pair<const char*, Handle<Object>> catches[] = {
std::make_pair("var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;",
handle(Smi::FromInt(2), isolate)),
std::make_pair("var a; try { undef.x } catch(e) { a = 2 }; return a;",
handle(Smi::FromInt(2), isolate)),
std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 }; return a;",
handle(Smi::FromInt(3), isolate)),
};
Handle<Object> return_val = callable().ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(2));
for (size_t i = 0; i < arraysize(catches); i++) {
std::string source(InterpreterTester::SourceForBody(catches[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*catches[i].second));
}
}
......@@ -2052,7 +2062,6 @@ TEST(InterpreterThrow) {
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
// TODO(rmcilroy): modify tests when we have real try catch support.
std::pair<const char*, Handle<Object>> throws[] = {
std::make_pair("throw undefined;\n",
factory->undefined_value()),
......
......@@ -787,6 +787,7 @@
'compiler/osr-forof': [SKIP],
'compiler/property-refs': [SKIP],
'compiler/regress-3786': [SKIP],
'compiler/regress-445907': [SKIP],
'compiler/regress-446647': [SKIP],
'compiler/regress-447567': [SKIP],
'compiler/regress-469089': [SKIP],
......@@ -851,6 +852,7 @@
'regress/regress-1079': [SKIP],
'regress/regress-109195': [SKIP],
'regress/regress-1114040': [SKIP],
'regress/regress-1118': [SKIP],
'regress/regress-1125': [SKIP],
'regress/regress-1129': [SKIP],
'regress/regress-1170187': [SKIP],
......@@ -893,6 +895,7 @@
'regress/regress-2339': [SKIP],
'regress/regress-2374': [SKIP],
'regress/regress-2593': [SKIP],
'regress/regress-259': [SKIP],
'regress/regress-2618': [SKIP],
'regress/regress-263': [SKIP],
'regress/regress-265': [SKIP],
......@@ -973,6 +976,7 @@
'regress/regress-806473': [SKIP],
'regress/regress-842017': [SKIP],
'regress/regress-84234': [SKIP],
'regress/regress-877615': [SKIP],
'regress/regress-88591': [SKIP],
'regress/regress-88858': [SKIP],
'regress/regress-94425': [SKIP],
......@@ -1062,6 +1066,7 @@
'regress/regress-osr-in-literal': [SKIP],
'regress/regress-prepare-break-while-recompile': [SKIP],
'regress/regress-put-prototype-transition': [SKIP],
'regress/regress-r3391': [SKIP],
'regress/regress-sliced-external-cons-regexp': [SKIP],
'regress/regress-store-heapobject': [SKIP],
'regress/regress-transcendental': [SKIP],
......@@ -1077,6 +1082,7 @@
'string-external-cached': [SKIP],
'string-externalize': [SKIP],
'string-natives': [SKIP],
'string-oom-array-join': [SKIP],
'string-replace-with-empty': [SKIP],
'string-slices': [SKIP],
'tools/profile': [SKIP],
......
......@@ -624,6 +624,7 @@
'built-ins/String/prototype/concat/S15.5.4.6_A2': [SKIP],
'built-ins/String/prototype/endsWith/this-is-undefined-throws': [SKIP],
'built-ins/String/prototype/includes/this-is-undefined-throws': [SKIP],
'built-ins/String/prototype/match/invoke-builtin-match': [SKIP],
'built-ins/String/prototype/repeat/this-is-undefined-throws': [SKIP],
'built-ins/String/prototype/startsWith/this-is-undefined-throws': [SKIP],
'built-ins/String/prototype/trim/15.5.4.20-1-1': [SKIP],
......
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