001/* 002 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.phases.common; 024 025import java.util.*; 026 027import com.oracle.graal.debug.*; 028import com.oracle.graal.debug.Debug.*; 029import jdk.internal.jvmci.meta.*; 030 031import com.oracle.graal.compiler.common.type.*; 032import com.oracle.graal.graph.*; 033import com.oracle.graal.nodes.*; 034import com.oracle.graal.nodes.CallTargetNode.InvokeKind; 035import com.oracle.graal.nodes.calc.*; 036import com.oracle.graal.nodes.extended.*; 037import com.oracle.graal.nodes.java.*; 038import com.oracle.graal.nodes.spi.*; 039import com.oracle.graal.nodes.type.*; 040import com.oracle.graal.nodes.util.*; 041import com.oracle.graal.phases.*; 042import com.oracle.graal.phases.graph.*; 043 044public class ConditionalEliminationPhase extends Phase { 045 046 private static final DebugMetric metricConditionRegistered = Debug.metric("ConditionRegistered"); 047 private static final DebugMetric metricTypeRegistered = Debug.metric("TypeRegistered"); 048 private static final DebugMetric metricNullnessRegistered = Debug.metric("NullnessRegistered"); 049 private static final DebugMetric metricObjectEqualsRegistered = Debug.metric("ObjectEqualsRegistered"); 050 private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved"); 051 private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved"); 052 private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved"); 053 private static final DebugMetric metricObjectEqualsRemoved = Debug.metric("ObjectEqualsRemoved"); 054 private static final DebugMetric metricGuardsRemoved = Debug.metric("GuardsRemoved"); 055 056 private StructuredGraph graph; 057 058 public ConditionalEliminationPhase() { 059 } 060 061 @Override 062 protected void run(StructuredGraph inputGraph) { 063 graph = inputGraph; 064 try (Scope s = Debug.scope("ConditionalElimination")) { 065 new ConditionalElimination(graph.start(), new State()).apply(); 066 } catch (Throwable e) { 067 throw Debug.handle(e); 068 } 069 } 070 071 /** 072 * Type information about a {@code value} that it produced by a {@code guard}. Usage of the 073 * stamp information requires adopting the guard. Usually this means replacing an existing guard 074 * with this guard. 075 */ 076 static class GuardedStamp { 077 private final ValueNode value; 078 private final Stamp stamp; 079 private final GuardNode guard; 080 081 GuardedStamp(ValueNode value, Stamp stamp, GuardNode guard) { 082 this.value = value; 083 this.stamp = stamp; 084 this.guard = guard; 085 } 086 087 public Stamp getStamp() { 088 return stamp; 089 } 090 091 public GuardNode getGuard() { 092 return guard; 093 } 094 095 public ValueNode getValue() { 096 return value; 097 } 098 } 099 100 public static class State extends MergeableState<State> implements Cloneable { 101 102 private Map<ValueNode, ResolvedJavaType> knownTypes; 103 private Set<ValueNode> knownNonNull; 104 private Set<ValueNode> knownNull; 105 private Map<LogicNode, GuardingNode> trueConditions; 106 private Map<LogicNode, GuardingNode> falseConditions; 107 private Map<ValueNode, GuardedStamp> valueConstraints; 108 109 public State() { 110 this.knownTypes = Node.newIdentityMap(); 111 this.knownNonNull = Node.newSet(); 112 this.knownNull = Node.newSet(); 113 this.trueConditions = Node.newIdentityMap(); 114 this.falseConditions = Node.newIdentityMap(); 115 this.valueConstraints = Node.newIdentityMap(); 116 } 117 118 public State(State other) { 119 this.knownTypes = Node.newIdentityMap(other.knownTypes); 120 this.knownNonNull = Node.newSet(other.knownNonNull); 121 this.knownNull = Node.newSet(other.knownNull); 122 this.trueConditions = Node.newIdentityMap(other.trueConditions); 123 this.falseConditions = Node.newIdentityMap(other.falseConditions); 124 this.valueConstraints = Node.newIdentityMap(other.valueConstraints); 125 } 126 127 @Override 128 public boolean merge(AbstractMergeNode merge, List<State> withStates) { 129 Map<ValueNode, ResolvedJavaType> newKnownTypes = Node.newIdentityMap(); 130 Map<LogicNode, GuardingNode> newTrueConditions = Node.newIdentityMap(); 131 Map<LogicNode, GuardingNode> newFalseConditions = Node.newIdentityMap(); 132 Map<ValueNode, GuardedStamp> newValueConstraints = Node.newIdentityMap(); 133 134 Set<ValueNode> newKnownNull = Node.newSet(knownNull); 135 Set<ValueNode> newKnownNonNull = Node.newSet(knownNonNull); 136 for (State state : withStates) { 137 newKnownNull.retainAll(state.knownNull); 138 newKnownNonNull.retainAll(state.knownNonNull); 139 } 140 141 for (Map.Entry<ValueNode, ResolvedJavaType> entry : knownTypes.entrySet()) { 142 ValueNode node = entry.getKey(); 143 ResolvedJavaType type = entry.getValue(); 144 145 for (State other : withStates) { 146 ResolvedJavaType otherType = other.getNodeType(node); 147 type = widen(type, otherType); 148 if (type == null) { 149 break; 150 } 151 } 152 if (type != null && !type.equals(StampTool.typeOrNull(node))) { 153 newKnownTypes.put(node, type); 154 } 155 } 156 157 for (Map.Entry<LogicNode, GuardingNode> entry : trueConditions.entrySet()) { 158 LogicNode check = entry.getKey(); 159 GuardingNode guard = entry.getValue(); 160 161 for (State other : withStates) { 162 GuardingNode otherGuard = other.trueConditions.get(check); 163 if (otherGuard == null) { 164 guard = null; 165 break; 166 } 167 if (otherGuard != guard) { 168 guard = merge; 169 } 170 } 171 if (guard != null) { 172 newTrueConditions.put(check, guard); 173 } 174 } 175 for (Map.Entry<LogicNode, GuardingNode> entry : falseConditions.entrySet()) { 176 LogicNode check = entry.getKey(); 177 GuardingNode guard = entry.getValue(); 178 179 for (State other : withStates) { 180 GuardingNode otherGuard = other.falseConditions.get(check); 181 if (otherGuard == null) { 182 guard = null; 183 break; 184 } 185 if (otherGuard != guard) { 186 guard = merge; 187 } 188 } 189 if (guard != null) { 190 newFalseConditions.put(check, guard); 191 } 192 } 193 194 // this piece of code handles phis 195 if (!(merge instanceof LoopBeginNode)) { 196 for (PhiNode phi : merge.phis()) { 197 if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) { 198 ValueNode firstValue = phi.valueAt(0); 199 ResolvedJavaType type = getNodeType(firstValue); 200 boolean nonNull = knownNonNull.contains(firstValue); 201 boolean isNull = knownNull.contains(firstValue); 202 203 for (int i = 0; i < withStates.size(); i++) { 204 State otherState = withStates.get(i); 205 ValueNode value = phi.valueAt(i + 1); 206 ResolvedJavaType otherType = otherState.getNodeType(value); 207 type = widen(type, otherType); 208 nonNull &= otherState.knownNonNull.contains(value); 209 isNull &= otherState.knownNull.contains(value); 210 } 211 if (type != null) { 212 newKnownTypes.put(phi, type); 213 } 214 if (nonNull) { 215 newKnownNonNull.add(phi); 216 } 217 if (isNull) { 218 newKnownNull.add(phi); 219 } 220 } 221 } 222 } 223 224 this.knownTypes = newKnownTypes; 225 this.knownNonNull = newKnownNonNull; 226 this.knownNull = newKnownNull; 227 this.trueConditions = newTrueConditions; 228 this.falseConditions = newFalseConditions; 229 this.valueConstraints = newValueConstraints; 230 return true; 231 } 232 233 public ResolvedJavaType getNodeType(ValueNode node) { 234 ResolvedJavaType result = knownTypes.get(GraphUtil.unproxify(node)); 235 return result == null ? StampTool.typeOrNull(node) : result; 236 } 237 238 public boolean isNull(ValueNode value) { 239 return StampTool.isPointerAlwaysNull(value) || knownNull.contains(GraphUtil.unproxify(value)); 240 } 241 242 public boolean isNonNull(ValueNode value) { 243 return StampTool.isPointerNonNull(value) || knownNonNull.contains(GraphUtil.unproxify(value)); 244 } 245 246 @Override 247 public State clone() { 248 return new State(this); 249 } 250 251 /** 252 * Adds information about a condition. If isTrue is true then the condition is known to 253 * hold, otherwise the condition is known not to hold. 254 */ 255 public void addCondition(boolean isTrue, LogicNode condition, GuardingNode anchor) { 256 if (isTrue) { 257 if (!trueConditions.containsKey(condition)) { 258 trueConditions.put(condition, anchor); 259 metricConditionRegistered.increment(); 260 } 261 } else { 262 if (!falseConditions.containsKey(condition)) { 263 falseConditions.put(condition, anchor); 264 metricConditionRegistered.increment(); 265 } 266 } 267 } 268 269 /** 270 * Adds information about the nullness of a value. If isNull is true then the value is known 271 * to be null, otherwise the value is known to be non-null. 272 */ 273 public void addNullness(boolean isNull, ValueNode value) { 274 if (isNull) { 275 if (!isNull(value)) { 276 metricNullnessRegistered.increment(); 277 knownNull.add(GraphUtil.unproxify(value)); 278 } 279 } else { 280 if (!isNonNull(value)) { 281 metricNullnessRegistered.increment(); 282 knownNonNull.add(GraphUtil.unproxify(value)); 283 } 284 } 285 } 286 287 public void addType(ResolvedJavaType type, ValueNode value) { 288 ValueNode original = GraphUtil.unproxify(value); 289 ResolvedJavaType knownType = getNodeType(original); 290 ResolvedJavaType newType = tighten(type, knownType); 291 292 if (!newType.equals(knownType)) { 293 knownTypes.put(original, newType); 294 metricTypeRegistered.increment(); 295 } 296 } 297 298 public void clear() { 299 knownTypes.clear(); 300 knownNonNull.clear(); 301 knownNull.clear(); 302 trueConditions.clear(); 303 falseConditions.clear(); 304 } 305 } 306 307 public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) { 308 if (a == null || b == null) { 309 return null; 310 } else if (a.equals(b)) { 311 return a; 312 } else { 313 return a.findLeastCommonAncestor(b); 314 } 315 } 316 317 public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) { 318 if (a == null) { 319 return b; 320 } else if (b == null) { 321 return a; 322 } else if (a.equals(b)) { 323 return a; 324 } else if (a.isAssignableFrom(b)) { 325 return b; 326 } else { 327 return a; 328 } 329 } 330 331 public class ConditionalElimination extends SinglePassNodeIterator<State> { 332 333 private final LogicNode trueConstant; 334 private final LogicNode falseConstant; 335 336 public ConditionalElimination(StartNode start, State initialState) { 337 super(start, initialState); 338 trueConstant = LogicConstantNode.tautology(graph); 339 falseConstant = LogicConstantNode.contradiction(graph); 340 } 341 342 @Override 343 public void finished() { 344 if (trueConstant.hasNoUsages()) { 345 graph.removeFloating(trueConstant); 346 } 347 if (falseConstant.hasNoUsages()) { 348 graph.removeFloating(falseConstant); 349 } 350 super.finished(); 351 } 352 353 private void registerCondition(boolean isTrue, LogicNode condition, GuardingNode anchor) { 354 if (!isTrue && condition instanceof ShortCircuitOrNode) { 355 /* 356 * We can only do this for fixed nodes, because floating guards will be registered 357 * at a BeginNode but might be "valid" only later due to data flow dependencies. 358 * Therefore, registering both conditions of a ShortCircuitOrNode for a floating 359 * guard could lead to cycles in data flow, because the guard will be used as anchor 360 * for both conditions, and one condition could be depending on the other. 361 */ 362 if (anchor instanceof FixedNode) { 363 ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition; 364 registerCondition(disjunction.isXNegated(), disjunction.getX(), anchor); 365 registerCondition(disjunction.isYNegated(), disjunction.getY(), anchor); 366 } 367 } 368 state.addCondition(isTrue, condition, anchor); 369 370 if (isTrue && condition instanceof InstanceOfNode) { 371 InstanceOfNode instanceOf = (InstanceOfNode) condition; 372 ValueNode object = instanceOf.getValue(); 373 state.addNullness(false, object); 374 state.addType(instanceOf.type(), object); 375 } else if (condition instanceof IsNullNode) { 376 IsNullNode nullCheck = (IsNullNode) condition; 377 state.addNullness(isTrue, nullCheck.getValue()); 378 } else if (condition instanceof ObjectEqualsNode) { 379 ObjectEqualsNode equals = (ObjectEqualsNode) condition; 380 ValueNode x = equals.getX(); 381 ValueNode y = equals.getY(); 382 if (isTrue) { 383 if (state.isNull(x) && !state.isNull(y)) { 384 metricObjectEqualsRegistered.increment(); 385 state.addNullness(true, y); 386 } else if (!state.isNull(x) && state.isNull(y)) { 387 metricObjectEqualsRegistered.increment(); 388 state.addNullness(true, x); 389 } 390 if (state.isNonNull(x) && !state.isNonNull(y)) { 391 metricObjectEqualsRegistered.increment(); 392 state.addNullness(false, y); 393 } else if (!state.isNonNull(x) && state.isNonNull(y)) { 394 metricObjectEqualsRegistered.increment(); 395 state.addNullness(false, x); 396 } 397 } else { 398 if (state.isNull(x) && !state.isNonNull(y)) { 399 metricObjectEqualsRegistered.increment(); 400 state.addNullness(false, y); 401 } else if (!state.isNonNull(x) && state.isNull(y)) { 402 metricObjectEqualsRegistered.increment(); 403 state.addNullness(false, x); 404 } 405 } 406 } 407 } 408 409 private void registerControlSplitInfo(Node pred, AbstractBeginNode begin) { 410 assert pred != null && begin != null; 411 /* 412 * We does not create value proxies for values it may connect accross loop exit node so 413 * we have to clear the state at loop exits if the graph needs value proxies 414 */ 415 if (begin instanceof LoopExitNode && begin.graph().hasValueProxies()) { 416 state.clear(); 417 } 418 419 if (pred instanceof IfNode) { 420 IfNode ifNode = (IfNode) pred; 421 422 if (!(ifNode.condition() instanceof LogicConstantNode)) { 423 registerCondition(begin == ifNode.trueSuccessor(), ifNode.condition(), begin); 424 } 425 } else if (pred instanceof TypeSwitchNode) { 426 TypeSwitchNode typeSwitch = (TypeSwitchNode) pred; 427 428 if (typeSwitch.value() instanceof LoadHubNode) { 429 LoadHubNode loadHub = (LoadHubNode) typeSwitch.value(); 430 ResolvedJavaType type = null; 431 for (int i = 0; i < typeSwitch.keyCount(); i++) { 432 if (typeSwitch.keySuccessor(i) == begin) { 433 if (type == null) { 434 type = typeSwitch.typeAt(i); 435 } else { 436 type = widen(type, typeSwitch.typeAt(i)); 437 } 438 } 439 } 440 if (type != null) { 441 state.addNullness(false, loadHub.getValue()); 442 state.addType(type, loadHub.getValue()); 443 } 444 } 445 } 446 } 447 448 private GuardedStamp computeGuardedStamp(GuardNode guard) { 449 if (guard.condition() instanceof IntegerBelowNode) { 450 if (guard.isNegated()) { 451 // Not sure how to reason about negated guards 452 return null; 453 } 454 IntegerBelowNode below = (IntegerBelowNode) guard.condition(); 455 if (below.getX().getKind() == Kind.Int && below.getX().isConstant() && !below.getY().isConstant()) { 456 Stamp stamp = StampTool.unsignedCompare(below.getX().stamp(), below.getY().stamp()); 457 if (stamp != null) { 458 return new GuardedStamp(below.getY(), stamp, guard); 459 } 460 } 461 if (below.getY().getKind() == Kind.Int && below.getY().isConstant() && !below.getX().isConstant()) { 462 Stamp stamp = StampTool.unsignedCompare(below.getX().stamp(), below.getY().stamp()); 463 if (stamp != null) { 464 return new GuardedStamp(below.getX(), stamp, guard); 465 } 466 } 467 } 468 return null; 469 } 470 471 private boolean eliminateTrivialGuardOrRegisterStamp(GuardNode guard) { 472 if (tryReplaceWithExistingGuard(guard)) { 473 return true; 474 } 475 // Can't be eliminated so accumulate any type information from the guard 476 registerConditionalStamp(guard); 477 return false; 478 } 479 480 /** 481 * Replace {@code guard} with {@code anchor} . 482 * 483 * @param guard The guard to eliminate. 484 * @param anchor Node to replace the guard. 485 */ 486 private void eliminateGuard(GuardNode guard, GuardingNode anchor) { 487 guard.replaceAtUsages(anchor.asNode()); 488 metricGuardsRemoved.increment(); 489 GraphUtil.killWithUnusedFloatingInputs(guard); 490 } 491 492 /** 493 * See if a conditional type constraint can prove this guard. 494 * 495 * @param guard 496 * @return true if the guard was eliminated. 497 */ 498 private boolean testImpliedGuard(GuardNode guard) { 499 if (state.valueConstraints.size() == 0) { 500 // Nothing to do. 501 return false; 502 } 503 504 GuardNode existingGuard = null; 505 if (guard.condition() instanceof IntegerBelowNode) { 506 IntegerBelowNode below = (IntegerBelowNode) guard.condition(); 507 IntegerStamp xStamp = (IntegerStamp) below.getX().stamp(); 508 IntegerStamp yStamp = (IntegerStamp) below.getY().stamp(); 509 GuardedStamp cstamp = state.valueConstraints.get(below.getX()); 510 if (cstamp != null) { 511 xStamp = (IntegerStamp) cstamp.getStamp(); 512 } else { 513 cstamp = state.valueConstraints.get(below.getY()); 514 if (cstamp != null) { 515 yStamp = (IntegerStamp) cstamp.getStamp(); 516 } 517 } 518 if (cstamp != null) { 519 if (cstamp.getGuard() == guard) { 520 // found ourselves 521 return false; 522 } 523 // See if we can use the other guard 524 if (!guard.isNegated() && !cstamp.getGuard().isNegated() && yStamp.isPositive()) { 525 if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) { 526 // Proven true 527 existingGuard = cstamp.getGuard(); 528 Debug.log("existing guard %s %1s proves %1s", existingGuard, existingGuard.condition(), guard.condition()); 529 } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) { 530 // An earlier guard proves that this will always fail but it's probably 531 // not worth trying to use it. 532 } 533 } 534 } 535 } else if (guard.condition() instanceof IntegerEqualsNode && guard.isNegated()) { 536 IntegerEqualsNode equals = (IntegerEqualsNode) guard.condition(); 537 GuardedStamp cstamp = state.valueConstraints.get(equals.getY()); 538 if (cstamp != null && equals.getX().isConstant()) { 539 IntegerStamp stamp = (IntegerStamp) cstamp.getStamp(); 540 if (!stamp.contains(equals.getX().asJavaConstant().asLong())) { 541 // x != n is true if n is outside the range of the stamp 542 existingGuard = cstamp.getGuard(); 543 Debug.log("existing guard %s %1s proves !%1s", existingGuard, existingGuard.condition(), guard.condition()); 544 } 545 } 546 } 547 548 if (existingGuard != null) { 549 // Found a guard which proves this guard to be true, so replace it. 550 eliminateGuard(guard, existingGuard); 551 return true; 552 } 553 return false; 554 } 555 556 private boolean tryReplaceWithExistingGuard(GuardNode guard) { 557 GuardingNode existingGuard = guard.isNegated() ? state.falseConditions.get(guard.condition()) : state.trueConditions.get(guard.condition()); 558 if (existingGuard != null && existingGuard != guard) { 559 eliminateGuard(guard, existingGuard); 560 return true; 561 } 562 return false; 563 } 564 565 private void registerConditionalStamp(GuardNode guard) { 566 GuardedStamp conditional = computeGuardedStamp(guard); 567 if (conditional != null) { 568 GuardedStamp other = state.valueConstraints.get(conditional.getValue()); 569 if (other == null) { 570 state.valueConstraints.put(conditional.getValue(), conditional); 571 } else if (guard.isNegated() != other.getGuard().isNegated()) { 572 // This seems impossible 573 // Debug.log("negated and !negated guards %1s %1s", guard, other.getGuard()); 574 } else if (!guard.isNegated()) { 575 // two different constraints, pick the one with the tightest type 576 // information 577 Stamp result = conditional.getStamp().join(other.getStamp()); 578 if (result == conditional.getStamp()) { 579 Debug.log("%1s overrides existing value %1s", guard.condition(), other.getGuard().condition()); 580 state.valueConstraints.put(conditional.getValue(), conditional); 581 } else if (result == other.getStamp()) { 582 // existing type constraint is best 583 Debug.log("existing value is best %s", other.getGuard()); 584 } else { 585 // The merger produced some combination of values 586 Debug.log("type merge produced new type %s", result); 587 } 588 } 589 } 590 } 591 592 /** 593 * Determines if, at the current point in the control flow, the condition is known to be 594 * true, false or unknown. In case of true or false the corresponding value is returned, 595 * otherwise null. 596 */ 597 private <T extends ValueNode> T evaluateCondition(LogicNode condition, T trueValue, T falseValue) { 598 if (state.trueConditions.containsKey(condition)) { 599 return trueValue; 600 } else if (state.falseConditions.containsKey(condition)) { 601 return falseValue; 602 } else { 603 if (condition instanceof InstanceOfNode) { 604 InstanceOfNode instanceOf = (InstanceOfNode) condition; 605 ValueNode object = instanceOf.getValue(); 606 if (state.isNull(object)) { 607 metricInstanceOfRemoved.increment(); 608 return falseValue; 609 } else if (state.isNonNull(object)) { 610 ResolvedJavaType type = state.getNodeType(object); 611 if (type != null && instanceOf.type().isAssignableFrom(type)) { 612 metricInstanceOfRemoved.increment(); 613 return trueValue; 614 } 615 } 616 } else if (condition instanceof IsNullNode) { 617 IsNullNode isNull = (IsNullNode) condition; 618 ValueNode object = isNull.getValue(); 619 if (state.isNull(object)) { 620 metricNullCheckRemoved.increment(); 621 return trueValue; 622 } else if (state.isNonNull(object)) { 623 metricNullCheckRemoved.increment(); 624 return falseValue; 625 } 626 } else if (condition instanceof ObjectEqualsNode) { 627 ObjectEqualsNode equals = (ObjectEqualsNode) condition; 628 ValueNode x = equals.getX(); 629 ValueNode y = equals.getY(); 630 if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) { 631 metricObjectEqualsRemoved.increment(); 632 return falseValue; 633 } else if (state.isNull(x) && state.isNull(y)) { 634 metricObjectEqualsRemoved.increment(); 635 return trueValue; 636 } 637 } 638 } 639 return null; 640 } 641 642 @Override 643 protected void node(FixedNode node) { 644 if (node instanceof AbstractBeginNode) { 645 processAbstractBegin((AbstractBeginNode) node); 646 } else if (node instanceof FixedGuardNode) { 647 processFixedGuard((FixedGuardNode) node); 648 } else if (node instanceof CheckCastNode) { 649 processCheckCast((CheckCastNode) node); 650 } else if (node instanceof ConditionAnchorNode) { 651 processConditionAnchor((ConditionAnchorNode) node); 652 } else if (node instanceof IfNode) { 653 processIf((IfNode) node); 654 } else if (node instanceof AbstractEndNode) { 655 processAbstractEnd((AbstractEndNode) node); 656 } else if (node instanceof Invoke) { 657 processInvoke((Invoke) node); 658 } 659 } 660 661 private void processIf(IfNode ifNode) { 662 LogicNode compare = ifNode.condition(); 663 664 LogicNode replacement = null; 665 GuardingNode replacementAnchor = null; 666 AbstractBeginNode survivingSuccessor = null; 667 if (state.trueConditions.containsKey(compare)) { 668 replacement = trueConstant; 669 replacementAnchor = state.trueConditions.get(compare); 670 survivingSuccessor = ifNode.trueSuccessor(); 671 } else if (state.falseConditions.containsKey(compare)) { 672 replacement = falseConstant; 673 replacementAnchor = state.falseConditions.get(compare); 674 survivingSuccessor = ifNode.falseSuccessor(); 675 } else { 676 replacement = evaluateCondition(compare, trueConstant, falseConstant); 677 if (replacement != null) { 678 if (replacement == trueConstant) { 679 survivingSuccessor = ifNode.trueSuccessor(); 680 } else { 681 assert replacement == falseConstant; 682 survivingSuccessor = ifNode.falseSuccessor(); 683 } 684 } 685 } 686 687 if (replacement != null) { 688 trySimplify(ifNode, compare, replacement, replacementAnchor, survivingSuccessor); 689 } 690 } 691 692 private void trySimplify(IfNode ifNode, LogicNode compare, LogicNode replacement, GuardingNode replacementAnchor, AbstractBeginNode survivingSuccessor) { 693 if (replacementAnchor != null && !(replacementAnchor instanceof AbstractBeginNode)) { 694 ValueAnchorNode anchor = graph.add(new ValueAnchorNode(replacementAnchor.asNode())); 695 graph.addBeforeFixed(ifNode, anchor); 696 } 697 boolean canSimplify = true; 698 for (Node n : survivingSuccessor.usages().snapshot()) { 699 if (n instanceof GuardNode || n instanceof ProxyNode) { 700 // Keep wired to the begin node. 701 } else { 702 if (replacementAnchor == null) { 703 // Cannot simplify this IfNode as there is no anchor. 704 canSimplify = false; 705 break; 706 } 707 // Rewire to the replacement anchor. 708 n.replaceFirstInput(survivingSuccessor, replacementAnchor.asNode()); 709 } 710 } 711 712 if (canSimplify) { 713 ifNode.setCondition(replacement); 714 if (compare.hasNoUsages()) { 715 GraphUtil.killWithUnusedFloatingInputs(compare); 716 } 717 } 718 } 719 720 private void processInvoke(Invoke invoke) { 721 if (invoke.callTarget() instanceof MethodCallTargetNode) { 722 MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); 723 ValueNode receiver = callTarget.receiver(); 724 if (receiver != null && callTarget.invokeKind().isIndirect()) { 725 ResolvedJavaType type = state.getNodeType(receiver); 726 if (!Objects.equals(type, StampTool.typeOrNull(receiver))) { 727 ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), invoke.getContextType()); 728 if (method != null) { 729 if (method.canBeStaticallyBound() || type.isLeaf() || type.isArray()) { 730 callTarget.setInvokeKind(InvokeKind.Special); 731 callTarget.setTargetMethod(method); 732 } 733 } 734 } 735 } 736 } 737 } 738 739 private void processAbstractEnd(AbstractEndNode endNode) { 740 for (PhiNode phi : endNode.merge().phis()) { 741 int index = endNode.merge().phiPredecessorIndex(endNode); 742 ValueNode value = phi.valueAt(index); 743 if (value instanceof ConditionalNode) { 744 ConditionalNode materialize = (ConditionalNode) value; 745 LogicNode compare = materialize.condition(); 746 ValueNode replacement = evaluateCondition(compare, materialize.trueValue(), materialize.falseValue()); 747 748 if (replacement != null) { 749 phi.setValueAt(index, replacement); 750 if (materialize.hasNoUsages()) { 751 GraphUtil.killWithUnusedFloatingInputs(materialize); 752 } 753 } 754 } 755 } 756 } 757 758 private void processConditionAnchor(ConditionAnchorNode conditionAnchorNode) { 759 LogicNode condition = conditionAnchorNode.condition(); 760 GuardingNode replacementAnchor = null; 761 if (conditionAnchorNode.isNegated()) { 762 if (state.falseConditions.containsKey(condition)) { 763 replacementAnchor = state.falseConditions.get(condition); 764 } 765 } else { 766 if (state.trueConditions.containsKey(condition)) { 767 replacementAnchor = state.trueConditions.get(condition); 768 } 769 } 770 if (replacementAnchor != null) { 771 conditionAnchorNode.replaceAtUsages(replacementAnchor.asNode()); 772 conditionAnchorNode.graph().removeFixed(conditionAnchorNode); 773 } 774 } 775 776 private void processCheckCast(CheckCastNode checkCast) { 777 ValueNode object = checkCast.object(); 778 boolean isNull = state.isNull(object); 779 ResolvedJavaType type = state.getNodeType(object); 780 if (isNull || (type != null && checkCast.type().isAssignableFrom(type))) { 781 boolean nonNull = state.isNonNull(object); 782 // if (true) 783 // throw new RuntimeException(checkCast.toString()); 784 GuardingNode replacementAnchor = null; 785 if (nonNull) { 786 replacementAnchor = searchAnchor(GraphUtil.unproxify(object), type); 787 } 788 if (replacementAnchor == null) { 789 replacementAnchor = AbstractBeginNode.prevBegin(checkCast); 790 } 791 assert !(replacementAnchor instanceof FloatingNode) : "unsafe to mix unlowered Checkcast with floating guards"; 792 PiNode piNode; 793 if (isNull) { 794 ConstantNode nullObject = ConstantNode.defaultForKind(Kind.Object, graph); 795 piNode = graph.unique(new PiNode(nullObject, nullObject.stamp(), replacementAnchor.asNode())); 796 } else { 797 piNode = graph.unique(new PiNode(object, StampFactory.declaredTrusted(type, nonNull), replacementAnchor.asNode())); 798 } 799 checkCast.replaceAtUsages(piNode); 800 graph.removeFixed(checkCast); 801 metricCheckCastRemoved.increment(); 802 } 803 } 804 805 private void processFixedGuard(FixedGuardNode guard) { 806 GuardingNode existingGuard = guard.isNegated() ? state.falseConditions.get(guard.condition()) : state.trueConditions.get(guard.condition()); 807 if (existingGuard != null && existingGuard instanceof FixedGuardNode) { 808 guard.replaceAtUsages(existingGuard.asNode()); 809 guard.graph().removeFixed(guard); 810 } else { 811 registerCondition(!guard.isNegated(), guard.condition(), guard); 812 } 813 } 814 815 private void processAbstractBegin(AbstractBeginNode begin) { 816 Node pred = begin.predecessor(); 817 818 if (pred != null) { 819 registerControlSplitInfo(pred, begin); 820 } 821 822 // First eliminate any guards which can be trivially removed and register any 823 // type constraints the guards produce. 824 for (GuardNode guard : begin.guards().snapshot()) { 825 eliminateTrivialGuardOrRegisterStamp(guard); 826 } 827 828 // Collect the guards which have produced conditional stamps. 829 // XXX (gd) IdentityHashMap.values().contains performs a linear search 830 // so we prefer to build a set 831 Set<GuardNode> provers = Node.newSet(); 832 for (GuardedStamp e : state.valueConstraints.values()) { 833 provers.add(e.getGuard()); 834 } 835 836 // Process the remaining guards. Guards which produced some type constraint should 837 // just be registered since they aren't trivially deleteable. Test the other guards 838 // to see if they can be deleted using type constraints. 839 for (GuardNode guard : begin.guards().snapshot()) { 840 if (provers.contains(guard) || !(tryReplaceWithExistingGuard(guard) || testImpliedGuard(guard))) { 841 registerCondition(!guard.isNegated(), guard.condition(), guard); 842 } 843 } 844 assert assertImpliedGuard(provers); 845 } 846 847 private boolean assertImpliedGuard(Set<GuardNode> provers) { 848 for (GuardNode guard : provers) { 849 assert !testImpliedGuard(guard) : "provers shouldn't be trivially eliminatable"; 850 } 851 return true; 852 } 853 854 private GuardingNode searchAnchor(ValueNode value, ResolvedJavaType type) { 855 for (Node n : value.usages()) { 856 if (n instanceof InstanceOfNode) { 857 InstanceOfNode instanceOfNode = (InstanceOfNode) n; 858 if (instanceOfNode.type().equals(type) && state.trueConditions.containsKey(instanceOfNode)) { 859 GuardingNode v = state.trueConditions.get(instanceOfNode); 860 if (v != null) { 861 return v; 862 } 863 } 864 } 865 } 866 867 for (Node n : value.usages()) { 868 if (n instanceof ValueProxy) { 869 ValueProxy proxyNode = (ValueProxy) n; 870 if (proxyNode.getOriginalNode() == value) { 871 GuardingNode result = searchAnchor((ValueNode) n, type); 872 if (result != null) { 873 return result; 874 } 875 } 876 877 } 878 } 879 880 return null; 881 } 882 } 883}