Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Side by Side Diff: src/compiler/js-global-object-specialization.cc

Issue 2664853002: [turbofan] Support fast access to the current global object. (Closed)
Patch Set: Fix typo in DCHECK. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // 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/compiler/type-cache.h"
15 #include "src/lookup.h"
16 #include "src/objects-inl.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21
22 struct JSGlobalObjectSpecialization::ScriptContextTableLookupResult {
23 Handle<Context> context;
24 bool immutable;
25 int index;
26 };
27
28 JSGlobalObjectSpecialization::JSGlobalObjectSpecialization(
29 Editor* editor, JSGraph* jsgraph, Handle<JSGlobalObject> global_object,
30 CompilationDependencies* dependencies)
31 : AdvancedReducer(editor),
32 jsgraph_(jsgraph),
33 global_object_(global_object),
34 dependencies_(dependencies),
35 type_cache_(TypeCache::Get()) {}
36
37 Reduction JSGlobalObjectSpecialization::Reduce(Node* node) {
38 switch (node->opcode()) {
39 case IrOpcode::kJSLoadGlobal:
40 return ReduceJSLoadGlobal(node);
41 case IrOpcode::kJSStoreGlobal:
42 return ReduceJSStoreGlobal(node);
43 default:
44 break;
45 }
46 return NoChange();
47 }
48
49 namespace {
50
51 FieldAccess ForPropertyCellValue(MachineRepresentation representation,
52 Type* type, MaybeHandle<Map> map,
53 Handle<Name> name) {
54 WriteBarrierKind kind = kFullWriteBarrier;
55 if (representation == MachineRepresentation::kTaggedSigned) {
56 kind = kNoWriteBarrier;
57 } else if (representation == MachineRepresentation::kTaggedPointer) {
58 kind = kPointerWriteBarrier;
59 }
60 MachineType r = MachineType::TypeForRepresentation(representation);
61 FieldAccess access = {
62 kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
63 return access;
64 }
65
66 } // namespace
67
68 Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
69 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
70 Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
71 Node* effect = NodeProperties::GetEffectInput(node);
72 Node* control = NodeProperties::GetControlInput(node);
73
74 // Try to lookup the name on the script context table first (lexical scoping).
75 ScriptContextTableLookupResult result;
76 if (LookupInScriptContextTable(name, &result)) {
77 if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
78 Node* context = jsgraph()->HeapConstant(result.context);
79 Node* value = effect = graph()->NewNode(
80 javascript()->LoadContext(0, result.index, result.immutable), context,
81 effect);
82 ReplaceWithValue(node, value, effect);
83 return Replace(value);
84 }
85
86 // Lookup on the global object instead. We only deal with own data
87 // properties of the global object here (represented as PropertyCell).
88 LookupIterator it(global_object(), name, LookupIterator::OWN);
89 it.TryLookupCachedProperty();
90 if (it.state() != LookupIterator::DATA) return NoChange();
91 if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
92 Handle<PropertyCell> property_cell = it.GetPropertyCell();
93 PropertyDetails property_details = property_cell->property_details();
94 Handle<Object> property_cell_value(property_cell->value(), isolate());
95
96 // Load from non-configurable, read-only data property on the global
97 // object can be constant-folded, even without deoptimization support.
98 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
99 Node* value = jsgraph()->Constant(property_cell_value);
100 ReplaceWithValue(node, value);
101 return Replace(value);
102 }
103
104 // Record a code dependency on the cell if we can benefit from the
105 // additional feedback, or the global property is configurable (i.e.
106 // can be deleted or reconfigured to an accessor property).
107 if (property_details.cell_type() != PropertyCellType::kMutable ||
108 property_details.IsConfigurable()) {
109 dependencies()->AssumePropertyCell(property_cell);
110 }
111
112 // Load from constant/undefined global property can be constant-folded.
113 if (property_details.cell_type() == PropertyCellType::kConstant ||
114 property_details.cell_type() == PropertyCellType::kUndefined) {
115 Node* value = jsgraph()->Constant(property_cell_value);
116 ReplaceWithValue(node, value);
117 return Replace(value);
118 }
119
120 // Load from constant type cell can benefit from type feedback.
121 MaybeHandle<Map> map;
122 Type* property_cell_value_type = Type::NonInternal();
123 MachineRepresentation representation = MachineRepresentation::kTagged;
124 if (property_details.cell_type() == PropertyCellType::kConstantType) {
125 // Compute proper type based on the current value in the cell.
126 if (property_cell_value->IsSmi()) {
127 property_cell_value_type = Type::SignedSmall();
128 representation = MachineRepresentation::kTaggedSigned;
129 } else if (property_cell_value->IsNumber()) {
130 property_cell_value_type = Type::Number();
131 representation = MachineRepresentation::kTaggedPointer;
132 } else {
133 Handle<Map> property_cell_value_map(
134 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
135 property_cell_value_type = Type::For(property_cell_value_map);
136 representation = MachineRepresentation::kTaggedPointer;
137
138 // We can only use the property cell value map for map check elimination
139 // if it's stable, i.e. the HeapObject wasn't mutated without the cell
140 // state being updated.
141 if (property_cell_value_map->is_stable()) {
142 dependencies()->AssumeMapStable(property_cell_value_map);
143 map = property_cell_value_map;
144 }
145 }
146 }
147 Node* value = effect = graph()->NewNode(
148 simplified()->LoadField(ForPropertyCellValue(
149 representation, property_cell_value_type, map, name)),
150 jsgraph()->HeapConstant(property_cell), effect, control);
151 ReplaceWithValue(node, value, effect, control);
152 return Replace(value);
153 }
154
155
156 Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
157 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
158 Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
159 Node* value = NodeProperties::GetValueInput(node, 0);
160 Node* effect = NodeProperties::GetEffectInput(node);
161 Node* control = NodeProperties::GetControlInput(node);
162
163 // Try to lookup the name on the script context table first (lexical scoping).
164 ScriptContextTableLookupResult result;
165 if (LookupInScriptContextTable(name, &result)) {
166 if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
167 if (result.immutable) return NoChange();
168 Node* context = jsgraph()->HeapConstant(result.context);
169 effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
170 value, context, effect, control);
171 ReplaceWithValue(node, value, effect, control);
172 return Replace(value);
173 }
174
175 // Lookup on the global object instead. We only deal with own data
176 // properties of the global object here (represented as PropertyCell).
177 LookupIterator it(global_object(), name, LookupIterator::OWN);
178 if (it.state() != LookupIterator::DATA) return NoChange();
179 if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
180 Handle<PropertyCell> property_cell = it.GetPropertyCell();
181 PropertyDetails property_details = property_cell->property_details();
182 Handle<Object> property_cell_value(property_cell->value(), isolate());
183
184 // Don't even bother trying to lower stores to read-only data properties.
185 if (property_details.IsReadOnly()) return NoChange();
186 switch (property_details.cell_type()) {
187 case PropertyCellType::kUndefined: {
188 return NoChange();
189 }
190 case PropertyCellType::kConstant: {
191 // Record a code dependency on the cell, and just deoptimize if the new
192 // value doesn't match the previous value stored inside the cell.
193 dependencies()->AssumePropertyCell(property_cell);
194 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), value,
195 jsgraph()->Constant(property_cell_value));
196 effect =
197 graph()->NewNode(simplified()->CheckIf(), check, effect, control);
198 break;
199 }
200 case PropertyCellType::kConstantType: {
201 // Record a code dependency on the cell, and just deoptimize if the new
202 // values' type doesn't match the type of the previous value in the cell.
203 dependencies()->AssumePropertyCell(property_cell);
204 Type* property_cell_value_type;
205 MachineRepresentation representation = MachineRepresentation::kTagged;
206 if (property_cell_value->IsHeapObject()) {
207 // We cannot do anything if the {property_cell_value}s map is no
208 // longer stable.
209 Handle<Map> property_cell_value_map(
210 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
211 if (!property_cell_value_map->is_stable()) return NoChange();
212 dependencies()->AssumeMapStable(property_cell_value_map);
213
214 // Check that the {value} is a HeapObject.
215 value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
216 value, effect, control);
217
218 // Check {value} map agains the {property_cell} map.
219 effect =
220 graph()->NewNode(simplified()->CheckMaps(
221 CheckMapsFlag::kNone,
222 ZoneHandleSet<Map>(property_cell_value_map)),
223 value, effect, control);
224 property_cell_value_type = Type::OtherInternal();
225 representation = MachineRepresentation::kTaggedPointer;
226 } else {
227 // Check that the {value} is a Smi.
228 value = effect =
229 graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
230 property_cell_value_type = Type::SignedSmall();
231 representation = MachineRepresentation::kTaggedSigned;
232 }
233 effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
234 representation, property_cell_value_type,
235 MaybeHandle<Map>(), name)),
236 jsgraph()->HeapConstant(property_cell), value,
237 effect, control);
238 break;
239 }
240 case PropertyCellType::kMutable: {
241 // Record a code dependency on the cell, and just deoptimize if the
242 // property ever becomes read-only.
243 dependencies()->AssumePropertyCell(property_cell);
244 effect = graph()->NewNode(
245 simplified()->StoreField(ForPropertyCellValue(
246 MachineRepresentation::kTagged, Type::NonInternal(),
247 MaybeHandle<Map>(), name)),
248 jsgraph()->HeapConstant(property_cell), value, effect, control);
249 break;
250 }
251 }
252 ReplaceWithValue(node, value, effect, control);
253 return Replace(value);
254 }
255
256 bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
257 Handle<Name> name, ScriptContextTableLookupResult* result) {
258 if (!name->IsString()) return false;
259 Handle<ScriptContextTable> script_context_table(
260 global_object()->native_context()->script_context_table(), isolate());
261 ScriptContextTable::LookupResult lookup_result;
262 if (!ScriptContextTable::Lookup(script_context_table,
263 Handle<String>::cast(name), &lookup_result)) {
264 return false;
265 }
266 Handle<Context> script_context = ScriptContextTable::GetContext(
267 script_context_table, lookup_result.context_index);
268 result->context = script_context;
269 result->immutable = lookup_result.mode == CONST;
270 result->index = lookup_result.slot_index;
271 return true;
272 }
273
274 Graph* JSGlobalObjectSpecialization::graph() const {
275 return jsgraph()->graph();
276 }
277
278 Isolate* JSGlobalObjectSpecialization::isolate() const {
279 return jsgraph()->isolate();
280 }
281
282 CommonOperatorBuilder* JSGlobalObjectSpecialization::common() const {
283 return jsgraph()->common();
284 }
285
286 JSOperatorBuilder* JSGlobalObjectSpecialization::javascript() const {
287 return jsgraph()->javascript();
288 }
289
290 SimplifiedOperatorBuilder* JSGlobalObjectSpecialization::simplified() const {
291 return jsgraph()->simplified();
292 }
293
294 } // namespace compiler
295 } // namespace internal
296 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698