Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/js-context-specialization.h" | 5 #include "src/compiler/js-context-specialization.h" |
| 6 | 6 |
| 7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
| 8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/js-operator.h" | 9 #include "src/compiler/js-operator.h" |
| 10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 case IrOpcode::kJSLoadContext: | 21 case IrOpcode::kJSLoadContext: |
| 22 return ReduceJSLoadContext(node); | 22 return ReduceJSLoadContext(node); |
| 23 case IrOpcode::kJSStoreContext: | 23 case IrOpcode::kJSStoreContext: |
| 24 return ReduceJSStoreContext(node); | 24 return ReduceJSStoreContext(node); |
| 25 default: | 25 default: |
| 26 break; | 26 break; |
| 27 } | 27 } |
| 28 return NoChange(); | 28 return NoChange(); |
| 29 } | 29 } |
| 30 | 30 |
| 31 namespace { | |
| 31 | 32 |
| 32 MaybeHandle<Context> JSContextSpecialization::GetSpecializationContext( | 33 Node* GetOuterContext(Node* node, size_t* depth) { |
| 33 Node* node) { | 34 Node* context = NodeProperties::GetContextInput(node); |
| 34 DCHECK(node->opcode() == IrOpcode::kJSLoadContext || | 35 while (*depth > 0 && IrOpcode::IsContextExtendingOpcode(context->opcode())) { |
| 35 node->opcode() == IrOpcode::kJSStoreContext); | 36 context = NodeProperties::GetContextInput(context); |
| 36 Node* const object = NodeProperties::GetContextInput(node); | 37 (*depth)--; |
| 37 return NodeProperties::GetSpecializationContext(object, context()); | 38 } |
| 39 return context; | |
| 40 } // XXX: Move to node-properties? | |
|
Michael Starzinger
2017/01/13 13:36:26
nit: s/XXX/TODO/ here. Also maybe move to in front
neis
2017/01/13 14:08:02
I actually moved it to NodeProperties now.
| |
| 41 | |
| 42 } // anonymous namespace | |
| 43 | |
| 44 Reduction JSContextSpecialization::StrengthenJSLoadContext(Node* node, | |
|
Michael Starzinger
2017/01/13 13:36:26
random non-actionable rambling: As discussed offli
neis
2017/01/13 14:08:02
Renamed to SimplifyJS...
| |
| 45 Node* new_context, | |
| 46 size_t new_depth) { | |
| 47 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); | |
| 48 const ContextAccess& access = ContextAccessOf(node->op()); | |
| 49 DCHECK_LE(new_depth, access.depth()); | |
| 50 | |
| 51 if (new_depth == access.depth() && | |
| 52 new_context == NodeProperties::GetContextInput(node)) { | |
| 53 return NoChange(); | |
| 54 } | |
| 55 | |
| 56 const Operator* op = jsgraph_->javascript()->LoadContext( | |
| 57 new_depth, access.index(), access.immutable()); | |
| 58 NodeProperties::ReplaceContextInput(node, new_context); | |
| 59 NodeProperties::ChangeOp(node, op); | |
| 60 return Changed(node); | |
| 38 } | 61 } |
| 39 | 62 |
| 63 Reduction JSContextSpecialization::StrengthenJSStoreContext(Node* node, | |
| 64 Node* new_context, | |
| 65 size_t new_depth) { | |
| 66 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); | |
| 67 const ContextAccess& access = ContextAccessOf(node->op()); | |
| 68 DCHECK_LE(new_depth, access.depth()); | |
| 69 | |
| 70 if (new_depth == access.depth() && | |
| 71 new_context == NodeProperties::GetContextInput(node)) { | |
| 72 return NoChange(); | |
| 73 } | |
| 74 | |
| 75 const Operator* op = | |
| 76 jsgraph_->javascript()->StoreContext(new_depth, access.index()); | |
| 77 NodeProperties::ReplaceContextInput(node, new_context); | |
| 78 NodeProperties::ChangeOp(node, op); | |
| 79 return Changed(node); | |
| 80 } | |
| 40 | 81 |
| 41 Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) { | 82 Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) { |
| 42 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); | 83 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); |
| 43 | 84 |
| 44 // Get the specialization context from the node. | 85 const ContextAccess& access = ContextAccessOf(node->op()); |
| 45 Handle<Context> context; | 86 size_t depth = access.depth(); |
| 46 if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange(); | |
| 47 | 87 |
| 48 // Find the right parent context. | 88 // First walk up the context chain in the graph until we reduce the depth to 0 |
| 49 const ContextAccess& access = ContextAccessOf(node->op()); | 89 // or hit a node that does not have a CreateXYZContext operator. |
| 50 for (size_t i = access.depth(); i > 0; --i) { | 90 Node* outer = GetOuterContext(node, &depth); |
| 51 context = handle(context->previous(), isolate()); | 91 |
| 92 Handle<Context> concrete; | |
| 93 if (!NodeProperties::GetSpecializationContext(outer, context()) | |
| 94 .ToHandle(&concrete)) { | |
| 95 // We do not have a concrete context object, so we can only partially reduce | |
| 96 // the load by folding-in the outer context node. | |
| 97 return StrengthenJSLoadContext(node, outer, depth); | |
| 52 } | 98 } |
| 53 | 99 |
| 54 // If the access itself is mutable, only fold-in the parent. | 100 // Now walk up the concrete context chain for the remaining depth. |
| 101 for (; depth > 0; --depth) { | |
| 102 concrete = handle(concrete->previous(), isolate()); | |
| 103 } | |
| 104 | |
| 55 if (!access.immutable()) { | 105 if (!access.immutable()) { |
| 56 // The access does not have to look up a parent, nothing to fold. | 106 // We found the requested context object but since the context slot is |
| 57 if (access.depth() == 0) { | 107 // mutable we can only partially reduce the load. |
| 58 return NoChange(); | 108 return StrengthenJSLoadContext(node, jsgraph()->Constant(concrete), depth); |
| 59 } | |
| 60 const Operator* op = jsgraph_->javascript()->LoadContext( | |
| 61 0, access.index(), access.immutable()); | |
| 62 NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context)); | |
| 63 NodeProperties::ChangeOp(node, op); | |
| 64 return Changed(node); | |
| 65 } | 109 } |
| 66 Handle<Object> value = | |
| 67 handle(context->get(static_cast<int>(access.index())), isolate()); | |
| 68 | 110 |
| 69 // Even though the context slot is immutable, the context might have escaped | 111 // Even though the context slot is immutable, the context might have escaped |
| 70 // before the function to which it belongs has initialized the slot. | 112 // before the function to which it belongs has initialized the slot. |
| 71 // We must be conservative and check if the value in the slot is currently the | 113 // We must be conservative and check if the value in the slot is currently |
| 72 // hole or undefined. If it is neither of these, then it must be initialized. | 114 // the hole or undefined. Only if it is neither of these, can we be sure that |
| 115 // it won't change anymore. | |
| 116 Handle<Object> value(concrete->get(static_cast<int>(access.index())), | |
| 117 isolate()); | |
| 73 if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) { | 118 if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) { |
| 74 return NoChange(); | 119 return StrengthenJSLoadContext(node, jsgraph()->Constant(concrete), depth); |
| 75 } | 120 } |
| 76 | 121 |
| 77 // Success. The context load can be replaced with the constant. | 122 // Success. The context load can be replaced with the constant. |
| 78 // TODO(titzer): record the specialization for sharing code across multiple | 123 // TODO(titzer): record the specialization for sharing code across multiple |
| 79 // contexts that have the same value in the corresponding context slot. | 124 // contexts that have the same value in the corresponding context slot. |
| 80 Node* constant = jsgraph_->Constant(value); | 125 Node* constant = jsgraph_->Constant(value); |
| 81 ReplaceWithValue(node, constant); | 126 ReplaceWithValue(node, constant); |
| 82 return Replace(constant); | 127 return Replace(constant); |
| 83 } | 128 } |
| 84 | 129 |
| 85 | 130 |
| 86 Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) { | 131 Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) { |
| 87 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); | 132 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); |
| 88 | 133 |
| 89 // Get the specialization context from the node. | 134 const ContextAccess& access = ContextAccessOf(node->op()); |
| 90 Handle<Context> context; | 135 size_t depth = access.depth(); |
| 91 if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange(); | |
| 92 | 136 |
| 93 // The access does not have to look up a parent, nothing to fold. | 137 // First walk up the context chain in the graph until we reduce the depth to 0 |
| 94 const ContextAccess& access = ContextAccessOf(node->op()); | 138 // or hit a node that does not have a CreateXYZContext operator. |
| 95 if (access.depth() == 0) { | 139 Node* outer = GetOuterContext(node, &depth); |
| 96 return NoChange(); | 140 |
| 141 Handle<Context> concrete; | |
| 142 if (!NodeProperties::GetSpecializationContext(outer, context()) | |
| 143 .ToHandle(&concrete)) { | |
| 144 // We do not have a concrete context object, so we can only partially reduce | |
| 145 // the load by folding-in the outer context node. | |
| 146 return StrengthenJSStoreContext(node, outer, depth); | |
| 97 } | 147 } |
| 98 | 148 |
| 99 // Find the right parent context. | 149 // Now walk up the concrete context chain for the remaining depth. |
| 100 for (size_t i = access.depth(); i > 0; --i) { | 150 for (; depth > 0; --depth) { |
| 101 context = handle(context->previous(), isolate()); | 151 concrete = handle(concrete->previous(), isolate()); |
| 102 } | 152 } |
| 103 | 153 |
| 104 NodeProperties::ReplaceContextInput(node, jsgraph_->Constant(context)); | 154 return StrengthenJSStoreContext(node, jsgraph()->Constant(concrete), depth); |
| 105 NodeProperties::ChangeOp(node, javascript()->StoreContext(0, access.index())); | |
| 106 return Changed(node); | |
| 107 } | 155 } |
| 108 | 156 |
| 109 | 157 |
| 110 Isolate* JSContextSpecialization::isolate() const { | 158 Isolate* JSContextSpecialization::isolate() const { |
| 111 return jsgraph()->isolate(); | 159 return jsgraph()->isolate(); |
| 112 } | 160 } |
| 113 | 161 |
| 114 | 162 |
| 115 JSOperatorBuilder* JSContextSpecialization::javascript() const { | 163 JSOperatorBuilder* JSContextSpecialization::javascript() const { |
| 116 return jsgraph()->javascript(); | 164 return jsgraph()->javascript(); |
| 117 } | 165 } |
| 118 | 166 |
| 119 } // namespace compiler | 167 } // namespace compiler |
| 120 } // namespace internal | 168 } // namespace internal |
| 121 } // namespace v8 | 169 } // namespace v8 |
| OLD | NEW |