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 }