OLD | NEW |
---|---|
(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 | |
OLD | NEW |