Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(580)

Unified Diff: test/cctest/compiler/test-js-context-specialization.cc

Issue 2559173003: [compiler] Generalize JSContextSpecialization. (Closed)
Patch Set: Feedback Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/opcodes.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/compiler/test-js-context-specialization.cc
diff --git a/test/cctest/compiler/test-js-context-specialization.cc b/test/cctest/compiler/test-js-context-specialization.cc
index d7812c6eb0842e62b427742b298cbde8c9a880c0..d8122c4fdbb9afc843049064462d696a2dd0e6e3 100644
--- a/test/cctest/compiler/test-js-context-specialization.cc
+++ b/test/cctest/compiler/test-js-context-specialization.cc
@@ -18,7 +18,7 @@ namespace compiler {
class ContextSpecializationTester : public HandleAndZoneScope {
public:
- ContextSpecializationTester()
+ explicit ContextSpecializationTester(MaybeHandle<Context> context)
: graph_(new (main_zone()) Graph(main_zone())),
common_(main_zone()),
javascript_(main_zone()),
@@ -27,7 +27,7 @@ class ContextSpecializationTester : public HandleAndZoneScope {
jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_,
&machine_),
reducer_(main_zone(), graph()),
- spec_(&reducer_, jsgraph(), MaybeHandle<Context>()) {}
+ spec_(&reducer_, jsgraph(), context) {}
JSContextSpecialization* spec() { return &spec_; }
Factory* factory() { return main_isolate()->factory(); }
@@ -37,6 +37,13 @@ class ContextSpecializationTester : public HandleAndZoneScope {
JSGraph* jsgraph() { return &jsgraph_; }
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:
Graph* graph_;
CommonOperatorBuilder common_;
@@ -48,9 +55,52 @@ class ContextSpecializationTester : public HandleAndZoneScope {
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);
-TEST(ReduceJSLoadContext) {
- ContextSpecializationTester t;
+ 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(ReduceJSLoadContext0) {
+ ContextSpecializationTester t((MaybeHandle<Context>()));
Node* start = t.graph()->NewNode(t.common()->Start(0));
t.graph()->SetStart(start);
@@ -114,14 +164,239 @@ TEST(ReduceJSLoadContext) {
CHECK(match.HasValue());
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());
+ }
- // 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.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
-TEST(ReduceJSStoreContext) {
- ContextSpecializationTester t;
+ 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());
+ }
+
+ {
+ 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();
+
+ 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* 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));
t.graph()->SetStart(start);
@@ -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) {
FunctionTester T(
« no previous file with comments | « src/compiler/opcodes.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698