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