Commit fd8cebb1 authored by neis's avatar neis Committed by Commit bot

[compiler] Generalize JSContextSpecialization.

With this CL, context loads and stores are "strengthened" by reducing
the incoming context chain and decreasing the depth accordingly,
whenever possible.  This enables more opportunities for specialization
and will let us easily add module context specialization later.

BUG=

Review-Url: https://codereview.chromium.org/2559173003
Cr-Commit-Position: refs/heads/master@{#42334}
parent a6fe748d
...@@ -28,50 +28,81 @@ Reduction JSContextSpecialization::Reduce(Node* node) { ...@@ -28,50 +28,81 @@ Reduction JSContextSpecialization::Reduce(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
Node* new_context,
size_t new_depth) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
const ContextAccess& access = ContextAccessOf(node->op());
DCHECK_LE(new_depth, access.depth());
if (new_depth == access.depth() &&
new_context == NodeProperties::GetContextInput(node)) {
return NoChange();
}
MaybeHandle<Context> JSContextSpecialization::GetSpecializationContext( const Operator* op = jsgraph_->javascript()->LoadContext(
Node* node) { new_depth, access.index(), access.immutable());
DCHECK(node->opcode() == IrOpcode::kJSLoadContext || NodeProperties::ReplaceContextInput(node, new_context);
node->opcode() == IrOpcode::kJSStoreContext); NodeProperties::ChangeOp(node, op);
Node* const object = NodeProperties::GetContextInput(node); return Changed(node);
return NodeProperties::GetSpecializationContext(object, context());
} }
Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
Node* new_context,
size_t new_depth) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
const ContextAccess& access = ContextAccessOf(node->op());
DCHECK_LE(new_depth, access.depth());
if (new_depth == access.depth() &&
new_context == NodeProperties::GetContextInput(node)) {
return NoChange();
}
const Operator* op =
jsgraph_->javascript()->StoreContext(new_depth, access.index());
NodeProperties::ReplaceContextInput(node, new_context);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) { Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
// Get the specialization context from the node.
Handle<Context> context;
if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange();
// Find the right parent context.
const ContextAccess& access = ContextAccessOf(node->op()); const ContextAccess& access = ContextAccessOf(node->op());
for (size_t i = access.depth(); i > 0; --i) { size_t depth = access.depth();
context = handle(context->previous(), isolate());
// First walk up the context chain in the graph as far as possible.
Node* outer = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete;
if (!NodeProperties::GetSpecializationContext(outer, context())
.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);
} }
// If the access itself is mutable, only fold-in the parent. // Now walk up the concrete context chain for the remaining depth.
if (!access.immutable()) { for (; depth > 0; --depth) {
// The access does not have to look up a parent, nothing to fold. concrete = handle(concrete->previous(), isolate());
if (access.depth() == 0) {
return NoChange();
} }
const Operator* op = jsgraph_->javascript()->LoadContext(
0, access.index(), access.immutable()); if (!access.immutable()) {
NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context)); // We found the requested context object but since the context slot is
NodeProperties::ChangeOp(node, op); // mutable we can only partially reduce the load.
return Changed(node); return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
} }
Handle<Object> value =
handle(context->get(static_cast<int>(access.index())), isolate());
// Even though the context slot is immutable, the context might have escaped // Even though the context slot is immutable, the context might have escaped
// before the function to which it belongs has initialized the slot. // before the function to which it belongs has initialized the slot.
// We must be conservative and check if the value in the slot is currently the // We must be conservative and check if the value in the slot is currently
// hole or undefined. If it is neither of these, then it must be initialized. // the hole or undefined. Only if it is neither of these, can we be sure that
// it won't change anymore.
Handle<Object> value(concrete->get(static_cast<int>(access.index())),
isolate());
if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) { if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) {
return NoChange(); return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
} }
// Success. The context load can be replaced with the constant. // Success. The context load can be replaced with the constant.
...@@ -86,24 +117,27 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) { ...@@ -86,24 +117,27 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) { Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
// Get the specialization context from the node.
Handle<Context> context;
if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange();
// The access does not have to look up a parent, nothing to fold.
const ContextAccess& access = ContextAccessOf(node->op()); const ContextAccess& access = ContextAccessOf(node->op());
if (access.depth() == 0) { size_t depth = access.depth();
return NoChange();
// 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);
Handle<Context> concrete;
if (!NodeProperties::GetSpecializationContext(outer, context())
.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);
} }
// Find the right parent context. // Now walk up the concrete context chain for the remaining depth.
for (size_t i = access.depth(); i > 0; --i) { for (; depth > 0; --depth) {
context = handle(context->previous(), isolate()); concrete = handle(concrete->previous(), isolate());
} }
NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context)); return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
NodeProperties::ChangeOp(node, javascript()->StoreContext(0, access.index()));
return Changed(node);
} }
......
...@@ -30,8 +30,10 @@ class JSContextSpecialization final : public AdvancedReducer { ...@@ -30,8 +30,10 @@ class JSContextSpecialization final : public AdvancedReducer {
Reduction ReduceJSLoadContext(Node* node); Reduction ReduceJSLoadContext(Node* node);
Reduction ReduceJSStoreContext(Node* node); Reduction ReduceJSStoreContext(Node* node);
// Returns the {Context} to specialize {node} to (if any). Reduction SimplifyJSStoreContext(Node* node, Node* new_context,
MaybeHandle<Context> GetSpecializationContext(Node* node); size_t new_depth);
Reduction SimplifyJSLoadContext(Node* node, Node* new_context,
size_t new_depth);
Isolate* isolate() const; Isolate* isolate() const;
JSOperatorBuilder* javascript() const; JSOperatorBuilder* javascript() const;
......
...@@ -338,6 +338,17 @@ MaybeHandle<Context> NodeProperties::GetSpecializationContext( ...@@ -338,6 +338,17 @@ MaybeHandle<Context> NodeProperties::GetSpecializationContext(
} }
// static
Node* NodeProperties::GetOuterContext(Node* node, size_t* depth) {
Node* context = NodeProperties::GetContextInput(node);
while (*depth > 0 &&
IrOpcode::IsContextChainExtendingOpcode(context->opcode())) {
context = NodeProperties::GetContextInput(context);
(*depth)--;
}
return context;
}
// static // static
Type* NodeProperties::GetTypeOrAny(Node* node) { Type* NodeProperties::GetTypeOrAny(Node* node) {
return IsTyped(node) ? node->type() : Type::Any(); return IsTyped(node) ? node->type() : Type::Any();
......
...@@ -132,6 +132,11 @@ class V8_EXPORT_PRIVATE NodeProperties final { ...@@ -132,6 +132,11 @@ class V8_EXPORT_PRIVATE NodeProperties final {
static MaybeHandle<Context> GetSpecializationContext( static MaybeHandle<Context> GetSpecializationContext(
Node* node, MaybeHandle<Context> context = MaybeHandle<Context>()); 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).
static Node* GetOuterContext(Node* node, size_t* depth);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Type. // Type.
......
...@@ -800,6 +800,10 @@ class V8_EXPORT_PRIVATE IrOpcode { ...@@ -800,6 +800,10 @@ class V8_EXPORT_PRIVATE IrOpcode {
(kNumberEqual <= value && value <= kStringLessThanOrEqual) || (kNumberEqual <= value && value <= kStringLessThanOrEqual) ||
(kWord32Equal <= value && value <= kFloat64LessThanOrEqual); (kWord32Equal <= value && value <= kFloat64LessThanOrEqual);
} }
static bool IsContextChainExtendingOpcode(Value value) {
return kJSCreateFunctionContext <= value && value <= kJSCreateScriptContext;
}
}; };
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, IrOpcode::Value); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, IrOpcode::Value);
......
...@@ -18,7 +18,7 @@ namespace compiler { ...@@ -18,7 +18,7 @@ namespace compiler {
class ContextSpecializationTester : public HandleAndZoneScope { class ContextSpecializationTester : public HandleAndZoneScope {
public: public:
ContextSpecializationTester() explicit ContextSpecializationTester(MaybeHandle<Context> context)
: graph_(new (main_zone()) Graph(main_zone())), : graph_(new (main_zone()) Graph(main_zone())),
common_(main_zone()), common_(main_zone()),
javascript_(main_zone()), javascript_(main_zone()),
...@@ -27,7 +27,7 @@ class ContextSpecializationTester : public HandleAndZoneScope { ...@@ -27,7 +27,7 @@ class ContextSpecializationTester : public HandleAndZoneScope {
jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_, jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_,
&machine_), &machine_),
reducer_(main_zone(), graph()), reducer_(main_zone(), graph()),
spec_(&reducer_, jsgraph(), MaybeHandle<Context>()) {} spec_(&reducer_, jsgraph(), context) {}
JSContextSpecialization* spec() { return &spec_; } JSContextSpecialization* spec() { return &spec_; }
Factory* factory() { return main_isolate()->factory(); } Factory* factory() { return main_isolate()->factory(); }
...@@ -37,6 +37,13 @@ class ContextSpecializationTester : public HandleAndZoneScope { ...@@ -37,6 +37,13 @@ class ContextSpecializationTester : public HandleAndZoneScope {
JSGraph* jsgraph() { return &jsgraph_; } JSGraph* jsgraph() { return &jsgraph_; }
Graph* graph() { return graph_; } Graph* graph() { return graph_; }
void CheckChangesToValue(Node* node, Handle<HeapObject> expected_value);
void CheckContextInputAndDepthChanges(
Node* node, Handle<Context> expected_new_context_object,
size_t expected_new_depth);
void CheckContextInputAndDepthChanges(Node* node, Node* expected_new_context,
size_t expected_new_depth);
private: private:
Graph* graph_; Graph* graph_;
CommonOperatorBuilder common_; CommonOperatorBuilder common_;
...@@ -48,9 +55,52 @@ class ContextSpecializationTester : public HandleAndZoneScope { ...@@ -48,9 +55,52 @@ class ContextSpecializationTester : public HandleAndZoneScope {
JSContextSpecialization spec_; JSContextSpecialization spec_;
}; };
void ContextSpecializationTester::CheckChangesToValue(
Node* node, Handle<HeapObject> expected_value) {
Reduction r = spec()->Reduce(node);
CHECK(r.Changed());
HeapObjectMatcher match(r.replacement());
CHECK(match.HasValue());
CHECK_EQ(*match.Value(), *expected_value);
}
void ContextSpecializationTester::CheckContextInputAndDepthChanges(
Node* node, Handle<Context> expected_new_context_object,
size_t expected_new_depth) {
ContextAccess access = OpParameter<ContextAccess>(node);
Reduction r = spec()->Reduce(node);
CHECK(r.Changed());
Node* new_context = NodeProperties::GetContextInput(r.replacement());
CHECK_EQ(IrOpcode::kHeapConstant, new_context->opcode());
HeapObjectMatcher match(new_context);
CHECK_EQ(*match.Value(), *expected_new_context_object);
ContextAccess new_access = OpParameter<ContextAccess>(r.replacement());
CHECK_EQ(new_access.depth(), expected_new_depth);
CHECK_EQ(new_access.index(), access.index());
CHECK_EQ(new_access.immutable(), access.immutable());
}
void ContextSpecializationTester::CheckContextInputAndDepthChanges(
Node* node, Node* expected_new_context, size_t expected_new_depth) {
ContextAccess access = OpParameter<ContextAccess>(node);
Reduction r = spec()->Reduce(node);
CHECK(r.Changed());
Node* new_context = NodeProperties::GetContextInput(r.replacement());
CHECK_EQ(new_context, expected_new_context);
ContextAccess new_access = OpParameter<ContextAccess>(r.replacement());
CHECK_EQ(new_access.depth(), expected_new_depth);
CHECK_EQ(new_access.index(), access.index());
CHECK_EQ(new_access.immutable(), access.immutable());
}
static const int slot_index = Context::NATIVE_CONTEXT_INDEX;
TEST(ReduceJSLoadContext) { TEST(ReduceJSLoadContext0) {
ContextSpecializationTester t; ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0)); Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start); t.graph()->SetStart(start);
...@@ -114,14 +164,239 @@ TEST(ReduceJSLoadContext) { ...@@ -114,14 +164,239 @@ TEST(ReduceJSLoadContext) {
CHECK(match.HasValue()); CHECK(match.HasValue());
CHECK_EQ(*expected, *match.Value()); CHECK_EQ(*expected, *match.Value());
} }
}
TEST(ReduceJSLoadContext1) {
// The graph's context chain ends in the incoming context parameter:
//
// context2 <-- context1 <-- context0 (= Parameter(0))
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, false), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, true), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 1);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 1);
}
}
TEST(ReduceJSLoadContext2) {
// The graph's context chain ends in a constant context (context_object1),
// which has has another outer context (context_object0).
//
// context2 <-- context1 <-- context0 (= HeapConstant(context_object1))
// context_object1 <~~ context_object0
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
Handle<Context> context_object0 = t.factory()->NewNativeContext();
Handle<Context> context_object1 = t.factory()->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
Node* context0 = t.jsgraph()->Constant(context_object1);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, false), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, true), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
// TODO(titzer): test with other kinds of contexts, e.g. a function context. {
// TODO(sigurds): test that loads below create context are not optimized Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value1);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context_object0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value0);
}
} }
TEST(ReduceJSLoadContext3) {
// Like in ReduceJSLoadContext1, the graph's context chain ends in the
// incoming context parameter. However, this time we provide a concrete
// context for this parameter as the "specialization context". We choose
// context_object2 from ReduceJSLoadContext2 for this, so almost all test
// expectations are the same as in ReduceJSLoadContext2.
HandleAndZoneScope handle_zone_scope;
auto factory = handle_zone_scope.main_isolate()->factory();
TEST(ReduceJSStoreContext) { Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
ContextSpecializationTester t; Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
Handle<Context> context_object0 = factory->NewNativeContext();
Handle<Context> context_object1 = factory->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
ContextSpecializationTester t(context_object1);
Node* start = t.graph()->NewNode(t.common()->Start(2));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, false), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(0, slot_index, true), context2, start);
CHECK(!t.spec()->Reduce(load).Changed());
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(1, slot_index, true), context2, start);
t.CheckContextInputAndDepthChanges(load, context1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context_object1, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(2, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value1);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, false), context2, start);
t.CheckContextInputAndDepthChanges(load, context_object0, 0);
}
{
Node* load = t.graph()->NewNode(
t.javascript()->LoadContext(3, slot_index, true), context2, start);
t.CheckChangesToValue(load, slot_value0);
}
}
TEST(ReduceJSStoreContext0) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0)); Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start); t.graph()->SetStart(start);
...@@ -182,6 +457,158 @@ TEST(ReduceJSStoreContext) { ...@@ -182,6 +457,158 @@ TEST(ReduceJSStoreContext) {
} }
} }
TEST(ReduceJSStoreContext1) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
context2, context2, start, start);
CHECK(!t.spec()->Reduce(store).Changed());
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context0, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context0, 1);
}
}
TEST(ReduceJSStoreContext2) {
ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
Handle<Context> context_object0 = t.factory()->NewNativeContext();
Handle<Context> context_object1 = t.factory()->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
Node* context0 = t.jsgraph()->Constant(context_object1);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
context2, context2, start, start);
CHECK(!t.spec()->Reduce(store).Changed());
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context0, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context_object0, 0);
}
}
TEST(ReduceJSStoreContext3) {
HandleAndZoneScope handle_zone_scope;
auto factory = handle_zone_scope.main_isolate()->factory();
Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
Handle<Context> context_object0 = factory->NewNativeContext();
Handle<Context> context_object1 = factory->NewNativeContext();
context_object1->set_previous(*context_object0);
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
ContextSpecializationTester t(context_object1);
Node* start = t.graph()->NewNode(t.common()->Start(2));
t.graph()->SetStart(start);
Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
const i::compiler::Operator* create_function_context =
t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
Node* context1 = t.graph()->NewNode(create_function_context, undefined,
context0, start, start);
Node* context2 = t.graph()->NewNode(create_function_context, undefined,
context1, start, start);
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
context2, context2, start, start);
CHECK(!t.spec()->Reduce(store).Changed());
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context_object1, 0);
}
{
Node* store =
t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
context2, context2, start, start);
t.CheckContextInputAndDepthChanges(store, context_object0, 0);
}
}
TEST(SpecializeJSFunction_ToConstant1) { TEST(SpecializeJSFunction_ToConstant1) {
FunctionTester T( FunctionTester T(
......
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