bdf142763a8887ca3db22cdda719b94eae24f86a
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / js-context-specialization.cc
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
3 // found in the LICENSE file.
4
5 #include "src/compiler/common-operator.h"
6 #include "src/compiler/generic-node-inl.h"
7 #include "src/compiler/graph-inl.h"
8 #include "src/compiler/js-context-specialization.h"
9 #include "src/compiler/js-operator.h"
10 #include "src/compiler/node-aux-data-inl.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties-inl.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 // TODO(titzer): factor this out to a common routine with js-typed-lowering.
19 static void ReplaceEffectfulWithValue(Node* node, Node* value) {
20   Node* effect = NULL;
21   if (OperatorProperties::HasEffectInput(node->op())) {
22     effect = NodeProperties::GetEffectInput(node);
23   }
24
25   // Requires distinguishing between value and effect edges.
26   UseIter iter = node->uses().begin();
27   while (iter != node->uses().end()) {
28     if (NodeProperties::IsEffectEdge(iter.edge())) {
29       DCHECK_NE(NULL, effect);
30       iter = iter.UpdateToAndIncrement(effect);
31     } else {
32       iter = iter.UpdateToAndIncrement(value);
33     }
34   }
35 }
36
37
38 class ContextSpecializationVisitor : public NullNodeVisitor {
39  public:
40   explicit ContextSpecializationVisitor(JSContextSpecializer* spec)
41       : spec_(spec) {}
42
43   GenericGraphVisit::Control Post(Node* node) {
44     switch (node->opcode()) {
45       case IrOpcode::kJSLoadContext: {
46         Reduction r = spec_->ReduceJSLoadContext(node);
47         if (r.Changed() && r.replacement() != node) {
48           ReplaceEffectfulWithValue(node, r.replacement());
49         }
50         break;
51       }
52       case IrOpcode::kJSStoreContext: {
53         Reduction r = spec_->ReduceJSStoreContext(node);
54         if (r.Changed() && r.replacement() != node) {
55           ReplaceEffectfulWithValue(node, r.replacement());
56         }
57         break;
58       }
59       default:
60         break;
61     }
62     return GenericGraphVisit::CONTINUE;
63   }
64
65  private:
66   JSContextSpecializer* spec_;
67 };
68
69
70 void JSContextSpecializer::SpecializeToContext() {
71   ReplaceEffectfulWithValue(context_, jsgraph_->Constant(info_->context()));
72
73   ContextSpecializationVisitor visitor(this);
74   jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
75 }
76
77
78 Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) {
79   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
80
81   ValueMatcher<Handle<Context> > match(NodeProperties::GetValueInput(node, 0));
82   // If the context is not constant, no reduction can occur.
83   if (!match.HasValue()) {
84     return Reducer::NoChange();
85   }
86
87   ContextAccess access = OpParameter<ContextAccess>(node);
88
89   // Find the right parent context.
90   Context* context = *match.Value();
91   for (int i = access.depth(); i > 0; --i) {
92     context = context->previous();
93   }
94
95   // If the access itself is mutable, only fold-in the parent.
96   if (!access.immutable()) {
97     // The access does not have to look up a parent, nothing to fold.
98     if (access.depth() == 0) {
99       return Reducer::NoChange();
100     }
101     Operator* op = jsgraph_->javascript()->LoadContext(0, access.index(),
102                                                        access.immutable());
103     node->set_op(op);
104     Handle<Object> context_handle = Handle<Object>(context, info_->isolate());
105     node->ReplaceInput(0, jsgraph_->Constant(context_handle));
106     return Reducer::Changed(node);
107   }
108   Handle<Object> value =
109       Handle<Object>(context->get(access.index()), info_->isolate());
110
111   // Even though the context slot is immutable, the context might have escaped
112   // before the function to which it belongs has initialized the slot.
113   // We must be conservative and check if the value in the slot is currently the
114   // hole or undefined. If it is neither of these, then it must be initialized.
115   if (value->IsUndefined() || value->IsTheHole()) {
116     return Reducer::NoChange();
117   }
118
119   // Success. The context load can be replaced with the constant.
120   // TODO(titzer): record the specialization for sharing code across multiple
121   // contexts that have the same value in the corresponding context slot.
122   return Reducer::Replace(jsgraph_->Constant(value));
123 }
124
125
126 Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) {
127   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
128
129   ValueMatcher<Handle<Context> > match(NodeProperties::GetValueInput(node, 0));
130   // If the context is not constant, no reduction can occur.
131   if (!match.HasValue()) {
132     return Reducer::NoChange();
133   }
134
135   ContextAccess access = OpParameter<ContextAccess>(node);
136
137   // The access does not have to look up a parent, nothing to fold.
138   if (access.depth() == 0) {
139     return Reducer::NoChange();
140   }
141
142   // Find the right parent context.
143   Context* context = *match.Value();
144   for (int i = access.depth(); i > 0; --i) {
145     context = context->previous();
146   }
147
148   Operator* op = jsgraph_->javascript()->StoreContext(0, access.index());
149   node->set_op(op);
150   Handle<Object> new_context_handle = Handle<Object>(context, info_->isolate());
151   node->ReplaceInput(0, jsgraph_->Constant(new_context_handle));
152
153   return Reducer::Changed(node);
154 }
155 }
156 }
157 }  // namespace v8::internal::compiler