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 jdk.vm.ci.code.CodeCacheProvider;
  27 import jdk.vm.ci.code.DebugInfo;
  28 import jdk.vm.ci.code.Register;
  29 import jdk.vm.ci.code.StackSlot;
  30 import jdk.vm.ci.code.site.Call;
  31 import jdk.vm.ci.code.site.ConstantReference;
  32 import jdk.vm.ci.code.site.DataPatch;
  33 import jdk.vm.ci.code.site.DataSectionReference;
  34 import jdk.vm.ci.code.site.Infopoint;
  35 import jdk.vm.ci.code.site.InfopointReason;
  36 import jdk.vm.ci.code.site.Mark;
  37 import jdk.vm.ci.code.site.Reference;
  38 import jdk.vm.ci.code.site.Site;
  39 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
  40 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
  41 import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
  42 import jdk.vm.ci.hotspot.HotSpotConstant;
  43 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
  44 import jdk.vm.ci.meta.Assumptions.Assumption;
  45 import jdk.vm.ci.meta.InvokeTarget;
  46 import jdk.vm.ci.meta.JavaKind;
  47 import jdk.vm.ci.meta.PlatformKind;
  48 import jdk.vm.ci.meta.ResolvedJavaMethod;
  49 import jdk.vm.ci.meta.VMConstant;
  50 import jdk.vm.ci.meta.ValueKind;
  51 
  52 import java.nio.ByteBuffer;
  53 import java.nio.ByteOrder;
  54 import java.util.ArrayList;
  55 import java.util.Arrays;
  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         growFrame(kind.getSizeInBytes());
 237         return StackSlot.get(new TestValueKind(kind), -curStackSlot, true);
 238     }
 239 
 240     protected void growFrame(int sizeInBytes) {
 241         curStackSlot += sizeInBytes;
 242         if (curStackSlot > frameSize) {
 243             int newFrameSize = curStackSlot;
 244             if (newFrameSize % stackAlignment != 0) {
 245                 newFrameSize += stackAlignment - (newFrameSize % stackAlignment);
 246             }
 247             emitGrowStack(newFrameSize - frameSize);
 248             frameSize = newFrameSize;
 249         }
 250     }
 251 
 252     protected void setDeoptRescueSlot(StackSlot deoptRescue) {
 253         this.deoptRescue = deoptRescue;
 254     }
 255 
 256     protected void recordCall(InvokeTarget target, int size, boolean direct, DebugInfo debugInfo) {
 257         sites.add(new Call(target, code.position(), size, direct, debugInfo));
 258     }
 259 
 260     protected void recordMark(Object id) {
 261         sites.add(new Mark(code.position(), id));
 262     }
 263 
 264     protected void recordImplicitException(DebugInfo info) {
 265         sites.add(new Infopoint(code.position(), info, InfopointReason.IMPLICIT_EXCEPTION));
 266     }
 267 
 268     protected void recordDataPatchInCode(Reference ref) {
 269         sites.add(new DataPatch(code.position(), ref));
 270     }
 271 
 272     protected void recordDataPatchInData(Reference ref) {
 273         dataPatches.add(new DataPatch(data.position(), ref));
 274     }
 275 
 276     public DataSectionReference emitDataItem(HotSpotConstant c) {
 277         DataSectionReference ref = new DataSectionReference();
 278         ref.setOffset(data.position());
 279 
 280         recordDataPatchInData(new ConstantReference((VMConstant) c));
 281         if (c.isCompressed()) {
 282             data.emitInt(0xDEADDEAD);
 283         } else {
 284             data.emitLong(0xDEADDEADDEADDEADL);
 285         }
 286 
 287         return ref;
 288     }
 289 
 290     public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) {
 291         int id = method.allocateCompileId(0);
 292         byte[] finishedCode = code.finish();
 293         Site[] finishedSites = sites.toArray(new Site[0]);
 294         byte[] finishedData = data.finish();
 295         DataPatch[] finishedDataPatches = dataPatches.toArray(new DataPatch[0]);
 296         return new HotSpotCompiledNmethod(method.getName(), finishedCode, finishedCode.length, finishedSites, new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], finishedData, 16,
 297                         finishedDataPatches, false, frameSize, deoptRescue, method, 0, id, 0L, false);
 298     }
 299 
 300     protected static class Buffer {
 301 
 302         private ByteBuffer data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder());
 303 
 304         private void ensureSize(int length) {
 305             if (length >= data.limit()) {
 306                 byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
 307                 ByteBuffer newData = ByteBuffer.wrap(newBuf);
 308                 newData.order(data.order());
 309                 newData.position(data.position());
 310                 data = newData;
 311             }
 312         }
 313 
 314         public int position() {
 315             return data.position();
 316         }
 317 
 318         public void emitByte(int b) {
 319             ensureSize(data.position() + 1);
 320             data.put((byte) (b & 0xFF));
 321         }
 322 
 323         public void emitShort(int b) {
 324             ensureSize(data.position() + 2);
 325             data.putShort((short) b);
 326         }
 327 
 328         public void emitInt(int b) {
 329             ensureSize(data.position() + 4);
 330             data.putInt(b);
 331         }
 332 
 333         public void emitLong(long b) {
 334             ensureSize(data.position() + 8);
 335             data.putLong(b);
 336         }
 337 
 338         public void emitFloat(float f) {
 339             ensureSize(data.position() + 4);
 340             data.putFloat(f);
 341         }
 342 
 343         public void align(int alignment) {
 344             int pos = data.position();
 345             int misaligned = pos % alignment;
 346             if (misaligned != 0) {
 347                 pos += alignment - misaligned;
 348                 data.position(pos);
 349             }
 350         }
 351 
 352         private byte[] finish() {
 353             return Arrays.copyOf(data.array(), data.position());
 354         }
 355     }
 356 }