Commit 24d78901 authored by neis's avatar neis Committed by Commit bot

[compiler][modules] Constant-fold loads of module cells.

1. Generalize context specialization such that the provided context
   can be any outer context of the function, not necessarily the
   immediate outer context.

2. Based on this: if function specialization is disabled, then
   specialize for the module context if there is one.

3. Extend typed lowering of module loads and stores such that if
   the operand is a Module constant, we constant-fold the cell load.
   That is, a JSLoadModule with a Module HeapConstant input becomes
   a LoadField with a Cell HeapConstant input, and similarly for
   JSStoreModule.

BUG=v8:1569

Review-Url: https://codereview.chromium.org/2841613002
Cr-Commit-Position: refs/heads/master@{#45083}
parent 0733add0
......@@ -83,6 +83,45 @@ Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
return Changed(node);
}
namespace {
bool IsContextParameter(Node* node) {
DCHECK_EQ(IrOpcode::kParameter, node->opcode());
Node* const start = NodeProperties::GetValueInput(node, 0);
DCHECK_EQ(IrOpcode::kStart, start->opcode());
int const index = ParameterIndexOf(node->op());
// The context is always the last parameter to a JavaScript function, and
// {Parameter} indices start at -1, so value outputs of {Start} look like
// this: closure, receiver, param0, ..., paramN, context.
return index == start->op()->ValueOutputCount() - 2;
}
// Given a context {node} and the {distance} from that context to the target
// context (which we want to read from or store to), try to return a
// specialization context. If successful, update {distance} to whatever
// distance remains from the specialization context.
MaybeHandle<Context> GetSpecializationContext(Node* node, size_t* distance,
Maybe<OuterContext> maybe_outer) {
switch (node->opcode()) {
case IrOpcode::kHeapConstant:
return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
case IrOpcode::kParameter: {
OuterContext outer;
if (maybe_outer.To(&outer) && IsContextParameter(node) &&
*distance >= outer.distance) {
*distance -= outer.distance;
return outer.context;
}
break;
}
default:
break;
}
return MaybeHandle<Context>();
}
} // anonymous namespace
Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
......@@ -90,14 +129,13 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
size_t depth = access.depth();
// First walk up the context chain in the graph as far as possible.
Node* outer = NodeProperties::GetOuterContext(node, &depth);
Node* context = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete;
if (!NodeProperties::GetSpecializationContext(outer, context())
.ToHandle(&concrete)) {
if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) {
// We do not have a concrete context object, so we can only partially reduce
// the load by folding-in the outer context node.
return SimplifyJSLoadContext(node, outer, depth);
return SimplifyJSLoadContext(node, context, depth);
}
// Now walk up the concrete context chain for the remaining depth.
......@@ -139,14 +177,13 @@ Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
// First walk up the context chain in the graph until we reduce the depth to 0
// or hit a node that does not have a CreateXYZContext operator.
Node* outer = NodeProperties::GetOuterContext(node, &depth);
Node* context = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete;
if (!NodeProperties::GetSpecializationContext(outer, context())
.ToHandle(&concrete)) {
if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) {
// We do not have a concrete context object, so we can only partially reduce
// the load by folding-in the outer context node.
return SimplifyJSStoreContext(node, outer, depth);
return SimplifyJSStoreContext(node, context, depth);
}
// Now walk up the concrete context chain for the remaining depth.
......
......@@ -15,17 +15,29 @@ namespace compiler {
class JSGraph;
class JSOperatorBuilder;
// Pair of a context and its distance from some point of reference.
struct OuterContext {
OuterContext() : context(), distance() {}
OuterContext(Handle<Context> context_, size_t distance_)
: context(context_), distance(distance_) {}
Handle<Context> context;
size_t distance;
};
// Specializes a given JSGraph to a given context, potentially constant folding
// some {LoadContext} nodes or strength reducing some {StoreContext} nodes.
// Additionally, constant-folds the function parameter if {closure} is given.
//
// The context can be the incoming function context or any outer context
// thereof, as indicated by {outer}'s {distance}.
class JSContextSpecialization final : public AdvancedReducer {
public:
JSContextSpecialization(Editor* editor, JSGraph* jsgraph,
MaybeHandle<Context> context,
Maybe<OuterContext> outer,
MaybeHandle<JSFunction> closure)
: AdvancedReducer(editor),
jsgraph_(jsgraph),
context_(context),
outer_(outer),
closure_(closure) {}
Reduction Reduce(Node* node) final;
......@@ -43,11 +55,11 @@ class JSContextSpecialization final : public AdvancedReducer {
Isolate* isolate() const;
JSOperatorBuilder* javascript() const;
JSGraph* jsgraph() const { return jsgraph_; }
MaybeHandle<Context> context() const { return context_; }
Maybe<OuterContext> outer() const { return outer_; }
MaybeHandle<JSFunction> closure() const { return closure_; }
JSGraph* const jsgraph_;
MaybeHandle<Context> context_;
Maybe<OuterContext> outer_;
MaybeHandle<JSFunction> closure_;
DISALLOW_COPY_AND_ASSIGN(JSContextSpecialization);
......
......@@ -1399,6 +1399,14 @@ Node* JSTypedLowering::BuildGetModuleCell(Node* node) {
int32_t cell_index = OpParameter<int32_t>(node);
Node* module = NodeProperties::GetValueInput(node, 0);
Type* module_type = NodeProperties::GetType(module);
if (module_type->IsHeapConstant()) {
Handle<Module> module_constant =
Handle<Module>::cast(module_type->AsHeapConstant()->Value());
Handle<Cell> cell_constant(module_constant->GetCell(cell_index), isolate());
return jsgraph()->HeapConstant(cell_constant);
}
FieldAccess field_access;
int index;
......
......@@ -436,31 +436,6 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
}
}
// static
MaybeHandle<Context> NodeProperties::GetSpecializationContext(
Node* node, MaybeHandle<Context> context) {
switch (node->opcode()) {
case IrOpcode::kHeapConstant:
return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
case IrOpcode::kParameter: {
Node* const start = NodeProperties::GetValueInput(node, 0);
DCHECK_EQ(IrOpcode::kStart, start->opcode());
int const index = ParameterIndexOf(node->op());
// The context is always the last parameter to a JavaScript function, and
// {Parameter} indices start at -1, so value outputs of {Start} look like
// this: closure, receiver, param0, ..., paramN, context.
if (index == start->op()->ValueOutputCount() - 2) {
return context;
}
break;
}
default:
break;
}
return MaybeHandle<Context>();
}
// static
Node* NodeProperties::GetOuterContext(Node* node, size_t* depth) {
Node* context = NodeProperties::GetContextInput(node);
......
......@@ -142,12 +142,6 @@ class V8_EXPORT_PRIVATE NodeProperties final {
// ---------------------------------------------------------------------------
// Context.
// Try to retrieve the specialization context from the given {node},
// optionally utilizing the knowledge about the (outermost) function
// {context}.
static MaybeHandle<Context> GetSpecializationContext(
Node* node, MaybeHandle<Context> context = MaybeHandle<Context>());
// Walk up the context chain from the given {node} until we reduce the {depth}
// to 0 or hit a node that does not extend the context chain ({depth} will be
// updated accordingly).
......
......@@ -781,6 +781,30 @@ struct GraphBuilderPhase {
}
};
namespace {
Maybe<OuterContext> GetModuleContext(Handle<JSFunction> closure) {
Context* current = closure->context();
size_t distance = 0;
while (!current->IsNativeContext()) {
if (current->IsModuleContext()) {
return Just(OuterContext(handle(current), distance));
}
current = current->previous();
distance++;
}
return Nothing<OuterContext>();
}
Maybe<OuterContext> ChooseSpecializationContext(CompilationInfo* info) {
if (info->is_function_context_specializing()) {
DCHECK(info->has_context());
return Just(OuterContext(handle(info->context()), 0));
}
return GetModuleContext(info->closure());
}
} // anonymous namespace
struct InliningPhase {
static const char* phase_name() { return "inlining"; }
......@@ -797,9 +821,7 @@ struct InliningPhase {
data->info()->dependencies());
JSContextSpecialization context_specialization(
&graph_reducer, data->jsgraph(),
data->info()->is_function_context_specializing()
? handle(data->info()->context())
: MaybeHandle<Context>(),
ChooseSpecializationContext(data->info()),
data->info()->is_function_context_specializing()
? data->info()->closure()
: MaybeHandle<JSFunction>());
......
......@@ -298,6 +298,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case PROPERTY_CELL_TYPE:
case MODULE_TYPE:
case MODULE_INFO_ENTRY_TYPE:
case CELL_TYPE:
return kOtherInternal;
// Remaining instance types are unsupported for now. If any of them do
......@@ -319,7 +320,6 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case PROMISE_REACTION_JOB_INFO_TYPE:
case DEBUG_INFO_TYPE:
case STACK_FRAME_INFO_TYPE:
case CELL_TYPE:
case WEAK_CELL_TYPE:
case PROTOTYPE_INFO_TYPE:
case TUPLE2_TYPE:
......
......@@ -21,7 +21,7 @@ namespace compiler {
class ContextSpecializationTester : public HandleAndZoneScope {
public:
explicit ContextSpecializationTester(MaybeHandle<Context> context)
explicit ContextSpecializationTester(Maybe<OuterContext> context)
: graph_(new (main_zone()) Graph(main_zone())),
common_(main_zone()),
javascript_(main_zone()),
......@@ -103,7 +103,7 @@ void ContextSpecializationTester::CheckContextInputAndDepthChanges(
static const int slot_index = Context::NATIVE_CONTEXT_INDEX;
TEST(ReduceJSLoadContext0) {
ContextSpecializationTester t((MaybeHandle<Context>()));
ContextSpecializationTester t(Nothing<OuterContext>());
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -174,7 +174,7 @@ TEST(ReduceJSLoadContext1) {
//
// context2 <-- context1 <-- context0 (= Parameter(0))
ContextSpecializationTester t((MaybeHandle<Context>()));
ContextSpecializationTester t(Nothing<OuterContext>());
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -239,12 +239,12 @@ TEST(ReduceJSLoadContext1) {
TEST(ReduceJSLoadContext2) {
// The graph's context chain ends in a constant context (context_object1),
// which has has another outer context (context_object0).
// which has another outer context (context_object0).
//
// context2 <-- context1 <-- context0 (= HeapConstant(context_object1))
// context_object1 <~~ context_object0
ContextSpecializationTester t((MaybeHandle<Context>()));
ContextSpecializationTester t(Nothing<OuterContext>());
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -335,7 +335,7 @@ TEST(ReduceJSLoadContext3) {
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
ContextSpecializationTester t(context_object1);
ContextSpecializationTester t(Just(OuterContext(context_object1, 0)));
Node* start = t.graph()->NewNode(t.common()->Start(2));
t.graph()->SetStart(start);
......@@ -399,7 +399,7 @@ TEST(ReduceJSLoadContext3) {
}
TEST(ReduceJSStoreContext0) {
ContextSpecializationTester t((MaybeHandle<Context>()));
ContextSpecializationTester t(Nothing<OuterContext>());
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -461,7 +461,7 @@ TEST(ReduceJSStoreContext0) {
}
TEST(ReduceJSStoreContext1) {
ContextSpecializationTester t((MaybeHandle<Context>()));
ContextSpecializationTester t(Nothing<OuterContext>());
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -505,7 +505,7 @@ TEST(ReduceJSStoreContext1) {
}
TEST(ReduceJSStoreContext2) {
ContextSpecializationTester t((MaybeHandle<Context>()));
ContextSpecializationTester t(Nothing<OuterContext>());
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
......@@ -570,7 +570,7 @@ TEST(ReduceJSStoreContext3) {
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
ContextSpecializationTester t(context_object1);
ContextSpecializationTester t(Just(OuterContext(context_object1, 0)));
Node* start = t.graph()->NewNode(t.common()->Start(2));
t.graph()->SetStart(start);
......
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