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

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

Issue 1407913003: [turbofan] Remove obsolete JSTypeFeedbackSpecializer and JSTypeFeedbackLowering. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@NamedAccess
Patch Set: REBASE Created 5 years, 2 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/js-type-feedback-lowering.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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-type-feedback.h"
6
7 #include "src/property-details.h"
8
9 #include "src/accessors.h"
10 #include "src/ast.h"
11 #include "src/compiler.h"
12 #include "src/type-info.h"
13
14 #include "src/compiler/access-builder.h"
15 #include "src/compiler/common-operator.h"
16 #include "src/compiler/frame-states.h"
17 #include "src/compiler/node-aux-data.h"
18 #include "src/compiler/node-matchers.h"
19 #include "src/compiler/operator-properties.h"
20 #include "src/compiler/simplified-operator.h"
21
22 namespace v8 {
23 namespace internal {
24 namespace compiler {
25
26 enum LoadOrStore { LOAD, STORE };
27
28 // TODO(turbofan): fix deoptimization problems
29 #define ENABLE_FAST_PROPERTY_LOADS false
30 #define ENABLE_FAST_PROPERTY_STORES false
31
32 JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone)
33 : type_feedback_id_map_(TypeFeedbackIdMap::key_compare(),
34 TypeFeedbackIdMap::allocator_type(zone)),
35 feedback_vector_slot_map_(TypeFeedbackIdMap::key_compare(),
36 TypeFeedbackIdMap::allocator_type(zone)) {}
37
38
39 void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) {
40 type_feedback_id_map_.insert(std::make_pair(node->id(), id));
41 }
42
43
44 void JSTypeFeedbackTable::Record(Node* node, FeedbackVectorSlot slot) {
45 feedback_vector_slot_map_.insert(std::make_pair(node->id(), slot));
46 }
47
48
49 Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) {
50 switch (node->opcode()) {
51 case IrOpcode::kJSLoadProperty:
52 return ReduceJSLoadProperty(node);
53 case IrOpcode::kJSLoadNamed:
54 return ReduceJSLoadNamed(node);
55 case IrOpcode::kJSLoadGlobal:
56 return ReduceJSLoadGlobal(node);
57 case IrOpcode::kJSStoreNamed:
58 return ReduceJSStoreNamed(node);
59 case IrOpcode::kJSStoreProperty:
60 return ReduceJSStoreProperty(node);
61 default:
62 break;
63 }
64 return NoChange();
65 }
66
67
68 static void AddFieldAccessTypes(FieldAccess* access,
69 PropertyDetails property_details) {
70 if (property_details.representation().IsSmi()) {
71 access->type = Type::SignedSmall();
72 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
73 } else if (property_details.representation().IsDouble()) {
74 access->type = Type::Number();
75 access->machine_type = kMachFloat64;
76 }
77 }
78
79
80 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
81 Handle<Name> name, FieldAccess* access) {
82 access->base_is_tagged = kTaggedBase;
83 access->offset = -1;
84 access->name = name;
85 access->type = Type::Any();
86 access->machine_type = kMachAnyTagged;
87
88 // Check for properties that have accessors but are JSObject fields.
89 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) {
90 // TODO(turbofan): fill in types for special JSObject field accesses.
91 return true;
92 }
93
94 // Check if the map is a dictionary.
95 if (map->is_dictionary_map()) return false;
96
97 // Search the descriptor array.
98 DescriptorArray* descriptors = map->instance_descriptors();
99 int number = descriptors->SearchWithCache(*name, *map);
100 if (number == DescriptorArray::kNotFound) return false;
101 PropertyDetails property_details = descriptors->GetDetails(number);
102
103 bool is_smi = property_details.representation().IsSmi();
104 bool is_double = property_details.representation().IsDouble();
105
106 if (property_details.type() != DATA) {
107 // TODO(turbofan): constant loads and stores.
108 return false;
109 }
110
111 // Transfer known types from property details.
112 AddFieldAccessTypes(access, property_details);
113
114 if (mode == STORE) {
115 if (property_details.IsReadOnly()) {
116 // TODO(turbofan): deopt, ignore or throw on readonly stores.
117 return false;
118 }
119 if (is_smi || is_double) {
120 // TODO(turbofan): check type and deopt for SMI/double stores.
121 return false;
122 }
123 }
124
125 int index = map->instance_descriptors()->GetFieldIndex(number);
126 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
127
128 if (field_index.is_inobject()) {
129 if (is_double && !map->IsUnboxedDoubleField(field_index)) {
130 // TODO(turbofan): support for out-of-line (MutableHeapNumber) loads.
131 return false;
132 }
133 access->offset = field_index.offset();
134 return true;
135 }
136
137 // TODO(turbofan): handle out of object properties.
138 return false;
139 }
140
141
142 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
143 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed);
144 if (mode() != kDeoptimizationEnabled) return NoChange();
145 Node* frame_state_before = GetFrameStateBefore(node);
146 if (frame_state_before == nullptr) return NoChange();
147
148 NamedAccess const& p = NamedAccessOf(node->op());
149 SmallMapList maps;
150
151 FeedbackVectorSlot slot = js_type_feedback_->FindFeedbackVectorSlot(node);
152 if (slot.IsInvalid() ||
153 oracle()->LoadInlineCacheState(slot) == UNINITIALIZED) {
154 // No type feedback ids or the load is uninitialized.
155 return NoChange();
156 }
157 oracle()->PropertyReceiverTypes(slot, p.name(), &maps);
158
159 Node* receiver = node->InputAt(0);
160 Node* effect = NodeProperties::GetEffectInput(node);
161
162 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
163 if (!ENABLE_FAST_PROPERTY_LOADS) return NoChange();
164
165 Handle<Map> map = maps.first();
166 FieldAccess field_access;
167 if (!GetInObjectFieldAccess(LOAD, map, p.name(), &field_access)) {
168 return NoChange();
169 }
170
171 Node* control = NodeProperties::GetControlInput(node);
172 Node* check_success;
173 Node* check_failed;
174 BuildMapCheck(receiver, map, true, effect, control, &check_success,
175 &check_failed);
176
177 // Build the actual load.
178 Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver,
179 effect, check_success);
180
181 // TODO(turbofan): handle slow case instead of deoptimizing.
182 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state_before,
183 effect, check_failed);
184 NodeProperties::MergeControlToEnd(graph(), common(), deopt);
185 ReplaceWithValue(node, load, load, check_success);
186 return Replace(load);
187 }
188
189
190 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadGlobal(Node* node) {
191 DCHECK(node->opcode() == IrOpcode::kJSLoadGlobal);
192 Handle<String> name =
193 Handle<String>::cast(LoadGlobalParametersOf(node->op()).name());
194 if (global_object_.is_null()) {
195 // Nothing else can be done if we don't have a global object.
196 return NoChange();
197 }
198
199 if (mode() == kDeoptimizationEnabled) {
200 // Handle lookups in the script context.
201 {
202 Handle<ScriptContextTable> script_contexts(
203 global_object_->native_context()->script_context_table());
204 ScriptContextTable::LookupResult lookup;
205 if (ScriptContextTable::Lookup(script_contexts, name, &lookup)) {
206 // TODO(turbofan): introduce a LoadContext here.
207 return NoChange();
208 }
209 }
210
211 // Constant promotion or cell access requires lazy deoptimization support.
212 LookupIterator it(global_object_, name, LookupIterator::OWN);
213
214 if (it.state() == LookupIterator::DATA) {
215 Handle<PropertyCell> cell = it.GetPropertyCell();
216 dependencies_->AssumePropertyCell(cell);
217
218 if (it.property_details().cell_type() == PropertyCellType::kConstant) {
219 // Constant promote the global's current value.
220 Handle<Object> constant_value(cell->value(), jsgraph()->isolate());
221 if (constant_value->IsConsString()) {
222 constant_value =
223 String::Flatten(Handle<String>::cast(constant_value));
224 }
225 Node* constant = jsgraph()->Constant(constant_value);
226 ReplaceWithValue(node, constant);
227 return Replace(constant);
228 } else {
229 // Load directly from the property cell.
230 FieldAccess access = AccessBuilder::ForPropertyCellValue();
231 Node* control = NodeProperties::GetControlInput(node);
232 Node* load_field = graph()->NewNode(
233 simplified()->LoadField(access), jsgraph()->Constant(cell),
234 NodeProperties::GetEffectInput(node), control);
235 ReplaceWithValue(node, load_field, load_field, control);
236 return Replace(load_field);
237 }
238 }
239 } else {
240 // TODO(turbofan): non-configurable properties on the global object
241 // should be loadable through a cell without deoptimization support.
242 }
243
244 return NoChange();
245 }
246
247
248 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
249 return NoChange();
250 }
251
252
253 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
254 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
255 Node* frame_state_before = GetFrameStateBefore(node);
256 if (frame_state_before == nullptr) return NoChange();
257
258 NamedAccess const& p = NamedAccessOf(node->op());
259 SmallMapList maps;
260 TypeFeedbackId id = js_type_feedback_->FindTypeFeedbackId(node);
261 if (id.IsNone() || oracle()->StoreIsUninitialized(id) == UNINITIALIZED) {
262 // No type feedback ids or the store is uninitialized.
263 // TODO(titzer): no feedback from vector ICs from stores.
264 return NoChange();
265 } else {
266 oracle()->AssignmentReceiverTypes(id, p.name(), &maps);
267 }
268
269 Node* receiver = node->InputAt(0);
270 Node* effect = NodeProperties::GetEffectInput(node);
271
272 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
273
274 if (!ENABLE_FAST_PROPERTY_STORES) return NoChange();
275
276 Handle<Map> map = maps.first();
277 FieldAccess field_access;
278 if (!GetInObjectFieldAccess(STORE, map, p.name(), &field_access)) {
279 return NoChange();
280 }
281
282 Node* control = NodeProperties::GetControlInput(node);
283 Node* check_success;
284 Node* check_failed;
285 BuildMapCheck(receiver, map, true, effect, control, &check_success,
286 &check_failed);
287
288 // Build the actual load.
289 Node* value = node->InputAt(1);
290 Node* store = graph()->NewNode(simplified()->StoreField(field_access),
291 receiver, value, effect, check_success);
292
293 // TODO(turbofan): handle slow case instead of deoptimizing.
294 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state_before,
295 effect, check_failed);
296 NodeProperties::MergeControlToEnd(graph(), common(), deopt);
297 ReplaceWithValue(node, store, store, check_success);
298 return Replace(store);
299 }
300
301
302 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) {
303 return NoChange();
304 }
305
306
307 void JSTypeFeedbackSpecializer::BuildMapCheck(Node* receiver, Handle<Map> map,
308 bool smi_check, Node* effect,
309 Node* control, Node** success,
310 Node** fail) {
311 Node* if_smi = nullptr;
312 if (smi_check) {
313 Node* branch_smi = graph()->NewNode(
314 common()->Branch(BranchHint::kFalse),
315 graph()->NewNode(simplified()->ObjectIsSmi(), receiver), control);
316 if_smi = graph()->NewNode(common()->IfTrue(), branch_smi);
317 control = graph()->NewNode(common()->IfFalse(), branch_smi);
318 }
319
320 FieldAccess map_access = AccessBuilder::ForMap();
321 Node* receiver_map = graph()->NewNode(simplified()->LoadField(map_access),
322 receiver, effect, control);
323 Node* map_const = jsgraph_->Constant(map);
324 Node* cmp = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
325 receiver_map, map_const);
326 Node* branch =
327 graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
328 *success = graph()->NewNode(common()->IfTrue(), branch);
329 *fail = graph()->NewNode(common()->IfFalse(), branch);
330
331 if (if_smi) {
332 *fail = graph()->NewNode(common()->Merge(2), *fail, if_smi);
333 }
334 }
335
336
337 // Get the frame state before an operation if it exists and has a valid
338 // bailout id.
339 Node* JSTypeFeedbackSpecializer::GetFrameStateBefore(Node* node) {
340 int count = OperatorProperties::GetFrameStateInputCount(node->op());
341 DCHECK_LE(count, 2);
342 if (count == 2) {
343 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
344 if (frame_state->opcode() == IrOpcode::kFrameState) {
345 BailoutId id = OpParameter<FrameStateInfo>(node).bailout_id();
346 if (id != BailoutId::None()) return frame_state;
347 }
348 }
349 return nullptr;
350 }
351
352 } // namespace compiler
353 } // namespace internal
354 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-type-feedback.h ('k') | src/compiler/js-type-feedback-lowering.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698