blob: d8c9f17fd4c207737b55780bd1cb9e306572524e [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 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/js-global-object-specialization.h"
6
7#include "src/compilation-dependencies.h"
8#include "src/compiler/access-builder.h"
9#include "src/compiler/common-operator.h"
10#include "src/compiler/js-graph.h"
11#include "src/compiler/js-operator.h"
12#include "src/compiler/node-properties.h"
13#include "src/compiler/simplified-operator.h"
14#include "src/lookup.h"
15#include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
16#include "src/type-cache.h"
17
18namespace v8 {
19namespace internal {
20namespace compiler {
21
22struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult {
23 Handle<Context> context;
24 bool immutable;
25 int index;
26};
27
28
29JSGlobalObjectSpecialization::JSGlobalObjectSpecialization(
Ben Murdoch097c5b22016-05-18 11:27:45 +010030 Editor* editor, JSGraph* jsgraph,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 MaybeHandle<Context> native_context, CompilationDependencies* dependencies)
32 : AdvancedReducer(editor),
33 jsgraph_(jsgraph),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 native_context_(native_context),
35 dependencies_(dependencies),
36 type_cache_(TypeCache::Get()) {}
37
38
39Reduction JSGlobalObjectSpecialization::Reduce(Node* node) {
40 switch (node->opcode()) {
41 case IrOpcode::kJSLoadGlobal:
42 return ReduceJSLoadGlobal(node);
43 case IrOpcode::kJSStoreGlobal:
44 return ReduceJSStoreGlobal(node);
45 default:
46 break;
47 }
48 return NoChange();
49}
50
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
52 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
53 Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
54 Node* effect = NodeProperties::GetEffectInput(node);
55 Node* control = NodeProperties::GetControlInput(node);
56
57 // Retrieve the global object from the given {node}.
58 Handle<JSGlobalObject> global_object;
59 if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange();
60
61 // Try to lookup the name on the script context table first (lexical scoping).
62 ScriptContextTableLookupResult result;
63 if (LookupInScriptContextTable(global_object, name, &result)) {
64 if (result.context->is_the_hole(result.index)) return NoChange();
65 Node* context = jsgraph()->HeapConstant(result.context);
66 Node* value = effect = graph()->NewNode(
67 javascript()->LoadContext(0, result.index, result.immutable), context,
68 context, effect);
69 ReplaceWithValue(node, value, effect);
70 return Replace(value);
71 }
72
73 // Lookup on the global object instead. We only deal with own data
74 // properties of the global object here (represented as PropertyCell).
75 LookupIterator it(global_object, name, LookupIterator::OWN);
76 if (it.state() != LookupIterator::DATA) return NoChange();
77 Handle<PropertyCell> property_cell = it.GetPropertyCell();
78 PropertyDetails property_details = property_cell->property_details();
79 Handle<Object> property_cell_value(property_cell->value(), isolate());
80
81 // Load from non-configurable, read-only data property on the global
82 // object can be constant-folded, even without deoptimization support.
83 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
84 Node* value = jsgraph()->Constant(property_cell_value);
85 ReplaceWithValue(node, value);
86 return Replace(value);
87 }
88
Ben Murdoch097c5b22016-05-18 11:27:45 +010089 // Record a code dependency on the cell if we can benefit from the
90 // additional feedback, or the global property is configurable (i.e.
91 // can be deleted or reconfigured to an accessor property).
92 if (property_details.cell_type() != PropertyCellType::kMutable ||
93 property_details.IsConfigurable()) {
94 dependencies()->AssumePropertyCell(property_cell);
95 }
96
97 // Load from constant/undefined global property can be constant-folded.
98 if (property_details.cell_type() == PropertyCellType::kConstant ||
99 property_details.cell_type() == PropertyCellType::kUndefined) {
100 Node* value = jsgraph()->Constant(property_cell_value);
101 ReplaceWithValue(node, value);
102 return Replace(value);
103 }
104
105 // Load from constant type cell can benefit from type feedback.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 Type* property_cell_value_type = Type::Tagged();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100107 if (property_details.cell_type() == PropertyCellType::kConstantType) {
108 // Compute proper type based on the current value in the cell.
109 if (property_cell_value->IsSmi()) {
110 property_cell_value_type = type_cache_.kSmi;
111 } else if (property_cell_value->IsNumber()) {
112 property_cell_value_type = type_cache_.kHeapNumber;
113 } else {
114 Handle<Map> property_cell_value_map(
115 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
116 property_cell_value_type =
117 Type::Class(property_cell_value_map, graph()->zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 }
120 Node* value = effect = graph()->NewNode(
121 simplified()->LoadField(
122 AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
123 jsgraph()->HeapConstant(property_cell), effect, control);
124 ReplaceWithValue(node, value, effect, control);
125 return Replace(value);
126}
127
128
129Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
130 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
131 Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
132 Node* value = NodeProperties::GetValueInput(node, 0);
133 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
134 Node* effect = NodeProperties::GetEffectInput(node);
135 Node* control = NodeProperties::GetControlInput(node);
136
137 // Retrieve the global object from the given {node}.
138 Handle<JSGlobalObject> global_object;
139 if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange();
140
141 // Try to lookup the name on the script context table first (lexical scoping).
142 ScriptContextTableLookupResult result;
143 if (LookupInScriptContextTable(global_object, name, &result)) {
144 if (result.context->is_the_hole(result.index)) return NoChange();
145 if (result.immutable) return NoChange();
146 Node* context = jsgraph()->HeapConstant(result.context);
147 effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
148 context, value, context, effect, control);
149 ReplaceWithValue(node, value, effect, control);
150 return Replace(value);
151 }
152
153 // Lookup on the global object instead. We only deal with own data
154 // properties of the global object here (represented as PropertyCell).
155 LookupIterator it(global_object, name, LookupIterator::OWN);
156 if (it.state() != LookupIterator::DATA) return NoChange();
157 Handle<PropertyCell> property_cell = it.GetPropertyCell();
158 PropertyDetails property_details = property_cell->property_details();
159 Handle<Object> property_cell_value(property_cell->value(), isolate());
160
161 // Don't even bother trying to lower stores to read-only data properties.
162 if (property_details.IsReadOnly()) return NoChange();
163 switch (property_details.cell_type()) {
164 case PropertyCellType::kUndefined: {
165 return NoChange();
166 }
167 case PropertyCellType::kConstant: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100168 // Record a code dependency on the cell, and just deoptimize if the new
169 // value doesn't match the previous value stored inside the cell.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 dependencies()->AssumePropertyCell(property_cell);
171 Node* check =
172 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
173 jsgraph()->Constant(property_cell_value));
Ben Murdochda12d292016-06-02 14:46:10 +0100174 control = graph()->NewNode(common()->DeoptimizeUnless(), check,
175 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 break;
177 }
178 case PropertyCellType::kConstantType: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100179 // Record a code dependency on the cell, and just deoptimize if the new
180 // values' type doesn't match the type of the previous value in the cell.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181 dependencies()->AssumePropertyCell(property_cell);
182 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
183 Type* property_cell_value_type = Type::TaggedSigned();
184 if (property_cell_value->IsHeapObject()) {
185 // Deoptimize if the {value} is a Smi.
Ben Murdochda12d292016-06-02 14:46:10 +0100186 control = graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
187 effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188
189 // Load the {value} map check against the {property_cell} map.
190 Node* value_map = effect =
191 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
192 value, effect, control);
193 Handle<Map> property_cell_value_map(
194 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
195 check = graph()->NewNode(
196 simplified()->ReferenceEqual(Type::Any()), value_map,
197 jsgraph()->HeapConstant(property_cell_value_map));
198 property_cell_value_type = Type::TaggedPointer();
199 }
Ben Murdochda12d292016-06-02 14:46:10 +0100200 control = graph()->NewNode(common()->DeoptimizeUnless(), check,
201 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 effect = graph()->NewNode(
203 simplified()->StoreField(
204 AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
205 jsgraph()->HeapConstant(property_cell), value, effect, control);
206 break;
207 }
208 case PropertyCellType::kMutable: {
209 // Store to non-configurable, data property on the global can be lowered
Ben Murdoch097c5b22016-05-18 11:27:45 +0100210 // to a field store, even without recording a code dependency on the cell,
211 // because the property cannot be deleted or reconfigured to an accessor
212 // or interceptor property.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 if (property_details.IsConfigurable()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100214 // Protect lowering by recording a code dependency on the cell.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 dependencies()->AssumePropertyCell(property_cell);
216 }
217 effect = graph()->NewNode(
218 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
219 jsgraph()->HeapConstant(property_cell), value, effect, control);
220 break;
221 }
222 }
223 ReplaceWithValue(node, value, effect, control);
224 return Replace(value);
225}
226
227
228MaybeHandle<JSGlobalObject> JSGlobalObjectSpecialization::GetGlobalObject(
229 Node* node) {
230 Node* const context = NodeProperties::GetContextInput(node);
231 return NodeProperties::GetSpecializationGlobalObject(context,
232 native_context());
233}
234
235
236bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
237 Handle<JSGlobalObject> global_object, Handle<Name> name,
238 ScriptContextTableLookupResult* result) {
239 if (!name->IsString()) return false;
240 Handle<ScriptContextTable> script_context_table(
241 global_object->native_context()->script_context_table(), isolate());
242 ScriptContextTable::LookupResult lookup_result;
243 if (!ScriptContextTable::Lookup(script_context_table,
244 Handle<String>::cast(name), &lookup_result)) {
245 return false;
246 }
247 Handle<Context> script_context = ScriptContextTable::GetContext(
248 script_context_table, lookup_result.context_index);
249 result->context = script_context;
250 result->immutable = IsImmutableVariableMode(lookup_result.mode);
251 result->index = lookup_result.slot_index;
252 return true;
253}
254
255
256Graph* JSGlobalObjectSpecialization::graph() const {
257 return jsgraph()->graph();
258}
259
260
261Isolate* JSGlobalObjectSpecialization::isolate() const {
262 return jsgraph()->isolate();
263}
264
265
266CommonOperatorBuilder* JSGlobalObjectSpecialization::common() const {
267 return jsgraph()->common();
268}
269
270
271JSOperatorBuilder* JSGlobalObjectSpecialization::javascript() const {
272 return jsgraph()->javascript();
273}
274
275
276SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const {
277 return jsgraph()->simplified();
278}
279
280} // namespace compiler
281} // namespace internal
282} // namespace v8