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

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

Issue 1021713005: [turbofan]: Integrate basic type feedback for property accesses. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 9 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/node-properties.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/type-info.h"
12
13 #include "src/compiler/access-builder.h"
14 #include "src/compiler/common-operator.h"
15 #include "src/compiler/node-aux-data.h"
16 #include "src/compiler/simplified-operator.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21
22 enum LoadOrStore { LOAD, STORE };
23
24 JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone)
25 : map_(TypeFeedbackIdMap::key_compare(),
26 TypeFeedbackIdMap::allocator_type(zone)) {}
27
28
29 void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) {
30 map_.insert(std::make_pair(node->id(), id));
31 }
32
33
34 Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) {
35 // TODO(turbofan): type feedback currently requires deoptimization.
36 if (!FLAG_turbo_deoptimization) return NoChange();
37 switch (node->opcode()) {
38 case IrOpcode::kJSLoadProperty:
39 return ReduceJSLoadProperty(node);
40 case IrOpcode::kJSLoadNamed:
41 return ReduceJSLoadNamed(node);
42 case IrOpcode::kJSStoreNamed:
43 return ReduceJSStoreNamed(node);
44 case IrOpcode::kJSStoreProperty:
45 return ReduceJSStoreProperty(node);
46 default:
47 break;
48 }
49 return NoChange();
50 }
51
52
53 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
54 Handle<Name> name, FieldAccess* access) {
55 access->base_is_tagged = kTaggedBase;
56 access->offset = -1;
57 access->name = name;
58 access->type = Type::Any();
59 access->machine_type = kMachAnyTagged;
60
61 // Check for properties that have accessors but are JSObject fields.
62 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) {
63 // TODO(turbofan): fill in types for special JSObject field accesses.
64 return true;
65 }
66
67 // Check if the map is a dictionary.
68 if (map->is_dictionary_map()) return false;
69
70 // Search the descriptor array.
71 DescriptorArray* descriptors = map->instance_descriptors();
72 int number = descriptors->SearchWithCache(*name, *map);
73 if (number == DescriptorArray::kNotFound) return false;
74 PropertyDetails property_details = descriptors->GetDetails(number);
75
76 bool is_smi = property_details.representation().IsSmi();
77 bool is_double = property_details.representation().IsDouble();
78
79 if (property_details.type() != DATA) {
80 // TODO(turbofan): constant loads and stores.
81 return false;
82 }
83
84 if (mode == STORE) {
85 if (property_details.IsReadOnly()) return false;
86 if (is_smi) {
87 // TODO(turbofan): SMI stores.
88 return false;
89 }
90 if (is_double) {
91 // TODO(turbofan): double stores.
92 return false;
93 }
94 } else {
95 // Check property details for loads.
96 if (is_smi) {
97 access->type = Type::SignedSmall();
98 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
99 }
100 if (is_double) {
101 access->type = Type::Number();
102 access->machine_type = kMachFloat64;
103 }
104 }
105
106 int index = map->instance_descriptors()->GetFieldIndex(number);
107 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
108
109 if (field_index.is_inobject()) {
110 access->offset = field_index.offset();
111 return true;
112 }
113
114 // TODO(turbofan): handle out of object properties.
115 return false;
116 }
117
118
119 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
120 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed);
121 TypeFeedbackId id = js_type_feedback_->find(node);
122 if (id.IsNone() || oracle()->LoadIsUninitialized(id)) return NoChange();
123
124 const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
125 SmallMapList maps;
126 Handle<Name> name = p.name().handle();
127 Node* receiver = node->InputAt(0);
128 Node* effect = NodeProperties::GetEffectInput(node);
129 GatherReceiverTypes(receiver, effect, id, name, &maps);
130
131 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
132
133 Handle<Map> map = maps.first();
134 FieldAccess field_access;
135 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) {
136 return NoChange();
137 }
138
139 Node* control = NodeProperties::GetControlInput(node);
140 Node* check_success;
141 Node* check_failed;
142 BuildMapCheck(receiver, map, true, effect, control, &check_success,
143 &check_failed);
144
145 // Build the actual load.
146 Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver,
147 effect, check_success);
148
149 // TODO(turbofan): handle slow case instead of deoptimizing.
150 // TODO(titzer): frame state should be from before the load.
151 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
152 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
153 check_failed);
154 NodeProperties::MergeControlToEnd(graph(), common(), deopt);
155 NodeProperties::ReplaceWithValue(node, load, load, check_success);
156 return Replace(load);
157 }
158
159
160 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
161 return NoChange();
162 }
163
164
165 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
166 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
167 TypeFeedbackId id = js_type_feedback_->find(node);
168 if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange();
169
170 const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
171 SmallMapList maps;
172 Handle<Name> name = p.name().handle();
173 Node* receiver = node->InputAt(0);
174 Node* effect = NodeProperties::GetEffectInput(node);
175 GatherReceiverTypes(receiver, effect, id, name, &maps);
176
177 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
178
179 Handle<Map> map = maps.first();
180 FieldAccess field_access;
181 if (!GetInObjectFieldAccess(STORE, map, name, &field_access)) {
182 return NoChange();
183 }
184
185 Node* control = NodeProperties::GetControlInput(node);
186 Node* check_success;
187 Node* check_failed;
188 BuildMapCheck(receiver, map, true, effect, control, &check_success,
189 &check_failed);
190
191 // Build the actual load.
192 Node* value = node->InputAt(1);
193 Node* store = graph()->NewNode(simplified()->StoreField(field_access),
194 receiver, value, effect, check_success);
195
196 // TODO(turbofan): handle slow case instead of deoptimizing.
197 // TODO(titzer): frame state should be from before the store.
198 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
199 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
200 check_failed);
201 NodeProperties::MergeControlToEnd(graph(), common(), deopt);
202 NodeProperties::ReplaceWithValue(node, store, store, check_success);
203 return Replace(store);
204 }
205
206
207 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) {
208 return NoChange();
209 }
210
211
212 void JSTypeFeedbackSpecializer::BuildMapCheck(Node* receiver, Handle<Map> map,
213 bool smi_check, Node* effect,
214 Node* control, Node** success,
215 Node** fail) {
216 Node* if_smi = nullptr;
217 if (smi_check) {
218 Node* branch_smi = graph()->NewNode(
219 common()->Branch(BranchHint::kFalse),
220 graph()->NewNode(simplified()->ObjectIsSmi(), receiver), control);
221 if_smi = graph()->NewNode(common()->IfTrue(), branch_smi);
222 control = graph()->NewNode(common()->IfFalse(), branch_smi);
223 }
224
225 FieldAccess map_access = AccessBuilder::ForMap();
226 Node* receiver_map = graph()->NewNode(simplified()->LoadField(map_access),
227 receiver, effect, control);
228 Node* map_const = jsgraph_->Constant(map);
229 Node* cmp = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
230 receiver_map, map_const);
231 Node* branch =
232 graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
233 *success = graph()->NewNode(common()->IfTrue(), branch);
234 *fail = graph()->NewNode(common()->IfFalse(), branch);
235
236 if (if_smi) {
237 *fail = graph()->NewNode(common()->Merge(2), *fail, if_smi);
238 }
239 }
240
241
242 void JSTypeFeedbackSpecializer::GatherReceiverTypes(Node* receiver,
243 Node* effect,
244 TypeFeedbackId id,
245 Handle<Name> name,
246 SmallMapList* maps) {
247 // TODO(turbofan): filter maps by initial receiver map if known
248 // TODO(turbofan): filter maps by native context (if specializing)
249 // TODO(turbofan): filter maps by effect chain
250 oracle()->PropertyReceiverTypes(id, name, maps);
251 }
252
253
254 } // namespace compiler
255 } // namespace internal
256 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-type-feedback.h ('k') | src/compiler/node-properties.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698