Commit 29f3e668 authored by neis's avatar neis Committed by Commit bot

[generators] Replace some runtime functions with Turbofan JS operators.

Introduce three new JS operators in Turbofan:
- JSGeneratorStore is used in implementing Ignition's SuspendGenerator bytecode.
- JSGeneratorRestoreContinuation and JSGeneratorRestoreRegister are used in
  implementing Ignition's ResumeGenerator bytecode.

Remove the runtime functions that were used to implement these bytecodes before.

BUG=v8:4907

Review-Url: https://codereview.chromium.org/1991203002
Cr-Commit-Position: refs/heads/master@{#36395}
parent ec2c5a03
......@@ -129,6 +129,40 @@ FieldAccess AccessBuilder::ForJSFunctionNextFunctionLink() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectContext() {
FieldAccess access = {kTaggedBase,
JSGeneratorObject::kContextOffset,
Handle<Name>(),
Type::Internal(),
MachineType::AnyTagged(),
kPointerWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectContinuation() {
TypeCache const& type_cache = TypeCache::Get();
FieldAccess access = {kTaggedBase,
JSGeneratorObject::kContinuationOffset,
Handle<Name>(),
type_cache.kSmi,
MachineType::AnyTagged(),
kNoWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectOperandStack() {
FieldAccess access = {kTaggedBase,
JSGeneratorObject::kOperandStackOffset,
Handle<Name>(),
Type::Internal(),
MachineType::AnyTagged(),
kPointerWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSArrayLength(ElementsKind elements_kind) {
TypeCache const& type_cache = TypeCache::Get();
......
......@@ -52,6 +52,15 @@ class AccessBuilder final : public AllStatic {
// Provides access to JSFunction::next_function_link() field.
static FieldAccess ForJSFunctionNextFunctionLink();
// Provides access to JSGeneratorObject::context() field.
static FieldAccess ForJSGeneratorObjectContext();
// Provides access to JSGeneratorObject::continuation() field.
static FieldAccess ForJSGeneratorObjectContinuation();
// Provides access to JSGeneratorObject::operand_stack() field.
static FieldAccess ForJSGeneratorObjectOperandStack();
// Provides access to JSArray::length() field.
static FieldAccess ForJSArrayLength(ElementsKind elements_kind);
......
......@@ -1377,15 +1377,19 @@ void BytecodeGraphBuilder::VisitSuspendGenerator() {
Node* generator = environment()->LookupRegister(
bytecode_iterator().GetRegisterOperand(0));
for (int i = 0; i < environment()->register_count(); ++i) {
Node* value = environment()->LookupRegister(interpreter::Register(i));
NewNode(javascript()->CallRuntime(Runtime::kGeneratorStoreRegister),
generator, jsgraph()->Constant(i), value);
int register_count = environment()->register_count();
int value_input_count = 2 + register_count;
Node** value_inputs = local_zone()->NewArray<Node*>(value_input_count);
value_inputs[0] = generator;
value_inputs[1] = state;
for (int i = 0; i < register_count; ++i) {
value_inputs[2 + i] =
environment()->LookupRegister(interpreter::Register(i));
}
NewNode(javascript()->CallRuntime(Runtime::kGeneratorSetContext), generator);
NewNode(javascript()->CallRuntime(Runtime::kGeneratorSetContinuation),
generator, state);
MakeNode(javascript()->GeneratorStore(register_count), value_input_count,
value_inputs, false);
}
void BytecodeGraphBuilder::VisitResumeGenerator() {
......@@ -1393,23 +1397,16 @@ void BytecodeGraphBuilder::VisitResumeGenerator() {
Node* generator = environment()->LookupRegister(
bytecode_iterator().GetRegisterOperand(0));
Node* state = NewNode(javascript()->CallRuntime(
Runtime::kGeneratorGetContinuation), generator);
// Bijection between registers and array indices must match that used in
// InterpreterAssembler::ExportRegisterFile.
for (int i = 0; i < environment()->register_count(); ++i) {
Node* value = NewNode(
javascript()->CallRuntime(Runtime::kGeneratorLoadRegister),
generator, jsgraph()->Constant(i));
Node* value = NewNode(javascript()->GeneratorRestoreRegister(i), generator);
environment()->BindRegister(interpreter::Register(i), value);
NewNode(javascript()->CallRuntime(Runtime::kGeneratorStoreRegister),
generator, jsgraph()->Constant(i), jsgraph()->StaleRegisterConstant());
}
NewNode(javascript()->CallRuntime(Runtime::kGeneratorSetContinuation),
generator, jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting));
Node* state =
NewNode(javascript()->GeneratorRestoreContinuation(), generator);
environment()->BindAccumulator(state, &states);
}
......
......@@ -74,8 +74,7 @@ class AdvancedReducer : public Reducer {
virtual void Revisit(Node* node) = 0;
// Replace value uses of {node} with {value} and effect uses of {node} with
// {effect}. If {effect == nullptr}, then use the effect input to {node}.
// All
// control uses will be relaxed assuming {node} cannot throw.
// All control uses will be relaxed assuming {node} cannot throw.
virtual void ReplaceWithValue(Node* node, Node* value, Node* effect,
Node* control) = 0;
};
......
......@@ -679,6 +679,17 @@ void JSGenericLowering::LowerJSStoreMessage(Node* node) {
NodeProperties::ChangeOp(node, machine()->Store(representation));
}
void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering.
}
void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering.
}
void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering.
}
void JSGenericLowering::LowerJSStackCheck(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
......
......@@ -376,34 +376,35 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) {
return OpParameter<CreateLiteralParameters>(op);
}
#define CACHED_OP_LIST(V) \
V(Equal, Operator::kNoProperties, 2, 1) \
V(NotEqual, Operator::kNoProperties, 2, 1) \
V(StrictEqual, Operator::kPure, 2, 1) \
V(StrictNotEqual, Operator::kPure, 2, 1) \
V(LessThan, Operator::kNoProperties, 2, 1) \
V(GreaterThan, Operator::kNoProperties, 2, 1) \
V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \
V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1) \
V(ToInteger, Operator::kNoProperties, 1, 1) \
V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \
V(ToNumber, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kFoldable, 1, 1) \
V(ToString, Operator::kNoProperties, 1, 1) \
V(Create, Operator::kEliminatable, 2, 1) \
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \
V(TypeOf, Operator::kPure, 1, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(ForInDone, Operator::kPure, 2, 1) \
V(ForInNext, Operator::kNoProperties, 4, 1) \
V(ForInPrepare, Operator::kNoProperties, 1, 3) \
V(ForInStep, Operator::kPure, 1, 1) \
V(LoadMessage, Operator::kNoThrow, 0, 1) \
V(StoreMessage, Operator::kNoThrow, 1, 0) \
V(StackCheck, Operator::kNoProperties, 0, 0) \
V(CreateWithContext, Operator::kNoProperties, 2, 1) \
#define CACHED_OP_LIST(V) \
V(Equal, Operator::kNoProperties, 2, 1) \
V(NotEqual, Operator::kNoProperties, 2, 1) \
V(StrictEqual, Operator::kPure, 2, 1) \
V(StrictNotEqual, Operator::kPure, 2, 1) \
V(LessThan, Operator::kNoProperties, 2, 1) \
V(GreaterThan, Operator::kNoProperties, 2, 1) \
V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \
V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1) \
V(ToInteger, Operator::kNoProperties, 1, 1) \
V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \
V(ToNumber, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kFoldable, 1, 1) \
V(ToString, Operator::kNoProperties, 1, 1) \
V(Create, Operator::kEliminatable, 2, 1) \
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \
V(TypeOf, Operator::kPure, 1, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(ForInDone, Operator::kPure, 2, 1) \
V(ForInNext, Operator::kNoProperties, 4, 1) \
V(ForInPrepare, Operator::kNoProperties, 1, 3) \
V(ForInStep, Operator::kPure, 1, 1) \
V(LoadMessage, Operator::kNoThrow, 0, 1) \
V(StoreMessage, Operator::kNoThrow, 1, 0) \
V(GeneratorRestoreContinuation, Operator::kNoThrow, 1, 1) \
V(StackCheck, Operator::kNoProperties, 0, 0) \
V(CreateWithContext, Operator::kNoProperties, 2, 1) \
V(CreateModuleContext, Operator::kNoProperties, 2, 1)
struct JSOperatorGlobalCache final {
......@@ -625,6 +626,21 @@ const Operator* JSOperatorBuilder::LoadProperty(
access); // parameter
}
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
register_count); // parameter
}
const Operator* JSOperatorBuilder::GeneratorRestoreRegister(int index) {
return new (zone()) Operator1<int>( // --
IrOpcode::kJSGeneratorRestoreRegister, Operator::kNoThrow, // opcode
"JSGeneratorRestoreRegister", // name
1, 1, 1, 1, 1, 0, // counts
index); // parameter
}
const Operator* JSOperatorBuilder::StoreNamed(LanguageMode language_mode,
Handle<Name> name,
......
......@@ -470,6 +470,13 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* LoadMessage();
const Operator* StoreMessage();
// Used to implement Ignition's SuspendGenerator bytecode.
const Operator* GeneratorStore(int register_count);
// Used to implement Ignition's ResumeGenerator bytecode.
const Operator* GeneratorRestoreContinuation();
const Operator* GeneratorRestoreRegister(int index);
const Operator* StackCheck();
const Operator* CreateFunctionContext(int slot_count);
......
......@@ -1630,6 +1630,104 @@ Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
Node* generator = NodeProperties::GetValueInput(node, 0);
Node* context = NodeProperties::GetContextInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
int register_count = OpParameter<int>(node);
FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectOperandStack();
FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
FieldAccess continuation_field =
AccessBuilder::ForJSGeneratorObjectContinuation();
Node* array = graph()->NewNode(simplified()->LoadField(array_field),
generator, effect, control);
for (int i = 0; i < register_count; ++i) {
Node* value = NodeProperties::GetValueInput(node, 2 + i);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
value, effect, control);
}
effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
context, effect, control);
// Change the JSGeneratorStore node to a StoreField node.
DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(1, OperatorProperties::GetContextInputCount(node->op()));
node->RemoveInput(NodeProperties::FirstContextIndex(node));
for (int i = 0; i < register_count; ++i) {
node->RemoveInput(NodeProperties::FirstValueIndex(node) + 2);
}
NodeProperties::RemoveType(node);
NodeProperties::ChangeOp(node, simplified()->StoreField(continuation_field));
NodeProperties::ReplaceEffectInput(node, effect);
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
Node* generator = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
FieldAccess continuation_field =
AccessBuilder::ForJSGeneratorObjectContinuation();
Node* continuation = graph()->NewNode(
simplified()->LoadField(continuation_field), generator, effect, control);
// Change the JSGeneratorRestoreContinuation node to a StoreField node.
DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(1, OperatorProperties::GetContextInputCount(node->op()));
node->RemoveInput(NodeProperties::FirstContextIndex(node));
node->InsertInput(
graph()->zone(), 1,
jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting));
NodeProperties::RemoveType(node);
NodeProperties::ChangeOp(node, simplified()->StoreField(continuation_field));
NodeProperties::ReplaceEffectInput(node, continuation);
ReplaceWithValue(node, continuation, node, control);
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
Node* generator = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
int index = OpParameter<int>(node);
FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectOperandStack();
FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
Node* array = graph()->NewNode(simplified()->LoadField(array_field),
generator, effect, control);
Node* element = graph()->NewNode(simplified()->LoadField(element_field),
array, array, control);
// Change the JSGeneratorRestoreRegister node to a StoreField node.
DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(1, OperatorProperties::GetContextInputCount(node->op()));
node->RemoveInput(NodeProperties::FirstContextIndex(node));
node->ReplaceInput(0, array);
node->InsertInput(graph()->zone(), 1, jsgraph()->StaleRegisterConstant());
NodeProperties::RemoveType(node);
NodeProperties::ChangeOp(node, simplified()->StoreField(element_field));
NodeProperties::ReplaceEffectInput(node, element);
ReplaceWithValue(node, element, node, control);
return Changed(node);
}
Reduction JSTypedLowering::ReduceSelect(Node* node) {
DCHECK_EQ(IrOpcode::kSelect, node->opcode());
......@@ -1766,6 +1864,12 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSForInNext(node);
case IrOpcode::kJSForInStep:
return ReduceJSForInStep(node);
case IrOpcode::kJSGeneratorStore:
return ReduceJSGeneratorStore(node);
case IrOpcode::kJSGeneratorRestoreContinuation:
return ReduceJSGeneratorRestoreContinuation(node);
case IrOpcode::kJSGeneratorRestoreRegister:
return ReduceJSGeneratorRestoreRegister(node);
case IrOpcode::kSelect:
return ReduceSelect(node);
default:
......
......@@ -76,6 +76,9 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSForInDone(Node* node);
Reduction ReduceJSForInNext(Node* node);
Reduction ReduceJSForInStep(Node* node);
Reduction ReduceJSGeneratorStore(Node* node);
Reduction ReduceJSGeneratorRestoreContinuation(Node* node);
Reduction ReduceJSGeneratorRestoreRegister(Node* node);
Reduction ReduceSelect(Node* node);
Reduction ReduceNumberBinop(Node* node, const Operator* numberOp);
Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
......
......@@ -144,11 +144,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
case Runtime::kForInDone:
case Runtime::kForInStep:
case Runtime::kGeneratorSetContext:
case Runtime::kGeneratorGetContinuation:
case Runtime::kGeneratorSetContinuation:
case Runtime::kGeneratorLoadRegister:
case Runtime::kGeneratorStoreRegister:
case Runtime::kGetSuperConstructor:
case Runtime::kIsFunction:
case Runtime::kNewClosure:
......
......@@ -140,17 +140,20 @@
V(JSCreateModuleContext) \
V(JSCreateScriptContext)
#define JS_OTHER_OP_LIST(V) \
V(JSCallConstruct) \
V(JSCallFunction) \
V(JSCallRuntime) \
V(JSConvertReceiver) \
V(JSForInDone) \
V(JSForInNext) \
V(JSForInPrepare) \
V(JSForInStep) \
V(JSLoadMessage) \
V(JSStoreMessage) \
#define JS_OTHER_OP_LIST(V) \
V(JSCallConstruct) \
V(JSCallFunction) \
V(JSCallRuntime) \
V(JSConvertReceiver) \
V(JSForInDone) \
V(JSForInNext) \
V(JSForInPrepare) \
V(JSForInStep) \
V(JSLoadMessage) \
V(JSStoreMessage) \
V(JSGeneratorStore) \
V(JSGeneratorRestoreContinuation) \
V(JSGeneratorRestoreRegister) \
V(JSStackCheck)
#define JS_OP_LIST(V) \
......
......@@ -1686,6 +1686,18 @@ Type* Typer::Visitor::TypeJSStoreMessage(Node* node) {
return nullptr;
}
Type* Typer::Visitor::TypeJSGeneratorStore(Node* node) {
UNREACHABLE();
return nullptr;
}
Type* Typer::Visitor::TypeJSGeneratorRestoreContinuation(Node* node) {
return typer_->cache_.kSmi;
}
Type* Typer::Visitor::TypeJSGeneratorRestoreRegister(Node* node) {
return Type::Any();
}
Type* Typer::Visitor::TypeJSStackCheck(Node* node) { return Type::Any(); }
......
......@@ -636,6 +636,18 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kJSStoreMessage:
break;
case IrOpcode::kJSGeneratorStore:
CheckNotTyped(node);
break;
case IrOpcode::kJSGeneratorRestoreContinuation:
CheckUpperIs(node, Type::SignedSmall());
break;
case IrOpcode::kJSGeneratorRestoreRegister:
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStackCheck:
// Type is empty.
CheckNotTyped(node);
......
......@@ -129,16 +129,6 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetResumeMode) {
}
RUNTIME_FUNCTION(Runtime_GeneratorSetContext) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
generator->set_context(isolate->context());
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
......@@ -148,45 +138,6 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
}
RUNTIME_FUNCTION(Runtime_GeneratorSetContinuation) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
CONVERT_SMI_ARG_CHECKED(continuation, 1);
generator->set_continuation(continuation);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GeneratorLoadRegister) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
DCHECK(FLAG_ignition && FLAG_ignition_generators);
DCHECK(generator->function()->shared()->HasBytecodeArray());
return generator->operand_stack()->get(index);
}
RUNTIME_FUNCTION(Runtime_GeneratorStoreRegister) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
DCHECK(FLAG_ignition && FLAG_ignition_generators);
DCHECK(generator->function()->shared()->HasBytecodeArray());
generator->operand_stack()->set(index, *value);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
......
......@@ -230,13 +230,9 @@ namespace internal {
F(GeneratorGetFunction, 1, 1) \
F(GeneratorGetReceiver, 1, 1) \
F(GeneratorGetInput, 1, 1) \
F(GeneratorSetContext, 1, 1) \
F(GeneratorGetContinuation, 1, 1) \
F(GeneratorSetContinuation, 2, 1) \
F(GeneratorGetSourcePosition, 1, 1) \
F(GeneratorGetResumeMode, 1, 1) \
F(GeneratorLoadRegister, 2, 1) \
F(GeneratorStoreRegister, 3, 1)
F(GeneratorGetResumeMode, 1, 1)
#ifdef V8_I18N_SUPPORT
#define FOR_EACH_INTRINSIC_I18N(F) \
......
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