/* * 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.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.nodes.Node; abstract class SlowPathSerializeArgumentNode extends Node { public abstract Object execute(NativeArgumentBuffer buffer, LibFFIType type, Object value); @Specialization(guards = {"type == cachedType"}) @SuppressWarnings("unused") protected Object cacheType(NativeArgumentBuffer buffer, LibFFIType type, Object value, @Cached("type") LibFFIType cachedType, @Cached("cachedType.createSerializeArgumentNode()") SerializeArgumentNode serialize) { return serialize.execute(buffer, value); } @Specialization(replaces = "cacheType", guards = "needNoUnbox(value)") protected Object genericWithoutUnbox(NativeArgumentBuffer buffer, LibFFIType type, Object value) { slowPathSerialize(buffer, type, value); return null; } @Specialization(replaces = "cacheType", guards = {"value != null", "!checkIsPointer(isPointer, value)"}) protected Object genericWithUnbox(NativeArgumentBuffer buffer, LibFFIType type, TruffleObject value, @Cached("createIsNull()") Node isNull, @Cached("createUnbox()") Node unbox, @Cached("createIsPointer()") Node isPointer, @Cached("createAsPointer()") Node asPointer, @Cached("createRecursive()") SlowPathSerializeArgumentNode recursive) { Object prepared = type.slowpathPrepareArgument(value); if (prepared == null) { if (ForeignAccess.sendIsPointer(isPointer, value)) { try { long pointer = ForeignAccess.sendAsPointer(asPointer, value); return recursive.execute(buffer, type, pointer); } catch (UnsupportedMessageException ex) { CompilerDirectives.transferToInterpreter(); throw UnsupportedTypeException.raise(ex, new Object[]{value}); } } else if (!ForeignAccess.sendIsNull(isNull, value)) { Object unboxed; try { unboxed = ForeignAccess.sendUnbox(unbox, value); } catch (UnsupportedMessageException ex) { throw UnsupportedTypeException.raise(ex, new Object[]{value}); } return recursive.execute(buffer, type, unboxed); } } slowPathSerialize(buffer, type, prepared); return null; } protected static Node createIsNull() { return Message.IS_NULL.createNode(); } protected static Node createUnbox() { return Message.UNBOX.createNode(); } protected static SlowPathSerializeArgumentNode createRecursive() { return SlowPathSerializeArgumentNodeGen.create(); } 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 needNoUnbox(Object value) { return value == null || !(value instanceof TruffleObject); } @TruffleBoundary private static void slowPathSerialize(NativeArgumentBuffer buffer, LibFFIType type, Object value) { type.serialize(buffer, value); } }