blob: a700b47cebc4ec130cf6750b961b8446d1eda5ab [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/compiler/js-context-specialization.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/compiler.h"
8#include "src/compiler/common-operator.h"
9#include "src/compiler/graph-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/compiler/js-operator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/compiler/node-matchers.h"
12#include "src/compiler/node-properties-inl.h"
13
14namespace v8 {
15namespace internal {
16namespace compiler {
17
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018Reduction JSContextSpecializer::Reduce(Node* node) {
19 if (node == context_) {
20 Node* constant = jsgraph_->Constant(info_->context());
21 NodeProperties::ReplaceWithValue(node, constant);
22 return Replace(constant);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024 if (node->opcode() == IrOpcode::kJSLoadContext) {
25 return ReduceJSLoadContext(node);
26 }
27 if (node->opcode() == IrOpcode::kJSStoreContext) {
28 return ReduceJSStoreContext(node);
29 }
30 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031}
32
33
34Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) {
35 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
36
37 HeapObjectMatcher<Context> m(NodeProperties::GetValueInput(node, 0));
38 // If the context is not constant, no reduction can occur.
39 if (!m.HasValue()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040040 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041 }
42
Emily Bernierd0a1eb72015-03-24 16:35:39 -040043 const ContextAccess& access = ContextAccessOf(node->op());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044
45 // Find the right parent context.
46 Context* context = *m.Value().handle();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047 for (size_t i = access.depth(); i > 0; --i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048 context = context->previous();
49 }
50
51 // If the access itself is mutable, only fold-in the parent.
52 if (!access.immutable()) {
53 // The access does not have to look up a parent, nothing to fold.
54 if (access.depth() == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056 }
57 const Operator* op = jsgraph_->javascript()->LoadContext(
58 0, access.index(), access.immutable());
59 node->set_op(op);
60 Handle<Object> context_handle = Handle<Object>(context, info_->isolate());
61 node->ReplaceInput(0, jsgraph_->Constant(context_handle));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040062 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064 Handle<Object> value = Handle<Object>(
65 context->get(static_cast<int>(access.index())), info_->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066
67 // Even though the context slot is immutable, the context might have escaped
68 // before the function to which it belongs has initialized the slot.
69 // We must be conservative and check if the value in the slot is currently the
70 // hole or undefined. If it is neither of these, then it must be initialized.
71 if (value->IsUndefined() || value->IsTheHole()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040072 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 }
74
75 // Success. The context load can be replaced with the constant.
76 // TODO(titzer): record the specialization for sharing code across multiple
77 // contexts that have the same value in the corresponding context slot.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 Node* constant = jsgraph_->Constant(value);
79 NodeProperties::ReplaceWithValue(node, constant);
80 return Replace(constant);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081}
82
83
84Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) {
85 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
86
87 HeapObjectMatcher<Context> m(NodeProperties::GetValueInput(node, 0));
88 // If the context is not constant, no reduction can occur.
89 if (!m.HasValue()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040090 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 }
92
Emily Bernierd0a1eb72015-03-24 16:35:39 -040093 const ContextAccess& access = ContextAccessOf(node->op());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094
95 // The access does not have to look up a parent, nothing to fold.
96 if (access.depth() == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040097 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 }
99
100 // Find the right parent context.
101 Context* context = *m.Value().handle();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400102 for (size_t i = access.depth(); i > 0; --i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 context = context->previous();
104 }
105
106 const Operator* op = jsgraph_->javascript()->StoreContext(0, access.index());
107 node->set_op(op);
108 Handle<Object> new_context_handle = Handle<Object>(context, info_->isolate());
109 node->ReplaceInput(0, jsgraph_->Constant(new_context_handle));
110
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400111 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112}
113
114} // namespace compiler
115} // namespace internal
116} // namespace v8