view graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/nfi/HotSpotNativeFunctionInterface.java @ 23347:f868bd0c3f02

Make CallingConvention in HotSpotHostBackend instead of passing it in as a parameter to GraalCompiler.compile
author Christian Wimmer <christian.wimmer@oracle.com>
date Thu, 21 Jan 2016 10:35:29 -0800
parents 52f4acf6f365
children
line wrap: on
line source

/*
 * Copyright (c) 2014, 2016, 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.
 *
 * 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.graal.truffle.hotspot.nfi;

import static com.oracle.graal.truffle.hotspot.nfi.NativeCallStubGraphBuilder.getGraph;
import static jdk.vm.ci.common.UnsafeUtil.createCString;
import static jdk.vm.ci.common.UnsafeUtil.writeCString;

import java.lang.reflect.Field;

import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
import jdk.vm.ci.hotspot.HotSpotVMConfig;
import jdk.vm.ci.meta.DefaultProfilingInfo;
import jdk.vm.ci.meta.TriState;
import sun.misc.Unsafe;

import com.oracle.graal.code.CompilationResult;
import com.oracle.graal.compiler.GraalCompiler;
import com.oracle.graal.compiler.target.Backend;
import com.oracle.graal.debug.Debug;
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.hotspot.HotSpotCompiledCodeBuilder;
import com.oracle.graal.hotspot.meta.HotSpotProviders;
import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
import com.oracle.graal.lir.phases.LIRSuites;
import com.oracle.graal.nodes.StructuredGraph;
import com.oracle.graal.phases.OptimisticOptimizations;
import com.oracle.graal.phases.PhaseSuite;
import com.oracle.graal.phases.tiers.HighTierContext;
import com.oracle.graal.phases.tiers.Suites;
import com.oracle.nfi.api.NativeFunctionInterface;
import com.oracle.nfi.api.NativeFunctionPointer;
import com.oracle.nfi.api.NativeLibraryHandle;

public class HotSpotNativeFunctionInterface implements NativeFunctionInterface {

    private final HotSpotProviders providers;
    private final Backend backend;
    private final HotSpotNativeLibraryHandle rtldDefault;
    private final HotSpotNativeFunctionPointer libraryLoadFunctionPointer;
    private final HotSpotNativeFunctionPointer functionLookupFunctionPointer;
    private final RawNativeCallNodeFactory factory;

    private HotSpotNativeFunctionHandle libraryLookupFunctionHandle;
    private HotSpotNativeFunctionHandle dllLookupFunctionHandle;

    public HotSpotNativeFunctionInterface(HotSpotProviders providers, RawNativeCallNodeFactory factory, Backend backend, long dlopen, long dlsym, long rtldDefault) {
        this.rtldDefault = rtldDefault == HotSpotVMConfig.INVALID_RTLD_DEFAULT_HANDLE ? null : new HotSpotNativeLibraryHandle("RTLD_DEFAULT", rtldDefault);
        this.providers = providers;
        assert backend != null;
        this.backend = backend;
        this.factory = factory;
        this.libraryLoadFunctionPointer = new HotSpotNativeFunctionPointer(dlopen, "os::dll_load");
        this.functionLookupFunctionPointer = new HotSpotNativeFunctionPointer(dlsym, "os::dll_lookup");
    }

    @Override
    public HotSpotNativeLibraryHandle getLibraryHandle(String libPath) {
        if (libraryLookupFunctionHandle == null) {
            libraryLookupFunctionHandle = createHandle(libraryLoadFunctionPointer, long.class, long.class, long.class, int.class);
        }

        int ebufLen = 1024;
        // Allocating a single chunk for both the error message buffer and the
        // file name simplifies deallocation below.
        long buffer = UNSAFE.allocateMemory(ebufLen + libPath.length() + 1);
        long ebuf = buffer;
        long libPathCString = writeCString(UNSAFE, libPath, buffer + ebufLen);
        try {
            long handle = (long) libraryLookupFunctionHandle.call(libPathCString, ebuf, ebufLen);
            if (handle == 0) {
                throw new UnsatisfiedLinkError(libPath);
            }
            return new HotSpotNativeLibraryHandle(libPath, handle);
        } finally {
            UNSAFE.freeMemory(buffer);
        }
    }

    @Override
    public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class<?> returnType, Class<?>... argumentTypes) {
        HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, library, false);
        return createHandle(functionPointer, returnType, argumentTypes);
    }

    @Override
    public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraries, String name, Class<?> returnType, Class<?>... argumentTypes) {
        HotSpotNativeFunctionPointer functionPointer = null;
        for (NativeLibraryHandle libraryHandle : libraries) {
            functionPointer = lookupFunctionPointer(name, libraryHandle, false);
            if (functionPointer != null) {
                return createHandle(functionPointer, returnType, argumentTypes);
            }
        }
        // Fall back to default library path
        return getFunctionHandle(name, returnType, argumentTypes);
    }

    @Override
    public HotSpotNativeFunctionHandle getFunctionHandle(String name, Class<?> returnType, Class<?>... argumentTypes) {
        if (rtldDefault == null) {
            throw new UnsatisfiedLinkError(name);
        }
        return getFunctionHandle(rtldDefault, name, returnType, argumentTypes);
    }

    private HotSpotNativeFunctionPointer lookupFunctionPointer(String name, NativeLibraryHandle library, boolean linkageErrorIfMissing) {
        if (name == null || library == null) {
            throw new NullPointerException();
        }

        if (dllLookupFunctionHandle == null) {
            dllLookupFunctionHandle = createHandle(functionLookupFunctionPointer, long.class, long.class, long.class);
        }

        long nameCString = createCString(UNSAFE, name);
        try {
            long functionPointer = (long) dllLookupFunctionHandle.call(((HotSpotNativeLibraryHandle) library).value, nameCString);
            if (functionPointer == 0L) {
                if (!linkageErrorIfMissing) {
                    return null;
                }
                throw new UnsatisfiedLinkError(name);
            }
            return new HotSpotNativeFunctionPointer(functionPointer, name);
        } finally {
            UNSAFE.freeMemory(nameCString);
        }
    }

    @Override
    public HotSpotNativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
        if (!(functionPointer instanceof HotSpotNativeFunctionPointer)) {
            throw new UnsatisfiedLinkError(functionPointer.getName());
        }
        return createHandle(functionPointer, returnType, argumentTypes);
    }

    private HotSpotNativeFunctionHandle createHandle(NativeFunctionPointer functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
        HotSpotNativeFunctionPointer hs = (HotSpotNativeFunctionPointer) functionPointer;
        if (hs != null) {
            InstalledCode code = installNativeFunctionStub(hs.value, returnType, argumentTypes);
            return new HotSpotNativeFunctionHandle(code, hs.name, argumentTypes);
        } else {
            return null;
        }
    }

    /**
     * Creates and installs a stub for calling a native function.
     */
    @SuppressWarnings("try")
    private InstalledCode installNativeFunctionStub(long functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
        StructuredGraph g = getGraph(providers, factory, functionPointer, returnType, argumentTypes);
        Suites suites = providers.getSuites().getDefaultSuites();
        LIRSuites lirSuites = providers.getSuites().getDefaultLIRSuites();
        PhaseSuite<HighTierContext> phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
        CompilationResult compResult = GraalCompiler.compileGraph(g, g.method(), providers, backend, phaseSuite, OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites,
                        lirSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
        InstalledCode installedCode;
        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) {
            HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(g.method(), null, compResult);
            installedCode = providers.getCodeCache().addCode(g.method(), compiledCode, null, null);
        } catch (Throwable e) {
            throw Debug.handle(e);
        }
        return installedCode;
    }

    @Override
    public HotSpotNativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraries, String name) {
        for (NativeLibraryHandle libraryHandle : libraries) {
            HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, libraryHandle, false);
            if (functionPointer != null) {
                return functionPointer;
            }
        }
        // Fall back to default library path
        if (rtldDefault == null) {
            throw new UnsatisfiedLinkError(name);
        }
        return lookupFunctionPointer(name, rtldDefault, false);
    }

    public boolean isDefaultLibrarySearchSupported() {
        return rtldDefault != null;
    }

    @Override
    public NativeFunctionPointer getNativeFunctionPointerFromRawValue(long rawValue) {
        return new HotSpotNativeFunctionPointer(rawValue, null);
    }

    private static final Unsafe UNSAFE = initUnsafe();

    private static Unsafe initUnsafe() {
        try {
            return Unsafe.getUnsafe();
        } catch (SecurityException se) {
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                return (Unsafe) theUnsafe.get(Unsafe.class);
            } catch (Exception e) {
                throw new RuntimeException("exception while trying to get Unsafe", e);
            }
        }
    }
}