java.lang.invoke.NativeMethodHandle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qbicc-rt-java.base Show documentation
Show all versions of qbicc-rt-java.base Show documentation
The Qbicc builder for the java.base JDK module
/*
* Copyright (c) 2020, 2021, 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 fallback 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 fallback 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: " + type + " != " + fallback.type());
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 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);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy