mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8254231: Implementation of Foreign Linker API (Incubator)
Reviewed-by: coleenp, ihse, dholmes, vlivanov
This commit is contained in:
parent
53f38353e0
commit
0fb31dbf3a
212 changed files with 67390 additions and 179 deletions
|
@ -605,6 +605,10 @@ public abstract class MethodHandle implements Constable {
|
|||
/*non-public*/
|
||||
static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
|
||||
|
||||
/** TODO */
|
||||
@IntrinsicCandidate
|
||||
/*non-public*/ static native @PolymorphicSignature Object linkToNative(Object... args) throws Throwable;
|
||||
|
||||
/**
|
||||
* Performs a variable arity invocation, passing the arguments in the given array
|
||||
* to the method handle, as if via an inexact {@link #invoke invoke} from a call site
|
||||
|
|
|
@ -27,6 +27,7 @@ package java.lang.invoke;
|
|||
|
||||
import jdk.internal.access.JavaLangInvokeAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.invoke.NativeEntryPoint;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
|
@ -1774,6 +1775,11 @@ abstract class MethodHandleImpl {
|
|||
return VarHandles.makeMemoryAddressViewHandle(carrier, skipAlignmentMaskCheck, alignmentMask, order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle nativeMethodHandle(NativeEntryPoint nep, MethodHandle fallback) {
|
||||
return NativeMethodHandle.make(nep, fallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) {
|
||||
return VarHandles.filterValue(target, filterToTarget, filterFromTarget);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2020, 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
|
||||
|
@ -86,7 +86,8 @@ final class MethodTypeForm {
|
|||
LF_TF = 18, // tryFinally
|
||||
LF_LOOP = 19, // loop
|
||||
LF_INVSPECIAL_IFC = 20, // DMH invokeSpecial of (private) interface method
|
||||
LF_LIMIT = 21;
|
||||
LF_INVNATIVE = 21, // NMH invokeNative
|
||||
LF_LIMIT = 22;
|
||||
|
||||
/** Return the type corresponding uniquely (1-1) to this MT-form.
|
||||
* It might have any primitive returns or arguments, but will have no references except Object.
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 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 java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.invoke.NativeEntryPoint;
|
||||
|
||||
import static java.lang.invoke.LambdaForm.*;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.LM_TRUSTED;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
|
||||
import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
|
||||
/**
|
||||
* This class models a method handle to a native function. A native method handle is made up of a {@link NativeEntryPoint},
|
||||
* which is used to capture the characteristics of the native call (such as calling convention to be used,
|
||||
* or whether a native transition is required) and a <em>fallback</em> method handle, which can be used
|
||||
* when intrinsification of this method handle is not possible.
|
||||
*/
|
||||
/*non-public*/ class NativeMethodHandle extends MethodHandle {
|
||||
final NativeEntryPoint nep;
|
||||
final MethodHandle fallback;
|
||||
|
||||
private NativeMethodHandle(MethodType type, LambdaForm form, MethodHandle fallback, NativeEntryPoint nep) {
|
||||
super(type, form);
|
||||
this.fallback = fallback;
|
||||
this.nep = nep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new native method handle with given {@link NativeEntryPoint} and <em>fallback</em> method handle.
|
||||
*/
|
||||
public static MethodHandle make(NativeEntryPoint nep, MethodHandle fallback) {
|
||||
MethodType type = nep.type();
|
||||
if (!allTypesPrimitive(type))
|
||||
throw new IllegalArgumentException("Type must only contain primitives: " + type);
|
||||
|
||||
if (type != fallback.type())
|
||||
throw new IllegalArgumentException("Type of fallback must match");
|
||||
|
||||
LambdaForm lform = preparedLambdaForm(type);
|
||||
return new NativeMethodHandle(type, lform, fallback, nep);
|
||||
}
|
||||
|
||||
private static boolean allTypesPrimitive(MethodType type) {
|
||||
if (!type.returnType().isPrimitive())
|
||||
return false;
|
||||
|
||||
for (Class<?> pType : type.parameterArray()) {
|
||||
if (!pType.isPrimitive())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
|
||||
|
||||
private static LambdaForm preparedLambdaForm(MethodType mtype) {
|
||||
int id = MethodTypeForm.LF_INVNATIVE;
|
||||
mtype = mtype.basicType();
|
||||
LambdaForm lform = mtype.form().cachedLambdaForm(id);
|
||||
if (lform != null) return lform;
|
||||
lform = makePreparedLambdaForm(mtype);
|
||||
return mtype.form().setCachedLambdaForm(id, lform);
|
||||
}
|
||||
|
||||
private static LambdaForm makePreparedLambdaForm(MethodType mtype) {
|
||||
MethodType linkerType = mtype.insertParameterTypes(0, MethodHandle.class)
|
||||
.appendParameterTypes(Object.class);
|
||||
MemberName linker = new MemberName(MethodHandle.class, "linkToNative", linkerType, REF_invokeStatic);
|
||||
try {
|
||||
linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED, NoSuchMethodException.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
final int NMH_THIS = 0;
|
||||
final int ARG_BASE = 1;
|
||||
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
|
||||
int nameCursor = ARG_LIMIT;
|
||||
final int GET_FALLBACK = nameCursor++;
|
||||
final int GET_NEP = nameCursor++;
|
||||
final int LINKER_CALL = nameCursor++;
|
||||
LambdaForm.Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
|
||||
assert (names.length == nameCursor);
|
||||
names[GET_FALLBACK] = new LambdaForm.Name(Lazy.NF_internalFallback, names[NMH_THIS]);
|
||||
names[GET_NEP] = new LambdaForm.Name(Lazy.NF_internalNativeEntryPoint, names[NMH_THIS]);
|
||||
Object[] outArgs = new Object[linkerType.parameterCount()];
|
||||
// Need to pass fallback here so we can call it without destroying the receiver register!!
|
||||
outArgs[0] = names[GET_FALLBACK];
|
||||
System.arraycopy(names, ARG_BASE, outArgs, 1, mtype.parameterCount());
|
||||
outArgs[outArgs.length - 1] = names[GET_NEP];
|
||||
names[LINKER_CALL] = new LambdaForm.Name(linker, outArgs);
|
||||
LambdaForm lform = new LambdaForm(ARG_LIMIT, names, LAST_RESULT);
|
||||
// This is a tricky bit of code. Don't send it through the LF interpreter.
|
||||
lform.compileToBytecode();
|
||||
return lform;
|
||||
}
|
||||
|
||||
final
|
||||
@Override
|
||||
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
|
||||
assert (this.getClass() == NativeMethodHandle.class); // must override in subclasses
|
||||
return new NativeMethodHandle(mt, lf, fallback, nep);
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundMethodHandle rebind() {
|
||||
return BoundMethodHandle.makeReinvoker(this);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static Object internalNativeEntryPoint(Object mh) {
|
||||
return ((NativeMethodHandle)mh).nep;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static MethodHandle internalFallback(Object mh) {
|
||||
return ((NativeMethodHandle)mh).fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-initialized NamedFunctions for bootstrapping purposes.
|
||||
* Factored in an inner class to delay initialization until first usage.
|
||||
*/
|
||||
private static class Lazy {
|
||||
|
||||
static final NamedFunction
|
||||
NF_internalNativeEntryPoint;
|
||||
static final NamedFunction
|
||||
NF_internalFallback;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<NativeMethodHandle> THIS_CLASS = NativeMethodHandle.class;
|
||||
NamedFunction[] nfs = new NamedFunction[]{
|
||||
NF_internalNativeEntryPoint = new NamedFunction(
|
||||
THIS_CLASS.getDeclaredMethod("internalNativeEntryPoint", Object.class)),
|
||||
NF_internalFallback = new NamedFunction(
|
||||
THIS_CLASS.getDeclaredMethod("internalFallback", Object.class))
|
||||
};
|
||||
for (NamedFunction nf : nfs) {
|
||||
// Each nf must be statically invocable or we get tied up in our bootstraps.
|
||||
assert (InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
|
||||
nf.resolve();
|
||||
}
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue