1 /* 2 * Copyright (c) 2015, 2016, 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 24 package jdk.vm.ci.code.test; 25 26 import java.nio.ByteBuffer; 27 import java.nio.ByteOrder; 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 31 import jdk.vm.ci.code.CodeCacheProvider; 32 import jdk.vm.ci.code.DebugInfo; 33 import jdk.vm.ci.code.Register; 34 import jdk.vm.ci.code.StackSlot; 35 import jdk.vm.ci.code.site.Call; 36 import jdk.vm.ci.code.site.ConstantReference; 37 import jdk.vm.ci.code.site.DataPatch; 38 import jdk.vm.ci.code.site.DataSectionReference; 39 import jdk.vm.ci.code.site.Infopoint; 40 import jdk.vm.ci.code.site.InfopointReason; 41 import jdk.vm.ci.code.site.Mark; 42 import jdk.vm.ci.code.site.Reference; 43 import jdk.vm.ci.code.site.Site; 44 import jdk.vm.ci.hotspot.HotSpotCompiledCode; 45 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; 46 import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; 47 import jdk.vm.ci.hotspot.HotSpotConstant; 48 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 49 import jdk.vm.ci.meta.Assumptions.Assumption; 50 import jdk.vm.ci.meta.InvokeTarget; 51 import jdk.vm.ci.meta.JavaKind; 52 import jdk.vm.ci.meta.PlatformKind; 53 import jdk.vm.ci.meta.ResolvedJavaMethod; 54 import jdk.vm.ci.meta.ValueKind; 55 import jdk.vm.ci.meta.VMConstant; 56 57 /** 58 * Simple assembler used by the code installation tests. 59 */ 60 public abstract class TestAssembler { 61 62 /** 63 * Emit the method prologue code (e.g. building the new stack frame). 64 */ 65 public abstract void emitPrologue(); 66 67 /** 68 * Emit the method epilogue code (e.g. the deopt handler). 69 */ 70 public abstract void emitEpilogue(); 71 72 /** 73 * Emit code to grow the stack frame. 74 * 75 * @param size the size in bytes that the stack should grow 76 */ 77 public abstract void emitGrowStack(int size); 78 79 /** 80 * Get the register containing the first 32-bit integer argument. 81 */ 82 public abstract Register emitIntArg0(); 83 84 /** 85 * Get the register containing the second 32-bit integer argument. 86 */ 87 public abstract Register emitIntArg1(); 88 89 /** 90 * Emit code to add two 32-bit integer registers. May reuse one of the argument registers. 91 */ 92 public abstract Register emitIntAdd(Register a, Register b); 93 94 /** 95 * Emit code to load a constant 32-bit integer to a register. 96 */ 97 public abstract Register emitLoadInt(int value); 98 99 /** 100 * Emit code to load a constant 64-bit integer to a register. 101 */ 102 public abstract Register emitLoadLong(long value); 103 104 /** 105 * Emit code to load a constant single-precision float to a register. 106 */ 107 public abstract Register emitLoadFloat(float value); 108 109 /** 110 * Emit code to load a constant oop or metaspace pointer to a register. The pointer may be wide 111 * or narrow, depending on {@link HotSpotConstant#isCompressed() c.isCompressed()}. 112 */ 113 public abstract Register emitLoadPointer(HotSpotConstant c); 114 115 /** 116 * Emit code to load a wide pointer from the {@link HotSpotCompiledCode#dataSection} to a 117 * register. 118 */ 119 public abstract Register emitLoadPointer(DataSectionReference ref); 120 121 /** 122 * Emit code to load a narrow pointer from the {@link HotSpotCompiledCode#dataSection} to a 123 * register. 124 */ 125 public abstract Register emitLoadNarrowPointer(DataSectionReference ref); 126 127 /** 128 * Emit code to load a (wide) pointer from a memory location to a register. 129 */ 130 public abstract Register emitLoadPointer(Register base, int offset); 131 132 /** 133 * Emit code to store a 32-bit integer from a register to a new stack slot. 134 */ 135 public abstract StackSlot emitIntToStack(Register a); 136 137 /** 138 * Emit code to store a 64-bit integer from a register to a new stack slot. 139 */ 140 public abstract StackSlot emitLongToStack(Register a); 141 142 /** 143 * Emit code to store a single-precision float from a register to a new stack slot. 144 */ 145 public abstract StackSlot emitFloatToStack(Register a); 146 147 /** 148 * Emit code to store a wide pointer from a register to a new stack slot. 149 */ 150 public abstract StackSlot emitPointerToStack(Register a); 151 152 /** 153 * Emit code to store a narrow pointer from a register to a new stack slot. 154 */ 155 public abstract StackSlot emitNarrowPointerToStack(Register a); 156 157 /** 158 * Emit code to uncompress a narrow pointer. The input pointer is guaranteed to be non-null. 159 */ 160 public abstract Register emitUncompressPointer(Register compressed, long base, int shift); 161 162 /** 163 * Emit code to return from a function, returning a 32-bit integer. 164 */ 165 public abstract void emitIntRet(Register a); 166 167 /** 168 * Emit code to return from a function, returning a wide oop pointer. 169 */ 170 public abstract void emitPointerRet(Register a); 171 172 /** 173 * Emit code that traps, forcing a deoptimization. 174 */ 175 public abstract void emitTrap(DebugInfo info); 176 177 public final ValueKind<?> narrowOopKind; 178 179 protected final Buffer code; 180 protected final Buffer data; 181 private final ArrayList<Site> sites; 182 private final ArrayList<DataPatch> dataPatches; 183 184 protected final CodeCacheProvider codeCache; 185 protected final TestHotSpotVMConfig config; 186 187 private final Register[] registers; 188 private int nextRegister; 189 190 protected int frameSize; 191 private int stackAlignment; 192 private int curStackSlot; 193 194 private StackSlot deoptRescue; 195 196 private static class TestValueKind extends ValueKind<TestValueKind> { 197 198 TestValueKind(PlatformKind kind) { 199 super(kind); 200 } 201 202 @Override 203 public TestValueKind changeType(PlatformKind kind) { 204 return new TestValueKind(kind); 205 } 206 } 207 208 protected TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config, int initialFrameSize, int stackAlignment, PlatformKind narrowOopKind, Register... registers) { 209 this.narrowOopKind = new TestValueKind(narrowOopKind); 210 211 this.code = new Buffer(); 212 this.data = new Buffer(); 213 this.sites = new ArrayList<>(); 214 this.dataPatches = new ArrayList<>(); 215 216 this.codeCache = codeCache; 217 this.config = config; 218 219 this.registers = registers; 220 this.nextRegister = 0; 221 222 this.frameSize = initialFrameSize; 223 this.stackAlignment = stackAlignment; 224 this.curStackSlot = initialFrameSize; 225 } 226 227 public ValueKind<?> getValueKind(JavaKind kind) { 228 return new TestValueKind(codeCache.getTarget().arch.getPlatformKind(kind)); 229 } 230 231 protected Register newRegister() { 232 return registers[nextRegister++]; 233 } 234 235 protected StackSlot newStackSlot(PlatformKind kind) { 236 curStackSlot += kind.getSizeInBytes(); 237 if (curStackSlot > frameSize) { 238 int newFrameSize = curStackSlot; 239 if (newFrameSize % stackAlignment != 0) { 240 newFrameSize += stackAlignment - (newFrameSize % stackAlignment); 241 } 242 emitGrowStack(newFrameSize - frameSize); 243 frameSize = newFrameSize; 244 } 245 return StackSlot.get(new TestValueKind(kind), -curStackSlot, true); 246 } 247 248 protected void setDeoptRescueSlot(StackSlot deoptRescue) { 249 this.deoptRescue = deoptRescue; 250 } 251 252 protected void recordCall(InvokeTarget target, int size, boolean direct, DebugInfo debugInfo) { 253 sites.add(new Call(target, code.position(), size, direct, debugInfo)); 254 } 255 256 protected void recordMark(Object id) { 257 sites.add(new Mark(code.position(), id)); 258 } 259 260 protected void recordImplicitException(DebugInfo info) { 261 sites.add(new Infopoint(code.position(), info, InfopointReason.IMPLICIT_EXCEPTION)); 262 } 263 264 protected void recordDataPatchInCode(Reference ref) { 265 sites.add(new DataPatch(code.position(), ref)); 266 } 267 268 protected void recordDataPatchInData(Reference ref) { 269 dataPatches.add(new DataPatch(data.position(), ref)); 270 } 271 272 public DataSectionReference emitDataItem(HotSpotConstant c) { 273 DataSectionReference ref = new DataSectionReference(); 274 ref.setOffset(data.position()); 275 276 recordDataPatchInData(new ConstantReference((VMConstant) c)); 277 if (c.isCompressed()) { 278 data.emitInt(0xDEADDEAD); 279 } else { 280 data.emitLong(0xDEADDEADDEADDEADL); 281 } 282 283 return ref; 284 } 285 286 public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) { 287 int id = method.allocateCompileId(0); 288 byte[] finishedCode = code.finish(); 289 Site[] finishedSites = sites.toArray(new Site[0]); 290 byte[] finishedData = data.finish(); 291 DataPatch[] finishedDataPatches = dataPatches.toArray(new DataPatch[0]); 292 return new HotSpotCompiledNmethod(method.getName(), finishedCode, finishedCode.length, finishedSites, new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], finishedData, 16, 293 finishedDataPatches, false, frameSize, deoptRescue, method, 0, id, 0L, false); 294 } 295 296 protected static class Buffer { 297 298 private ByteBuffer data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder()); 299 300 private void ensureSize(int length) { 301 if (length >= data.limit()) { 302 byte[] newBuf = Arrays.copyOf(data.array(), length * 4); 303 ByteBuffer newData = ByteBuffer.wrap(newBuf); 304 newData.order(data.order()); 305 newData.position(data.position()); 306 data = newData; 307 } 308 } 309 310 public int position() { 311 return data.position(); 312 } 313 314 public void emitByte(int b) { 315 ensureSize(data.position() + 1); 316 data.put((byte) (b & 0xFF)); 317 } 318 319 public void emitShort(int b) { 320 ensureSize(data.position() + 2); 321 data.putShort((short) b); 322 } 323 324 public void emitInt(int b) { 325 ensureSize(data.position() + 4); 326 data.putInt(b); 327 } 328 329 public void emitLong(long b) { 330 ensureSize(data.position() + 8); 331 data.putLong(b); 332 } 333 334 public void emitFloat(float f) { 335 ensureSize(data.position() + 4); 336 data.putFloat(f); 337 } 338 339 public void align(int alignment) { 340 int pos = data.position(); 341 int misaligned = pos % alignment; 342 if (misaligned != 0) { 343 pos += alignment - misaligned; 344 data.position(pos); 345 } 346 } 347 348 private byte[] finish() { 349 return Arrays.copyOf(data.array(), data.position()); 350 } 351 } 352 }