/*
* 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 com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.interop.java.JavaInterop;
import com.oracle.truffle.api.nodes.Node;
abstract class SerializeArgumentNode extends Node {
abstract Object execute(NativeArgumentBuffer buffer, Object arg);
protected static Node createIsNull() {
return Message.IS_NULL.createNode();
}
protected static Node createIsPointer() {
return Message.IS_POINTER.createNode();
}
protected static Node createAsPointer() {
return Message.AS_POINTER.createNode();
}
protected static boolean checkIsPointer(Node isPointer, TruffleObject object) {
return ForeignAccess.sendIsPointer(isPointer, object);
}
protected static boolean checkNull(Node isNull, TruffleObject object) {
return ForeignAccess.sendIsNull(isNull, object);
}
abstract static class SerializeUnboxingArgumentNode extends SerializeArgumentNode {
protected final LibFFIType argType;
SerializeUnboxingArgumentNode(LibFFIType argType) {
this.argType = argType;
}
@SuppressWarnings("unused")
protected boolean isSpecialized(TruffleObject arg) {
return false;
}
@Specialization(guards = {"!isSpecialized(arg)", "checkNull(isNull, arg)"})
@SuppressWarnings("unused")
protected Object serializeNull(NativeArgumentBuffer buffer, TruffleObject arg,
@Cached("createIsNull()") Node isNull) {
argType.serialize(buffer, null);
return null;
}
@Specialization(guards = {"!isSpecialized(arg)", "checkIsPointer(isPointer, arg)"})
@SuppressWarnings("unused")
protected Object serializePointer(NativeArgumentBuffer buffer, TruffleObject arg,
@Cached("createIsPointer()") Node isPointer,
@Cached("createAsPointer()") Node asPointer,
@Cached("argType.createSerializeArgumentNode()") SerializeArgumentNode serialize) {
try {
long pointer = ForeignAccess.sendAsPointer(asPointer, arg);
serialize.execute(buffer, new NativePointer(pointer));
} catch (UnsupportedMessageException ex) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(ex, new Object[]{arg});
}
return null;
}
@Specialization(guards = {"!isSpecialized(arg)", "!checkNull(isNull, arg)", "!checkIsPointer(isPointer, arg)"})
@SuppressWarnings("unused")
protected Object serializeUnbox(NativeArgumentBuffer buffer, TruffleObject arg,
@Cached("createIsPointer()") Node isPointer,
@Cached("createIsNull()") Node isNull,
@Cached("createUnbox()") Node unbox,
@Cached("argType.createSerializeArgumentNode()") SerializeArgumentNode serialize) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, arg);
serialize.execute(buffer, unboxed);
} catch (UnsupportedMessageException ex) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(ex, new Object[]{arg});
}
return null;
}
protected static Node createUnbox() {
return Message.UNBOX.createNode();
}
}
abstract static class SerializeSimpleArgumentNode extends SerializeUnboxingArgumentNode {
SerializeSimpleArgumentNode(LibFFIType argType) {
super(argType);
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeByte(NativeArgumentBuffer buffer, byte arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeBoolean(NativeArgumentBuffer buffer, boolean arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeShort(NativeArgumentBuffer buffer, short arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeChar(NativeArgumentBuffer buffer, char arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeInt(NativeArgumentBuffer buffer, int arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeLong(NativeArgumentBuffer buffer, long arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeFloat(NativeArgumentBuffer buffer, float arg) {
argType.serialize(buffer, arg);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeDouble(NativeArgumentBuffer buffer, double arg) {
argType.serialize(buffer, arg);
return null;
}
}
abstract static class SerializePointerArgumentNode extends SerializeSimpleArgumentNode {
SerializePointerArgumentNode(LibFFIType type) {
super(type);
}
@Override
protected boolean isSpecialized(TruffleObject arg) {
return arg instanceof NativeString || arg instanceof NativePointer;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeNativeString(NativeArgumentBuffer buffer, NativeString string) {
argType.serialize(buffer, string);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeNativePointer(NativeArgumentBuffer buffer, NativePointer ptr) {
argType.serialize(buffer, ptr);
return null;
}
}
abstract static class SerializeStringArgumentNode extends SerializeUnboxingArgumentNode {
SerializeStringArgumentNode(LibFFIType type) {
super(type);
}
@Override
protected boolean isSpecialized(TruffleObject arg) {
return arg instanceof NativeString;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeString(NativeArgumentBuffer buffer, String string) {
argType.serialize(buffer, string);
return null;
}
@Specialization(insertBefore = "serializeNull")
protected Object serializeNativeString(NativeArgumentBuffer buffer, NativeString string) {
argType.serialize(buffer, string);
return null;
}
}
static class SerializeObjectArgumentNode extends SerializeArgumentNode {
private final LibFFIType argType;
SerializeObjectArgumentNode(LibFFIType argType) {
this.argType = argType;
}
@Override
Object execute(NativeArgumentBuffer buffer, Object object) {
argType.serialize(buffer, object);
return null;
}
}
abstract static class SerializeArrayArgumentNode extends SerializeArgumentNode {
final LibFFIType.ArrayType argType;
SerializeArrayArgumentNode(LibFFIType.ArrayType argType) {
this.argType = argType;
}
@Specialization(guards = "checkNull(isNull, arg)")
@SuppressWarnings("unused")
protected Object serializeNull(NativeArgumentBuffer buffer, TruffleObject arg,
@Cached("createIsNull()") Node isNull) {
argType.serialize(buffer, null);
return null;
}
@Specialization(guards = "isJavaObject(arrayType, object)")
protected Object serializeArray(NativeArgumentBuffer buffer, TruffleObject object, @Cached("argType.getArrayType(object)") Class<?> arrayType) {
argType.serialize(buffer, JavaInterop.asJavaObject(arrayType, object));
return null;
}
@Fallback
@SuppressWarnings("unused")
protected Object error(NativeArgumentBuffer buffer, Object object) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(new Object[]{object});
}
protected static boolean isJavaObject(Class<?> arrayType, TruffleObject object) {
if (arrayType != null) {
return JavaInterop.isJavaObject(arrayType, object);
} else {
return false;
}
}
}
abstract static class SerializeClosureArgumentNode extends SerializeArgumentNode {
private final LibFFIType argType;
private final LibFFISignature signature;
SerializeClosureArgumentNode(LibFFIType argType, LibFFISignature signature) {
this.argType = argType;
this.signature = signature;
}
protected boolean isSpecialized(TruffleObject arg) {
return arg instanceof NativePointer;
}
@Specialization
protected Object serializeNativePointer(NativeArgumentBuffer buffer, NativePointer object) {
argType.serialize(buffer, object);
return null;
}
@Specialization(limit = "5", guards = {"!isSpecialized(object)", "object == cachedObject"})
@SuppressWarnings("unused")
protected Object serializeCached(NativeArgumentBuffer buffer, TruffleObject object,
@Cached("object") TruffleObject cachedObject,
@Cached("createClosure(object)") LibFFIClosure closure) {
argType.serialize(buffer, closure);
return null;
}
@Specialization(guards = "!isSpecialized(object)")
protected Object serializeFallback(NativeArgumentBuffer buffer, TruffleObject object) {
argType.serialize(buffer, createClosure(object));
return null;
}
@TruffleBoundary
protected LibFFIClosure createClosure(TruffleObject object) {
return LibFFIClosure.create(signature, object);
}
}
}