1 /*
   2  * Copyright (c) 2009, 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;
  24 
  25 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
  26 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
  27 import static jdk.vm.ci.code.ValueUtil.isConstantJavaValue;
  28 import static jdk.vm.ci.code.ValueUtil.isIllegalJavaValue;
  29 import static jdk.vm.ci.code.ValueUtil.isVirtualObject;
  30 
  31 import java.util.Arrays;
  32 import java.util.EnumSet;
  33 
  34 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
  35 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
  36 import org.graalvm.compiler.lir.framemap.FrameMap;
  37 import org.graalvm.compiler.lir.util.IndexedValueMap;
  38 
  39 import jdk.vm.ci.code.BytecodeFrame;
  40 import jdk.vm.ci.code.DebugInfo;
  41 import jdk.vm.ci.code.StackLockValue;
  42 import jdk.vm.ci.code.VirtualObject;
  43 import jdk.vm.ci.meta.AllocatableValue;
  44 import jdk.vm.ci.meta.JavaValue;
  45 import jdk.vm.ci.meta.Value;
  46 
  47 /**
  48  * This class represents garbage collection and deoptimization information attached to a LIR
  49  * instruction.
  50  */
  51 public class LIRFrameState {
  52 
  53     public final BytecodeFrame topFrame;
  54     private final VirtualObject[] virtualObjects;
  55     public final LabelRef exceptionEdge;
  56     protected DebugInfo debugInfo;
  57 
  58     private IndexedValueMap liveBasePointers;
  59 
  60     public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
  61         this.topFrame = topFrame;
  62         this.virtualObjects = virtualObjects;
  63         this.exceptionEdge = exceptionEdge;
  64     }
  65 
  66     public boolean hasDebugInfo() {
  67         return debugInfo != null;
  68     }
  69 
  70     public DebugInfo debugInfo() {
  71         assert debugInfo != null : "debug info not allocated yet";
  72         return debugInfo;
  73     }
  74 
  75     /**
  76      * Iterates the frame state and calls the {@link InstructionValueProcedure} for every variable.
  77      *
  78      * @param proc The procedure called for variables.
  79      */
  80     public void forEachState(LIRInstruction inst, InstructionValueProcedure proc) {
  81         for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
  82             processValues(inst, cur.values, proc);
  83         }
  84         if (virtualObjects != null) {
  85             for (VirtualObject obj : virtualObjects) {
  86                 processValues(inst, obj.getValues(), proc);
  87             }
  88         }
  89         if (liveBasePointers != null) {
  90             liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
  91         }
  92     }
  93 
  94     /**
  95      * Iterates the frame state and calls the {@link InstructionValueConsumer} for every variable.
  96      *
  97      * @param proc The procedure called for variables.
  98      */
  99     public void visitEachState(LIRInstruction inst, InstructionValueConsumer proc) {
 100         for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
 101             visitValues(inst, cur.values, proc);
 102         }
 103         if (virtualObjects != null) {
 104             for (VirtualObject obj : virtualObjects) {
 105                 visitValues(inst, obj.getValues(), proc);
 106             }
 107         }
 108         if (liveBasePointers != null) {
 109             liveBasePointers.visitEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
 110         }
 111     }
 112 
 113     /**
 114      * We filter out constant and illegal values ourself before calling the procedure, so
 115      * {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set.
 116      */
 117     protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
 118 
 119     protected void processValues(LIRInstruction inst, JavaValue[] values, InstructionValueProcedure proc) {
 120         for (int i = 0; i < values.length; i++) {
 121             JavaValue value = values[i];
 122             if (isIllegalJavaValue(value)) {
 123                 continue;
 124             }
 125             if (value instanceof AllocatableValue) {
 126                 AllocatableValue allocatable = (AllocatableValue) value;
 127                 Value result = proc.doValue(inst, allocatable, OperandMode.ALIVE, STATE_FLAGS);
 128                 if (!allocatable.identityEquals(result)) {
 129                     values[i] = (JavaValue) result;
 130                 }
 131             } else if (value instanceof StackLockValue) {
 132                 StackLockValue monitor = (StackLockValue) value;
 133                 JavaValue owner = monitor.getOwner();
 134                 if (owner instanceof AllocatableValue) {
 135                     monitor.setOwner((JavaValue) proc.doValue(inst, (AllocatableValue) owner, OperandMode.ALIVE, STATE_FLAGS));
 136                 }
 137                 Value slot = monitor.getSlot();
 138                 if (isVirtualStackSlot(slot)) {
 139                     monitor.setSlot(asAllocatableValue(proc.doValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS)));
 140                 }
 141             } else {
 142                 assert unprocessed(value);
 143             }
 144         }
 145     }
 146 
 147     protected void visitValues(LIRInstruction inst, JavaValue[] values, InstructionValueConsumer proc) {
 148         for (int i = 0; i < values.length; i++) {
 149             JavaValue value = values[i];
 150             if (isIllegalJavaValue(value)) {
 151                 continue;
 152             } else if (value instanceof AllocatableValue) {
 153                 proc.visitValue(inst, (AllocatableValue) value, OperandMode.ALIVE, STATE_FLAGS);
 154             } else if (value instanceof StackLockValue) {
 155                 StackLockValue monitor = (StackLockValue) value;
 156                 JavaValue owner = monitor.getOwner();
 157                 if (owner instanceof AllocatableValue) {
 158                     proc.visitValue(inst, (AllocatableValue) owner, OperandMode.ALIVE, STATE_FLAGS);
 159                 }
 160                 Value slot = monitor.getSlot();
 161                 if (isVirtualStackSlot(slot)) {
 162                     proc.visitValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS);
 163                 }
 164             } else {
 165                 assert unprocessed(value);
 166             }
 167         }
 168     }
 169 
 170     private boolean unprocessed(JavaValue value) {
 171         if (isIllegalJavaValue(value)) {
 172             // Ignore dead local variables.
 173             return true;
 174         } else if (isConstantJavaValue(value)) {
 175             // Ignore constants, the register allocator does not need to see them.
 176             return true;
 177         } else if (isVirtualObject(value)) {
 178             assert Arrays.asList(virtualObjects).contains(value);
 179             return true;
 180         } else {
 181             return false;
 182         }
 183     }
 184 
 185     /**
 186      * Called by the register allocator to initialize the frame state.
 187      *
 188      * @param frameMap The frame map.
 189      * @param canHaveRegisters True if there can be any register map entries.
 190      */
 191     public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
 192         debugInfo = new DebugInfo(topFrame, virtualObjects);
 193     }
 194 
 195     public IndexedValueMap getLiveBasePointers() {
 196         return liveBasePointers;
 197     }
 198 
 199     public void setLiveBasePointers(IndexedValueMap liveBasePointers) {
 200         this.liveBasePointers = liveBasePointers;
 201     }
 202 
 203     @Override
 204     public String toString() {
 205         return debugInfo != null ? debugInfo.toString() : topFrame != null ? topFrame.toString() : "<empty>";
 206     }
 207 }