Commit 5c66d6fc authored by mvstanton's avatar mvstanton Committed by Commit bot

[turbofan] Create-lowering support for CreateGeneratorObject

We can inline the allocation of the generator object as long as our
closure is constant.

BUG=v8:6352

Review-Url: https://codereview.chromium.org/2867603002
Cr-Commit-Position: refs/heads/master@{#45200}
parent cdbf01ff
......@@ -179,6 +179,24 @@ FieldAccess AccessBuilder::ForJSGeneratorObjectContext() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectFunction() {
FieldAccess access = {kTaggedBase, JSGeneratorObject::kFunctionOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::Function(), MachineType::TaggedPointer(),
kPointerWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectReceiver() {
FieldAccess access = {kTaggedBase, JSGeneratorObject::kReceiverOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::Internal(), MachineType::TaggedPointer(),
kPointerWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectContinuation() {
FieldAccess access = {
......@@ -199,15 +217,6 @@ FieldAccess AccessBuilder::ForJSGeneratorObjectInputOrDebugPos() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSAsyncGeneratorObjectAwaitInputOrDebugPos() {
FieldAccess access = {
kTaggedBase, JSAsyncGeneratorObject::kAwaitInputOrDebugPosOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::NonInternal(), MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSGeneratorObjectRegisterFile() {
......@@ -229,6 +238,36 @@ FieldAccess AccessBuilder::ForJSGeneratorObjectResumeMode() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSAsyncGeneratorObjectQueue() {
FieldAccess access = {
kTaggedBase, JSAsyncGeneratorObject::kQueueOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::NonInternal(), MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSAsyncGeneratorObjectAwaitInputOrDebugPos() {
FieldAccess access = {
kTaggedBase, JSAsyncGeneratorObject::kAwaitInputOrDebugPosOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::NonInternal(), MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSAsyncGeneratorObjectAwaitedPromise() {
FieldAccess access = {
kTaggedBase, JSAsyncGeneratorObject::kAwaitedPromiseOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::NonInternal(), MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSArrayLength(ElementsKind elements_kind) {
TypeCache const& type_cache = TypeCache::Get();
......
......@@ -82,16 +82,28 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to JSGeneratorObject::input_or_debug_pos() field.
static FieldAccess ForJSGeneratorObjectInputOrDebugPos();
// Provides access to JSAsyncGeneratorObject::await_input_or_debug_pos()
// field.
static FieldAccess ForJSAsyncGeneratorObjectAwaitInputOrDebugPos();
// Provides access to JSGeneratorObject::register_file() field.
static FieldAccess ForJSGeneratorObjectRegisterFile();
// Provides access to JSGeneratorObject::function() field.
static FieldAccess ForJSGeneratorObjectFunction();
// Provides access to JSGeneratorObject::receiver() field.
static FieldAccess ForJSGeneratorObjectReceiver();
// Provides access to JSGeneratorObject::resume_mode() field.
static FieldAccess ForJSGeneratorObjectResumeMode();
// Provides access to JSAsyncGeneratorObject::queue() field.
static FieldAccess ForJSAsyncGeneratorObjectQueue();
// Provides access to JSAsyncGeneratorObject::await_input_or_debug_pos()
// field.
static FieldAccess ForJSAsyncGeneratorObjectAwaitInputOrDebugPos();
// Provides access to JSAsyncGeneratorObject::awaited_promise() field.
static FieldAccess ForJSAsyncGeneratorObjectAwaitedPromise();
// Provides access to JSArray::length() field.
static FieldAccess ForJSArrayLength(ElementsKind elements_kind);
......
......@@ -228,6 +228,8 @@ Reduction JSCreateLowering::Reduce(Node* node) {
return ReduceJSCreateCatchContext(node);
case IrOpcode::kJSCreateBlockContext:
return ReduceJSCreateBlockContext(node);
case IrOpcode::kJSCreateGeneratorObject:
return ReduceJSCreateGeneratorObject(node);
default:
break;
}
......@@ -548,6 +550,71 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
return NoChange();
}
Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateGeneratorObject, node->opcode());
Node* const closure = NodeProperties::GetValueInput(node, 0);
Node* const receiver = NodeProperties::GetValueInput(node, 1);
Node* const context = NodeProperties::GetContextInput(node);
Type* const closure_type = NodeProperties::GetType(closure);
Node* effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
// Extract constructor and original constructor function.
if (closure_type->IsHeapConstant()) {
DCHECK(closure_type->AsHeapConstant()->Value()->IsJSFunction());
Handle<JSFunction> js_function =
Handle<JSFunction>::cast(closure_type->AsHeapConstant()->Value());
JSFunction::EnsureHasInitialMap(js_function);
Handle<Map> initial_map(js_function->initial_map());
initial_map->CompleteInobjectSlackTracking();
DCHECK(initial_map->instance_type() == JS_GENERATOR_OBJECT_TYPE ||
initial_map->instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
// Add a dependency on the {initial_map} to make sure that this code is
// deoptimized whenever the {initial_map} of the {original_constructor}
// changes.
dependencies()->AssumeInitialMapCantChange(initial_map);
DCHECK(js_function->shared()->HasBytecodeArray());
int size = js_function->shared()->bytecode_array()->register_count();
Node* elements = effect = AllocateElements(
effect, control, FAST_HOLEY_ELEMENTS, size, NOT_TENURED);
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(initial_map->instance_size());
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
Node* undefined = jsgraph()->UndefinedConstant();
a.Store(AccessBuilder::ForMap(), initial_map);
a.Store(AccessBuilder::ForJSObjectProperties(), empty_fixed_array);
a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context);
a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure);
a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver);
a.Store(AccessBuilder::ForJSGeneratorObjectInputOrDebugPos(), undefined);
a.Store(AccessBuilder::ForJSGeneratorObjectResumeMode(),
jsgraph()->Constant(JSGeneratorObject::kNext));
a.Store(AccessBuilder::ForJSGeneratorObjectContinuation(),
jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting));
a.Store(AccessBuilder::ForJSGeneratorObjectRegisterFile(), elements);
if (initial_map->instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE) {
a.Store(AccessBuilder::ForJSAsyncGeneratorObjectQueue(), undefined);
a.Store(AccessBuilder::ForJSAsyncGeneratorObjectAwaitInputOrDebugPos(),
undefined);
a.Store(AccessBuilder::ForJSAsyncGeneratorObjectAwaitedPromise(),
undefined);
}
// Handle in-object properties, too.
for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
undefined);
}
a.FinishAndChange(node);
return Changed(node);
}
return NoChange();
}
Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
int capacity,
Handle<AllocationSite> site) {
......
......@@ -57,6 +57,7 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Reduction ReduceJSCreateWithContext(Node* node);
Reduction ReduceJSCreateCatchContext(Node* node);
Reduction ReduceJSCreateBlockContext(Node* node);
Reduction ReduceJSCreateGeneratorObject(Node* node);
Reduction ReduceNewArray(Node* node, Node* length, int capacity,
Handle<AllocationSite> site);
Reduction ReduceNewArray(Node* node, std::vector<Node*> values,
......
......@@ -1714,6 +1714,7 @@ void Verifier::VerifyNode(Node* node) {
bool check_no_control = node->op()->ControlOutputCount() == 0;
bool check_no_effect = node->op()->EffectOutputCount() == 0;
bool check_no_frame_state = node->opcode() != IrOpcode::kFrameState;
int effect_edges = 0;
if (check_no_effect || check_no_control) {
for (Edge edge : node->use_edges()) {
Node* const user = edge.from();
......@@ -1722,6 +1723,7 @@ void Verifier::VerifyNode(Node* node) {
CHECK(!check_no_control);
} else if (NodeProperties::IsEffectEdge(edge)) {
CHECK(!check_no_effect);
effect_edges++;
} else if (NodeProperties::IsFrameStateEdge(edge)) {
CHECK(!check_no_frame_state);
}
......
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