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 }