hotspot/test/compiler/jvmci/code/TestAssembler.java
author rschatz
Wed, 03 Feb 2016 12:16:44 +0100
changeset 35823 59a847ec6ee3
parent 35591 35ab7c6816e9
child 35844 8a1952516600
permissions -rw-r--r--
8146608: [JVMCI] DebugInfo Tests on DeoptimizeALot runs fails in assert(_pc == *pc_addr || pc == *pc_addr) frame::patch_pc() /frame_x86.cpp:285 Reviewed-by: twisti

/*
 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package compiler.jvmci.code;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;

import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.DataSectionReference;
import jdk.vm.ci.code.site.Infopoint;
import jdk.vm.ci.code.site.InfopointReason;
import jdk.vm.ci.code.site.Reference;
import jdk.vm.ci.code.site.Site;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
import jdk.vm.ci.hotspot.HotSpotConstant;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.Assumptions.Assumption;
import jdk.vm.ci.meta.LIRKind;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.VMConstant;

/**
 * Simple assembler used by the code installation tests.
 */
public abstract class TestAssembler {

    /**
     * Emit the method prologue code (e.g. building the new stack frame).
     */
    public abstract void emitPrologue();

    /**
     * Emit code to grow the stack frame.
     *
     * @param size the size in bytes that the stack should grow
     */
    public abstract void emitGrowStack(int size);

    /**
     * Get the register containing the first 32-bit integer argument.
     */
    public abstract Register emitIntArg0();

    /**
     * Get the register containing the second 32-bit integer argument.
     */
    public abstract Register emitIntArg1();

    /**
     * Emit code to add two 32-bit integer registers. May reuse one of the argument registers.
     */
    public abstract Register emitIntAdd(Register a, Register b);

    /**
     * Emit code to load a constant 32-bit integer to a register.
     */
    public abstract Register emitLoadInt(int value);

    /**
     * Emit code to load a constant 64-bit integer to a register.
     */
    public abstract Register emitLoadLong(long value);

    /**
     * Emit code to load a constant single-precision float to a register.
     */
    public abstract Register emitLoadFloat(float value);

    /**
     * Emit code to load a constant oop or metaspace pointer to a register. The pointer may be wide
     * or narrow, depending on {@link HotSpotConstant#isCompressed() c.isCompressed()}.
     */
    public abstract Register emitLoadPointer(HotSpotConstant c);

    /**
     * Emit code to load a wide pointer from the {@link HotSpotCompiledCode#dataSection} to a
     * register.
     */
    public abstract Register emitLoadPointer(DataSectionReference ref);

    /**
     * Emit code to load a narrow pointer from the {@link HotSpotCompiledCode#dataSection} to a
     * register.
     */
    public abstract Register emitLoadNarrowPointer(DataSectionReference ref);

    /**
     * Emit code to load a (wide) pointer from a memory location to a register.
     */
    public abstract Register emitLoadPointer(Register base, int offset);

    /**
     * Emit code to store a 32-bit integer from a register to a new stack slot.
     */
    public abstract StackSlot emitIntToStack(Register a);

    /**
     * Emit code to store a 64-bit integer from a register to a new stack slot.
     */
    public abstract StackSlot emitLongToStack(Register a);

    /**
     * Emit code to store a single-precision float from a register to a new stack slot.
     */
    public abstract StackSlot emitFloatToStack(Register a);

    /**
     * Emit code to store a wide pointer from a register to a new stack slot.
     */
    public abstract StackSlot emitPointerToStack(Register a);

    /**
     * Emit code to store a narrow pointer from a register to a new stack slot.
     */
    public abstract StackSlot emitNarrowPointerToStack(Register a);

    /**
     * Emit code to uncompress a narrow pointer. The input pointer is guaranteed to be non-null.
     */
    public abstract Register emitUncompressPointer(Register compressed, long base, int shift);

    /**
     * Emit code to return from a function, returning a 32-bit integer.
     */
    public abstract void emitIntRet(Register a);

    /**
     * Emit code to return from a function, returning a wide oop pointer.
     */
    public abstract void emitPointerRet(Register a);

    /**
     * Emit code that traps, forcing a deoptimization.
     */
    public abstract void emitTrap(DebugInfo info);

    public final LIRKind narrowOopKind;

    protected final Buffer code;
    protected final Buffer data;
    private final ArrayList<Site> sites;
    private final ArrayList<DataPatch> dataPatches;

    protected final CodeCacheProvider codeCache;

    private final Register[] registers;
    private int nextRegister;

    protected int frameSize;
    private int stackAlignment;
    private int curStackSlot;

    private StackSlot deoptRescue;

    protected TestAssembler(CodeCacheProvider codeCache, int initialFrameSize, int stackAlignment, PlatformKind narrowOopKind, Register... registers) {
        this.narrowOopKind = LIRKind.reference(narrowOopKind);

        this.code = new Buffer();
        this.data = new Buffer();
        this.sites = new ArrayList<>();
        this.dataPatches = new ArrayList<>();

        this.codeCache = codeCache;

        this.registers = registers;
        this.nextRegister = 0;

        this.frameSize = initialFrameSize;
        this.stackAlignment = stackAlignment;
        this.curStackSlot = initialFrameSize;
    }

    protected Register newRegister() {
        return registers[nextRegister++];
    }

    protected StackSlot newStackSlot(LIRKind kind) {
        curStackSlot += kind.getPlatformKind().getSizeInBytes();
        if (curStackSlot > frameSize) {
            int newFrameSize = curStackSlot;
            if (newFrameSize % stackAlignment != 0) {
                newFrameSize += stackAlignment - (newFrameSize % stackAlignment);
            }
            emitGrowStack(newFrameSize - frameSize);
            frameSize = newFrameSize;
        }
        return StackSlot.get(kind, -curStackSlot, true);
    }

    protected void setDeoptRescueSlot(StackSlot deoptRescue) {
        this.deoptRescue = deoptRescue;
    }

    protected void recordImplicitException(DebugInfo info) {
        sites.add(new Infopoint(code.position(), info, InfopointReason.IMPLICIT_EXCEPTION));
    }

    protected void recordDataPatchInCode(Reference ref) {
        sites.add(new DataPatch(code.position(), ref));
    }

    protected void recordDataPatchInData(Reference ref) {
        dataPatches.add(new DataPatch(data.position(), ref));
    }

    public DataSectionReference emitDataItem(HotSpotConstant c) {
        DataSectionReference ref = new DataSectionReference();
        ref.setOffset(data.position());

        recordDataPatchInData(new ConstantReference((VMConstant) c));
        if (c.isCompressed()) {
            data.emitInt(0xDEADDEAD);
        } else {
            data.emitLong(0xDEADDEADDEADDEADL);
        }

        return ref;
    }

    public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) {
        int id = method.allocateCompileId(0);
        byte[] finishedCode = code.finish();
        Site[] finishedSites = sites.toArray(new Site[0]);
        byte[] finishedData = data.finish();
        DataPatch[] finishedDataPatches = dataPatches.toArray(new DataPatch[0]);
        return new HotSpotCompiledNmethod(method.getName(), finishedCode, finishedCode.length, finishedSites, new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], finishedData, 16,
                        finishedDataPatches, false, frameSize, deoptRescue, method, 0, id, 0L, false);
    }

    protected static class Buffer {

        private ByteBuffer data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder());

        private void ensureSize(int length) {
            if (length >= data.limit()) {
                byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
                ByteBuffer newData = ByteBuffer.wrap(newBuf);
                newData.order(data.order());
                newData.position(data.position());
                data = newData;
            }
        }

        public int position() {
            return data.position();
        }

        public void emitByte(int b) {
            ensureSize(data.position() + 1);
            data.put((byte) (b & 0xFF));
        }

        public void emitShort(int b) {
            ensureSize(data.position() + 2);
            data.putShort((short) b);
        }

        public void emitInt(int b) {
            ensureSize(data.position() + 4);
            data.putInt(b);
        }

        public void emitLong(long b) {
            ensureSize(data.position() + 8);
            data.putLong(b);
        }

        public void emitFloat(float f) {
            ensureSize(data.position() + 4);
            data.putFloat(f);
        }

        public void align(int alignment) {
            int pos = data.position();
            int misaligned = pos % alignment;
            if (misaligned != 0) {
                pos += alignment - misaligned;
                data.position(pos);
            }
        }

        private byte[] finish() {
            return Arrays.copyOf(data.array(), data.position());
        }
    }
}