Introduce bytecodes for assisting generator suspend and resume.

The new bytecodes replace two runtime functions. They are still unsupported by the bytecode graphbuilder, though.

BUG=v8:4907
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#35716}
This commit is contained in:
neis 2016-04-22 02:17:58 -07:00 committed by Commit bot
parent f4a9a50147
commit b090715250
16 changed files with 275 additions and 159 deletions

View File

@ -406,7 +406,7 @@ Node* CodeStubAssembler::AllocateRawAligned(Node* size_in_bytes,
return address.value();
}
Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) {
Node* CodeStubAssembler::Allocate(Node* size_in_bytes, AllocationFlags flags) {
bool const new_space = !(flags & kPretenured);
Node* top_address = ExternalConstant(
new_space
@ -419,13 +419,15 @@ Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) {
#ifdef V8_HOST_ARCH_32_BIT
if (flags & kDoubleAlignment) {
return AllocateRawAligned(IntPtrConstant(size_in_bytes), flags, top_address,
limit_address);
return AllocateRawAligned(size_in_bytes, flags, top_address, limit_address);
}
#endif
return AllocateRawUnaligned(IntPtrConstant(size_in_bytes), flags, top_address,
limit_address);
return AllocateRawUnaligned(size_in_bytes, flags, top_address, limit_address);
}
Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) {
return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags);
}
Node* CodeStubAssembler::InnerAllocate(Node* previous, int offset) {
@ -492,6 +494,19 @@ Node* CodeStubAssembler::LoadNameHash(Node* name) {
IntPtrConstant(Name::kHashFieldOffset - kHeapObjectTag));
}
Node* CodeStubAssembler::AllocateUninitializedFixedArray(Node* length) {
Node* header_size = IntPtrConstant(FixedArray::kHeaderSize);
Node* data_size = WordShl(length, IntPtrConstant(kPointerSizeLog2));
Node* total_size = IntPtrAdd(data_size, header_size);
Node* result = Allocate(total_size, kNone);
StoreMapNoWriteBarrier(result, LoadRoot(Heap::kFixedArrayMapRootIndex));
StoreObjectFieldNoWriteBarrier(result, FixedArray::kLengthOffset,
SmiTag(length));
return result;
}
Node* CodeStubAssembler::LoadFixedArrayElementInt32Index(
Node* object, Node* index, int additional_offset) {
Node* header_size = IntPtrConstant(additional_offset +
@ -537,6 +552,12 @@ Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), value);
}
Node* CodeStubAssembler::StoreObjectField(
Node* object, int offset, Node* value) {
return Store(MachineRepresentation::kTagged, object,
IntPtrConstant(offset - kHeapObjectTag), value);
}
Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
Node* object, int offset, Node* value, MachineRepresentation rep) {
return StoreNoWriteBarrier(rep, object,

View File

@ -68,6 +68,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* SmiMin(compiler::Node* a, compiler::Node* b);
// Allocate an object of the given size.
compiler::Node* Allocate(compiler::Node* size, AllocationFlags flags = kNone);
compiler::Node* Allocate(int size, AllocationFlags flags = kNone);
compiler::Node* InnerAllocate(compiler::Node* previous, int offset);
@ -123,6 +124,8 @@ class CodeStubAssembler : public compiler::CodeAssembler {
// Load the instance size of a Map.
compiler::Node* LoadMapInstanceSize(compiler::Node* map);
compiler::Node* AllocateUninitializedFixedArray(compiler::Node* length);
// Load an array element from a FixedArray.
compiler::Node* LoadFixedArrayElementInt32Index(compiler::Node* object,
compiler::Node* int32_index,
@ -137,6 +140,8 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* StoreHeapNumberValue(compiler::Node* object,
compiler::Node* value);
// Store a field to an object on the heap.
compiler::Node* StoreObjectField(
compiler::Node* object, int offset, compiler::Node* value);
compiler::Node* StoreObjectFieldNoWriteBarrier(
compiler::Node* object, int offset, compiler::Node* value,
MachineRepresentation rep = MachineRepresentation::kTagged);

View File

@ -1362,6 +1362,14 @@ void BytecodeGraphBuilder::VisitForInStep() {
environment()->BindAccumulator(index, &states);
}
void BytecodeGraphBuilder::VisitSuspendGenerator() {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitResumeGenerator() {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitWide() {
// Consumed by the BytecodeArrayIterator.
UNREACHABLE();

View File

@ -176,6 +176,13 @@ Node* CodeAssembler::ChangeUint32ToWord(Node* value) {
return value;
}
Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) {
if (raw_assembler_->machine()->Is64()) {
value = raw_assembler_->ChangeInt32ToInt64(value);
}
return value;
}
#define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \
Node* CodeAssembler::name(Node* a) { return raw_assembler_->name(a); }
CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)

View File

@ -245,6 +245,8 @@ class CodeAssembler {
Node* TruncateFloat64ToInt32JavaScript(Node* a);
// No-op on 32-bit, otherwise zero extend.
Node* ChangeUint32ToWord(Node* value);
// No-op on 32-bit, otherwise sign extend.
Node* ChangeInt32ToIntPtr(Node* value);
// Projections
Node* Projection(int index, Node* value);

View File

@ -941,6 +941,24 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
}
BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
Register generator) {
OperandScale operand_scale = OperandSizesToScale(generator.SizeOfOperand());
OutputScaled(Bytecode::kSuspendGenerator, operand_scale,
RegisterOperand(generator));
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
Register generator) {
OperandScale operand_scale = OperandSizesToScale(generator.SizeOfOperand());
OutputScaled(Bytecode::kResumeGenerator, operand_scale,
RegisterOperand(generator));
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(int handler_id,
bool will_catch) {
handler_table_builder()->SetHandlerTarget(handler_id, bytecodes()->size());

View File

@ -243,6 +243,10 @@ class BytecodeArrayBuilder final : public ZoneObject {
int feedback_slot);
BytecodeArrayBuilder& ForInStep(Register index);
// Generators.
BytecodeArrayBuilder& SuspendGenerator(Register generator);
BytecodeArrayBuilder& ResumeGenerator(Register generator);
// Exception handling.
BytecodeArrayBuilder& MarkHandler(int handler_id, bool will_catch);
BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);

View File

@ -644,8 +644,7 @@ void BytecodeGenerator::VisitGeneratorPrologue() {
RegisterAllocationScope register_scope(this);
Register state = register_allocator()->NewRegister();
builder()
->CallRuntime(Runtime::kResumeIgnitionGenerator, Register::new_target(),
1)
->ResumeGenerator(Register::new_target())
.StoreAccumulatorInRegister(state);
// TODO(neis): Optimize this by using a proper jump table.
@ -2218,16 +2217,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
builder()->SetExpressionPosition(expr);
Register value = VisitForRegisterValue(expr->expression());
register_allocator()->PrepareForConsecutiveAllocations(2);
Register generator = register_allocator()->NextConsecutiveRegister();
Register state = register_allocator()->NextConsecutiveRegister();
Register generator = VisitForRegisterValue(expr->generator_object());
// Save context, registers, and state. Then return.
VisitForRegisterValue(expr->generator_object(), generator);
builder()
->LoadLiteral(Smi::FromInt(id))
.StoreAccumulatorInRegister(state)
.CallRuntime(Runtime::kSuspendIgnitionGenerator, generator, 2)
.SuspendGenerator(generator)
.LoadAccumulatorWithRegister(value)
.Return(); // Hard return (ignore any finally blocks).

View File

@ -241,6 +241,10 @@ namespace interpreter {
V(ReThrow, AccumulatorUse::kRead) \
V(Return, AccumulatorUse::kNone) \
\
/* Generators */ \
V(SuspendGenerator, AccumulatorUse::kRead, OperandType::kReg) \
V(ResumeGenerator, AccumulatorUse::kWrite, OperandType::kReg) \
\
/* Debugger */ \
V(Debugger, AccumulatorUse::kNone) \
DEBUG_BREAK_BYTECODE_LIST(V) \

View File

@ -371,11 +371,6 @@ Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) {
return Load(MachineType::AnyTagged(), constant_pool, entry_offset);
}
Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
return Load(MachineType::AnyTagged(), object,
IntPtrConstant(offset - kHeapObjectTag));
}
Node* InterpreterAssembler::LoadContextSlot(Node* context, int slot_index) {
return Load(MachineType::AnyTagged(), context,
IntPtrConstant(Context::SlotOffset(slot_index)));
@ -713,6 +708,75 @@ bool InterpreterAssembler::TargetSupportsUnalignedAccess() {
#endif
}
Node* InterpreterAssembler::RegisterCount() {
Node* bytecode_array = LoadRegister(Register::bytecode_array());
Node* frame_size = LoadObjectField(
bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32());
return Word32Sar(frame_size, Int32Constant(kPointerSizeLog2));
}
Node* InterpreterAssembler::ExportRegisterFile() {
Node* register_count = RegisterCount();
Node* array =
AllocateUninitializedFixedArray(ChangeInt32ToIntPtr(register_count));
Variable var_index(this, MachineRepresentation::kWord32);
var_index.Bind(Int32Constant(0));
// Iterate over register file and write values into array.
Label loop(this, &var_index), done_loop(this);
Goto(&loop);
Bind(&loop);
{
Node* index = var_index.value();
Node* condition = Int32LessThan(index, register_count);
GotoUnless(condition, &done_loop);
Node* reg_index =
Int32Sub(Int32Constant(Register(0).ToOperand()), index);
Node* value = LoadRegister(ChangeInt32ToIntPtr(reg_index));
// No write barrier needed for writing into freshly allocated object.
StoreFixedArrayElementNoWriteBarrier(
array, ChangeInt32ToIntPtr(index), value);
var_index.Bind(Int32Add(index, Int32Constant(1)));
Goto(&loop);
}
Bind(&done_loop);
return array;
}
Node* InterpreterAssembler::ImportRegisterFile(Node* array) {
Node* register_count = RegisterCount();
Variable var_index(this, MachineRepresentation::kWord32);
var_index.Bind(Int32Constant(0));
// Iterate over array and write values into register file.
Label loop(this, &var_index), done_loop(this);
Goto(&loop);
Bind(&loop);
{
Node* index = var_index.value();
Node* condition = Int32LessThan(index, register_count);
GotoUnless(condition, &done_loop);
Node* value = LoadFixedArrayElementInt32Index(array, index);
Node* reg_index =
Int32Sub(Int32Constant(Register(0).ToOperand()), index);
StoreRegister(value, ChangeInt32ToIntPtr(reg_index));
var_index.Bind(Int32Add(index, Int32Constant(1)));
Goto(&loop);
}
Bind(&done_loop);
return array;
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -50,6 +50,13 @@ class InterpreterAssembler : public CodeStubAssembler {
compiler::Node* GetContext();
void SetContext(compiler::Node* value);
// Number of registers.
compiler::Node* RegisterCount();
// Backup/restore register file to/from a fixed array.
compiler::Node* ExportRegisterFile();
compiler::Node* ImportRegisterFile(compiler::Node* array);
// Loads from and stores to the interpreter register file.
compiler::Node* LoadRegister(Register reg);
compiler::Node* LoadRegister(compiler::Node* reg_index);
@ -67,9 +74,6 @@ class InterpreterAssembler : public CodeStubAssembler {
// Load constant at |index| in the constant pool.
compiler::Node* LoadConstantPoolEntry(compiler::Node* index);
// Load a field from an object on the heap.
compiler::Node* LoadObjectField(compiler::Node* object, int offset);
// Load |slot_index| from |context|.
compiler::Node* LoadContextSlot(compiler::Node* context, int slot_index);
compiler::Node* LoadContextSlot(compiler::Node* context,

View File

@ -1695,6 +1695,49 @@ void Interpreter::DoIllegal(InterpreterAssembler* assembler) {
__ Abort(kInvalidBytecode);
}
// SuspendGenerator <generator>
//
// Exports the register file and stores it into the generator. Also stores the
// current context and the state given in the accumulator into the generator.
void Interpreter::DoSuspendGenerator(InterpreterAssembler* assembler) {
Node* generator_reg = __ BytecodeOperandReg(0);
Node* generator = __ LoadRegister(generator_reg);
Node* array = __ ExportRegisterFile();
Node* context = __ GetContext();
Node* state = __ GetAccumulator();
__ StoreObjectField(generator, JSGeneratorObject::kOperandStackOffset, array);
__ StoreObjectField(generator, JSGeneratorObject::kContextOffset, context);
__ StoreObjectField(generator, JSGeneratorObject::kContinuationOffset, state);
__ Dispatch();
}
// ResumeGenerator <generator>
//
// Imports the register file stored in the generator. Also loads the
// generator's state and stores it in the accumulator, before overwriting it
// with kGeneratorExecuting.
void Interpreter::DoResumeGenerator(InterpreterAssembler* assembler) {
Node* generator_reg = __ BytecodeOperandReg(0);
Node* generator = __ LoadRegister(generator_reg);
__ ImportRegisterFile(
__ LoadObjectField(generator, JSGeneratorObject::kOperandStackOffset));
__ StoreObjectField(generator, JSGeneratorObject::kOperandStackOffset,
__ HeapConstant(isolate_->factory()->empty_fixed_array()));
Node* old_state =
__ LoadObjectField(generator, JSGeneratorObject::kContinuationOffset);
Node* new_state = __ Int32Constant(JSGeneratorObject::kGeneratorExecuting);
__ StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
__ SmiTag(new_state));
__ SetAccumulator(old_state);
__ Dispatch();
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -145,60 +145,5 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_SuspendIgnitionGenerator) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
CONVERT_ARG_HANDLE_CHECKED(Smi, state, 1);
JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame();
Handle<JSFunction> function(frame->function());
CHECK(function->shared()->is_generator());
CHECK_EQ(frame->type(), StackFrame::INTERPRETED);
// Save register file.
int size = function->shared()->bytecode_array()->register_count();
Handle<FixedArray> register_file = isolate->factory()->NewFixedArray(size);
for (int i = 0; i < size; ++i) {
Object* value =
static_cast<InterpretedFrame*>(frame)->ReadInterpreterRegister(i);
register_file->set(i, value);
}
generator->set_operand_stack(*register_file);
generator->set_context(Context::cast(frame->context()));
generator->set_continuation(state->value());
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ResumeIgnitionGenerator) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame();
Handle<JSFunction> function(frame->function());
CHECK(function->shared()->is_generator());
CHECK_EQ(frame->type(), StackFrame::INTERPRETED);
// Restore register file.
int size = function->shared()->bytecode_array()->register_count();
DCHECK_EQ(size, generator->operand_stack()->length());
for (int i = 0; i < size; ++i) {
Object* value = generator->operand_stack()->get(i);
static_cast<InterpretedFrame*>(frame)->WriteInterpreterRegister(i, value);
}
generator->set_operand_stack(isolate->heap()->empty_fixed_array());
int state = generator->continuation();
generator->set_continuation(JSGeneratorObject::kGeneratorExecuting);
return Smi::FromInt(state);
}
} // namespace internal
} // namespace v8

View File

@ -237,9 +237,7 @@ namespace internal {
F(GeneratorGetInput, 1, 1) \
F(GeneratorGetContinuation, 1, 1) \
F(GeneratorGetSourcePosition, 1, 1) \
F(GeneratorGetResumeMode, 1, 1) \
F(SuspendIgnitionGenerator, 2, 1) \
F(ResumeIgnitionGenerator, 1, 1)
F(GeneratorGetResumeMode, 1, 1)
#ifdef V8_I18N_SUPPORT
#define FOR_EACH_INTRINSIC_I18N(F) \

View File

@ -13,17 +13,17 @@ ignition generators: yes
snippet: "
function* f() { }
"
frame size: 11
frame size: 10
parameter count: 1
bytecode array length: 201
bytecode array length: 193
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(15),
B(CallRuntime), U16(Runtime::kResumeIgnitionGenerator), R(new_target), U8(1),
B(JumpIfUndefined), U8(12),
B(ResumeGenerator), R(new_target),
B(Star), R(1),
B(LdaZero),
B(TestEqualStrict), R(1),
B(JumpIfTrue), U8(54),
B(JumpIfTrue), U8(49),
B(Illegal),
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), U8(1),
B(PushContext), R(0),
@ -41,32 +41,31 @@ bytecodes: [
B(LdaContextSlot), R(context), U8(5),
B(Star), R(5),
B(LdaZero),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kSuspendIgnitionGenerator), R(5), U8(2),
B(SuspendGenerator), R(5),
B(Ldar), R(4),
B(Return),
B(CallRuntime), U16(Runtime::kGeneratorGetInput), R(5), U8(1),
B(Star), R(7),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kGeneratorGetResumeMode), R(5), U8(1),
B(Star), R(8),
B(Star), R(7),
B(LdaZero),
B(TestEqualStrict), R(8),
B(TestEqualStrict), R(7),
B(JumpIfTrue), U8(31),
B(LdaSmi), U8(2),
B(TestEqualStrict), R(8),
B(TestEqualStrict), R(7),
B(JumpIfTrue), U8(22),
B(Jump), U8(2),
B(Mov), R(7), R(9),
B(Mov), R(6), R(8),
B(LdaTrue),
B(Star), R(10),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(9), U8(2),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(8), U8(2),
B(Star), R(2),
B(LdaZero),
B(Star), R(1),
B(Jump), U8(38),
B(Ldar), R(7),
B(Ldar), R(6),
B(Throw),
B(Ldar), R(7),
B(Ldar), R(6),
B(LdaUndefined),
B(Star), R(4),
B(LdaTrue),
@ -110,27 +109,27 @@ bytecodes: [
constant pool: [
]
handlers: [
[33, 137, 143],
[30, 129, 135],
]
---
snippet: "
function* f() { yield 42 }
"
frame size: 11
frame size: 10
parameter count: 1
bytecode array length: 298
bytecode array length: 285
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(21),
B(CallRuntime), U16(Runtime::kResumeIgnitionGenerator), R(new_target), U8(1),
B(JumpIfUndefined), U8(18),
B(ResumeGenerator), R(new_target),
B(Star), R(1),
B(LdaZero),
B(TestEqualStrict), R(1),
B(JumpIfTrue), U8(60),
B(JumpIfTrue), U8(55),
B(LdaSmi), U8(1),
B(TestEqualStrict), R(1),
B(JumpIfTrueConstant), U8(0),
B(JumpIfTrue), U8(125),
B(Illegal),
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), U8(1),
B(PushContext), R(0),
@ -148,32 +147,31 @@ bytecodes: [
B(LdaContextSlot), R(context), U8(5),
B(Star), R(5),
B(LdaZero),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kSuspendIgnitionGenerator), R(5), U8(2),
B(SuspendGenerator), R(5),
B(Ldar), R(4),
B(Return),
B(CallRuntime), U16(Runtime::kGeneratorGetInput), R(5), U8(1),
B(Star), R(7),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kGeneratorGetResumeMode), R(5), U8(1),
B(Star), R(8),
B(Star), R(7),
B(LdaZero),
B(TestEqualStrict), R(8),
B(TestEqualStrict), R(7),
B(JumpIfTrue), U8(31),
B(LdaSmi), U8(2),
B(TestEqualStrict), R(8),
B(TestEqualStrict), R(7),
B(JumpIfTrue), U8(22),
B(Jump), U8(2),
B(Mov), R(7), R(9),
B(Mov), R(6), R(8),
B(LdaTrue),
B(Star), R(10),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(9), U8(2),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(8), U8(2),
B(Star), R(2),
B(LdaZero),
B(Star), R(1),
B(Jump), U8(120),
B(Ldar), R(7),
B(Jump), U8(115),
B(Ldar), R(6),
B(Throw),
B(Ldar), R(7),
B(Ldar), R(6),
B(LdaSmi), U8(42),
B(Star), R(4),
B(LdaFalse),
@ -183,32 +181,31 @@ bytecodes: [
B(LdaContextSlot), R(context), U8(5),
B(Star), R(4),
B(LdaSmi), U8(1),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kSuspendIgnitionGenerator), R(4), U8(2),
B(SuspendGenerator), R(4),
B(Ldar), R(6),
B(Return),
B(CallRuntime), U16(Runtime::kGeneratorGetInput), R(4), U8(1),
B(Star), R(7),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kGeneratorGetResumeMode), R(4), U8(1),
B(Star), R(8),
B(Star), R(7),
B(LdaZero),
B(TestEqualStrict), R(8),
B(TestEqualStrict), R(7),
B(JumpIfTrue), U8(32),
B(LdaSmi), U8(2),
B(TestEqualStrict), R(8),
B(TestEqualStrict), R(7),
B(JumpIfTrue), U8(23),
B(Jump), U8(2),
B(Mov), R(7), R(9),
B(Mov), R(5), R(8),
B(LdaTrue),
B(Star), R(10),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(9), U8(2),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(8), U8(2),
B(Star), R(2),
B(LdaSmi), U8(1),
B(Star), R(1),
B(Jump), U8(38),
B(Ldar), R(7),
B(Ldar), R(5),
B(Throw),
B(Ldar), R(7),
B(Ldar), R(5),
B(LdaUndefined),
B(Star), R(4),
B(LdaTrue),
@ -255,27 +252,26 @@ bytecodes: [
B(Return),
]
constant pool: [
kInstanceTypeDontCare,
]
handlers: [
[39, 225, 231],
[36, 212, 218],
]
---
snippet: "
function* f() { for (let x of [42]) yield x }
"
frame size: 17
frame size: 16
parameter count: 1
bytecode array length: 786
bytecode array length: 773
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(21),
B(CallRuntime), U16(Runtime::kResumeIgnitionGenerator), R(new_target), U8(1),
B(JumpIfUndefined), U8(18),
B(ResumeGenerator), R(new_target),
B(Star), R(3),
B(LdaZero),
B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(60),
B(JumpIfTrue), U8(55),
B(LdaSmi), U8(1),
B(TestEqualStrict), R(3),
B(JumpIfTrueConstant), U8(8),
@ -296,32 +292,31 @@ bytecodes: [
B(LdaContextSlot), R(context), U8(5),
B(Star), R(7),
B(LdaZero),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kSuspendIgnitionGenerator), R(7), U8(2),
B(SuspendGenerator), R(7),
B(Ldar), R(6),
B(Return),
B(CallRuntime), U16(Runtime::kGeneratorGetInput), R(7), U8(1),
B(Star), R(9),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kGeneratorGetResumeMode), R(7), U8(1),
B(Star), R(10),
B(Star), R(9),
B(LdaZero),
B(TestEqualStrict), R(10),
B(TestEqualStrict), R(9),
B(JumpIfTrue), U8(31),
B(LdaSmi), U8(2),
B(TestEqualStrict), R(10),
B(TestEqualStrict), R(9),
B(JumpIfTrue), U8(22),
B(Jump), U8(2),
B(Mov), R(9), R(11),
B(Mov), R(8), R(10),
B(LdaTrue),
B(Star), R(12),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(11), U8(2),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(10), U8(2),
B(Star), R(4),
B(LdaZero),
B(Star), R(3),
B(JumpConstant), U8(16),
B(Ldar), R(9),
B(Ldar), R(8),
B(Throw),
B(Ldar), R(9),
B(Ldar), R(8),
B(LdaConstant), U8(0),
B(Star), R(6),
B(Ldar), R(closure),
@ -391,25 +386,24 @@ bytecodes: [
B(LdaContextSlot), R(1), U8(5),
B(Star), R(10),
B(LdaSmi), U8(1),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kSuspendIgnitionGenerator), R(10), U8(2),
B(SuspendGenerator), R(10),
B(Ldar), R(12),
B(Return),
B(CallRuntime), U16(Runtime::kGeneratorGetInput), R(10), U8(1),
B(Star), R(13),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kGeneratorGetResumeMode), R(10), U8(1),
B(Star), R(14),
B(Star), R(13),
B(LdaZero),
B(TestEqualStrict), R(14),
B(TestEqualStrict), R(13),
B(JumpIfTrue), U8(45),
B(LdaSmi), U8(2),
B(TestEqualStrict), R(14),
B(TestEqualStrict), R(13),
B(JumpIfTrue), U8(36),
B(Jump), U8(2),
B(Mov), R(13), R(15),
B(Mov), R(11), R(14),
B(LdaTrue),
B(Star), R(16),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(15), U8(2),
B(Star), R(15),
B(CallRuntime), U16(Runtime::kCreateIterResultObject), R(14), U8(2),
B(PopContext), R(2),
B(PopContext), R(2),
B(PopContext), R(2),
@ -421,13 +415,13 @@ bytecodes: [
B(LdaZero),
B(Star), R(6),
B(Jump), U8(78),
B(Ldar), R(13),
B(Ldar), R(11),
B(Throw),
B(Ldar), R(13),
B(Ldar), R(11),
B(PopContext), R(2),
B(LdaZero),
B(StaContextSlot), R(1), U8(9),
B(Wide), B(Jump), U16(-210),
B(Wide), B(Jump), U16(-205),
B(Jump), U8(49),
B(Star), R(11),
B(LdaConstant), U8(10),
@ -621,9 +615,9 @@ constant pool: [
kInstanceTypeDontCare,
]
handlers: [
[39, 704, 710],
[154, 440, 446],
[157, 391, 393],
[548, 563, 565],
[36, 691, 697],
[146, 427, 433],
[149, 378, 380],
[535, 550, 552],
]

View File

@ -289,6 +289,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperation(Token::Value::ADD, reg)
.JumpIfFalse(&start);
// Emit generator operations
builder.SuspendGenerator(reg)
.ResumeGenerator(reg);
// Intrinsics handled by the interpreter.
builder.CallRuntime(Runtime::kInlineIsArray, reg, 1)
.CallRuntime(Runtime::kInlineIsArray, wide, 1);