| 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 1370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1381 TRACE(" has incomplete virtual object info.\n"); | 1381 TRACE(" has incomplete virtual object info.\n"); |
| 1382 } | 1382 } |
| 1383 } | 1383 } |
| 1384 | 1384 |
| 1385 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1385 void EscapeAnalysis::ProcessLoadField(Node* node) { |
| 1386 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1386 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
| 1387 ForwardVirtualState(node); | 1387 ForwardVirtualState(node); |
| 1388 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1388 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1389 VirtualState* state = virtual_states_[node->id()]; | 1389 VirtualState* state = virtual_states_[node->id()]; |
| 1390 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1390 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1391 if (!object->IsTracked()) return; |
| 1391 int offset = OffsetForFieldAccess(node); | 1392 int offset = OffsetForFieldAccess(node); |
| 1392 if (!object->IsTracked() || | 1393 if (static_cast<size_t>(offset) >= object->field_count()) return; |
| 1393 static_cast<size_t>(offset) >= object->field_count()) { | |
| 1394 return; | |
| 1395 } | |
| 1396 Node* value = object->GetField(offset); | 1394 Node* value = object->GetField(offset); |
| 1397 if (value) { | 1395 if (value) { |
| 1398 value = ResolveReplacement(value); | 1396 value = ResolveReplacement(value); |
| 1399 } | 1397 } |
| 1400 // Record that the load has this alias. | 1398 // Record that the load has this alias. |
| 1401 UpdateReplacement(state, node, value); | 1399 UpdateReplacement(state, node, value); |
| 1402 } else if (from->opcode() == IrOpcode::kPhi && | 1400 } else if (from->opcode() == IrOpcode::kPhi && |
| 1403 FieldAccessOf(node->op()).offset % kPointerSize == 0) { | 1401 FieldAccessOf(node->op()).offset % kPointerSize == 0) { |
| 1404 int offset = OffsetForFieldAccess(node); | 1402 int offset = OffsetForFieldAccess(node); |
| 1405 // Only binary phis are supported for now. | 1403 // Only binary phis are supported for now. |
| 1406 ProcessLoadFromPhi(offset, from, node, state); | 1404 ProcessLoadFromPhi(offset, from, node, state); |
| 1407 } else { | 1405 } else { |
| 1408 UpdateReplacement(state, node, nullptr); | 1406 UpdateReplacement(state, node, nullptr); |
| 1409 } | 1407 } |
| 1410 } | 1408 } |
| 1411 | 1409 |
| 1412 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1410 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
| 1413 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1411 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
| 1414 ForwardVirtualState(node); | 1412 ForwardVirtualState(node); |
| 1415 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1413 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1416 VirtualState* state = virtual_states_[node->id()]; | 1414 VirtualState* state = virtual_states_[node->id()]; |
| 1417 Node* index_node = node->InputAt(1); | 1415 Node* index_node = node->InputAt(1); |
| 1418 NumberMatcher index(index_node); | 1416 NumberMatcher index(index_node); |
| 1419 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1417 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1420 index_node->opcode() != IrOpcode::kInt64Constant && | 1418 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1421 index_node->opcode() != IrOpcode::kFloat32Constant && | 1419 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1422 index_node->opcode() != IrOpcode::kFloat64Constant); | 1420 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1423 if (index.HasValue()) { | 1421 if (index.HasValue()) { |
| 1424 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1422 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1423 if (!object->IsTracked()) return; |
| 1425 int offset = OffsetForElementAccess(node, index.Value()); | 1424 int offset = OffsetForElementAccess(node, index.Value()); |
| 1426 if (!object->IsTracked() || | 1425 if (static_cast<size_t>(offset) >= object->field_count()) return; |
| 1427 static_cast<size_t>(offset) >= object->field_count()) { | |
| 1428 return; | |
| 1429 } | |
| 1430 Node* value = object->GetField(offset); | 1426 Node* value = object->GetField(offset); |
| 1431 if (value) { | 1427 if (value) { |
| 1432 value = ResolveReplacement(value); | 1428 value = ResolveReplacement(value); |
| 1433 } | 1429 } |
| 1434 // Record that the load has this alias. | 1430 // Record that the load has this alias. |
| 1435 UpdateReplacement(state, node, value); | 1431 UpdateReplacement(state, node, value); |
| 1436 } else if (from->opcode() == IrOpcode::kPhi) { | 1432 } else if (from->opcode() == IrOpcode::kPhi) { |
| 1437 int offset = OffsetForElementAccess(node, index.Value()); | 1433 int offset = OffsetForElementAccess(node, index.Value()); |
| 1438 ProcessLoadFromPhi(offset, from, node, state); | 1434 ProcessLoadFromPhi(offset, from, node, state); |
| 1439 } else { | 1435 } else { |
| 1440 UpdateReplacement(state, node, nullptr); | 1436 UpdateReplacement(state, node, nullptr); |
| 1441 } | 1437 } |
| 1442 } else { | 1438 } else { |
| 1443 // We have a load from a non-const index, cannot eliminate object. | 1439 // We have a load from a non-const index, cannot eliminate object. |
| 1444 if (status_analysis_->SetEscaped(from)) { | 1440 if (status_analysis_->SetEscaped(from)) { |
| 1445 TRACE( | 1441 TRACE( |
| 1446 "Setting #%d (%s) to escaped because load element #%d from non-const " | 1442 "Setting #%d (%s) to escaped because load element #%d from non-const " |
| 1447 "index #%d (%s)\n", | 1443 "index #%d (%s)\n", |
| 1448 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | 1444 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
| 1449 index_node->op()->mnemonic()); | 1445 index_node->op()->mnemonic()); |
| 1450 } | 1446 } |
| 1451 } | 1447 } |
| 1452 } | 1448 } |
| 1453 | 1449 |
| 1454 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1450 void EscapeAnalysis::ProcessStoreField(Node* node) { |
| 1455 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1451 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 1456 ForwardVirtualState(node); | 1452 ForwardVirtualState(node); |
| 1457 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1453 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1458 VirtualState* state = virtual_states_[node->id()]; | 1454 VirtualState* state = virtual_states_[node->id()]; |
| 1459 VirtualObject* obj = GetVirtualObject(state, to); | 1455 if (VirtualObject* object = GetVirtualObject(state, to)) { |
| 1460 int offset = OffsetForFieldAccess(node); | 1456 if (!object->IsTracked()) return; |
| 1461 if (obj && obj->IsTracked() && | 1457 int offset = OffsetForFieldAccess(node); |
| 1462 static_cast<size_t>(offset) < obj->field_count()) { | 1458 if (static_cast<size_t>(offset) >= object->field_count()) return; |
| 1463 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); | 1459 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
| 1464 // TODO(mstarzinger): The following is a workaround to not track the code | 1460 // TODO(mstarzinger): The following is a workaround to not track the code |
| 1465 // entry field in virtual JSFunction objects. We only ever store the inner | 1461 // entry field in virtual JSFunction objects. We only ever store the inner |
| 1466 // pointer into the compile lazy stub in this field and the deoptimizer has | 1462 // pointer into the compile lazy stub in this field and the deoptimizer has |
| 1467 // this assumption hard-coded in {TranslatedState::MaterializeAt} as well. | 1463 // this assumption hard-coded in {TranslatedState::MaterializeAt} as well. |
| 1468 if (val->opcode() == IrOpcode::kInt32Constant || | 1464 if (val->opcode() == IrOpcode::kInt32Constant || |
| 1469 val->opcode() == IrOpcode::kInt64Constant) { | 1465 val->opcode() == IrOpcode::kInt64Constant) { |
| 1470 DCHECK_EQ(JSFunction::kCodeEntryOffset, FieldAccessOf(node->op()).offset); | 1466 DCHECK_EQ(JSFunction::kCodeEntryOffset, FieldAccessOf(node->op()).offset); |
| 1471 val = slot_not_analyzed_; | 1467 val = slot_not_analyzed_; |
| 1472 } | 1468 } |
| 1473 if (obj->GetField(offset) != val) { | 1469 if (object->GetField(offset) != val) { |
| 1474 obj = CopyForModificationAt(obj, state, node); | 1470 object = CopyForModificationAt(object, state, node); |
| 1475 obj->SetField(offset, val); | 1471 object->SetField(offset, val); |
| 1476 } | 1472 } |
| 1477 } | 1473 } |
| 1478 } | 1474 } |
| 1479 | 1475 |
| 1480 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1476 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
| 1481 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1477 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 1482 ForwardVirtualState(node); | 1478 ForwardVirtualState(node); |
| 1483 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1479 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1484 Node* index_node = node->InputAt(1); | 1480 Node* index_node = node->InputAt(1); |
| 1485 NumberMatcher index(index_node); | 1481 NumberMatcher index(index_node); |
| 1486 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1482 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1487 index_node->opcode() != IrOpcode::kInt64Constant && | 1483 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1488 index_node->opcode() != IrOpcode::kFloat32Constant && | 1484 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1489 index_node->opcode() != IrOpcode::kFloat64Constant); | 1485 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1490 VirtualState* state = virtual_states_[node->id()]; | 1486 VirtualState* state = virtual_states_[node->id()]; |
| 1491 VirtualObject* obj = GetVirtualObject(state, to); | |
| 1492 if (index.HasValue()) { | 1487 if (index.HasValue()) { |
| 1493 int offset = OffsetForElementAccess(node, index.Value()); | 1488 if (VirtualObject* object = GetVirtualObject(state, to)) { |
| 1494 if (obj && obj->IsTracked() && | 1489 if (!object->IsTracked()) return; |
| 1495 static_cast<size_t>(offset) < obj->field_count()) { | 1490 int offset = OffsetForElementAccess(node, index.Value()); |
| 1491 if (static_cast<size_t>(offset) >= object->field_count()) return; |
| 1496 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); | 1492 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
| 1497 if (obj->GetField(offset) != val) { | 1493 if (object->GetField(offset) != val) { |
| 1498 obj = CopyForModificationAt(obj, state, node); | 1494 object = CopyForModificationAt(object, state, node); |
| 1499 obj->SetField(offset, val); | 1495 object->SetField(offset, val); |
| 1500 } | 1496 } |
| 1501 } | 1497 } |
| 1502 } else { | 1498 } else { |
| 1503 // We have a store to a non-const index, cannot eliminate object. | 1499 // We have a store to a non-const index, cannot eliminate object. |
| 1504 if (status_analysis_->SetEscaped(to)) { | 1500 if (status_analysis_->SetEscaped(to)) { |
| 1505 TRACE( | 1501 TRACE( |
| 1506 "Setting #%d (%s) to escaped because store element #%d to non-const " | 1502 "Setting #%d (%s) to escaped because store element #%d to non-const " |
| 1507 "index #%d (%s)\n", | 1503 "index #%d (%s)\n", |
| 1508 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), | 1504 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), |
| 1509 index_node->op()->mnemonic()); | 1505 index_node->op()->mnemonic()); |
| 1510 } | 1506 } |
| 1511 if (obj && obj->IsTracked()) { | 1507 if (VirtualObject* object = GetVirtualObject(state, to)) { |
| 1512 if (!obj->AllFieldsClear()) { | 1508 if (!object->IsTracked()) return; |
| 1513 obj = CopyForModificationAt(obj, state, node); | 1509 if (!object->AllFieldsClear()) { |
| 1514 obj->ClearAllFields(); | 1510 object = CopyForModificationAt(object, state, node); |
| 1511 object->ClearAllFields(); |
| 1515 TRACE("Cleared all fields of @%d:#%d\n", | 1512 TRACE("Cleared all fields of @%d:#%d\n", |
| 1516 status_analysis_->GetAlias(obj->id()), obj->id()); | 1513 status_analysis_->GetAlias(object->id()), object->id()); |
| 1517 } | 1514 } |
| 1518 } | 1515 } |
| 1519 } | 1516 } |
| 1520 } | 1517 } |
| 1521 | 1518 |
| 1522 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1519 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| 1523 if ((node->opcode() == IrOpcode::kFinishRegion || | 1520 if ((node->opcode() == IrOpcode::kFinishRegion || |
| 1524 node->opcode() == IrOpcode::kAllocate) && | 1521 node->opcode() == IrOpcode::kAllocate) && |
| 1525 IsVirtual(node)) { | 1522 IsVirtual(node)) { |
| 1526 if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()], | 1523 if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()], |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 } | 1606 } |
| 1610 } | 1607 } |
| 1611 return false; | 1608 return false; |
| 1612 } | 1609 } |
| 1613 | 1610 |
| 1614 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } | 1611 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } |
| 1615 | 1612 |
| 1616 } // namespace compiler | 1613 } // namespace compiler |
| 1617 } // namespace internal | 1614 } // namespace internal |
| 1618 } // namespace v8 | 1615 } // namespace v8 |
| OLD | NEW |