/* * Copyright (c) 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.oracle.truffle.nfi; import java.nio.ByteBuffer; import java.nio.ByteOrder; abstract class NativeArgumentBuffer { final int[] patches; final Object[] objects; private int objIdx; enum TypeTag { // keep this in sync with the code in com.oracle.truffle.nfi.native/src/internal.h OBJECT, STRING, CLOSURE, BOOLEAN_ARRAY, BYTE_ARRAY, CHAR_ARRAY, SHORT_ARRAY, INT_ARRAY, LONG_ARRAY, FLOAT_ARRAY, DOUBLE_ARRAY; int encode(int offset) { int encoded = (offset << 4) | (ordinal() & 0x0F); assert getTag(encoded) == this && getOffset(encoded) == offset : "error encoding type tag, maybe offset is too big?"; return encoded; } static TypeTag getTag(int encoded) { return values()[encoded & 0x0F]; } static int getOffset(int encoded) { return encoded >>> 4; } } static final class Array extends NativeArgumentBuffer { private static final Class<? extends ByteBuffer> heapByteBuffer = ByteBuffer.wrap(new byte[0]).getClass(); final byte[] prim; private final ByteBuffer primBuffer; Array(int primSize, int objCount) { super(objCount); this.prim = new byte[primSize]; this.primBuffer = ByteBuffer.wrap(prim).order(ByteOrder.nativeOrder()); } @Override protected ByteBuffer getPrimBuffer() { return heapByteBuffer.cast(primBuffer); } } static final class Direct extends NativeArgumentBuffer { private static final Class<? extends ByteBuffer> directByteBuffer = ByteBuffer.allocateDirect(0).getClass(); private final ByteBuffer primBuffer; Direct(ByteBuffer primBuffer, int objCount) { super(objCount); this.primBuffer = directByteBuffer.cast(primBuffer).slice().order(ByteOrder.nativeOrder()); } @Override protected ByteBuffer getPrimBuffer() { return directByteBuffer.cast(primBuffer); } } int getPatchCount() { return objIdx; } private NativeArgumentBuffer(int objCount) { if (objCount > 0) { patches = new int[objCount]; objects = new Object[objCount]; } else { patches = null; objects = null; } objIdx = 0; } public void align(int alignment) { assert alignment >= 1; int pos = getPrimBuffer().position(); if (pos % alignment != 0) { pos += alignment - (pos % alignment); getPrimBuffer().position(pos); } } protected abstract ByteBuffer getPrimBuffer(); public byte getInt8() { return getPrimBuffer().get(); } public void putInt8(byte b) { getPrimBuffer().put(b); } public short getInt16() { return getPrimBuffer().getShort(); } public void putInt16(short s) { getPrimBuffer().putShort(s); } public int getInt32() { return getPrimBuffer().getInt(); } public void putInt32(int i) { getPrimBuffer().putInt(i); } public long getInt64() { return getPrimBuffer().getLong(); } public void putInt64(long l) { getPrimBuffer().putLong(l); } public float getFloat() { return getPrimBuffer().getFloat(); } public void putFloat(float f) { getPrimBuffer().putFloat(f); } public double getDouble() { return getPrimBuffer().getDouble(); } public void putDouble(double d) { getPrimBuffer().putDouble(d); } public long getPointer(int size) { switch (size) { case 4: return getInt32(); case 8: return getInt64(); default: throw new AssertionError("unexpected pointer size " + size); } } public void putPointer(long ptr, int size) { switch (size) { case 4: putInt32((int) ptr); break; case 8: putInt64(ptr); break; default: throw new AssertionError("unexpected pointer size " + size); } } public Object getObject(int size) { int pos = getPrimBuffer().position(); getPrimBuffer().position(pos + size); throw new AssertionError("passing TruffleObject from native back to Truffle not yet supported"); } public void putObject(TypeTag tag, Object o, int size) { int pos = getPrimBuffer().position(); int idx = objIdx++; patches[idx] = tag.encode(pos); objects[idx] = o; getPrimBuffer().position(pos + size); } }