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

Side by Side Diff: src/compiler/js-type-feedback.cc

Issue 1110503002: [turbofan] Reland: Optimize loads from the global object in JSTypeFeedbackSpecializer. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 7 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
« no previous file with comments | « src/compiler/js-type-feedback.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/js-type-feedback.h" 5 #include "src/compiler/js-type-feedback.h"
6 6
7 #include "src/property-details.h" 7 #include "src/property-details.h"
8 8
9 #include "src/accessors.h" 9 #include "src/accessors.h"
10 #include "src/ast.h" 10 #include "src/ast.h"
11 #include "src/compiler.h"
11 #include "src/type-info.h" 12 #include "src/type-info.h"
12 13
13 #include "src/compiler/access-builder.h" 14 #include "src/compiler/access-builder.h"
14 #include "src/compiler/common-operator.h" 15 #include "src/compiler/common-operator.h"
15 #include "src/compiler/node-aux-data.h" 16 #include "src/compiler/node-aux-data.h"
16 #include "src/compiler/node-matchers.h" 17 #include "src/compiler/node-matchers.h"
17 #include "src/compiler/operator-properties.h" 18 #include "src/compiler/operator-properties.h"
18 #include "src/compiler/simplified-operator.h" 19 #include "src/compiler/simplified-operator.h"
19 20
20 namespace v8 { 21 namespace v8 {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 } 72 }
72 return ReduceJSStoreProperty(node); 73 return ReduceJSStoreProperty(node);
73 } 74 }
74 default: 75 default:
75 break; 76 break;
76 } 77 }
77 return NoChange(); 78 return NoChange();
78 } 79 }
79 80
80 81
82 static void AddFieldAccessTypes(FieldAccess* access,
83 PropertyDetails property_details) {
84 if (property_details.representation().IsSmi()) {
85 access->type = Type::SignedSmall();
86 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
87 } else if (property_details.representation().IsDouble()) {
88 access->type = Type::Number();
89 access->machine_type = kMachFloat64;
90 }
91 }
92
93
81 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, 94 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
82 Handle<Name> name, FieldAccess* access) { 95 Handle<Name> name, FieldAccess* access) {
83 access->base_is_tagged = kTaggedBase; 96 access->base_is_tagged = kTaggedBase;
84 access->offset = -1; 97 access->offset = -1;
85 access->name = name; 98 access->name = name;
86 access->type = Type::Any(); 99 access->type = Type::Any();
87 access->machine_type = kMachAnyTagged; 100 access->machine_type = kMachAnyTagged;
88 101
89 // Check for properties that have accessors but are JSObject fields. 102 // Check for properties that have accessors but are JSObject fields.
90 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) { 103 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) {
(...skipping 11 matching lines...) Expand all
102 PropertyDetails property_details = descriptors->GetDetails(number); 115 PropertyDetails property_details = descriptors->GetDetails(number);
103 116
104 bool is_smi = property_details.representation().IsSmi(); 117 bool is_smi = property_details.representation().IsSmi();
105 bool is_double = property_details.representation().IsDouble(); 118 bool is_double = property_details.representation().IsDouble();
106 119
107 if (property_details.type() != DATA) { 120 if (property_details.type() != DATA) {
108 // TODO(turbofan): constant loads and stores. 121 // TODO(turbofan): constant loads and stores.
109 return false; 122 return false;
110 } 123 }
111 124
125 // Transfer known types from property details.
126 AddFieldAccessTypes(access, property_details);
127
112 if (mode == STORE) { 128 if (mode == STORE) {
113 if (property_details.IsReadOnly()) return false; 129 if (property_details.IsReadOnly()) {
114 if (is_smi) { 130 // TODO(turbofan): deopt, ignore or throw on readonly stores.
115 // TODO(turbofan): SMI stores.
116 return false; 131 return false;
117 } 132 }
118 if (is_double) { 133 if (is_smi || is_double) {
119 // TODO(turbofan): double stores. 134 // TODO(turbofan): check type and deopt for SMI/double stores.
120 return false; 135 return false;
121 } 136 }
122 } else {
123 // Check property details for loads.
124 if (is_smi) {
125 access->type = Type::SignedSmall();
126 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
127 }
128 if (is_double) {
129 access->type = Type::Number();
130 access->machine_type = kMachFloat64;
131 }
132 } 137 }
133 138
134 int index = map->instance_descriptors()->GetFieldIndex(number); 139 int index = map->instance_descriptors()->GetFieldIndex(number);
135 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double); 140 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
136 141
137 if (field_index.is_inobject()) { 142 if (field_index.is_inobject()) {
138 access->offset = field_index.offset(); 143 access->offset = field_index.offset();
139 return true; 144 return true;
140 } 145 }
141 146
142 // TODO(turbofan): handle out of object properties. 147 // TODO(turbofan): handle out of object properties.
143 return false; 148 return false;
144 } 149 }
145 150
146 151
152 static bool IsGlobalObject(Node* node) {
153 return NodeProperties::IsTyped(node) &&
154 NodeProperties::GetBounds(node).upper->Is(Type::GlobalObject());
155 }
156
157
147 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { 158 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
148 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); 159 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed);
160 Node* receiver = node->InputAt(0);
161 if (IsGlobalObject(receiver)) {
162 return ReduceJSLoadNamedForGlobalVariable(node);
163 }
164
165 if (!FLAG_turbo_deoptimization) return NoChange();
149 // TODO(titzer): deopt locations are wrong for property accesses 166 // TODO(titzer): deopt locations are wrong for property accesses
150 if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange(); 167 if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange();
151 168
152 // TODO(turbofan): handle vector-based type feedback. 169 // TODO(turbofan): handle vector-based type feedback.
153 TypeFeedbackId id = js_type_feedback_->find(node); 170 TypeFeedbackId id = js_type_feedback_->find(node);
154 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { 171 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) {
155 return NoChange(); 172 return NoChange();
156 } 173 }
157 174
158 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); 175 const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
159 SmallMapList maps; 176 SmallMapList maps;
160 Handle<Name> name = p.name().handle(); 177 Handle<Name> name = p.name().handle();
161 Node* receiver = node->InputAt(0);
162 Node* effect = NodeProperties::GetEffectInput(node); 178 Node* effect = NodeProperties::GetEffectInput(node);
163 GatherReceiverTypes(receiver, effect, id, name, &maps); 179 GatherReceiverTypes(receiver, effect, id, name, &maps);
164 180
165 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism 181 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
166 182
167 Handle<Map> map = maps.first(); 183 Handle<Map> map = maps.first();
168 FieldAccess field_access; 184 FieldAccess field_access;
169 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) { 185 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) {
170 return NoChange(); 186 return NoChange();
171 } 187 }
(...skipping 12 matching lines...) Expand all
184 // TODO(titzer): frame state should be from before the load. 200 // TODO(titzer): frame state should be from before the load.
185 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); 201 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
186 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, 202 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
187 check_failed); 203 check_failed);
188 NodeProperties::MergeControlToEnd(graph(), common(), deopt); 204 NodeProperties::MergeControlToEnd(graph(), common(), deopt);
189 NodeProperties::ReplaceWithValue(node, load, load, check_success); 205 NodeProperties::ReplaceWithValue(node, load, load, check_success);
190 return Replace(load); 206 return Replace(load);
191 } 207 }
192 208
193 209
210 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedForGlobalVariable(
211 Node* node) {
212 Handle<String> name =
213 Handle<String>::cast(LoadNamedParametersOf(node->op()).name().handle());
214 // Try to optimize loads from the global object.
215 Handle<Object> constant_value =
216 jsgraph()->isolate()->factory()->GlobalConstantFor(name);
217 if (!constant_value.is_null()) {
218 // Always optimize global constants.
219 Node* constant = jsgraph()->Constant(constant_value);
220 NodeProperties::ReplaceWithValue(node, constant);
221 return Replace(constant);
222 }
223
224 if (global_object_.is_null()) {
225 // Nothing else can be done if we don't have a global object.
226 return NoChange();
227 }
228
229 if (FLAG_turbo_deoptimization) {
230 // Handle lookups in the script context.
231 {
232 Handle<ScriptContextTable> script_contexts(
233 global_object_->native_context()->script_context_table());
234 ScriptContextTable::LookupResult lookup;
235 if (ScriptContextTable::Lookup(script_contexts, name, &lookup)) {
236 // TODO(turbofan): introduce a LoadContext here.
237 return NoChange();
238 }
239 }
240
241 // Constant promotion or cell access requires lazy deoptimization support.
242 LookupIterator it(global_object_, name, LookupIterator::OWN);
243
244 if (it.state() == LookupIterator::DATA) {
245 Handle<PropertyCell> cell = it.GetPropertyCell();
246 dependencies_->AssumePropertyCell(cell);
247
248 if (it.property_details().cell_type() == PropertyCellType::kConstant) {
249 // Constant promote the global's current value.
250 Handle<Object> constant_value(cell->value(), jsgraph()->isolate());
251 if (constant_value->IsConsString()) {
252 constant_value =
253 String::Flatten(Handle<String>::cast(constant_value));
254 }
255 Node* constant = jsgraph()->Constant(constant_value);
256 NodeProperties::ReplaceWithValue(node, constant);
257 return Replace(constant);
258 } else {
259 // Load directly from the property cell.
260 FieldAccess access = AccessBuilder::ForPropertyCellValue();
261 Node* control = NodeProperties::GetControlInput(node);
262 Node* load_field = graph()->NewNode(
263 simplified()->LoadField(access), jsgraph()->Constant(cell),
264 NodeProperties::GetEffectInput(node), control);
265 NodeProperties::ReplaceWithValue(node, load_field, load_field, control);
266 return Replace(load_field);
267 }
268 }
269 } else {
270 // TODO(turbofan): non-configurable properties on the global object
271 // should be loadable through a cell without deoptimization support.
272 }
273
274 return NoChange();
275 }
276
277
194 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { 278 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
195 return NoChange(); 279 return NoChange();
196 } 280 }
197 281
198 282
199 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { 283 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
200 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); 284 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
201 // TODO(titzer): deopt locations are wrong for property accesses 285 // TODO(titzer): deopt locations are wrong for property accesses
202 if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange(); 286 if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange();
203 287
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 // TODO(turbofan): filter maps by initial receiver map if known 368 // TODO(turbofan): filter maps by initial receiver map if known
285 // TODO(turbofan): filter maps by native context (if specializing) 369 // TODO(turbofan): filter maps by native context (if specializing)
286 // TODO(turbofan): filter maps by effect chain 370 // TODO(turbofan): filter maps by effect chain
287 oracle()->PropertyReceiverTypes(id, name, maps); 371 oracle()->PropertyReceiverTypes(id, name, maps);
288 } 372 }
289 373
290 374
291 } // namespace compiler 375 } // namespace compiler
292 } // namespace internal 376 } // namespace internal
293 } // namespace v8 377 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-type-feedback.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698