OLD | NEW |
---|---|
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/simplified-operator.h" | 18 #include "src/compiler/simplified-operator.h" |
18 | 19 |
19 namespace v8 { | 20 namespace v8 { |
20 namespace internal { | 21 namespace internal { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 } | 64 } |
64 return ReduceJSStoreProperty(node); | 65 return ReduceJSStoreProperty(node); |
65 } | 66 } |
66 default: | 67 default: |
67 break; | 68 break; |
68 } | 69 } |
69 return NoChange(); | 70 return NoChange(); |
70 } | 71 } |
71 | 72 |
72 | 73 |
74 static void AddFieldAccessTypes(FieldAccess* access, | |
75 PropertyDetails property_details) { | |
76 if (property_details.representation().IsSmi()) { | |
77 access->type = Type::SignedSmall(); | |
78 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged); | |
79 } else if (property_details.representation().IsDouble()) { | |
80 access->type = Type::Number(); | |
81 access->machine_type = kMachFloat64; | |
82 } | |
83 } | |
84 | |
85 | |
73 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, | 86 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, |
74 Handle<Name> name, FieldAccess* access) { | 87 Handle<Name> name, FieldAccess* access) { |
75 access->base_is_tagged = kTaggedBase; | 88 access->base_is_tagged = kTaggedBase; |
76 access->offset = -1; | 89 access->offset = -1; |
77 access->name = name; | 90 access->name = name; |
78 access->type = Type::Any(); | 91 access->type = Type::Any(); |
79 access->machine_type = kMachAnyTagged; | 92 access->machine_type = kMachAnyTagged; |
80 | 93 |
81 // Check for properties that have accessors but are JSObject fields. | 94 // Check for properties that have accessors but are JSObject fields. |
82 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) { | 95 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) { |
(...skipping 11 matching lines...) Expand all Loading... | |
94 PropertyDetails property_details = descriptors->GetDetails(number); | 107 PropertyDetails property_details = descriptors->GetDetails(number); |
95 | 108 |
96 bool is_smi = property_details.representation().IsSmi(); | 109 bool is_smi = property_details.representation().IsSmi(); |
97 bool is_double = property_details.representation().IsDouble(); | 110 bool is_double = property_details.representation().IsDouble(); |
98 | 111 |
99 if (property_details.type() != DATA) { | 112 if (property_details.type() != DATA) { |
100 // TODO(turbofan): constant loads and stores. | 113 // TODO(turbofan): constant loads and stores. |
101 return false; | 114 return false; |
102 } | 115 } |
103 | 116 |
117 // Transfer known types from property details. | |
118 AddFieldAccessTypes(access, property_details); | |
119 | |
104 if (mode == STORE) { | 120 if (mode == STORE) { |
105 if (property_details.IsReadOnly()) return false; | 121 if (property_details.IsReadOnly()) { |
106 if (is_smi) { | 122 // TODO(turbofan): deopt, ignore or throw on readonly stores. |
107 // TODO(turbofan): SMI stores. | |
108 return false; | 123 return false; |
109 } | 124 } |
110 if (is_double) { | 125 if (is_smi || is_double) { |
111 // TODO(turbofan): double stores. | 126 // TODO(turbofan): check type and deopt for SMI/double stores. |
112 return false; | 127 return false; |
113 } | 128 } |
114 } else { | |
115 // Check property details for loads. | |
116 if (is_smi) { | |
117 access->type = Type::SignedSmall(); | |
118 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged); | |
119 } | |
120 if (is_double) { | |
121 access->type = Type::Number(); | |
122 access->machine_type = kMachFloat64; | |
123 } | |
124 } | 129 } |
125 | 130 |
126 int index = map->instance_descriptors()->GetFieldIndex(number); | 131 int index = map->instance_descriptors()->GetFieldIndex(number); |
127 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double); | 132 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double); |
128 | 133 |
129 if (field_index.is_inobject()) { | 134 if (field_index.is_inobject()) { |
130 access->offset = field_index.offset(); | 135 access->offset = field_index.offset(); |
131 return true; | 136 return true; |
132 } | 137 } |
133 | 138 |
134 // TODO(turbofan): handle out of object properties. | 139 // TODO(turbofan): handle out of object properties. |
135 return false; | 140 return false; |
136 } | 141 } |
137 | 142 |
138 | 143 |
144 static bool IsGlobalObject(Node* node) { | |
145 return NodeProperties::IsTyped(node) && | |
146 NodeProperties::GetBounds(node).upper->Is(Type::GlobalObject()); | |
147 } | |
148 | |
149 | |
139 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { | 150 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
140 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); | 151 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); |
152 Node* receiver = node->InputAt(0); | |
153 if (IsGlobalObject(receiver)) { | |
154 return ReduceJSLoadNamedFromGlobalObject(node); | |
155 } | |
156 | |
141 // TODO(turbofan): type feedback currently requires deoptimization. | 157 // TODO(turbofan): type feedback currently requires deoptimization. |
142 if (!FLAG_turbo_deoptimization) return NoChange(); | 158 if (!FLAG_turbo_deoptimization) return NoChange(); |
143 | 159 |
144 // TODO(turbofan): handle vector-based type feedback. | 160 // TODO(turbofan): handle vector-based type feedback. |
145 TypeFeedbackId id = js_type_feedback_->find(node); | 161 TypeFeedbackId id = js_type_feedback_->find(node); |
146 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { | 162 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { |
147 return NoChange(); | 163 return NoChange(); |
148 } | 164 } |
149 | 165 |
150 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); | 166 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); |
151 SmallMapList maps; | 167 SmallMapList maps; |
152 Handle<Name> name = p.name().handle(); | 168 Handle<Name> name = p.name().handle(); |
153 Node* receiver = node->InputAt(0); | |
154 Node* effect = NodeProperties::GetEffectInput(node); | 169 Node* effect = NodeProperties::GetEffectInput(node); |
155 GatherReceiverTypes(receiver, effect, id, name, &maps); | 170 GatherReceiverTypes(receiver, effect, id, name, &maps); |
156 | 171 |
157 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism | 172 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism |
158 | 173 |
159 Handle<Map> map = maps.first(); | 174 Handle<Map> map = maps.first(); |
160 FieldAccess field_access; | 175 FieldAccess field_access; |
161 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) { | 176 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) { |
162 return NoChange(); | 177 return NoChange(); |
163 } | 178 } |
(...skipping 12 matching lines...) Expand all Loading... | |
176 // TODO(titzer): frame state should be from before the load. | 191 // TODO(titzer): frame state should be from before the load. |
177 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); | 192 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
178 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, | 193 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, |
179 check_failed); | 194 check_failed); |
180 NodeProperties::MergeControlToEnd(graph(), common(), deopt); | 195 NodeProperties::MergeControlToEnd(graph(), common(), deopt); |
181 NodeProperties::ReplaceWithValue(node, load, load, check_success); | 196 NodeProperties::ReplaceWithValue(node, load, load, check_success); |
182 return Replace(load); | 197 return Replace(load); |
183 } | 198 } |
184 | 199 |
185 | 200 |
201 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedFromGlobalObject( | |
202 Node* node) { | |
203 Handle<Name> name = LoadNamedParametersOf(node->op()).name().handle(); | |
204 // Try to optimize loads from the global object. | |
205 Handle<Object> constant_value = | |
206 jsgraph()->isolate()->factory()->GlobalConstantFor(name); | |
207 if (!constant_value.is_null()) { | |
208 // Always optimize global constants. | |
209 Node* constant = jsgraph()->Constant(constant_value); | |
210 NodeProperties::ReplaceWithValue(node, constant); | |
211 return Replace(constant); | |
212 } | |
213 | |
214 if (global_object_.is_null()) { | |
215 // Nothing else can be done if we don't have a global object. | |
216 return NoChange(); | |
217 } | |
218 | |
219 if (FLAG_turbo_deoptimization) { | |
220 // Constant promotion or cell access requires lazy deoptimization support. | |
221 LookupIterator it(global_object_, name, LookupIterator::OWN); | |
222 | |
223 if (it.state() == LookupIterator::DATA) { | |
224 Handle<PropertyCell> cell = it.GetPropertyCell(); | |
225 dependencies_->AssumePropertyCell(cell); | |
226 | |
227 if (it.property_details().cell_type() == PropertyCellType::kConstant) { | |
228 // Constant promote the global's current value. | |
229 Handle<Object> constant_value(cell->value(), jsgraph()->isolate()); | |
230 if (constant_value->IsConsString()) { | |
231 constant_value = | |
232 String::Flatten(Handle<String>::cast(constant_value)); | |
Michael Starzinger
2015/04/21 12:34:01
rant: We need to flatten strings here? SRSLY? OMG!
titzer
2015/04/21 12:56:52
Agreed, cribbed this one from Crankyshaft.
| |
233 } | |
234 Node* constant = jsgraph()->Constant(constant_value); | |
235 NodeProperties::ReplaceWithValue(node, constant); | |
236 return Replace(constant); | |
237 } else { | |
238 // Load directly from the property cell. | |
239 FieldAccess access = AccessBuilder::ForPropertyCellValue(); | |
240 Node* control = NodeProperties::GetControlInput(node); | |
241 Node* load_field = graph()->NewNode( | |
242 simplified()->LoadField(access), jsgraph()->Constant(cell), | |
243 NodeProperties::GetEffectInput(node), control); | |
244 NodeProperties::ReplaceWithValue(node, load_field, load_field, control); | |
245 return Replace(load_field); | |
246 } | |
247 } | |
248 } else { | |
249 // TODO(turbofan): non-configurable properties on the global object | |
250 // should be loadable through a cell without deoptimization support. | |
251 } | |
252 | |
253 return NoChange(); | |
254 } | |
255 | |
256 | |
186 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { | 257 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { |
187 return NoChange(); | 258 return NoChange(); |
188 } | 259 } |
189 | 260 |
190 | 261 |
191 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { | 262 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { |
192 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); | 263 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); |
193 // TODO(turbofan): type feedback currently requires deoptimization. | 264 // TODO(turbofan): type feedback currently requires deoptimization. |
194 if (!FLAG_turbo_deoptimization) return NoChange(); | 265 if (!FLAG_turbo_deoptimization) return NoChange(); |
195 | 266 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 // TODO(turbofan): filter maps by initial receiver map if known | 347 // TODO(turbofan): filter maps by initial receiver map if known |
277 // TODO(turbofan): filter maps by native context (if specializing) | 348 // TODO(turbofan): filter maps by native context (if specializing) |
278 // TODO(turbofan): filter maps by effect chain | 349 // TODO(turbofan): filter maps by effect chain |
279 oracle()->PropertyReceiverTypes(id, name, maps); | 350 oracle()->PropertyReceiverTypes(id, name, maps); |
280 } | 351 } |
281 | 352 |
282 | 353 |
283 } // namespace compiler | 354 } // namespace compiler |
284 } // namespace internal | 355 } // namespace internal |
285 } // namespace v8 | 356 } // namespace v8 |
OLD | NEW |