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:
parent
f4a9a50147
commit
b090715250
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user