/* * Copyright (c) 2009, 2012, 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.sun.max.vm.actor.member; import static com.sun.max.vm.jni.JniFunctions.JxxFunctionsLogger.*; import com.sun.max.annotate.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.compiler.target.*; import com.sun.max.vm.jni.*; import com.sun.max.vm.jni.JniFunctions.LogOperations; /** * A native function represents a {@linkplain #makeSymbol() symbol} associated with a {@linkplain #classMethodActor() * method} that can be {@linkplain #link() linked} at runtime to produce a native machine code pointer. */ public final class NativeFunction { private final ClassMethodActor classMethodActor; private String symbol; private Address address = Address.zero(); /** * The stub generated for calling this native function. */ private TargetMethod stub; /** * The safepoint position associated with the native call. */ private int nativeCallSafepointPos; public Address address() { return address; } public NativeFunction(ClassMethodActor classMethodActor) { this.classMethodActor = classMethodActor; } public ClassMethodActor classMethodActor() { return classMethodActor; } /** * Gets the address of the safepoint position associated with the call to this native function from within its native stub. */ public CodePointer nativeCallSafepointAddress() { return stub.codeAt(nativeCallSafepointPos); } /** * Sets the safepoint position associated with the call to this native function (from within its native stub). */ public void setCallSite(TargetMethod stub, int safepointPos) { assert this.stub == null : "cannot have more than one stub per native method"; this.stub = stub; this.nativeCallSafepointPos = safepointPos; } /** * Gets the native symbol derived from the method this native function implements. * * Only the first call to this method can cause allocation. Subsequent calls return the value cached by the * first call. */ public String makeSymbol() { if (symbol == null) { final ClassMethodActor m = classMethodActor; symbol = m.isCFunction() ? m.name.toString() : Mangle.mangleMethod(m.holder().typeDescriptor, m.name.toString(), m.descriptor(), true); } return symbol; } /** * Gets the native function pointer for this native function, linking it first if necessary. * * There's no need to synchronize this method - it's fine for multiple threads to each link the native function in * the case where's there is a race as the result of resolution will always be the same value. * * ATTENTION: do not declare this synchronized - it is called in the primordial phase. * * @throws UnsatisfiedLinkError if the native function cannot be found */ @INLINE public Address link() throws UnsatisfiedLinkError { if (address.isZero()) { return link0(); } return address; } @NEVER_INLINE public Address link0() throws UnsatisfiedLinkError { address = DynamicLinker.lookup(classMethodActor, makeSymbol()).asAddress(); if (JniFunctions.logger.enabled()) { JniFunctions.logger.log(LogOperations.DynamicLink.ordinal(), LINK_ENTRY, MethodID.fromMethodActor(classMethodActor), address); } // this tracing is in response to -verbose:jni if (!MaxineVM.isPrimordialOrPristine()) { if (NativeInterfaces.verbose()) { Log.println("[Dynamic-linking native method " + classMethodActor.holder().name + "." + classMethodActor.name + " = " + address.toHexString() + "]"); } } return address; } /** * Determines if the native function pointer has been linked. */ public boolean isLinked() { return !address.isZero(); } /** * Sets (or clears) the machine code address for this native function. */ public void setAddress(Address address) { this.address = address; if (JniFunctions.logger.enabled()) { JniFunctions.logger.log(LogOperations.RegisterNativeMethod.ordinal(), REGISTER_ENTRY, MethodID.fromMethodActor(classMethodActor), address); } // this tracing is in response to -verbose:jni if (!MaxineVM.isPrimordialOrPristine()) { if (NativeInterfaces.verbose()) { Log.println("[" + (address.isZero() ? "Unregistering" : "Registering") + " JNI native method " + classMethodActor.holder().name + "." + classMethodActor.name + "]"); } } } }