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

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

Powered by Google App Engine
This is Rietveld 408576698