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 7b62f74587747ef5e0fa95c93e8160ccbc7626c5..740d9f3d497350c78e14bf83388b4a85df7d41a7 100644 |
--- a/test/cctest/compiler/test-js-context-specialization.cc |
+++ b/test/cctest/compiler/test-js-context-specialization.cc |
@@ -55,46 +55,45 @@ TEST(ReduceJSLoadContext) { |
// Make a context and initialize it a bit for this test. |
Handle<Context> native = t.factory()->NewNativeContext(); |
- Handle<Context> ctx1 = t.factory()->NewNativeContext(); |
- Handle<Context> ctx2 = t.factory()->NewNativeContext(); |
- ctx2->set_previous(*ctx1); |
- ctx1->set_previous(*native); |
+ Handle<Context> subcontext1 = t.factory()->NewNativeContext(); |
+ Handle<Context> subcontext2 = t.factory()->NewNativeContext(); |
+ subcontext2->set_previous(*subcontext1); |
+ subcontext1->set_previous(*native); |
Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!"); |
const int slot = Context::GLOBAL_OBJECT_INDEX; |
native->set(slot, *expected); |
Node* const_context = t.jsgraph()->Constant(native); |
+ Node* deep_const_context = t.jsgraph()->Constant(subcontext2); |
Node* param_context = t.NewNode(t.common()->Parameter(0), start); |
JSContextSpecializer spec(t.info(), t.jsgraph(), const_context); |
{ |
// Mutable slot, constant context, depth = 0 => do nothing. |
- t.info()->SetContext(native); |
Node* load = t.NewNode(t.javascript()->LoadContext(0, 0, false), |
- const_context, start, start); |
+ const_context, const_context, start); |
Reduction r = spec.ReduceJSLoadContext(load); |
CHECK(!r.Changed()); |
} |
{ |
// Mutable slot, non-constant context, depth = 0 => do nothing. |
- t.info()->SetContext(native); |
Node* load = t.NewNode(t.javascript()->LoadContext(0, 0, false), |
- param_context, start, start); |
+ param_context, param_context, start); |
Reduction r = spec.ReduceJSLoadContext(load); |
CHECK(!r.Changed()); |
} |
{ |
- // Mutable slot, non-constant context, depth > 0 => fold-in parent context. |
- t.info()->SetContext(ctx2); |
+ // Mutable slot, constant context, depth > 0 => fold-in parent context. |
Node* load = t.NewNode( |
t.javascript()->LoadContext(2, Context::GLOBAL_EVAL_FUN_INDEX, false), |
- param_context, start, start); |
+ deep_const_context, deep_const_context, start); |
Reduction r = spec.ReduceJSLoadContext(load); |
CHECK(r.Changed()); |
- CHECK_EQ(IrOpcode::kHeapConstant, r.replacement()->InputAt(0)->opcode()); |
- ValueMatcher<Handle<Context> > match(r.replacement()->InputAt(0)); |
+ Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0); |
+ CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode()); |
+ ValueMatcher<Handle<Context> > match(new_context_input); |
CHECK_EQ(*native, *match.Value()); |
ContextAccess access = static_cast<Operator1<ContextAccess>*>( |
r.replacement()->op())->parameter(); |
@@ -104,10 +103,9 @@ TEST(ReduceJSLoadContext) { |
} |
{ |
- // Immutable slot, constant context => specialize. |
- t.info()->SetContext(native); |
+ // Immutable slot, constant context, depth = 0 => specialize. |
Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true), |
- const_context, start, start); |
+ const_context, const_context, start); |
Reduction r = spec.ReduceJSLoadContext(load); |
CHECK(r.Changed()); |
CHECK(r.replacement() != load); |
@@ -117,22 +115,73 @@ TEST(ReduceJSLoadContext) { |
CHECK_EQ(*expected, *match.Value()); |
} |
+ // TODO(titzer): test with other kinds of contexts, e.g. a function context. |
+ // TODO(sigurds): test that loads below create context are not optimized |
+} |
+ |
+ |
+TEST(ReduceJSStoreContext) { |
+ ContextSpecializationTester t; |
+ |
+ Node* start = t.NewNode(t.common()->Start(0)); |
+ t.graph()->SetStart(start); |
+ |
+ // Make a context and initialize it a bit for this test. |
+ Handle<Context> native = t.factory()->NewNativeContext(); |
+ Handle<Context> subcontext1 = t.factory()->NewNativeContext(); |
+ Handle<Context> subcontext2 = t.factory()->NewNativeContext(); |
+ subcontext2->set_previous(*subcontext1); |
+ subcontext1->set_previous(*native); |
+ Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!"); |
+ const int slot = Context::GLOBAL_OBJECT_INDEX; |
+ native->set(slot, *expected); |
+ |
+ Node* const_context = t.jsgraph()->Constant(native); |
+ Node* deep_const_context = t.jsgraph()->Constant(subcontext2); |
+ Node* param_context = t.NewNode(t.common()->Parameter(0), start); |
+ JSContextSpecializer spec(t.info(), t.jsgraph(), const_context); |
+ |
{ |
- // Immutable slot, non-constant context => specialize. |
- t.info()->SetContext(native); |
- Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true), |
- param_context, start, start); |
- Reduction r = spec.ReduceJSLoadContext(load); |
- CHECK(r.Changed()); |
- CHECK(r.replacement() != load); |
+ // Mutable slot, constant context, depth = 0 => do nothing. |
+ Node* load = t.NewNode(t.javascript()->StoreContext(0, 0), const_context, |
+ const_context, start); |
+ Reduction r = spec.ReduceJSStoreContext(load); |
+ CHECK(!r.Changed()); |
+ } |
- ValueMatcher<Handle<Object> > match(r.replacement()); |
- CHECK(match.HasValue()); |
- CHECK_EQ(*expected, *match.Value()); |
+ { |
+ // Mutable slot, non-constant context, depth = 0 => do nothing. |
+ Node* load = t.NewNode(t.javascript()->StoreContext(0, 0), param_context, |
+ param_context, start); |
+ Reduction r = spec.ReduceJSStoreContext(load); |
+ CHECK(!r.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 |
+ { |
+ // Immutable slot, constant context, depth = 0 => do nothing. |
+ Node* load = t.NewNode(t.javascript()->StoreContext(0, slot), const_context, |
+ const_context, start); |
+ Reduction r = spec.ReduceJSStoreContext(load); |
+ CHECK(!r.Changed()); |
+ } |
+ |
+ { |
+ // Mutable slot, constant context, depth > 0 => fold-in parent context. |
+ Node* load = t.NewNode( |
+ t.javascript()->StoreContext(2, Context::GLOBAL_EVAL_FUN_INDEX), |
+ deep_const_context, deep_const_context, start); |
+ Reduction r = spec.ReduceJSStoreContext(load); |
+ CHECK(r.Changed()); |
+ Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0); |
+ CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode()); |
+ ValueMatcher<Handle<Context> > match(new_context_input); |
+ CHECK_EQ(*native, *match.Value()); |
+ ContextAccess access = static_cast<Operator1<ContextAccess>*>( |
+ r.replacement()->op())->parameter(); |
+ CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index()); |
+ CHECK_EQ(0, access.depth()); |
+ CHECK_EQ(false, access.immutable()); |
+ } |
} |
@@ -162,17 +211,25 @@ TEST(SpecializeToContext) { |
{ |
// Check that SpecializeToContext() replaces values and forwards effects |
// correctly, and folds values from constant and non-constant contexts |
- Node* effect_in = t.NewNode(t.common()->Start(0)); |
+ Node* effect_in = start; |
Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true), |
- const_context, const_context, effect_in, start); |
+ const_context, const_context, effect_in); |
Node* value_use = t.ChangeTaggedToInt32(load); |
Node* other_load = t.NewNode(t.javascript()->LoadContext(0, slot, true), |
- param_context, param_context, load, start); |
+ param_context, param_context, load); |
Node* effect_use = other_load; |
Node* other_use = t.ChangeTaggedToInt32(other_load); |
+ Node* add = t.NewNode(t.javascript()->Add(), value_use, other_use, |
+ param_context, other_load, start); |
+ |
+ Node* ret = t.NewNode(t.common()->Return(), add, effect_use, start); |
+ Node* end = t.NewNode(t.common()->End(), ret); |
+ USE(end); |
+ t.graph()->SetEnd(end); |
+ |
// Double check the above graph is what we expect, or the test is broken. |
CheckEffectInput(effect_in, load); |
CheckEffectInput(load, effect_use); |