| 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/compiler.h" |
| 12 #include "src/type-info.h" | 12 #include "src/type-info.h" |
| 13 | 13 |
| 14 #include "src/compiler/access-builder.h" | 14 #include "src/compiler/access-builder.h" |
| 15 #include "src/compiler/common-operator.h" | 15 #include "src/compiler/common-operator.h" |
| 16 #include "src/compiler/frame-states.h" |
| 16 #include "src/compiler/node-aux-data.h" | 17 #include "src/compiler/node-aux-data.h" |
| 17 #include "src/compiler/node-matchers.h" | 18 #include "src/compiler/node-matchers.h" |
| 18 #include "src/compiler/operator-properties.h" | 19 #include "src/compiler/operator-properties.h" |
| 19 #include "src/compiler/simplified-operator.h" | 20 #include "src/compiler/simplified-operator.h" |
| 20 | 21 |
| 21 namespace v8 { | 22 namespace v8 { |
| 22 namespace internal { | 23 namespace internal { |
| 23 namespace compiler { | 24 namespace compiler { |
| 24 | 25 |
| 25 enum LoadOrStore { LOAD, STORE }; | 26 enum LoadOrStore { LOAD, STORE }; |
| 26 | 27 |
| 27 #define EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT false | |
| 28 | |
| 29 JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone) | 28 JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone) |
| 30 : map_(TypeFeedbackIdMap::key_compare(), | 29 : map_(TypeFeedbackIdMap::key_compare(), |
| 31 TypeFeedbackIdMap::allocator_type(zone)) {} | 30 TypeFeedbackIdMap::allocator_type(zone)) {} |
| 32 | 31 |
| 33 | 32 |
| 34 void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) { | 33 void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) { |
| 35 map_.insert(std::make_pair(node->id(), id)); | 34 map_.insert(std::make_pair(node->id(), id)); |
| 36 } | 35 } |
| 37 | 36 |
| 38 | 37 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 | 155 |
| 157 | 156 |
| 158 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { | 157 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
| 159 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); | 158 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); |
| 160 Node* receiver = node->InputAt(0); | 159 Node* receiver = node->InputAt(0); |
| 161 if (IsGlobalObject(receiver)) { | 160 if (IsGlobalObject(receiver)) { |
| 162 return ReduceJSLoadNamedForGlobalVariable(node); | 161 return ReduceJSLoadNamedForGlobalVariable(node); |
| 163 } | 162 } |
| 164 | 163 |
| 165 if (!FLAG_turbo_deoptimization) return NoChange(); | 164 if (!FLAG_turbo_deoptimization) return NoChange(); |
| 166 // TODO(titzer): deopt locations are wrong for property accesses | 165 Node* frame_state_before = GetFrameStateBefore(node); |
| 167 if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange(); | 166 if (frame_state_before == nullptr) return NoChange(); |
| 168 | 167 |
| 169 // TODO(turbofan): handle vector-based type feedback. | 168 // TODO(turbofan): handle vector-based type feedback. |
| 170 TypeFeedbackId id = js_type_feedback_->find(node); | 169 TypeFeedbackId id = js_type_feedback_->find(node); |
| 171 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { | 170 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { |
| 172 return NoChange(); | 171 return NoChange(); |
| 173 } | 172 } |
| 174 | 173 |
| 175 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); | 174 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); |
| 176 SmallMapList maps; | 175 SmallMapList maps; |
| 177 Handle<Name> name = p.name().handle(); | 176 Handle<Name> name = p.name().handle(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 190 Node* check_success; | 189 Node* check_success; |
| 191 Node* check_failed; | 190 Node* check_failed; |
| 192 BuildMapCheck(receiver, map, true, effect, control, &check_success, | 191 BuildMapCheck(receiver, map, true, effect, control, &check_success, |
| 193 &check_failed); | 192 &check_failed); |
| 194 | 193 |
| 195 // Build the actual load. | 194 // Build the actual load. |
| 196 Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver, | 195 Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver, |
| 197 effect, check_success); | 196 effect, check_success); |
| 198 | 197 |
| 199 // TODO(turbofan): handle slow case instead of deoptimizing. | 198 // TODO(turbofan): handle slow case instead of deoptimizing. |
| 200 // TODO(titzer): frame state should be from before the load. | 199 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state_before, |
| 201 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); | 200 effect, check_failed); |
| 202 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, | |
| 203 check_failed); | |
| 204 NodeProperties::MergeControlToEnd(graph(), common(), deopt); | 201 NodeProperties::MergeControlToEnd(graph(), common(), deopt); |
| 205 NodeProperties::ReplaceWithValue(node, load, load, check_success); | 202 NodeProperties::ReplaceWithValue(node, load, load, check_success); |
| 206 return Replace(load); | 203 return Replace(load); |
| 207 } | 204 } |
| 208 | 205 |
| 209 | 206 |
| 210 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedForGlobalVariable( | 207 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedForGlobalVariable( |
| 211 Node* node) { | 208 Node* node) { |
| 212 Handle<String> name = | 209 Handle<String> name = |
| 213 Handle<String>::cast(LoadNamedParametersOf(node->op()).name().handle()); | 210 Handle<String>::cast(LoadNamedParametersOf(node->op()).name().handle()); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 } | 272 } |
| 276 | 273 |
| 277 | 274 |
| 278 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { | 275 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { |
| 279 return NoChange(); | 276 return NoChange(); |
| 280 } | 277 } |
| 281 | 278 |
| 282 | 279 |
| 283 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { | 280 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { |
| 284 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); | 281 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); |
| 285 // TODO(titzer): deopt locations are wrong for property accesses | 282 Node* frame_state_before = GetFrameStateBefore(node); |
| 286 if (!EAGER_DEOPT_LOCATIONS_FOR_PROPERTY_ACCESS_ARE_CORRECT) return NoChange(); | 283 if (frame_state_before == nullptr) return NoChange(); |
| 287 | 284 |
| 288 TypeFeedbackId id = js_type_feedback_->find(node); | 285 TypeFeedbackId id = js_type_feedback_->find(node); |
| 289 if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange(); | 286 if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange(); |
| 290 | 287 |
| 291 const StoreNamedParameters& p = StoreNamedParametersOf(node->op()); | 288 const StoreNamedParameters& p = StoreNamedParametersOf(node->op()); |
| 292 SmallMapList maps; | 289 SmallMapList maps; |
| 293 Handle<Name> name = p.name().handle(); | 290 Handle<Name> name = p.name().handle(); |
| 294 Node* receiver = node->InputAt(0); | 291 Node* receiver = node->InputAt(0); |
| 295 Node* effect = NodeProperties::GetEffectInput(node); | 292 Node* effect = NodeProperties::GetEffectInput(node); |
| 296 GatherReceiverTypes(receiver, effect, id, name, &maps); | 293 GatherReceiverTypes(receiver, effect, id, name, &maps); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 308 Node* check_failed; | 305 Node* check_failed; |
| 309 BuildMapCheck(receiver, map, true, effect, control, &check_success, | 306 BuildMapCheck(receiver, map, true, effect, control, &check_success, |
| 310 &check_failed); | 307 &check_failed); |
| 311 | 308 |
| 312 // Build the actual load. | 309 // Build the actual load. |
| 313 Node* value = node->InputAt(1); | 310 Node* value = node->InputAt(1); |
| 314 Node* store = graph()->NewNode(simplified()->StoreField(field_access), | 311 Node* store = graph()->NewNode(simplified()->StoreField(field_access), |
| 315 receiver, value, effect, check_success); | 312 receiver, value, effect, check_success); |
| 316 | 313 |
| 317 // TODO(turbofan): handle slow case instead of deoptimizing. | 314 // TODO(turbofan): handle slow case instead of deoptimizing. |
| 318 // TODO(titzer): frame state should be from before the store. | 315 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state_before, |
| 319 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); | 316 effect, check_failed); |
| 320 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, | |
| 321 check_failed); | |
| 322 NodeProperties::MergeControlToEnd(graph(), common(), deopt); | 317 NodeProperties::MergeControlToEnd(graph(), common(), deopt); |
| 323 NodeProperties::ReplaceWithValue(node, store, store, check_success); | 318 NodeProperties::ReplaceWithValue(node, store, store, check_success); |
| 324 return Replace(store); | 319 return Replace(store); |
| 325 } | 320 } |
| 326 | 321 |
| 327 | 322 |
| 328 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) { | 323 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) { |
| 329 return NoChange(); | 324 return NoChange(); |
| 330 } | 325 } |
| 331 | 326 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 TypeFeedbackId id, | 360 TypeFeedbackId id, |
| 366 Handle<Name> name, | 361 Handle<Name> name, |
| 367 SmallMapList* maps) { | 362 SmallMapList* maps) { |
| 368 // TODO(turbofan): filter maps by initial receiver map if known | 363 // TODO(turbofan): filter maps by initial receiver map if known |
| 369 // TODO(turbofan): filter maps by native context (if specializing) | 364 // TODO(turbofan): filter maps by native context (if specializing) |
| 370 // TODO(turbofan): filter maps by effect chain | 365 // TODO(turbofan): filter maps by effect chain |
| 371 oracle()->PropertyReceiverTypes(id, name, maps); | 366 oracle()->PropertyReceiverTypes(id, name, maps); |
| 372 } | 367 } |
| 373 | 368 |
| 374 | 369 |
| 370 // Get the frame state before an operation if it exists and has a valid |
| 371 // bailout id. |
| 372 Node* JSTypeFeedbackSpecializer::GetFrameStateBefore(Node* node) { |
| 373 int count = OperatorProperties::GetFrameStateInputCount(node->op()); |
| 374 DCHECK_LE(count, 2); |
| 375 if (count == 2) { |
| 376 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 377 if (frame_state->opcode() == IrOpcode::kFrameState) { |
| 378 BailoutId id = OpParameter<FrameStateCallInfo>(node).bailout_id(); |
| 379 if (id != BailoutId::None()) return frame_state; |
| 380 } |
| 381 } |
| 382 return nullptr; |
| 383 } |
| 384 |
| 375 } // namespace compiler | 385 } // namespace compiler |
| 376 } // namespace internal | 386 } // namespace internal |
| 377 } // namespace v8 | 387 } // namespace v8 |
| OLD | NEW |