[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}
This commit is contained in:
rmcilroy 2016-02-04 04:33:13 -08:00 committed by Commit bot
parent 0f075613e7
commit 1ce720f2a4
25 changed files with 1254 additions and 700 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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));

View File

@ -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();

View File

@ -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(),

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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();
}

View File

@ -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);

View File

@ -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) \

View File

@ -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.

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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', {

File diff suppressed because it is too large Load Diff

View File

@ -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],

View File

@ -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;