Commit 1ce720f2 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add explicit StackCheck bytecodes on function entry and back branches.

Moves the stack check from the function entry trampoline to instead be
after function activation using an explicit StackCheck bytecode. Also
add stack checks on back edges of loops.

BUG=v8:4280,v8:4678
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#33730}
parent 0f075613
......@@ -1042,18 +1042,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
__ b(hs, &ok);
__ push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load accumulator, register file, bytecode offset, dispatch table into
// registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
......
......@@ -1052,17 +1052,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
__ CompareRoot(jssp, Heap::kStackLimitRootIndex);
__ B(hs, &ok);
__ Push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ Pop(kInterpreterBytecodeArrayRegister);
__ Bind(&ok);
}
// Load accumulator, register file, bytecode offset, dispatch table into
// registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
......
......@@ -533,8 +533,7 @@ VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
return VectorSlotPair(feedback_vector, slot);
}
bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
bool BytecodeGraphBuilder::CreateGraph() {
// Set up the basic structure of the graph. Outputs for {Start} are
// the formal parameters (including the receiver) plus context and
// closure.
......@@ -550,7 +549,7 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
GetFunctionContext());
set_environment(&env);
CreateGraphBody(stack_check);
VisitBytecodes();
// Finish the basic structure of the graph.
DCHECK_NE(0u, exit_controls_.size());
......@@ -562,20 +561,6 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
return true;
}
void BytecodeGraphBuilder::CreateGraphBody(bool stack_check) {
// TODO(oth): Review ast-graph-builder equivalent, i.e. arguments
// object setup, this function variable if used, tracing hooks.
if (stack_check) {
Node* node = NewNode(javascript()->StackCheck());
PrepareEntryFrameState(node);
}
VisitBytecodes();
}
void BytecodeGraphBuilder::VisitBytecodes() {
BytecodeBranchAnalysis analysis(bytecode_array(), local_zone());
analysis.Analyze();
......@@ -1521,6 +1506,12 @@ void BytecodeGraphBuilder::VisitJumpIfUndefinedConstantWide() {
BuildJumpIfEqual(jsgraph()->UndefinedConstant());
}
void BytecodeGraphBuilder::VisitStackCheck() {
FrameStateBeforeAndAfter states(this);
Node* node = NewNode(javascript()->StackCheck());
environment()->RecordAfterState(node, &states);
}
void BytecodeGraphBuilder::VisitReturn() {
Node* control =
NewNode(common()->Return(), environment()->LookupAccumulator());
......@@ -1677,16 +1668,6 @@ void BytecodeGraphBuilder::EnterAndExitExceptionHandlers(int current_offset) {
}
}
void BytecodeGraphBuilder::PrepareEntryFrameState(Node* node) {
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node, 0)->opcode());
NodeProperties::ReplaceFrameStateInput(
node, 0, environment()->Checkpoint(BailoutId(0),
OutputFrameStateCombine::Ignore()));
}
Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
Node** value_inputs, bool incomplete) {
DCHECK_EQ(op->ValueInputCount(), value_input_count);
......
......@@ -23,13 +23,12 @@ class BytecodeGraphBuilder {
JSGraph* jsgraph);
// Creates a graph by visiting bytecodes.
bool CreateGraph(bool stack_check = true);
bool CreateGraph();
private:
class Environment;
class FrameStateBeforeAndAfter;
void CreateGraphBody(bool stack_check);
void VisitBytecodes();
// Get or create the node that represents the outer function closure.
......@@ -161,9 +160,6 @@ class BytecodeGraphBuilder {
// Simulates entry and exit of exception handlers.
void EnterAndExitExceptionHandlers(int current_offset);
// Attaches a frame state to |node| for the entry to the function.
void PrepareEntryFrameState(Node* node);
// Growth increment for the temporary buffer used to construct input lists to
// new nodes.
static const int kInputBufferSizeIncrement = 64;
......
......@@ -584,6 +584,11 @@ Node* InterpreterAssembler::CallRuntime(Node* function_id, Node* first_arg,
return CallN(descriptor, code_target, args);
}
Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id) {
CallPrologue();
Node* return_val = raw_assembler_->CallRuntime0(function_id, GetContext());
return return_val;
}
Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
Node* arg1) {
......@@ -702,6 +707,20 @@ void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) {
raw_assembler_->TailCallN(call_descriptor(), target_code_object, args);
}
void InterpreterAssembler::StackCheck() {
RawMachineLabel ok, stack_guard;
Node* sp = raw_assembler_->LoadStackPointer();
Node* stack_limit = raw_assembler_->Load(
MachineType::Pointer(),
raw_assembler_->ExternalConstant(
ExternalReference::address_of_stack_limit(isolate())));
Node* condition = raw_assembler_->UintPtrGreaterThanOrEqual(sp, stack_limit);
raw_assembler_->Branch(condition, &ok, &stack_guard);
raw_assembler_->Bind(&stack_guard);
CallRuntime(Runtime::kStackGuard);
raw_assembler_->Goto(&ok);
raw_assembler_->Bind(&ok);
}
void InterpreterAssembler::Abort(BailoutReason bailout_reason) {
Node* abort_id = SmiTag(Int32Constant(bailout_reason));
......
......@@ -136,6 +136,7 @@ class InterpreterAssembler {
// Call runtime function.
Node* CallRuntime(Node* function_id, Node* first_arg, Node* arg_count,
int return_size = 1);
Node* CallRuntime(Runtime::FunctionId function_id);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1, Node* arg2);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1, Node* arg2,
......@@ -150,6 +151,9 @@ class InterpreterAssembler {
// word values |lhs| and |rhs| are equal.
void JumpIfWordEqual(Node* lhs, Node* rhs, Node* jump_offset);
// Perform a stack guard check.
void StackCheck();
// Returns from the function.
void Return();
......
......@@ -515,7 +515,7 @@ struct GraphBuilderPhase {
if (data->info()->shared_info()->HasBytecodeArray()) {
BytecodeGraphBuilder graph_builder(temp_zone, data->info(),
data->jsgraph());
succeeded = graph_builder.CreateGraph(stack_check);
succeeded = graph_builder.CreateGraph();
} else {
AstGraphBuilderWithPositions graph_builder(
temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
......
......@@ -152,6 +152,19 @@ Node* RawMachineAssembler::CallNWithFrameState(CallDescriptor* desc,
return AddNode(common()->Call(desc), input_count, buffer);
}
Node* RawMachineAssembler::CallRuntime0(Runtime::FunctionId function,
Node* context) {
CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
zone(), function, 0, Operator::kNoProperties, CallDescriptor::kNoFlags);
int return_count = static_cast<int>(descriptor->ReturnCount());
Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
Node* ref = AddNode(
common()->ExternalConstant(ExternalReference(function, isolate())));
Node* arity = Int32Constant(0);
return AddNode(common()->Call(descriptor), centry, ref, arity, context);
}
Node* RawMachineAssembler::CallRuntime1(Runtime::FunctionId function,
Node* arg1, Node* context) {
......
......@@ -278,6 +278,10 @@ class RawMachineAssembler {
Node* Int32GreaterThanOrEqual(Node* a, Node* b) {
return Int32LessThanOrEqual(b, a);
}
Node* Uint32GreaterThan(Node* a, Node* b) { return Uint32LessThan(b, a); }
Node* Uint32GreaterThanOrEqual(Node* a, Node* b) {
return Uint32LessThanOrEqual(b, a);
}
Node* Int32Neg(Node* a) { return Int32Sub(Int32Constant(0), a); }
Node* Int64Add(Node* a, Node* b) {
......@@ -318,6 +322,10 @@ class RawMachineAssembler {
Node* Int64GreaterThanOrEqual(Node* a, Node* b) {
return Int64LessThanOrEqual(b, a);
}
Node* Uint64GreaterThan(Node* a, Node* b) { return Uint64LessThan(b, a); }
Node* Uint64GreaterThanOrEqual(Node* a, Node* b) {
return Uint64LessThanOrEqual(b, a);
}
Node* Uint64Div(Node* a, Node* b) {
return AddNode(machine()->Uint64Div(), a, b);
}
......@@ -342,6 +350,19 @@ class RawMachineAssembler {
#undef INTPTR_BINOP
#define UINTPTR_BINOP(prefix, name) \
Node* UintPtr##name(Node* a, Node* b) { \
return kPointerSize == 8 ? prefix##64##name(a, b) \
: prefix##32##name(a, b); \
}
UINTPTR_BINOP(Uint, LessThan);
UINTPTR_BINOP(Uint, LessThanOrEqual);
UINTPTR_BINOP(Uint, GreaterThanOrEqual);
UINTPTR_BINOP(Uint, GreaterThan);
#undef UINTPTR_BINOP
Node* Float32Add(Node* a, Node* b) {
return AddNode(machine()->Float32Add(), a, b);
}
......@@ -567,6 +588,8 @@ class RawMachineAssembler {
// Call a given call descriptor and the given arguments and frame-state.
Node* CallNWithFrameState(CallDescriptor* desc, Node* function, Node** args,
Node* frame_state);
// Call to a runtime function with zero arguments.
Node* CallRuntime0(Runtime::FunctionId function, Node* context);
// Call to a runtime function with one arguments.
Node* CallRuntime1(Runtime::FunctionId function, Node* arg0, Node* context);
// Call to a runtime function with two arguments.
......
......@@ -600,19 +600,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(masm->isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &ok);
__ push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load accumulator, register file, bytecode offset, dispatch table into
// registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
......
......@@ -964,6 +964,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
return OutputJump(Bytecode::kJumpIfUndefined, label);
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck() {
Output(Bytecode::kStackCheck);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
Output(Bytecode::kThrow);
......
......@@ -236,6 +236,8 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
BytecodeArrayBuilder& StackCheck();
BytecodeArrayBuilder& Throw();
BytecodeArrayBuilder& ReThrow();
BytecodeArrayBuilder& Return();
......
......@@ -609,6 +609,9 @@ void BytecodeGenerator::MakeBytecodeBody() {
// Visit declarations within the function scope.
VisitDeclarations(scope()->declarations());
// Perform a stack-check before the body.
builder()->StackCheck();
// Visit statements in the function body.
VisitStatements(info()->literal()->body());
}
......@@ -921,20 +924,25 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
UNREACHABLE();
}
void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
LoopBuilder* loop_builder) {
ControlScopeForIteration execution_control(this, stmt, loop_builder);
builder()->StackCheck();
Visit(stmt->body());
}
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
LoopBuilder loop_builder(builder());
ControlScopeForIteration execution_control(this, stmt, &loop_builder);
loop_builder.LoopHeader();
if (stmt->cond()->ToBooleanIsFalse()) {
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
loop_builder.Condition();
} else if (stmt->cond()->ToBooleanIsTrue()) {
loop_builder.Condition();
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
loop_builder.JumpToHeader();
} else {
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
loop_builder.Condition();
VisitForAccumulatorValue(stmt->cond());
loop_builder.JumpToHeaderIfTrue();
......@@ -942,7 +950,6 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
loop_builder.EndLoop();
}
void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
if (stmt->cond()->ToBooleanIsFalse()) {
// If the condition is false there is no need to generate the loop.
......@@ -950,14 +957,13 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
}
LoopBuilder loop_builder(builder());
ControlScopeForIteration execution_control(this, stmt, &loop_builder);
loop_builder.LoopHeader();
loop_builder.Condition();
if (!stmt->cond()->ToBooleanIsTrue()) {
VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse();
}
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
loop_builder.JumpToHeader();
loop_builder.EndLoop();
}
......@@ -974,15 +980,13 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
}
LoopBuilder loop_builder(builder());
ControlScopeForIteration execution_control(this, stmt, &loop_builder);
loop_builder.LoopHeader();
loop_builder.Condition();
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse();
}
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
if (stmt->next() != nullptr) {
loop_builder.Next();
Visit(stmt->next());
......@@ -1043,7 +1047,6 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
}
LoopBuilder loop_builder(builder());
ControlScopeForIteration control_scope(this, stmt, &loop_builder);
BytecodeLabel subject_null_label, subject_undefined_label, not_object_label;
// Prepare the state for executing ForIn.
......@@ -1077,7 +1080,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->ForInNext(receiver, index, cache_type);
loop_builder.ContinueIfUndefined();
VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
loop_builder.Next();
builder()->ForInStep(index);
builder()->StoreAccumulatorInRegister(index);
......@@ -1102,7 +1105,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
loop_builder.BreakIfTrue();
VisitForEffect(stmt->assign_each());
Visit(stmt->body());
VisitIterationBody(stmt, &loop_builder);
loop_builder.JumpToHeader();
loop_builder.EndLoop();
}
......
......@@ -13,6 +13,8 @@ namespace v8 {
namespace internal {
namespace interpreter {
class LoopBuilder;
class BytecodeGenerator final : public AstVisitor {
public:
BytecodeGenerator(Isolate* isolate, Zone* zone);
......@@ -94,6 +96,9 @@ class BytecodeGenerator final : public AstVisitor {
Register value_out);
void VisitForInAssignment(Expression* expr, FeedbackVectorSlot slot);
// Visit the body of a loop iteration.
void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
// Visit a statement and switch scopes, the context is in the accumulator.
void VisitInScope(Statement* stmt, Scope* scope);
......
......@@ -259,6 +259,9 @@ namespace interpreter {
OperandType::kRegPair16) \
V(ForInStep, OperandType::kReg8) \
\
/* Perform a stack guard check */ \
V(StackCheck, OperandType::kNone) \
\
/* Non-local flow control */ \
V(Throw, OperandType::kNone) \
V(ReThrow, OperandType::kNone) \
......
......@@ -91,7 +91,6 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info);
if (FLAG_print_bytecode) {
OFStream os(stdout);
os << "Function: " << info->GetDebugName().get() << std::endl;
bytecodes->Print(os);
os << std::flush;
}
......@@ -1788,6 +1787,14 @@ void Interpreter::DoCreateRestArguments(
__ Dispatch();
}
// StackCheck
//
// Performs a stack guard check.
void Interpreter::DoStackCheck(compiler::InterpreterAssembler* assembler) {
__ StackCheck();
__ Dispatch();
}
// Throw
//
// Throws the exception in the accumulator.
......
......@@ -1031,17 +1031,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
__ LoadRoot(at, Heap::kStackLimitRootIndex);
__ Branch(&ok, hs, sp, Operand(at));
__ push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load bytecode offset and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ Addu(kInterpreterRegisterFileRegister, fp,
......
......@@ -1024,17 +1024,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
__ LoadRoot(at, Heap::kStackLimitRootIndex);
__ Branch(&ok, hs, sp, Operand(at));
__ push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load bytecode offset and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ Daddu(kInterpreterRegisterFileRegister, fp,
......
......@@ -1032,18 +1032,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
__ LoadRoot(r0, Heap::kStackLimitRootIndex);
__ cmp(sp, r0);
__ bge(&ok);
__ push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load accumulator, register file, bytecode offset, dispatch table into
// registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
......
......@@ -670,17 +670,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, &ok, Label::kNear);
__ Push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ Pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load accumulator, register file, bytecode offset, dispatch table into
// registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
......
......@@ -601,19 +601,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Allow simulator stop operations if FLAG_stop_at is set.
// - Code aging of the BytecodeArray object.
// Perform stack guard check.
{
Label ok;
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(masm->isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &ok);
__ push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard);
__ pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
// Load accumulator, register file, bytecode offset, dispatch table into
// registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
......
......@@ -682,21 +682,6 @@
'test-func-name-inference/MethodAssignmentInAnonymousFunctionCall': [SKIP],
'test-func-name-inference/AssignmentAndCall': [SKIP],
'test-func-name-inference/ReturnAnonymousFunction': [SKIP],
# TODO(rmcilroy,4680): Test timeouts.
'test-thread-termination/TerminateOnlyV8ThreadFromThreadItself': [SKIP],
'test-thread-termination/TerminateOnlyV8ThreadFromThreadItselfNoLoop': [SKIP],
'test-thread-termination/TerminateOnlyV8ThreadFromOtherThread': [SKIP],
'test-thread-termination/TerminateAndReenterFromThreadItself': [SKIP],
'test-thread-termination/TerminateCancelTerminateFromThreadItself': [SKIP],
'test-thread-termination/TerminationInInnerTryCall': [SKIP],
'test-thread-termination/TerminateFromOtherThreadWhileMicrotaskRunning': [SKIP],
'test-api/RequestInterruptTestWithFunctionCall': [SKIP],
'test-api/RequestInterruptTestWithAccessor': [SKIP],
'test-api/RequestInterruptTestWithNativeAccessor': [SKIP],
'test-api/RequestInterruptTestWithMethodCall': [SKIP],
'test-api/RequestMultipleInterrupts': [SKIP],
'test-api/RequestInterruptTestWithMethodCallAndInterceptor': [SKIP],
}], # ignition == True
['ignition == True and mode == debug and arch == x64', {
......
......@@ -759,6 +759,9 @@
# TODO(4674): This might be failing because of missing context switch.
'with-leave': [FAIL],
# TODO(4690): Failing in debugger DebuggerInspectableFrame.
'for-in-opt': [FAIL],
'arguments-load-across-eval': [SKIP],
'array-constructor': [PASS, SLOW],
'array-functions-prototype-misc': [SKIP],
......
......@@ -195,6 +195,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
.JumpIfFalse(&start);
// Emit stack check bytecode.
builder.StackCheck();
// Emit throw and re-throw in it's own basic block so that the rest of the
// code isn't omitted due to being dead.
BytecodeLabel after_throw;
......
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