Commit b0907152 authored by neis's avatar neis Committed by Commit bot

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}
parent f4a9a501
......@@ -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,
......
......@@ -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);
......
......@@ -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();
......
......@@ -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)
......
......@@ -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);
......
......@@ -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());
......
......@@ -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);
......
......@@ -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).
......
......@@ -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) \
......
......@@ -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
......@@ -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,
......
......@@ -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
......@@ -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
......@@ -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) \
......
......@@ -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],
]
......@@ -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);
......
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