1 /* 2 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.lir.gen; 24 25 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 26 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; 27 28 import java.util.EnumSet; 29 30 import org.graalvm.compiler.lir.LIRInstruction; 31 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 32 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 33 import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; 34 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; 35 36 import jdk.vm.ci.meta.AllocatableValue; 37 import jdk.vm.ci.meta.Constant; 38 import jdk.vm.ci.meta.JavaConstant; 39 import jdk.vm.ci.meta.Value; 40 41 /** 42 * Wrapper for {@link MoveFactory} that checks that the instructions created adhere to the contract 43 * of {@link MoveFactory}. 44 */ 45 public final class VerifyingMoveFactory implements MoveFactory { 46 47 private final MoveFactory inner; 48 49 public VerifyingMoveFactory(MoveFactory inner) { 50 this.inner = inner; 51 } 52 53 @Override 54 public boolean canInlineConstant(JavaConstant c) { 55 return inner.canInlineConstant(c); 56 } 57 58 @Override 59 public boolean allowConstantToStackMove(Constant constant) { 60 return inner.allowConstantToStackMove(constant); 61 } 62 63 @Override 64 public LIRInstruction createMove(AllocatableValue result, Value input) { 65 LIRInstruction inst = inner.createMove(result, input); 66 assert checkResult(inst, result, input); 67 return inst; 68 } 69 70 @Override 71 public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { 72 LIRInstruction inst = inner.createStackMove(result, input); 73 assert checkResult(inst, result, input); 74 return inst; 75 } 76 77 @Override 78 public LIRInstruction createLoad(AllocatableValue result, Constant input) { 79 LIRInstruction inst = inner.createLoad(result, input); 80 assert inst instanceof LoadConstantOp && checkResult(inst, result, null); 81 return inst; 82 } 83 84 /** Closure for {@link VerifyingMoveFactory#checkResult}. */ 85 @SuppressWarnings("unused") 86 private static class CheckClosure { 87 88 private final AllocatableValue result; 89 private final Value input; 90 91 private int tempCount = 0; 92 private int aliveCount = 0; 93 private int stateCount = 0; 94 private int inputCount = 0; 95 private int outputCount = 0; 96 97 CheckClosure(AllocatableValue result, Value input) { 98 this.result = result; 99 this.input = input; 100 } 101 102 void tempProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 103 assert false : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode); 104 tempCount++; 105 } 106 107 void stateProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 108 assert false : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode); 109 stateCount++; 110 } 111 112 void aliveProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 113 assert !isVariable(value) && flags.contains(OperandFlag.UNINITIALIZED) : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode); 114 aliveCount++; 115 } 116 117 void inputProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 118 assert value.equals(input) || isJavaConstant(value) : String.format("SpillMoveFactory: Instruction %s can only have %s as input, got %s", op, input, value); 119 inputCount++; 120 } 121 122 void outputProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 123 assert value.equals(result) : String.format("SpillMoveFactory: Instruction %s can only have %s as input, got %s", op, input, value); 124 outputCount++; 125 } 126 } 127 128 /** 129 * Checks that the instructions adheres to the contract of {@link MoveFactory}. 130 */ 131 private static boolean checkResult(LIRInstruction inst, AllocatableValue result, Value input) { 132 133 VerifyingMoveFactory.CheckClosure c = new CheckClosure(result, input); 134 inst.visitEachInput(c::inputProc); 135 inst.visitEachOutput(c::outputProc); 136 inst.visitEachAlive(c::aliveProc); 137 inst.visitEachTemp(c::tempProc); 138 inst.visitEachState(c::stateProc); 139 140 assert c.outputCount >= 1 : "no output produced" + inst; 141 assert c.stateCount == 0 : "SpillMoveFactory: instruction must not have a state: " + inst; 142 return true; 143 } 144 }