001/*
002 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.truffle.hotspot.nfi;
024
025import jdk.internal.jvmci.code.*;
026import jdk.internal.jvmci.code.CallingConvention.*;
027import com.oracle.graal.debug.*;
028import com.oracle.graal.debug.Debug.*;
029import jdk.internal.jvmci.hotspot.*;
030import jdk.internal.jvmci.meta.*;
031import static com.oracle.graal.truffle.hotspot.nfi.NativeCallStubGraphBuilder.*;
032import static jdk.internal.jvmci.code.CodeUtil.*;
033import static jdk.internal.jvmci.common.UnsafeAccess.*;
034
035import com.oracle.graal.compiler.*;
036import com.oracle.graal.compiler.target.*;
037import com.oracle.graal.hotspot.meta.*;
038import com.oracle.graal.lir.asm.*;
039import com.oracle.graal.lir.phases.*;
040import com.oracle.graal.nodes.*;
041import com.oracle.graal.phases.*;
042import com.oracle.graal.phases.tiers.*;
043import com.oracle.nfi.api.*;
044
045public class HotSpotNativeFunctionInterface implements NativeFunctionInterface {
046
047    private final HotSpotProviders providers;
048    private final Backend backend;
049    private final HotSpotNativeLibraryHandle rtldDefault;
050    private final HotSpotNativeFunctionPointer libraryLoadFunctionPointer;
051    private final HotSpotNativeFunctionPointer functionLookupFunctionPointer;
052    private final RawNativeCallNodeFactory factory;
053
054    private HotSpotNativeFunctionHandle libraryLookupFunctionHandle;
055    private HotSpotNativeFunctionHandle dllLookupFunctionHandle;
056
057    public HotSpotNativeFunctionInterface(HotSpotProviders providers, RawNativeCallNodeFactory factory, Backend backend, long dlopen, long dlsym, long rtldDefault) {
058        this.rtldDefault = rtldDefault == HotSpotVMConfig.INVALID_RTLD_DEFAULT_HANDLE ? null : new HotSpotNativeLibraryHandle("RTLD_DEFAULT", rtldDefault);
059        this.providers = providers;
060        assert backend != null;
061        this.backend = backend;
062        this.factory = factory;
063        this.libraryLoadFunctionPointer = new HotSpotNativeFunctionPointer(dlopen, "os::dll_load");
064        this.functionLookupFunctionPointer = new HotSpotNativeFunctionPointer(dlsym, "os::dll_lookup");
065    }
066
067    @Override
068    public HotSpotNativeLibraryHandle getLibraryHandle(String libPath) {
069        if (libraryLookupFunctionHandle == null) {
070            libraryLookupFunctionHandle = createHandle(libraryLoadFunctionPointer, long.class, long.class, long.class, int.class);
071        }
072
073        int ebufLen = 1024;
074        // Allocating a single chunk for both the error message buffer and the
075        // file name simplifies deallocation below.
076        long buffer = unsafe.allocateMemory(ebufLen + libPath.length() + 1);
077        long ebuf = buffer;
078        long libPathCString = writeCString(libPath, buffer + ebufLen);
079        try {
080            long handle = (long) libraryLookupFunctionHandle.call(libPathCString, ebuf, ebufLen);
081            if (handle == 0) {
082                throw new UnsatisfiedLinkError(libPath);
083            }
084            return new HotSpotNativeLibraryHandle(libPath, handle);
085        } finally {
086            unsafe.freeMemory(buffer);
087        }
088    }
089
090    @Override
091    public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class<?> returnType, Class<?>... argumentTypes) {
092        HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, library, false);
093        return createHandle(functionPointer, returnType, argumentTypes);
094    }
095
096    @Override
097    public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraries, String name, Class<?> returnType, Class<?>... argumentTypes) {
098        HotSpotNativeFunctionPointer functionPointer = null;
099        for (NativeLibraryHandle libraryHandle : libraries) {
100            functionPointer = lookupFunctionPointer(name, libraryHandle, false);
101            if (functionPointer != null) {
102                return createHandle(functionPointer, returnType, argumentTypes);
103            }
104        }
105        // Fall back to default library path
106        return getFunctionHandle(name, returnType, argumentTypes);
107    }
108
109    @Override
110    public HotSpotNativeFunctionHandle getFunctionHandle(String name, Class<?> returnType, Class<?>... argumentTypes) {
111        if (rtldDefault == null) {
112            throw new UnsatisfiedLinkError(name);
113        }
114        return getFunctionHandle(rtldDefault, name, returnType, argumentTypes);
115    }
116
117    private HotSpotNativeFunctionPointer lookupFunctionPointer(String name, NativeLibraryHandle library, boolean linkageErrorIfMissing) {
118        if (name == null || library == null) {
119            throw new NullPointerException();
120        }
121
122        if (dllLookupFunctionHandle == null) {
123            dllLookupFunctionHandle = createHandle(functionLookupFunctionPointer, long.class, long.class, long.class);
124        }
125        long nameCString = createCString(name);
126        try {
127            long functionPointer = (long) dllLookupFunctionHandle.call(((HotSpotNativeLibraryHandle) library).value, nameCString);
128            if (functionPointer == 0L) {
129                if (!linkageErrorIfMissing) {
130                    return null;
131                }
132                throw new UnsatisfiedLinkError(name);
133            }
134            return new HotSpotNativeFunctionPointer(functionPointer, name);
135        } finally {
136            unsafe.freeMemory(nameCString);
137        }
138    }
139
140    @Override
141    public HotSpotNativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
142        if (!(functionPointer instanceof HotSpotNativeFunctionPointer)) {
143            throw new UnsatisfiedLinkError(functionPointer.getName());
144        }
145        return createHandle(functionPointer, returnType, argumentTypes);
146    }
147
148    private HotSpotNativeFunctionHandle createHandle(NativeFunctionPointer functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
149        HotSpotNativeFunctionPointer hs = (HotSpotNativeFunctionPointer) functionPointer;
150        if (hs != null) {
151            InstalledCode code = installNativeFunctionStub(hs.value, returnType, argumentTypes);
152            return new HotSpotNativeFunctionHandle(code, hs.name, argumentTypes);
153        } else {
154            return null;
155        }
156    }
157
158    /**
159     * Creates and installs a stub for calling a native function.
160     */
161    private InstalledCode installNativeFunctionStub(long functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
162        StructuredGraph g = getGraph(providers, factory, functionPointer, returnType, argumentTypes);
163        Suites suites = providers.getSuites().createSuites();
164        LIRSuites lirSuites = providers.getSuites().createLIRSuites();
165        PhaseSuite<HighTierContext> phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
166        CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false);
167        CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), phaseSuite, OptimisticOptimizations.ALL,
168                        DefaultProfilingInfo.get(TriState.UNKNOWN), suites, lirSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
169        InstalledCode installedCode;
170        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) {
171            installedCode = providers.getCodeCache().addMethod(g.method(), compResult, null, null);
172        } catch (Throwable e) {
173            throw Debug.handle(e);
174        }
175        return installedCode;
176    }
177
178    @Override
179    public HotSpotNativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraries, String name) {
180        for (NativeLibraryHandle libraryHandle : libraries) {
181            HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, libraryHandle, false);
182            if (functionPointer != null) {
183                return functionPointer;
184            }
185        }
186        // Fall back to default library path
187        if (rtldDefault == null) {
188            throw new UnsatisfiedLinkError(name);
189        }
190        return lookupFunctionPointer(name, rtldDefault, false);
191    }
192
193    public boolean isDefaultLibrarySearchSupported() {
194        return rtldDefault != null;
195    }
196
197    @Override
198    public NativeFunctionPointer getNativeFunctionPointerFromRawValue(long rawValue) {
199        return new HotSpotNativeFunctionPointer(rawValue, null);
200    }
201}