blob: 31407e83dce6da280365b02414d85cf18e733e53 [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"
Ben Murdoch61f157c2016-09-16 13:49:30 +010015#include "src/objects-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016#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();
Ben Murdochc5610432016-08-08 18:44:38 +010077 if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078 Handle<PropertyCell> property_cell = it.GetPropertyCell();
79 PropertyDetails property_details = property_cell->property_details();
80 Handle<Object> property_cell_value(property_cell->value(), isolate());
81
82 // Load from non-configurable, read-only data property on the global
83 // object can be constant-folded, even without deoptimization support.
84 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
85 Node* value = jsgraph()->Constant(property_cell_value);
86 ReplaceWithValue(node, value);
87 return Replace(value);
88 }
89
Ben Murdoch097c5b22016-05-18 11:27:45 +010090 // Record a code dependency on the cell if we can benefit from the
91 // additional feedback, or the global property is configurable (i.e.
92 // can be deleted or reconfigured to an accessor property).
93 if (property_details.cell_type() != PropertyCellType::kMutable ||
94 property_details.IsConfigurable()) {
95 dependencies()->AssumePropertyCell(property_cell);
96 }
97
98 // Load from constant/undefined global property can be constant-folded.
99 if (property_details.cell_type() == PropertyCellType::kConstant ||
100 property_details.cell_type() == PropertyCellType::kUndefined) {
101 Node* value = jsgraph()->Constant(property_cell_value);
102 ReplaceWithValue(node, value);
103 return Replace(value);
104 }
105
106 // Load from constant type cell can benefit from type feedback.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 Type* property_cell_value_type = Type::Tagged();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100108 if (property_details.cell_type() == PropertyCellType::kConstantType) {
109 // Compute proper type based on the current value in the cell.
110 if (property_cell_value->IsSmi()) {
111 property_cell_value_type = type_cache_.kSmi;
112 } else if (property_cell_value->IsNumber()) {
113 property_cell_value_type = type_cache_.kHeapNumber;
114 } else {
115 Handle<Map> property_cell_value_map(
116 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
117 property_cell_value_type =
118 Type::Class(property_cell_value_map, graph()->zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 }
121 Node* value = effect = graph()->NewNode(
122 simplified()->LoadField(
123 AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
124 jsgraph()->HeapConstant(property_cell), effect, control);
125 ReplaceWithValue(node, value, effect, control);
126 return Replace(value);
127}
128
129
130Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
131 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
132 Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
133 Node* value = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 Node* effect = NodeProperties::GetEffectInput(node);
135 Node* control = NodeProperties::GetControlInput(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100136 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137
138 // Retrieve the global object from the given {node}.
139 Handle<JSGlobalObject> global_object;
140 if (!GetGlobalObject(node).ToHandle(&global_object)) return NoChange();
141
142 // Try to lookup the name on the script context table first (lexical scoping).
143 ScriptContextTableLookupResult result;
144 if (LookupInScriptContextTable(global_object, name, &result)) {
145 if (result.context->is_the_hole(result.index)) return NoChange();
146 if (result.immutable) return NoChange();
147 Node* context = jsgraph()->HeapConstant(result.context);
148 effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
149 context, value, context, effect, control);
150 ReplaceWithValue(node, value, effect, control);
151 return Replace(value);
152 }
153
154 // Lookup on the global object instead. We only deal with own data
155 // properties of the global object here (represented as PropertyCell).
156 LookupIterator it(global_object, name, LookupIterator::OWN);
157 if (it.state() != LookupIterator::DATA) return NoChange();
Ben Murdochc5610432016-08-08 18:44:38 +0100158 if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 Handle<PropertyCell> property_cell = it.GetPropertyCell();
160 PropertyDetails property_details = property_cell->property_details();
161 Handle<Object> property_cell_value(property_cell->value(), isolate());
162
163 // Don't even bother trying to lower stores to read-only data properties.
164 if (property_details.IsReadOnly()) return NoChange();
165 switch (property_details.cell_type()) {
166 case PropertyCellType::kUndefined: {
167 return NoChange();
168 }
169 case PropertyCellType::kConstant: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100170 // Record a code dependency on the cell, and just deoptimize if the new
171 // value doesn't match the previous value stored inside the cell.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 dependencies()->AssumePropertyCell(property_cell);
173 Node* check =
174 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
175 jsgraph()->Constant(property_cell_value));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100176 control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
177 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178 break;
179 }
180 case PropertyCellType::kConstantType: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100181 // Record a code dependency on the cell, and just deoptimize if the new
182 // values' type doesn't match the type of the previous value in the cell.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 dependencies()->AssumePropertyCell(property_cell);
184 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
185 Type* property_cell_value_type = Type::TaggedSigned();
186 if (property_cell_value->IsHeapObject()) {
187 // Deoptimize if the {value} is a Smi.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100188 control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
189 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190
191 // Load the {value} map check against the {property_cell} map.
192 Node* value_map = effect =
193 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
194 value, effect, control);
195 Handle<Map> property_cell_value_map(
196 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
197 check = graph()->NewNode(
198 simplified()->ReferenceEqual(Type::Any()), value_map,
199 jsgraph()->HeapConstant(property_cell_value_map));
200 property_cell_value_type = Type::TaggedPointer();
201 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100202 control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
203 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 effect = graph()->NewNode(
205 simplified()->StoreField(
206 AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
207 jsgraph()->HeapConstant(property_cell), value, effect, control);
208 break;
209 }
210 case PropertyCellType::kMutable: {
211 // Store to non-configurable, data property on the global can be lowered
Ben Murdoch097c5b22016-05-18 11:27:45 +0100212 // to a field store, even without recording a code dependency on the cell,
213 // because the property cannot be deleted or reconfigured to an accessor
214 // or interceptor property.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 if (property_details.IsConfigurable()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 // Protect lowering by recording a code dependency on the cell.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 dependencies()->AssumePropertyCell(property_cell);
218 }
219 effect = graph()->NewNode(
220 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
221 jsgraph()->HeapConstant(property_cell), value, effect, control);
222 break;
223 }
224 }
225 ReplaceWithValue(node, value, effect, control);
226 return Replace(value);
227}
228
229
230MaybeHandle<JSGlobalObject> JSGlobalObjectSpecialization::GetGlobalObject(
231 Node* node) {
232 Node* const context = NodeProperties::GetContextInput(node);
233 return NodeProperties::GetSpecializationGlobalObject(context,
234 native_context());
235}
236
237
238bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
239 Handle<JSGlobalObject> global_object, Handle<Name> name,
240 ScriptContextTableLookupResult* result) {
241 if (!name->IsString()) return false;
242 Handle<ScriptContextTable> script_context_table(
243 global_object->native_context()->script_context_table(), isolate());
244 ScriptContextTable::LookupResult lookup_result;
245 if (!ScriptContextTable::Lookup(script_context_table,
246 Handle<String>::cast(name), &lookup_result)) {
247 return false;
248 }
249 Handle<Context> script_context = ScriptContextTable::GetContext(
250 script_context_table, lookup_result.context_index);
251 result->context = script_context;
252 result->immutable = IsImmutableVariableMode(lookup_result.mode);
253 result->index = lookup_result.slot_index;
254 return true;
255}
256
257
258Graph* JSGlobalObjectSpecialization::graph() const {
259 return jsgraph()->graph();
260}
261
262
263Isolate* JSGlobalObjectSpecialization::isolate() const {
264 return jsgraph()->isolate();
265}
266
267
268CommonOperatorBuilder* JSGlobalObjectSpecialization::common() const {
269 return jsgraph()->common();
270}
271
272
273JSOperatorBuilder* JSGlobalObjectSpecialization::javascript() const {
274 return jsgraph()->javascript();
275}
276
277
278SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const {
279 return jsgraph()->simplified();
280}
281
282} // namespace compiler
283} // namespace internal
284} // namespace v8