[turbofan] extend escape analysis to reduce CheckMaps
R=bmeurer@chromium.org
BUG=
Review-Url: https://codereview.chromium.org/2680973013
Cr-Original-Commit-Position: refs/heads/master@{#43163}
Committed: f01c8a6e4b
Review-Url: https://codereview.chromium.org/2680973013
Cr-Commit-Position: refs/heads/master@{#43478}
This commit is contained in:
parent
3c36aacc87
commit
9881b6c740
@ -46,6 +46,8 @@ Reduction EscapeAnalysisReducer::ReduceNode(Node* node) {
|
||||
case IrOpcode::kStoreField:
|
||||
case IrOpcode::kStoreElement:
|
||||
return ReduceStore(node);
|
||||
case IrOpcode::kCheckMaps:
|
||||
return ReduceCheckMaps(node);
|
||||
case IrOpcode::kAllocate:
|
||||
return ReduceAllocate(node);
|
||||
case IrOpcode::kFinishRegion:
|
||||
@ -171,6 +173,21 @@ Reduction EscapeAnalysisReducer::ReduceStore(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction EscapeAnalysisReducer::ReduceCheckMaps(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kCheckMaps);
|
||||
if (node->id() < static_cast<NodeId>(fully_reduced_.length())) {
|
||||
fully_reduced_.Add(node->id());
|
||||
}
|
||||
if (escape_analysis()->IsVirtual(
|
||||
SkipTypeGuards(NodeProperties::GetValueInput(node, 0))) &&
|
||||
!escape_analysis()->IsEscaped(node)) {
|
||||
TRACE("Removed #%d (%s) from effect chain\n", node->id(),
|
||||
node->op()->mnemonic());
|
||||
RelaxEffectsAndControls(node);
|
||||
return Changed(node);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction EscapeAnalysisReducer::ReduceAllocate(Node* node) {
|
||||
DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
|
||||
|
@ -38,6 +38,7 @@ class V8_EXPORT_PRIVATE EscapeAnalysisReducer final
|
||||
Reduction ReduceNode(Node* node);
|
||||
Reduction ReduceLoad(Node* node);
|
||||
Reduction ReduceStore(Node* node);
|
||||
Reduction ReduceCheckMaps(Node* node);
|
||||
Reduction ReduceAllocate(Node* node);
|
||||
Reduction ReduceFinishRegion(Node* node);
|
||||
Reduction ReduceReferenceEqual(Node* node);
|
||||
|
@ -807,6 +807,7 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
|
||||
case IrOpcode::kStateValues:
|
||||
case IrOpcode::kReferenceEqual:
|
||||
case IrOpcode::kFinishRegion:
|
||||
case IrOpcode::kCheckMaps:
|
||||
if (IsEscaped(use) && SetEscaped(rep)) {
|
||||
TRACE(
|
||||
"Setting #%d (%s) to escaped because of use by escaping node "
|
||||
@ -1124,6 +1125,9 @@ bool EscapeAnalysis::Process(Node* node) {
|
||||
case IrOpcode::kLoadElement:
|
||||
ProcessLoadElement(node);
|
||||
break;
|
||||
case IrOpcode::kCheckMaps:
|
||||
ProcessCheckMaps(node);
|
||||
break;
|
||||
case IrOpcode::kStart:
|
||||
ProcessStart(node);
|
||||
break;
|
||||
@ -1161,6 +1165,10 @@ void EscapeAnalysis::ProcessAllocationUsers(Node* node) {
|
||||
case IrOpcode::kFinishRegion:
|
||||
case IrOpcode::kObjectIsSmi:
|
||||
break;
|
||||
case IrOpcode::kCheckMaps: {
|
||||
CheckMapsParameters params = CheckMapsParametersOf(node->op());
|
||||
if (params.flags() == CheckMapsFlag::kNone) break;
|
||||
} // Fallthrough.
|
||||
default:
|
||||
VirtualState* state = virtual_states_[node->id()];
|
||||
if (VirtualObject* obj =
|
||||
@ -1514,6 +1522,46 @@ void EscapeAnalysis::ProcessLoadField(Node* node) {
|
||||
}
|
||||
}
|
||||
|
||||
void EscapeAnalysis::ProcessCheckMaps(Node* node) {
|
||||
DCHECK_EQ(node->opcode(), IrOpcode::kCheckMaps);
|
||||
ForwardVirtualState(node);
|
||||
Node* checked = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
|
||||
if (FLAG_turbo_experimental) {
|
||||
VirtualState* state = virtual_states_[node->id()];
|
||||
if (VirtualObject* object = GetVirtualObject(state, checked)) {
|
||||
if (!object->IsTracked()) {
|
||||
if (status_analysis_->SetEscaped(node)) {
|
||||
TRACE(
|
||||
"Setting #%d (%s) to escaped because checked object #%i is not "
|
||||
"tracked\n",
|
||||
node->id(), node->op()->mnemonic(), object->id());
|
||||
}
|
||||
return;
|
||||
}
|
||||
CheckMapsParameters params = CheckMapsParametersOf(node->op());
|
||||
|
||||
Node* value = object->GetField(HeapObject::kMapOffset / kPointerSize);
|
||||
if (value) {
|
||||
value = ResolveReplacement(value);
|
||||
// TODO(tebbi): We want to extend this beyond constant folding with a
|
||||
// CheckMapsValue operator that takes the load-eliminated map value as
|
||||
// input.
|
||||
if (value->opcode() == IrOpcode::kHeapConstant &&
|
||||
params.maps().contains(ZoneHandleSet<Map>(
|
||||
Handle<Map>::cast(OpParameter<Handle<HeapObject>>(value))))) {
|
||||
TRACE("CheckMaps #%i seems to be redundant (until now).\n",
|
||||
node->id());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status_analysis_->SetEscaped(node)) {
|
||||
TRACE("Setting #%d (%s) to escaped (checking #%i)\n", node->id(),
|
||||
node->op()->mnemonic(), checked->id());
|
||||
}
|
||||
}
|
||||
|
||||
void EscapeAnalysis::ProcessLoadElement(Node* node) {
|
||||
DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement);
|
||||
ForwardVirtualState(node);
|
||||
|
@ -45,6 +45,7 @@ class V8_EXPORT_PRIVATE EscapeAnalysis {
|
||||
void ProcessStoreField(Node* node);
|
||||
void ProcessLoadElement(Node* node);
|
||||
void ProcessStoreElement(Node* node);
|
||||
void ProcessCheckMaps(Node* node);
|
||||
void ProcessAllocationUsers(Node* node);
|
||||
void ProcessAllocation(Node* node);
|
||||
void ProcessFinishRegion(Node* node);
|
||||
|
@ -499,6 +499,8 @@ DEFINE_BOOL(turbo_stress_instruction_scheduling, false,
|
||||
"randomly schedule instructions to stress dependency tracking")
|
||||
DEFINE_BOOL(turbo_store_elimination, true,
|
||||
"enable store-store elimination in TurboFan")
|
||||
DEFINE_BOOL(turbo_experimental, false,
|
||||
"enable crashing features, for testing purposes only")
|
||||
// TODO(turbofan): Rename --crankshaft to --optimize eventually.
|
||||
DEFINE_IMPLICATION(turbo, crankshaft)
|
||||
|
||||
|
17
test/mjsunit/compiler/escape-analysis-13.js
Normal file
17
test/mjsunit/compiler/escape-analysis-13.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --turbo --turbo-escape --turbo-experimental
|
||||
|
||||
function f() {
|
||||
var x = {};
|
||||
x.a = "a";
|
||||
x.b = "b";
|
||||
assertEquals("a", x.a);
|
||||
assertEquals("b", x.b);
|
||||
}
|
||||
f();
|
||||
f();
|
||||
% OptimizeFunctionOnNextCall(f);
|
||||
f();
|
Loading…
Reference in New Issue
Block a user