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 1309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1320 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1320 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
1321 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1321 DCHECK(IsVirtual(left) && IsVirtual(right)); |
1322 left = ResolveReplacement(left); | 1322 left = ResolveReplacement(left); |
1323 right = ResolveReplacement(right); | 1323 right = ResolveReplacement(right); |
1324 if (IsEquivalentPhi(left, right)) { | 1324 if (IsEquivalentPhi(left, right)) { |
1325 return true; | 1325 return true; |
1326 } | 1326 } |
1327 return false; | 1327 return false; |
1328 } | 1328 } |
1329 | 1329 |
1330 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1330 namespace { |
1331 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1331 |
1332 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1332 int OffsetForFieldAccess(Node* node) { |
| 1333 FieldAccess access = FieldAccessOf(node->op()); |
| 1334 DCHECK_EQ(access.offset % kPointerSize, 0); |
| 1335 return access.offset / kPointerSize; |
1333 } | 1336 } |
1334 | 1337 |
| 1338 int OffsetForElementAccess(Node* node, int index) { |
| 1339 ElementAccess access = ElementAccessOf(node->op()); |
| 1340 DCHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1341 kPointerSizeLog2); |
| 1342 DCHECK_EQ(access.header_size % kPointerSize, 0); |
| 1343 return access.header_size / kPointerSize + index; |
| 1344 } |
| 1345 |
| 1346 } // namespace |
| 1347 |
1335 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, | 1348 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, |
1336 VirtualState* state) { | 1349 VirtualState* state) { |
1337 TRACE("Load #%d from phi #%d", load->id(), from->id()); | 1350 TRACE("Load #%d from phi #%d", load->id(), from->id()); |
1338 | 1351 |
1339 cache_->fields().clear(); | 1352 cache_->fields().clear(); |
1340 for (int i = 0; i < load->op()->ValueInputCount(); ++i) { | 1353 for (int i = 0; i < load->op()->ValueInputCount(); ++i) { |
1341 Node* input = NodeProperties::GetValueInput(load, i); | 1354 Node* input = NodeProperties::GetValueInput(load, i); |
1342 cache_->fields().push_back(input); | 1355 cache_->fields().push_back(input); |
1343 } | 1356 } |
1344 | 1357 |
(...skipping 22 matching lines...) Expand all Loading... |
1367 TRACE(" has incomplete virtual object info.\n"); | 1380 TRACE(" has incomplete virtual object info.\n"); |
1368 } | 1381 } |
1369 } | 1382 } |
1370 | 1383 |
1371 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1384 void EscapeAnalysis::ProcessLoadField(Node* node) { |
1372 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1385 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
1373 ForwardVirtualState(node); | 1386 ForwardVirtualState(node); |
1374 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1387 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1375 VirtualState* state = virtual_states_[node->id()]; | 1388 VirtualState* state = virtual_states_[node->id()]; |
1376 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1389 if (VirtualObject* object = GetVirtualObject(state, from)) { |
1377 int offset = OffsetFromAccess(node); | 1390 int offset = OffsetForFieldAccess(node); |
1378 if (!object->IsTracked() || | 1391 if (!object->IsTracked() || |
1379 static_cast<size_t>(offset) >= object->field_count()) { | 1392 static_cast<size_t>(offset) >= object->field_count()) { |
1380 return; | 1393 return; |
1381 } | 1394 } |
1382 Node* value = object->GetField(offset); | 1395 Node* value = object->GetField(offset); |
1383 if (value) { | 1396 if (value) { |
1384 value = ResolveReplacement(value); | 1397 value = ResolveReplacement(value); |
1385 } | 1398 } |
1386 // Record that the load has this alias. | 1399 // Record that the load has this alias. |
1387 UpdateReplacement(state, node, value); | 1400 UpdateReplacement(state, node, value); |
1388 } else if (from->opcode() == IrOpcode::kPhi && | 1401 } else if (from->opcode() == IrOpcode::kPhi && |
1389 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { | 1402 FieldAccessOf(node->op()).offset % kPointerSize == 0) { |
1390 int offset = OffsetFromAccess(node); | 1403 int offset = OffsetForFieldAccess(node); |
1391 // Only binary phis are supported for now. | 1404 // Only binary phis are supported for now. |
1392 ProcessLoadFromPhi(offset, from, node, state); | 1405 ProcessLoadFromPhi(offset, from, node, state); |
1393 } else { | 1406 } else { |
1394 UpdateReplacement(state, node, nullptr); | 1407 UpdateReplacement(state, node, nullptr); |
1395 } | 1408 } |
1396 } | 1409 } |
1397 | 1410 |
1398 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1411 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
1399 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1412 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
1400 ForwardVirtualState(node); | 1413 ForwardVirtualState(node); |
1401 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1414 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1402 VirtualState* state = virtual_states_[node->id()]; | 1415 VirtualState* state = virtual_states_[node->id()]; |
1403 Node* index_node = node->InputAt(1); | 1416 Node* index_node = node->InputAt(1); |
1404 NumberMatcher index(index_node); | 1417 NumberMatcher index(index_node); |
1405 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1418 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
1406 index_node->opcode() != IrOpcode::kInt64Constant && | 1419 index_node->opcode() != IrOpcode::kInt64Constant && |
1407 index_node->opcode() != IrOpcode::kFloat32Constant && | 1420 index_node->opcode() != IrOpcode::kFloat32Constant && |
1408 index_node->opcode() != IrOpcode::kFloat64Constant); | 1421 index_node->opcode() != IrOpcode::kFloat64Constant); |
1409 ElementAccess access = OpParameter<ElementAccess>(node); | |
1410 if (index.HasValue()) { | 1422 if (index.HasValue()) { |
1411 int offset = index.Value() + access.header_size / kPointerSize; | |
1412 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1423 if (VirtualObject* object = GetVirtualObject(state, from)) { |
1413 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1424 int offset = OffsetForElementAccess(node, index.Value()); |
1414 kPointerSizeLog2); | |
1415 CHECK_EQ(access.header_size % kPointerSize, 0); | |
1416 | |
1417 if (!object->IsTracked() || | 1425 if (!object->IsTracked() || |
1418 static_cast<size_t>(offset) >= object->field_count()) { | 1426 static_cast<size_t>(offset) >= object->field_count()) { |
1419 return; | 1427 return; |
1420 } | 1428 } |
1421 | |
1422 Node* value = object->GetField(offset); | 1429 Node* value = object->GetField(offset); |
1423 if (value) { | 1430 if (value) { |
1424 value = ResolveReplacement(value); | 1431 value = ResolveReplacement(value); |
1425 } | 1432 } |
1426 // Record that the load has this alias. | 1433 // Record that the load has this alias. |
1427 UpdateReplacement(state, node, value); | 1434 UpdateReplacement(state, node, value); |
1428 } else if (from->opcode() == IrOpcode::kPhi) { | 1435 } else if (from->opcode() == IrOpcode::kPhi) { |
1429 ElementAccess access = OpParameter<ElementAccess>(node); | 1436 int offset = OffsetForElementAccess(node, index.Value()); |
1430 int offset = index.Value() + access.header_size / kPointerSize; | |
1431 ProcessLoadFromPhi(offset, from, node, state); | 1437 ProcessLoadFromPhi(offset, from, node, state); |
1432 } else { | 1438 } else { |
1433 UpdateReplacement(state, node, nullptr); | 1439 UpdateReplacement(state, node, nullptr); |
1434 } | 1440 } |
1435 } else { | 1441 } else { |
1436 // We have a load from a non-const index, cannot eliminate object. | 1442 // We have a load from a non-const index, cannot eliminate object. |
1437 if (status_analysis_->SetEscaped(from)) { | 1443 if (status_analysis_->SetEscaped(from)) { |
1438 TRACE( | 1444 TRACE( |
1439 "Setting #%d (%s) to escaped because load element #%d from non-const " | 1445 "Setting #%d (%s) to escaped because load element #%d from non-const " |
1440 "index #%d (%s)\n", | 1446 "index #%d (%s)\n", |
1441 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | 1447 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
1442 index_node->op()->mnemonic()); | 1448 index_node->op()->mnemonic()); |
1443 } | 1449 } |
1444 } | 1450 } |
1445 } | 1451 } |
1446 | 1452 |
1447 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1453 void EscapeAnalysis::ProcessStoreField(Node* node) { |
1448 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1454 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
1449 ForwardVirtualState(node); | 1455 ForwardVirtualState(node); |
1450 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1456 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1451 VirtualState* state = virtual_states_[node->id()]; | 1457 VirtualState* state = virtual_states_[node->id()]; |
1452 VirtualObject* obj = GetVirtualObject(state, to); | 1458 VirtualObject* obj = GetVirtualObject(state, to); |
1453 int offset = OffsetFromAccess(node); | 1459 int offset = OffsetForFieldAccess(node); |
1454 if (obj && obj->IsTracked() && | 1460 if (obj && obj->IsTracked() && |
1455 static_cast<size_t>(offset) < obj->field_count()) { | 1461 static_cast<size_t>(offset) < obj->field_count()) { |
1456 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); | 1462 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
1457 if (obj->GetField(offset) != val) { | 1463 if (obj->GetField(offset) != val) { |
1458 obj = CopyForModificationAt(obj, state, node); | 1464 obj = CopyForModificationAt(obj, state, node); |
1459 obj->SetField(offset, val); | 1465 obj->SetField(offset, val); |
1460 } | 1466 } |
1461 } | 1467 } |
1462 } | 1468 } |
1463 | 1469 |
1464 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1470 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
1465 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1471 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
1466 ForwardVirtualState(node); | 1472 ForwardVirtualState(node); |
1467 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1473 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1468 Node* index_node = node->InputAt(1); | 1474 Node* index_node = node->InputAt(1); |
1469 NumberMatcher index(index_node); | 1475 NumberMatcher index(index_node); |
1470 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1476 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
1471 index_node->opcode() != IrOpcode::kInt64Constant && | 1477 index_node->opcode() != IrOpcode::kInt64Constant && |
1472 index_node->opcode() != IrOpcode::kFloat32Constant && | 1478 index_node->opcode() != IrOpcode::kFloat32Constant && |
1473 index_node->opcode() != IrOpcode::kFloat64Constant); | 1479 index_node->opcode() != IrOpcode::kFloat64Constant); |
1474 ElementAccess access = OpParameter<ElementAccess>(node); | |
1475 VirtualState* state = virtual_states_[node->id()]; | 1480 VirtualState* state = virtual_states_[node->id()]; |
1476 VirtualObject* obj = GetVirtualObject(state, to); | 1481 VirtualObject* obj = GetVirtualObject(state, to); |
1477 if (index.HasValue()) { | 1482 if (index.HasValue()) { |
1478 int offset = index.Value() + access.header_size / kPointerSize; | 1483 int offset = OffsetForElementAccess(node, index.Value()); |
1479 if (obj && obj->IsTracked() && | 1484 if (obj && obj->IsTracked() && |
1480 static_cast<size_t>(offset) < obj->field_count()) { | 1485 static_cast<size_t>(offset) < obj->field_count()) { |
1481 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | |
1482 kPointerSizeLog2); | |
1483 CHECK_EQ(access.header_size % kPointerSize, 0); | |
1484 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); | 1486 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
1485 if (obj->GetField(offset) != val) { | 1487 if (obj->GetField(offset) != val) { |
1486 obj = CopyForModificationAt(obj, state, node); | 1488 obj = CopyForModificationAt(obj, state, node); |
1487 obj->SetField(offset, val); | 1489 obj->SetField(offset, val); |
1488 } | 1490 } |
1489 } | 1491 } |
1490 } else { | 1492 } else { |
1491 // We have a store to a non-const index, cannot eliminate object. | 1493 // We have a store to a non-const index, cannot eliminate object. |
1492 if (status_analysis_->SetEscaped(to)) { | 1494 if (status_analysis_->SetEscaped(to)) { |
1493 TRACE( | 1495 TRACE( |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1597 } | 1599 } |
1598 } | 1600 } |
1599 return false; | 1601 return false; |
1600 } | 1602 } |
1601 | 1603 |
1602 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } | 1604 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } |
1603 | 1605 |
1604 } // namespace compiler | 1606 } // namespace compiler |
1605 } // namespace internal | 1607 } // namespace internal |
1606 } // namespace v8 | 1608 } // namespace v8 |
OLD | NEW |