diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/PrimExternalCallNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/PrimExternalCallNode.java index 6ddf68fd5..a3a1c4a3d 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/PrimExternalCallNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/PrimExternalCallNode.java @@ -1,30 +1,60 @@ package de.hpi.swa.trufflesqueak.nodes.plugins.ffi; -import java.util.HashMap; -import java.util.Map; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; - +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; +import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; import de.hpi.swa.trufflesqueak.util.NFIUtils; +import java.util.HashMap; +import java.util.Map; + public final class PrimExternalCallNode extends AbstractPrimitiveNode { - private final String moduleName; - private final String functionName; + private final Object moduleLibrary; + private final InteropLibrary moduleInteropLibrary; + private final Object functionSymbol; + private final InteropLibrary functionInteropLibrary; private final int numReceiverAndArguments; private static final Map loadedLibraries = new HashMap<>(); - public PrimExternalCallNode(final String moduleName, final String functionName, final int numReceiverAndArguments) { - this.moduleName = moduleName; - this.functionName = functionName; + public PrimExternalCallNode(final Object moduleLibrary, final InteropLibrary moduleInteropLibrary, final Object functionSymbol, final InteropLibrary functionInteropLibrary, + final int numReceiverAndArguments) { + this.moduleLibrary = moduleLibrary; + this.moduleInteropLibrary = moduleInteropLibrary; + this.functionSymbol = functionSymbol; + this.functionInteropLibrary = functionInteropLibrary; this.numReceiverAndArguments = numReceiverAndArguments; } + public static PrimExternalCallNode load(final String moduleName, final String functionName, final int numReceiverAndArguments) + throws UnsupportedMessageException, UnknownIdentifierException, UnsupportedTypeException, ArityException { + final SqueakImageContext context = SqueakImageContext.getSlow(); + final Object moduleLibrary = loadedLibraries.computeIfAbsent(moduleName, (String s) -> NFIUtils.loadLibrary(context, moduleName, "{ " + + // TODO, see below + // "initialiseModule():SINT64; " + + "setInterpreter(POINTER):SINT64; " + + // Currently not called, since plugins are never unloaded + // "shutdownModule():SINT64; " + + " }")); + if (moduleLibrary == null) { + return null; + } + final InteropLibrary moduleInteropLibrary = NFIUtils.getInteropLibrary(moduleLibrary); + + final Object functionSymbol = NFIUtils.loadMember(context, moduleLibrary, functionName, "():SINT64"); + final InteropLibrary functionInteropLibrary = NFIUtils.getInteropLibrary(functionSymbol); + + return new PrimExternalCallNode(moduleLibrary, moduleInteropLibrary, functionSymbol, functionInteropLibrary, numReceiverAndArguments); + } + @Override public Object execute(final VirtualFrame frame) { return doExternalCall(frame.materialize()); @@ -32,20 +62,12 @@ public Object execute(final VirtualFrame frame) { @Override public Object executeWithArguments(final VirtualFrame frame, final Object... receiverAndArguments) { - // arguments are handled via manipulation of the stack pointer, see above + // arguments are handled via manipulation of the stack pointer, see below return execute(frame); } @TruffleBoundary private Object doExternalCall(final MaterializedFrame frame) { - final Object moduleLibrary = loadedLibraries.computeIfAbsent(moduleName, (String s) -> NFIUtils.loadLibrary(getContext(), moduleName, "{ " + - // TODO, see below - // "initialiseModule():SINT64; " + - "setInterpreter(POINTER):SINT64; " + - // Currently not called, since plugins are never unloaded - // "shutdownModule():SINT64; " + - " }")); - final InteropLibrary moduleInteropLibrary = NFIUtils.getInteropLibrary(moduleLibrary); InterpreterProxy interpreterProxy = null; try { interpreterProxy = InterpreterProxy.instanceFor(getContext(), frame, numReceiverAndArguments); @@ -61,16 +83,12 @@ private Object doExternalCall(final MaterializedFrame frame) { moduleInteropLibrary.invokeMember(moduleLibrary, "setInterpreter", InterpreterProxy.getPointer()); - final Object functionSymbol = NFIUtils.loadMember(getContext(), moduleLibrary, functionName, "():SINT64"); - final InteropLibrary functionInteropLibrary = NFIUtils.getInteropLibrary(functionSymbol); // return value is unused, the actual return value is pushed onto the stack (see below) functionInteropLibrary.execute(functionSymbol); // The return value is pushed onto the stack by the plugin via the InterpreterProxy, but - // TruffleSqueak - // expects the return value to be returned by this function - // (AbstractSendNode.executeVoid). - // Pop the return value and return it. + // TruffleSqueak expects the return value to be returned by this function + // (AbstractSendNode.executeVoid). Pop the return value and return it. final Object returnValue = FrameAccess.getStackValue(frame, FrameAccess.getStackPointer(frame) - 1, FrameAccess.getNumArguments(frame)); FrameAccess.setStackPointer(frame, FrameAccess.getStackPointer(frame) - 1); return returnValue; diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/PrimitiveNodeFactory.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/PrimitiveNodeFactory.java index 85ca0a150..a432ab325 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/PrimitiveNodeFactory.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/PrimitiveNodeFactory.java @@ -7,6 +7,10 @@ package de.hpi.swa.trufflesqueak.nodes.primitives; import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; import de.hpi.swa.trufflesqueak.model.ArrayObject; import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; import de.hpi.swa.trufflesqueak.model.NativeObject; @@ -206,7 +210,12 @@ public static AbstractPrimitiveNode getOrCreateNamed(final CompiledCodeObject me if (moduleName.equals("SqueakFFIPrims")) { return null; } - return new PrimExternalCallNode(moduleName, functionName, numReceiverAndArguments); + try { + return PrimExternalCallNode.load(moduleName, functionName, numReceiverAndArguments); + } catch (UnsupportedMessageException | UnknownIdentifierException | ArityException | UnsupportedTypeException e) { + assert false : e.getMessage(); + return null; + } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/NFIUtils.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/NFIUtils.java index 3734d27c8..c0e2323ca 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/NFIUtils.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/NFIUtils.java @@ -1,7 +1,5 @@ package de.hpi.swa.trufflesqueak.util; -import java.io.File; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleFile; import com.oracle.truffle.api.interop.ArityException; @@ -13,10 +11,10 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.source.Source; - -import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; import de.hpi.swa.trufflesqueak.image.SqueakImageContext; +import java.io.File; + public final class NFIUtils { @ExportLibrary(InteropLibrary.class) @@ -155,7 +153,7 @@ public static Object loadLibrary(final SqueakImageContext context, final String final String libName = System.mapLibraryName(moduleName); final TruffleFile libPath = context.getHomePath().resolve("lib" + File.separatorChar + libName); if (!libPath.exists()) { - throw PrimitiveFailed.GENERIC_ERROR; + return null; } final String nfiCode = "load \"" + libPath.getAbsoluteFile().getPath() + "\" " + boundSymbols; return executeNFI(context, nfiCode);