Index: src/compiler/js-context-specialization.cc |
diff --git a/src/compiler/js-context-specialization.cc b/src/compiler/js-context-specialization.cc |
index 2b12d3add6bf8ae6a6c30ffe6b9f7086ed76513e..9a2edc13e31ff1c830d829deb2ac2ae9aac99021 100644 |
--- a/src/compiler/js-context-specialization.cc |
+++ b/src/compiler/js-context-specialization.cc |
@@ -28,50 +28,81 @@ Reduction JSContextSpecialization::Reduce(Node* node) { |
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( |
- Node* node) { |
- DCHECK(node->opcode() == IrOpcode::kJSLoadContext || |
- node->opcode() == IrOpcode::kJSStoreContext); |
- Node* const object = NodeProperties::GetContextInput(node); |
- return NodeProperties::GetSpecializationContext(object, context()); |
+ const Operator* op = jsgraph_->javascript()->LoadContext( |
+ new_depth, access.index(), access.immutable()); |
+ NodeProperties::ReplaceContextInput(node, new_context); |
+ NodeProperties::ChangeOp(node, op); |
+ return Changed(node); |
} |
+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) { |
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()); |
- for (size_t i = access.depth(); i > 0; --i) { |
- context = handle(context->previous(), isolate()); |
+ size_t depth = access.depth(); |
+ |
+ // 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); |
+ } |
+ |
+ // Now walk up the concrete context chain for the remaining depth. |
+ for (; depth > 0; --depth) { |
+ concrete = handle(concrete->previous(), isolate()); |
} |
- // If the access itself is mutable, only fold-in the parent. |
if (!access.immutable()) { |
- // The access does not have to look up a parent, nothing to fold. |
- if (access.depth() == 0) { |
- return NoChange(); |
- } |
- const Operator* op = jsgraph_->javascript()->LoadContext( |
- 0, access.index(), access.immutable()); |
- NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context)); |
- NodeProperties::ChangeOp(node, op); |
- return Changed(node); |
+ // We found the requested context object but since the context slot is |
+ // mutable we can only partially reduce the load. |
+ 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 |
// 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 |
- // hole or undefined. If it is neither of these, then it must be initialized. |
+ // We must be conservative and check if the value in the slot is currently |
+ // 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())) { |
- return NoChange(); |
+ return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth); |
} |
// Success. The context load can be replaced with the constant. |
@@ -86,24 +117,27 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) { |
Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) { |
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()); |
- if (access.depth() == 0) { |
- return NoChange(); |
+ size_t depth = access.depth(); |
+ |
+ // 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. |
- for (size_t i = access.depth(); i > 0; --i) { |
- context = handle(context->previous(), isolate()); |
+ // Now walk up the concrete context chain for the remaining depth. |
+ for (; depth > 0; --depth) { |
+ concrete = handle(concrete->previous(), isolate()); |
} |
- NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context)); |
- NodeProperties::ChangeOp(node, javascript()->StoreContext(0, access.index())); |
- return Changed(node); |
+ return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth); |
} |