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 }