Mercurial > hg > truffle
view graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java @ 15483:01a8820c1228
[flow-sensitive] minor refactorings for readability, documentation
author | Miguel Garcia <miguel.m.garcia@oracle.com> |
---|---|
date | Fri, 02 May 2014 21:05:13 +0200 |
parents | edf0c031da76 |
children | 49a917f9fa07 |
line wrap: on
line source
/* * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.graal.phases.common.cfs; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.IsNullNode; import com.oracle.graal.nodes.extended.GuardingNode; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.tiers.PhaseContext; /** * <p> * This class implements control-flow sensitive reductions for * {@link com.oracle.graal.nodes.FixedGuardNode}. * </p> * * <p> * The laundry-list of all flow-sensitive reductions is summarized in * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} * </p> * * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode) */ public abstract class FixedGuardReduction extends CheckCastReduction { public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) { super(start, initialState, context); } /** * <p> * Upon visiting a {@link com.oracle.graal.nodes.FixedGuardNode}, based on flow-sensitive * conditions, we need to determine whether: * <ul> * <li>it is redundant (in which case it should be simplified), or</li> * <li>flow-sensitive information can be gained from it.</li> * </ul> * </p> * * <p> * This method realizes the above by inspecting the * {@link com.oracle.graal.nodes.FixedGuardNode}'s condition: * <ol> * <li>a constant condition signals the node won't be reduced here</li> * <li>the outcome of the condition can be predicted:</li> * <ul> * <li> * "always succeeds", after finding an equivalent (or stronger) * {@link com.oracle.graal.nodes.extended.GuardingNode} in scope. The * {@link com.oracle.graal.nodes.FixedGuardNode} is removed after replacing its usages with the * existing guarding node</li> * <li> * "always fails", which warrants making that explicit by making the condition constant, see * {@link #markFixedGuardNodeAlwaysFails(com.oracle.graal.nodes.FixedGuardNode)}</li> * </ul> * <li>otherwise the condition is tracked flow-sensitively</li> * </ol> * </p> * * <p> * Precondition: the condition hasn't been deverbosified yet. * </p> */ protected final void visitFixedGuardNode(FixedGuardNode f) { /* * A FixedGuardNode with LogicConstantNode condition is left untouched. * `FixedGuardNode.simplify()` will eventually remove the FixedGuardNode (in case it * "always succeeds") or kill code ("always fails"). */ if (f.condition() instanceof LogicConstantNode) { if (FlowUtil.alwaysFails(f.isNegated(), f.condition())) { state.impossiblePath(); // let FixedGuardNode(false).simplify() prune the dead-code control-path return; } assert FlowUtil.alwaysSucceeds(f.isNegated(), f.condition()); return; } /* * Attempt to eliminate the current FixedGuardNode by using another GuardingNode already in * scope and with equivalent condition. */ GuardingNode existingGuard = f.isNegated() ? state.falseFacts.get(f.condition()) : state.trueFacts.get(f.condition()); if (existingGuard != null) { // assert existingGuard instanceof FixedGuardNode; metricFixedGuardNodeRemoved.increment(); f.replaceAtUsages(existingGuard.asNode()); graph.removeFixed(f); return; } final LogicNode cond = f.condition(); final boolean isTrue = !f.isNegated(); /* * A FixedGuardNode can only be removed provided a replacement anchor is found (so called * "evidence"), ie an anchor that amounts to the same combination of (negated, condition) as * for the FixedGuardNode at hand. Just deverbosifying the condition in place isn't * semantics-preserving. */ // TODO what about isDependencyTainted if (cond instanceof IsNullNode) { final IsNullNode isNullNode = (IsNullNode) cond; if (isTrue) { // grab an anchor attesting nullness final GuardingNode replacement = reasoner.nonTrivialNullAnchor(isNullNode.object()); if (replacement != null) { removeFixedGuardNode(f, replacement); return; } if (state.isNonNull(isNullNode.object())) { markFixedGuardNodeAlwaysFails(f); return; } // can't produce evidence, fall-through to addFact } else { // grab an anchor attesting non-nullness final Witness w = state.typeInfo(isNullNode.object()); if (w != null && w.isNonNull()) { removeFixedGuardNode(f, w.guard()); return; } if (state.isNull(isNullNode.object())) { markFixedGuardNodeAlwaysFails(f); return; } // can't produce evidence, fall-through to addFact } } else if (cond instanceof InstanceOfNode) { final InstanceOfNode iOf = (InstanceOfNode) cond; final Witness w = state.typeInfo(iOf.object()); if (isTrue) { // grab an anchor attesting instanceof if (w != null) { if (w.isNonNull() && w.type() != null) { if (iOf.type().isAssignableFrom(w.type())) { removeFixedGuardNode(f, w.guard()); return; } if (State.knownNotToConform(w.type(), iOf.type())) { markFixedGuardNodeAlwaysFails(f); return; } } } if (state.isNull(iOf.object())) { markFixedGuardNodeAlwaysFails(f); return; } // can't produce evidence, fall-through to addFact } else { // grab an anchor attesting not-instanceof // (1 of 2) attempt determining nullness final GuardingNode nullGuard = reasoner.nonTrivialNullAnchor(iOf.object()); if (nullGuard != null) { removeFixedGuardNode(f, nullGuard); return; } // (2 of 2) attempt determining known-not-to-conform if (w != null && !w.cluelessAboutType()) { if (State.knownNotToConform(w.type(), iOf.type())) { removeFixedGuardNode(f, w.guard()); return; } } // can't produce evidence, fall-through to addFact } } else if (isTrue && cond instanceof ShortCircuitOrNode) { CastCheckExtractor cce = CastCheckExtractor.extract(cond); if (cce != null && !State.isDependencyTainted(cce.subject, f)) { // grab an anchor attesting check-cast Witness w = state.typeInfo(cce.subject); if (w != null && w.type() != null) { if (cce.type.isAssignableFrom(w.type())) { removeFixedGuardNode(f, w.guard()); return; } if (State.knownNotToConform(w.type(), cce.type)) { markFixedGuardNodeAlwaysFails(f); return; } } } // can't produce evidence, fall-through to addFact } state.addFact(isTrue, cond, f); } /** * Porcelain method. */ private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) { metricFixedGuardNodeRemoved.increment(); state.impossiblePath(); f.setCondition(f.isNegated() ? trueConstant : falseConstant); // `f.condition()` if unused will be removed in finished() } /** * Porcelain method. * * <p> * The `replacement` guard must be such that it implies the `old` guard. Moreover, rhe * `replacement` guard must be in scope. * </p> */ private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) { if (replacement == null) { return; } metricFixedGuardNodeRemoved.increment(); old.replaceAtUsages(replacement.asNode()); graph.removeFixed(old); // `old.condition()` if unused will be removed in finished() } }