[generators] Implement %GeneratorGetSourcePosition.
This runtime function now also works for Ignition generators. It returns the source position of the yield at which a suspended generator got suspended. This works by storing the current bytecode offset at suspension and using an existing mechanism to map it back to a source position. TBR=littledan@chromium.org BUG= Review-Url: https://codereview.chromium.org/2079613003 Cr-Commit-Position: refs/heads/master@{#37140}
This commit is contained in:
parent
1f12208101
commit
7c57ffc1df
@ -693,8 +693,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(r1);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ str(r0, FieldMemOperand(r1, JSGeneratorObject::kInputOffset));
|
||||
__ RecordWriteField(r1, JSGeneratorObject::kInputOffset, r0, r3,
|
||||
__ str(r0, FieldMemOperand(r1, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
__ RecordWriteField(r1, JSGeneratorObject::kInputOrDebugPosOffset, r0, r3,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -700,8 +700,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(x1);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ Str(x0, FieldMemOperand(x1, JSGeneratorObject::kInputOffset));
|
||||
__ RecordWriteField(x1, JSGeneratorObject::kInputOffset, x0, x3,
|
||||
__ Str(x0, FieldMemOperand(x1, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
__ RecordWriteField(x1, JSGeneratorObject::kInputOrDebugPosOffset, x0, x3,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -152,10 +152,13 @@ FieldAccess AccessBuilder::ForJSGeneratorObjectContinuation() {
|
||||
}
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSGeneratorObjectInput() {
|
||||
FieldAccess access = {
|
||||
kTaggedBase, JSGeneratorObject::kInputOffset, Handle<Name>(),
|
||||
Type::Any(), MachineType::AnyTagged(), kFullWriteBarrier};
|
||||
FieldAccess AccessBuilder::ForJSGeneratorObjectInputOrDebugPos() {
|
||||
FieldAccess access = {kTaggedBase,
|
||||
JSGeneratorObject::kInputOrDebugPosOffset,
|
||||
Handle<Name>(),
|
||||
Type::Any(),
|
||||
MachineType::AnyTagged(),
|
||||
kFullWriteBarrier};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
@ -58,8 +58,8 @@ class AccessBuilder final : public AllStatic {
|
||||
// Provides access to JSGeneratorObject::continuation() field.
|
||||
static FieldAccess ForJSGeneratorObjectContinuation();
|
||||
|
||||
// Provides access to JSGeneratorObject::input() field.
|
||||
static FieldAccess ForJSGeneratorObjectInput();
|
||||
// Provides access to JSGeneratorObject::input_or_debug_pos() field.
|
||||
static FieldAccess ForJSGeneratorObjectInputOrDebugPos();
|
||||
|
||||
// Provides access to JSGeneratorObject::operand_stack() field.
|
||||
static FieldAccess ForJSGeneratorObjectOperandStack();
|
||||
|
@ -1419,15 +1419,21 @@ void BytecodeGraphBuilder::VisitSuspendGenerator() {
|
||||
Node* state = environment()->LookupAccumulator();
|
||||
Node* generator = environment()->LookupRegister(
|
||||
bytecode_iterator().GetRegisterOperand(0));
|
||||
// The offsets used by the bytecode iterator are relative to a different base
|
||||
// than what is used in the interpreter, hence the addition.
|
||||
Node* offset =
|
||||
jsgraph()->Constant(bytecode_iterator().current_offset() +
|
||||
(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||
|
||||
int register_count = environment()->register_count();
|
||||
int value_input_count = 2 + register_count;
|
||||
int value_input_count = 3 + register_count;
|
||||
|
||||
Node** value_inputs = local_zone()->NewArray<Node*>(value_input_count);
|
||||
value_inputs[0] = generator;
|
||||
value_inputs[1] = state;
|
||||
value_inputs[2] = offset;
|
||||
for (int i = 0; i < register_count; ++i) {
|
||||
value_inputs[2 + i] =
|
||||
value_inputs[3 + i] =
|
||||
environment()->LookupRegister(interpreter::Register(i));
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
|
||||
return ReduceDoubleLo(node);
|
||||
case Runtime::kInlineGeneratorClose:
|
||||
return ReduceGeneratorClose(node);
|
||||
case Runtime::kInlineGeneratorGetInput:
|
||||
return ReduceGeneratorGetInput(node);
|
||||
case Runtime::kInlineGeneratorGetInputOrDebugPos:
|
||||
return ReduceGeneratorGetInputOrDebugPos(node);
|
||||
case Runtime::kInlineGeneratorGetResumeMode:
|
||||
return ReduceGeneratorGetResumeMode(node);
|
||||
case Runtime::kInlineIsArray:
|
||||
@ -157,12 +157,12 @@ Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
|
||||
return Change(node, op, generator, closed, effect, control);
|
||||
}
|
||||
|
||||
Reduction JSIntrinsicLowering::ReduceGeneratorGetInput(Node* node) {
|
||||
Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
|
||||
Node* const generator = NodeProperties::GetValueInput(node, 0);
|
||||
Node* const effect = NodeProperties::GetEffectInput(node);
|
||||
Node* const control = NodeProperties::GetControlInput(node);
|
||||
Operator const* const op =
|
||||
simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectInput());
|
||||
Operator const* const op = simplified()->LoadField(
|
||||
AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
|
||||
|
||||
return Change(node, op, generator, effect, control);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class JSIntrinsicLowering final : public AdvancedReducer {
|
||||
Reduction ReduceDoubleHi(Node* node);
|
||||
Reduction ReduceDoubleLo(Node* node);
|
||||
Reduction ReduceGeneratorClose(Node* node);
|
||||
Reduction ReduceGeneratorGetInput(Node* node);
|
||||
Reduction ReduceGeneratorGetInputOrDebugPos(Node* node);
|
||||
Reduction ReduceGeneratorGetResumeMode(Node* node);
|
||||
Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
|
||||
Reduction ReduceIsJSReceiver(Node* node);
|
||||
|
@ -722,7 +722,7 @@ const Operator* JSOperatorBuilder::GeneratorStore(int register_count) {
|
||||
return new (zone()) Operator1<int>( // --
|
||||
IrOpcode::kJSGeneratorStore, Operator::kNoThrow, // opcode
|
||||
"JSGeneratorStore", // name
|
||||
2 + register_count, 1, 1, 0, 1, 0, // counts
|
||||
3 + register_count, 1, 1, 0, 1, 0, // counts
|
||||
register_count); // parameter
|
||||
}
|
||||
|
||||
|
@ -1743,6 +1743,7 @@ Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
|
||||
Node* generator = NodeProperties::GetValueInput(node, 0);
|
||||
Node* continuation = NodeProperties::GetValueInput(node, 1);
|
||||
Node* offset = NodeProperties::GetValueInput(node, 2);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
@ -1752,12 +1753,14 @@ Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
|
||||
FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
|
||||
FieldAccess continuation_field =
|
||||
AccessBuilder::ForJSGeneratorObjectContinuation();
|
||||
FieldAccess input_or_debug_pos_field =
|
||||
AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
|
||||
|
||||
Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
|
||||
generator, effect, control);
|
||||
|
||||
for (int i = 0; i < register_count; ++i) {
|
||||
Node* value = NodeProperties::GetValueInput(node, 2 + i);
|
||||
Node* value = NodeProperties::GetValueInput(node, 3 + i);
|
||||
effect = graph()->NewNode(
|
||||
simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
|
||||
value, effect, control);
|
||||
@ -1767,6 +1770,8 @@ Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
|
||||
context, effect, control);
|
||||
effect = graph()->NewNode(simplified()->StoreField(continuation_field),
|
||||
generator, continuation, effect, control);
|
||||
effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
|
||||
generator, offset, effect, control);
|
||||
|
||||
ReplaceWithValue(node, effect, effect, control);
|
||||
return Changed(effect);
|
||||
|
@ -1828,7 +1828,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, r0 holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ ldr(r1, FieldMemOperand(r0, JSGeneratorObject::kResumeModeOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, JSGeneratorObject::kInputOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ cmp(r1, Operand(Smi::FromInt(JSGeneratorObject::kReturn)));
|
||||
|
@ -3567,7 +3567,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, x0 holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ Ldr(x1, FieldMemOperand(x0, JSGeneratorObject::kResumeModeOffset));
|
||||
__ Ldr(x0, FieldMemOperand(x0, JSGeneratorObject::kInputOffset));
|
||||
__ Ldr(x0, FieldMemOperand(x0, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ Cmp(x1, Operand(Smi::FromInt(JSGeneratorObject::kReturn)));
|
||||
|
@ -1744,7 +1744,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, eax holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ mov(ebx, FieldOperand(eax, JSGeneratorObject::kResumeModeOffset));
|
||||
__ mov(eax, FieldOperand(eax, JSGeneratorObject::kInputOffset));
|
||||
__ mov(eax, FieldOperand(eax, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ cmp(ebx, Immediate(Smi::FromInt(JSGeneratorObject::kReturn)));
|
||||
|
@ -1823,7 +1823,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, v0 holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ lw(a1, FieldMemOperand(v0, JSGeneratorObject::kResumeModeOffset));
|
||||
__ lw(v0, FieldMemOperand(v0, JSGeneratorObject::kInputOffset));
|
||||
__ lw(v0, FieldMemOperand(v0, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
__ Branch(&resume, eq, a1, Operand(Smi::FromInt(JSGeneratorObject::kNext)));
|
||||
__ Push(result_register());
|
||||
__ Branch(&exception, eq, a1,
|
||||
|
@ -1824,7 +1824,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, v0 holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ ld(a1, FieldMemOperand(v0, JSGeneratorObject::kResumeModeOffset));
|
||||
__ ld(v0, FieldMemOperand(v0, JSGeneratorObject::kInputOffset));
|
||||
__ ld(v0, FieldMemOperand(v0, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
__ Branch(&resume, eq, a1, Operand(Smi::FromInt(JSGeneratorObject::kNext)));
|
||||
__ Push(result_register());
|
||||
__ Branch(&exception, eq, a1,
|
||||
|
@ -1786,7 +1786,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, r3 holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ LoadP(r4, FieldMemOperand(r3, JSGeneratorObject::kResumeModeOffset));
|
||||
__ LoadP(r3, FieldMemOperand(r3, JSGeneratorObject::kInputOffset));
|
||||
__ LoadP(r3, FieldMemOperand(r3, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ CmpSmiLiteral(r4, Smi::FromInt(JSGeneratorObject::kReturn), r0);
|
||||
|
@ -1744,7 +1744,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, r2 holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ LoadP(r3, FieldMemOperand(r2, JSGeneratorObject::kResumeModeOffset));
|
||||
__ LoadP(r2, FieldMemOperand(r2, JSGeneratorObject::kInputOffset));
|
||||
__ LoadP(r2, FieldMemOperand(r2, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ CmpSmiLiteral(r3, Smi::FromInt(JSGeneratorObject::kReturn), r0);
|
||||
|
@ -1768,7 +1768,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, rax holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ movp(rbx, FieldOperand(rax, JSGeneratorObject::kResumeModeOffset));
|
||||
__ movp(rax, FieldOperand(rax, JSGeneratorObject::kInputOffset));
|
||||
__ movp(rax, FieldOperand(rax, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ SmiCompare(rbx, Smi::FromInt(JSGeneratorObject::kReturn));
|
||||
|
@ -1741,7 +1741,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
||||
// When we arrive here, eax holds the generator object.
|
||||
__ RecordGeneratorContinuation();
|
||||
__ mov(ebx, FieldOperand(eax, JSGeneratorObject::kResumeModeOffset));
|
||||
__ mov(eax, FieldOperand(eax, JSGeneratorObject::kInputOffset));
|
||||
__ mov(eax, FieldOperand(eax, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
|
||||
STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
|
||||
__ cmp(ebx, Immediate(Smi::FromInt(JSGeneratorObject::kReturn)));
|
||||
|
@ -384,8 +384,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(ebx);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ mov(FieldOperand(ebx, JSGeneratorObject::kInputOffset), eax);
|
||||
__ RecordWriteField(ebx, JSGeneratorObject::kInputOffset, eax, ecx,
|
||||
__ mov(FieldOperand(ebx, JSGeneratorObject::kInputOrDebugPosOffset), eax);
|
||||
__ RecordWriteField(ebx, JSGeneratorObject::kInputOrDebugPosOffset, eax, ecx,
|
||||
kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -2234,7 +2234,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
|
||||
|
||||
Register input = register_allocator()->NewRegister();
|
||||
builder()
|
||||
->CallRuntime(Runtime::kInlineGeneratorGetInput, generator, 1)
|
||||
->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator, 1)
|
||||
.StoreAccumulatorInRegister(input);
|
||||
|
||||
Register resume_mode = register_allocator()->NewRegister();
|
||||
|
@ -146,6 +146,9 @@ class InterpreterAssembler : public CodeStubAssembler {
|
||||
void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
|
||||
BailoutReason bailout_reason);
|
||||
|
||||
// Returns the offset from the BytecodeArrayPointer of the current bytecode.
|
||||
compiler::Node* BytecodeOffset();
|
||||
|
||||
protected:
|
||||
Bytecode bytecode() const { return bytecode_; }
|
||||
static bool TargetSupportsUnalignedAccess();
|
||||
@ -153,8 +156,6 @@ class InterpreterAssembler : public CodeStubAssembler {
|
||||
private:
|
||||
// Returns a tagged pointer to the current function's BytecodeArray object.
|
||||
compiler::Node* BytecodeArrayTaggedPointer();
|
||||
// Returns the offset from the BytecodeArrayPointer of the current bytecode.
|
||||
compiler::Node* BytecodeOffset();
|
||||
// Returns a raw pointer to first entry in the interpreter dispatch table.
|
||||
compiler::Node* DispatchTableRawPointer();
|
||||
|
||||
|
@ -1791,7 +1791,8 @@ void Interpreter::DoNop(InterpreterAssembler* assembler) { __ Dispatch(); }
|
||||
// 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.
|
||||
// current context, the state given in the accumulator, and the current bytecode
|
||||
// offset (for debugging purposes) into the generator.
|
||||
void Interpreter::DoSuspendGenerator(InterpreterAssembler* assembler) {
|
||||
Node* generator_reg = __ BytecodeOperandReg(0);
|
||||
Node* generator = __ LoadRegister(generator_reg);
|
||||
@ -1816,6 +1817,10 @@ void Interpreter::DoSuspendGenerator(InterpreterAssembler* assembler) {
|
||||
__ StoreObjectField(generator, JSGeneratorObject::kContextOffset, context);
|
||||
__ StoreObjectField(generator, JSGeneratorObject::kContinuationOffset, state);
|
||||
|
||||
Node* offset = __ SmiTag(__ BytecodeOffset());
|
||||
__ StoreObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset,
|
||||
offset);
|
||||
|
||||
__ Dispatch();
|
||||
|
||||
__ Bind(&if_stepping);
|
||||
|
@ -815,8 +815,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(a1);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ sw(v0, FieldMemOperand(a1, JSGeneratorObject::kInputOffset));
|
||||
__ RecordWriteField(a1, JSGeneratorObject::kInputOffset, v0, a3,
|
||||
__ sw(v0, FieldMemOperand(a1, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
__ RecordWriteField(a1, JSGeneratorObject::kInputOrDebugPosOffset, v0, a3,
|
||||
kRAHasNotBeenSaved, kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -680,8 +680,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(a1);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ sd(v0, FieldMemOperand(a1, JSGeneratorObject::kInputOffset));
|
||||
__ RecordWriteField(a1, JSGeneratorObject::kInputOffset, v0, a3,
|
||||
__ sd(v0, FieldMemOperand(a1, JSGeneratorObject::kInputOrDebugPosOffset));
|
||||
__ RecordWriteField(a1, JSGeneratorObject::kInputOrDebugPosOffset, v0, a3,
|
||||
kRAHasNotBeenSaved, kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -6343,22 +6343,22 @@ void Foreign::set_foreign_address(Address value) {
|
||||
ACCESSORS(JSGeneratorObject, function, JSFunction, kFunctionOffset)
|
||||
ACCESSORS(JSGeneratorObject, context, Context, kContextOffset)
|
||||
ACCESSORS(JSGeneratorObject, receiver, Object, kReceiverOffset)
|
||||
ACCESSORS(JSGeneratorObject, input, Object, kInputOffset)
|
||||
ACCESSORS(JSGeneratorObject, input_or_debug_pos, Object, kInputOrDebugPosOffset)
|
||||
SMI_ACCESSORS(JSGeneratorObject, resume_mode, kResumeModeOffset)
|
||||
SMI_ACCESSORS(JSGeneratorObject, continuation, kContinuationOffset)
|
||||
ACCESSORS(JSGeneratorObject, operand_stack, FixedArray, kOperandStackOffset)
|
||||
|
||||
bool JSGeneratorObject::is_suspended() {
|
||||
bool JSGeneratorObject::is_suspended() const {
|
||||
DCHECK_LT(kGeneratorExecuting, 0);
|
||||
DCHECK_LT(kGeneratorClosed, 0);
|
||||
return continuation() >= 0;
|
||||
}
|
||||
|
||||
bool JSGeneratorObject::is_closed() {
|
||||
bool JSGeneratorObject::is_closed() const {
|
||||
return continuation() == kGeneratorClosed;
|
||||
}
|
||||
|
||||
bool JSGeneratorObject::is_executing() {
|
||||
bool JSGeneratorObject::is_executing() const {
|
||||
return continuation() == kGeneratorExecuting;
|
||||
}
|
||||
|
||||
|
@ -18863,5 +18863,22 @@ void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
|
||||
}
|
||||
}
|
||||
|
||||
int JSGeneratorObject::source_position() const {
|
||||
CHECK(is_suspended());
|
||||
if (function()->shared()->HasBytecodeArray()) {
|
||||
// New-style generators.
|
||||
int offset = Smi::cast(input_or_debug_pos())->value();
|
||||
// The stored bytecode offset is relative to a different base than what
|
||||
// is used in the source position table, hence the subtraction.
|
||||
offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
|
||||
return function()->shared()->bytecode_array()->SourcePosition(offset);
|
||||
} else {
|
||||
// Old-style generators.
|
||||
int offset = continuation();
|
||||
CHECK(0 <= offset && offset < function()->code()->instruction_size());
|
||||
return function()->code()->SourcePosition(offset);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -7363,23 +7363,32 @@ class JSGeneratorObject: public JSObject {
|
||||
// [receiver]: The receiver of the suspended computation.
|
||||
DECL_ACCESSORS(receiver, Object)
|
||||
|
||||
// [input]: The most recent input value.
|
||||
DECL_ACCESSORS(input, Object)
|
||||
// [input_or_debug_pos]
|
||||
// For executing generators: the most recent input value.
|
||||
// For suspended new-style generators: debug information (bytecode offset).
|
||||
// For suspended old-style generators: unused.
|
||||
// There is currently no need to remember the most recent input value for a
|
||||
// suspended generator.
|
||||
DECL_ACCESSORS(input_or_debug_pos, Object)
|
||||
|
||||
// [resume_mode]: The most recent resume mode.
|
||||
enum ResumeMode { kNext, kReturn, kThrow };
|
||||
DECL_INT_ACCESSORS(resume_mode)
|
||||
|
||||
// [continuation]: Offset into code of continuation.
|
||||
// [continuation]
|
||||
//
|
||||
// A positive offset indicates a suspended generator. The special
|
||||
// A positive value indicates a suspended generator. The special
|
||||
// kGeneratorExecuting and kGeneratorClosed values indicate that a generator
|
||||
// cannot be resumed.
|
||||
inline int continuation() const;
|
||||
inline void set_continuation(int continuation);
|
||||
inline bool is_closed();
|
||||
inline bool is_executing();
|
||||
inline bool is_suspended();
|
||||
inline bool is_closed() const;
|
||||
inline bool is_executing() const;
|
||||
inline bool is_suspended() const;
|
||||
|
||||
// For suspended generators: the source position at which the generator
|
||||
// is suspended.
|
||||
int source_position() const;
|
||||
|
||||
// [operand_stack]: Saved operand stack.
|
||||
DECL_ACCESSORS(operand_stack, FixedArray)
|
||||
@ -7397,8 +7406,8 @@ class JSGeneratorObject: public JSObject {
|
||||
static const int kFunctionOffset = JSObject::kHeaderSize;
|
||||
static const int kContextOffset = kFunctionOffset + kPointerSize;
|
||||
static const int kReceiverOffset = kContextOffset + kPointerSize;
|
||||
static const int kInputOffset = kReceiverOffset + kPointerSize;
|
||||
static const int kResumeModeOffset = kInputOffset + kPointerSize;
|
||||
static const int kInputOrDebugPosOffset = kReceiverOffset + kPointerSize;
|
||||
static const int kResumeModeOffset = kInputOrDebugPosOffset + kPointerSize;
|
||||
static const int kContinuationOffset = kResumeModeOffset + kPointerSize;
|
||||
static const int kOperandStackOffset = kContinuationOffset + kPointerSize;
|
||||
static const int kSize = kOperandStackOffset + kPointerSize;
|
||||
|
@ -680,13 +680,14 @@ Expression* ParserTraits::NewTargetExpression(Scope* scope,
|
||||
Expression* ParserTraits::FunctionSentExpression(Scope* scope,
|
||||
AstNodeFactory* factory,
|
||||
int pos) {
|
||||
// We desugar function.sent into %_GeneratorGetInput(generator).
|
||||
// We desugar function.sent into %_GeneratorGetInputOrDebugPos(generator).
|
||||
Zone* zone = parser_->zone();
|
||||
ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(1, zone);
|
||||
VariableProxy* generator = factory->NewVariableProxy(
|
||||
parser_->function_state_->generator_object_variable());
|
||||
args->Add(generator, zone);
|
||||
return factory->NewCallRuntime(Runtime::kInlineGeneratorGetInput, args, pos);
|
||||
return factory->NewCallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos,
|
||||
args, pos);
|
||||
}
|
||||
|
||||
|
||||
|
@ -691,8 +691,9 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(r4);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ StoreP(r3, FieldMemOperand(r4, JSGeneratorObject::kInputOffset), r0);
|
||||
__ RecordWriteField(r4, JSGeneratorObject::kInputOffset, r3, r6,
|
||||
__ StoreP(r3, FieldMemOperand(r4, JSGeneratorObject::kInputOrDebugPosOffset),
|
||||
r0);
|
||||
__ RecordWriteField(r4, JSGeneratorObject::kInputOrDebugPosOffset, r3, r6,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -40,7 +40,6 @@ RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
|
||||
return *generator;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
|
||||
HandleScope handle_scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
@ -91,8 +90,6 @@ RUNTIME_FUNCTION(Runtime_GeneratorClose) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Returns function of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
@ -101,8 +98,6 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
|
||||
return generator->function();
|
||||
}
|
||||
|
||||
|
||||
// Returns receiver of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
@ -111,17 +106,14 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
|
||||
return generator->receiver();
|
||||
}
|
||||
|
||||
|
||||
// Returns input of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetInput) {
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetInputOrDebugPos) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->input();
|
||||
return generator->input_or_debug_pos();
|
||||
}
|
||||
|
||||
// Returns resume mode of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetResumeMode) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
@ -130,7 +122,6 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetResumeMode) {
|
||||
return Smi::FromInt(generator->resume_mode());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
@ -139,20 +130,13 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
|
||||
return Smi::FromInt(generator->continuation());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
if (!generator->is_suspended()) return isolate->heap()->undefined_value();
|
||||
|
||||
if (generator->function()->shared()->HasBytecodeArray()) UNIMPLEMENTED();
|
||||
|
||||
Handle<Code> code(generator->function()->code(), isolate);
|
||||
int offset = generator->continuation();
|
||||
CHECK(0 <= offset && offset < code->instruction_size());
|
||||
return Smi::FromInt(code->SourcePosition(offset));
|
||||
return Smi::FromInt(generator->source_position());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -236,7 +236,7 @@ namespace internal {
|
||||
F(GeneratorClose, 1, 1) \
|
||||
F(GeneratorGetFunction, 1, 1) \
|
||||
F(GeneratorGetReceiver, 1, 1) \
|
||||
F(GeneratorGetInput, 1, 1) \
|
||||
F(GeneratorGetInputOrDebugPos, 1, 1) \
|
||||
F(GeneratorGetContinuation, 1, 1) \
|
||||
F(GeneratorGetSourcePosition, 1, 1) \
|
||||
F(GeneratorGetResumeMode, 1, 1)
|
||||
|
@ -679,8 +679,9 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(r3);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ StoreP(r2, FieldMemOperand(r3, JSGeneratorObject::kInputOffset), r0);
|
||||
__ RecordWriteField(r3, JSGeneratorObject::kInputOffset, r2, r5,
|
||||
__ StoreP(r2, FieldMemOperand(r3, JSGeneratorObject::kInputOrDebugPosOffset),
|
||||
r0);
|
||||
__ RecordWriteField(r3, JSGeneratorObject::kInputOrDebugPosOffset, r2, r5,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -458,8 +458,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(rbx);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ movp(FieldOperand(rbx, JSGeneratorObject::kInputOffset), rax);
|
||||
__ RecordWriteField(rbx, JSGeneratorObject::kInputOffset, rax, rcx,
|
||||
__ movp(FieldOperand(rbx, JSGeneratorObject::kInputOrDebugPosOffset), rax);
|
||||
__ RecordWriteField(rbx, JSGeneratorObject::kInputOrDebugPosOffset, rax, rcx,
|
||||
kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -396,8 +396,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
__ AssertGeneratorObject(ebx);
|
||||
|
||||
// Store input value into generator object.
|
||||
__ mov(FieldOperand(ebx, JSGeneratorObject::kInputOffset), eax);
|
||||
__ RecordWriteField(ebx, JSGeneratorObject::kInputOffset, eax, ecx,
|
||||
__ mov(FieldOperand(ebx, JSGeneratorObject::kInputOrDebugPosOffset), eax);
|
||||
__ RecordWriteField(ebx, JSGeneratorObject::kInputOrDebugPosOffset, eax, ecx,
|
||||
kDontSaveFPRegs);
|
||||
|
||||
// Store resume mode into generator object.
|
||||
|
@ -47,7 +47,7 @@ bytecodes: [
|
||||
/* 16 S> */ B(Return),
|
||||
B(LdaSmi), U8(-2),
|
||||
B(Star), R(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInput), R(6), U8(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(6), U8(1),
|
||||
B(Star), R(7),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(6), U8(1),
|
||||
B(Star), R(8),
|
||||
@ -153,7 +153,7 @@ bytecodes: [
|
||||
/* 25 S> */ B(Return),
|
||||
B(LdaSmi), U8(-2),
|
||||
B(Star), R(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInput), R(6), U8(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(6), U8(1),
|
||||
B(Star), R(7),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(6), U8(1),
|
||||
B(Star), R(8),
|
||||
@ -187,7 +187,7 @@ bytecodes: [
|
||||
/* 25 S> */ B(Return),
|
||||
B(LdaSmi), U8(-2),
|
||||
B(Star), R(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInput), R(5), U8(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(5), U8(1),
|
||||
B(Star), R(6),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(5), U8(1),
|
||||
B(Star), R(8),
|
||||
@ -299,7 +299,7 @@ bytecodes: [
|
||||
/* 44 S> */ B(Return),
|
||||
B(LdaSmi), U8(-2),
|
||||
B(Star), R(3),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInput), R(8), U8(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(8), U8(1),
|
||||
B(Star), R(9),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(8), U8(1),
|
||||
B(Star), R(10),
|
||||
@ -394,7 +394,7 @@ bytecodes: [
|
||||
/* 44 S> */ B(Return),
|
||||
B(LdaSmi), U8(-2),
|
||||
B(Star), R(3),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInput), R(11), U8(1),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(11), U8(1),
|
||||
B(Star), R(12),
|
||||
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(11), U8(1),
|
||||
B(Star), R(14),
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --expose-debug-as debug
|
||||
// Flags: --expose-debug-as debug --ignition-generators
|
||||
// Test the mirror object for functions.
|
||||
|
||||
function *generator(f) {
|
||||
|
Loading…
Reference in New Issue
Block a user