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