| 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/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 1381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1392 } | 1392 } |
| 1393 | 1393 |
| 1394 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1394 void EscapeAnalysis::ProcessLoadField(Node* node) { |
| 1395 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1395 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
| 1396 ForwardVirtualState(node); | 1396 ForwardVirtualState(node); |
| 1397 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1397 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1398 VirtualState* state = virtual_states_[node->id()]; | 1398 VirtualState* state = virtual_states_[node->id()]; |
| 1399 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1399 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1400 if (!object->IsTracked()) return; | 1400 if (!object->IsTracked()) return; |
| 1401 int offset = OffsetForFieldAccess(node); | 1401 int offset = OffsetForFieldAccess(node); |
| 1402 if (static_cast<size_t>(offset) >= object->field_count()) return; | 1402 if (static_cast<size_t>(offset) >= object->field_count()) { |
| 1403 // We have a load from a field that is not inside the {object}. This |
| 1404 // can only happen with conflicting type feedback and for dead {node}s. |
| 1405 // For now, we just mark the {object} as escaping. |
| 1406 // TODO(turbofan): Consider introducing an Undefined or None operator |
| 1407 // that we can replace this load with, since we know it's dead code. |
| 1408 if (status_analysis_->SetEscaped(from)) { |
| 1409 TRACE( |
| 1410 "Setting #%d (%s) to escaped because load field #%d from " |
| 1411 "offset %d outside of object\n", |
| 1412 from->id(), from->op()->mnemonic(), node->id(), offset); |
| 1413 } |
| 1414 return; |
| 1415 } |
| 1403 Node* value = object->GetField(offset); | 1416 Node* value = object->GetField(offset); |
| 1404 if (value) { | 1417 if (value) { |
| 1405 value = ResolveReplacement(value); | 1418 value = ResolveReplacement(value); |
| 1406 } | 1419 } |
| 1407 // Record that the load has this alias. | 1420 // Record that the load has this alias. |
| 1408 UpdateReplacement(state, node, value); | 1421 UpdateReplacement(state, node, value); |
| 1409 } else if (from->opcode() == IrOpcode::kPhi && | 1422 } else if (from->opcode() == IrOpcode::kPhi && |
| 1410 FieldAccessOf(node->op()).offset % kPointerSize == 0) { | 1423 FieldAccessOf(node->op()).offset % kPointerSize == 0) { |
| 1411 int offset = OffsetForFieldAccess(node); | 1424 int offset = OffsetForFieldAccess(node); |
| 1412 // Only binary phis are supported for now. | 1425 // Only binary phis are supported for now. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1457 } | 1470 } |
| 1458 | 1471 |
| 1459 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1472 void EscapeAnalysis::ProcessStoreField(Node* node) { |
| 1460 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1473 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 1461 ForwardVirtualState(node); | 1474 ForwardVirtualState(node); |
| 1462 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1475 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1463 VirtualState* state = virtual_states_[node->id()]; | 1476 VirtualState* state = virtual_states_[node->id()]; |
| 1464 if (VirtualObject* object = GetVirtualObject(state, to)) { | 1477 if (VirtualObject* object = GetVirtualObject(state, to)) { |
| 1465 if (!object->IsTracked()) return; | 1478 if (!object->IsTracked()) return; |
| 1466 int offset = OffsetForFieldAccess(node); | 1479 int offset = OffsetForFieldAccess(node); |
| 1467 if (static_cast<size_t>(offset) >= object->field_count()) return; | 1480 if (static_cast<size_t>(offset) >= object->field_count()) { |
| 1481 // We have a store to a field that is not inside the {object}. This |
| 1482 // can only happen with conflicting type feedback and for dead {node}s. |
| 1483 // For now, we just mark the {object} as escaping. |
| 1484 // TODO(turbofan): Consider just eliminating the store in the reducer |
| 1485 // pass, as it's dead code anyways. |
| 1486 if (status_analysis_->SetEscaped(to)) { |
| 1487 TRACE( |
| 1488 "Setting #%d (%s) to escaped because store field #%d to " |
| 1489 "offset %d outside of object\n", |
| 1490 to->id(), to->op()->mnemonic(), node->id(), offset); |
| 1491 } |
| 1492 return; |
| 1493 } |
| 1468 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); | 1494 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
| 1469 // TODO(mstarzinger): The following is a workaround to not track some well | 1495 // TODO(mstarzinger): The following is a workaround to not track some well |
| 1470 // known raw fields. We only ever store default initial values into these | 1496 // known raw fields. We only ever store default initial values into these |
| 1471 // fields which are hard-coded in {TranslatedState::MaterializeAt} as well. | 1497 // fields which are hard-coded in {TranslatedState::MaterializeAt} as well. |
| 1472 if (val->opcode() == IrOpcode::kInt32Constant || | 1498 if (val->opcode() == IrOpcode::kInt32Constant || |
| 1473 val->opcode() == IrOpcode::kInt64Constant) { | 1499 val->opcode() == IrOpcode::kInt64Constant) { |
| 1474 DCHECK(FieldAccessOf(node->op()).offset == JSFunction::kCodeEntryOffset || | 1500 DCHECK(FieldAccessOf(node->op()).offset == JSFunction::kCodeEntryOffset || |
| 1475 FieldAccessOf(node->op()).offset == Name::kHashFieldOffset); | 1501 FieldAccessOf(node->op()).offset == Name::kHashFieldOffset); |
| 1476 val = slot_not_analyzed_; | 1502 val = slot_not_analyzed_; |
| 1477 } | 1503 } |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 } | 1662 } |
| 1637 } | 1663 } |
| 1638 return false; | 1664 return false; |
| 1639 } | 1665 } |
| 1640 | 1666 |
| 1641 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } | 1667 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } |
| 1642 | 1668 |
| 1643 } // namespace compiler | 1669 } // namespace compiler |
| 1644 } // namespace internal | 1670 } // namespace internal |
| 1645 } // namespace v8 | 1671 } // namespace v8 |
| OLD | NEW |