/*
* Copyright (c) 2007, 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.jni;
import static com.sun.max.vm.classfile.ErrorContext.*;
import static com.sun.max.vm.jni.JniFunctions.*;
import java.lang.reflect.*;
import java.nio.*;
import com.sun.max.*;
import com.sun.max.annotate.*;
import com.sun.max.lang.*;
import com.sun.max.memory.*;
import com.sun.max.program.*;
import com.sun.max.unsafe.*;
import com.sun.max.util.*;
import com.sun.max.vm.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.classfile.*;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.heap.*;
import com.sun.max.vm.jdk.*;
import com.sun.max.vm.layout.*;
import com.sun.max.vm.monitor.*;
import com.sun.max.vm.object.*;
import com.sun.max.vm.reference.*;
import com.sun.max.vm.runtime.*;
import com.sun.max.vm.thread.*;
import com.sun.max.vm.type.*;
import com.sun.max.vm.value.*;
/**
* Template from which (parts of) {@link JniFunctions} is generated. The static initializer of
* {@link JniFunctions} includes a call to {@link JniFunctionsGenerator#generate(boolean, Class, Class)}
* to double-check that the source is up-to-date with respect to any edits made to this class.
*
* All the methods annotated by {@link VM_ENTRY_POINT} appear in the exact same order as specified in
* jni.h. In addition, any methods annotated by {@link VM_ENTRY_POINT} that are declared
* {@code native} have implementations in jni.c and their entries in the JNI function table
* are initialized in jni.c.
*/
@HOSTED_ONLY
public final class JniFunctionsSource {
private JniFunctionsSource() {
}
@VM_ENTRY_POINT
private static native void reserved0();
@VM_ENTRY_POINT
private static native void reserved1();
@VM_ENTRY_POINT
private static native void reserved2();
@VM_ENTRY_POINT
private static native void reserved3();
// Checkstyle: stop method name check
@VM_ENTRY_POINT
private static native int GetVersion(Pointer env);
private static final Class[] defineClassParameterTypes = {String.class, byte[].class, int.class, int.class};
@VM_ENTRY_POINT
private static JniHandle DefineClass(Pointer env, Pointer slashifiedName, JniHandle classLoader, Pointer buffer, int length) throws ClassFormatError {
final byte[] bytes = new byte[length];
Memory.readBytes(buffer, length, bytes);
try {
// TODO: find out whether already dottified class names should be rejected by this function
String name = dottify(CString.utf8ToJava(slashifiedName));
ClassLoader cl = (ClassLoader) classLoader.unhand();
if (cl == null) {
cl = BootClassLoader.BOOT_CLASS_LOADER;
}
Class javaClass = ClassfileReader.defineClassActor(name, cl, bytes, 0, bytes.length, null, null, false).toJava();
return JniHandles.createLocalHandle(javaClass);
} catch (Utf8Exception utf8Exception) {
throw classFormatError("Invalid class name");
}
}
private static Class findClass(ClassLoader classLoader, String slashifiedName) throws ClassNotFoundException {
if (slashifiedName.startsWith("[")) {
TypeDescriptor descriptor = JavaTypeDescriptor.parseTypeDescriptor(slashifiedName);
return descriptor.resolve(classLoader).toJava();
}
return classLoader.loadClass(dottify(slashifiedName));
}
@VM_ENTRY_POINT
private static JniHandle FindClass(Pointer env, Pointer name) throws ClassNotFoundException {
String className;
try {
className = CString.utf8ToJava(name);
} catch (Utf8Exception utf8Exception) {
throw new ClassNotFoundException();
}
// Skip our frame
Class caller = JDK_sun_reflect_Reflection.getCallerClassForFindClass(1);
ClassLoader classLoader = caller == null ? ClassLoader.getSystemClassLoader() : ClassActor.fromJava(caller).classLoader;
final Class javaClass = findClass(classLoader, className);
Snippets.makeClassInitialized(ClassActor.fromJava(javaClass));
return JniHandles.createLocalHandle(javaClass);
}
@VM_ENTRY_POINT
private static MethodID FromReflectedMethod(Pointer env, JniHandle reflectedMethod) {
final MethodActor methodActor = MethodActor.fromJava((Method) reflectedMethod.unhand());
return MethodID.fromMethodActor(methodActor);
}
@VM_ENTRY_POINT
private static FieldID FromReflectedField(Pointer env, JniHandle field) {
final FieldActor fieldActor = FieldActor.fromJava((Field) field.unhand());
return FieldID.fromFieldActor(fieldActor);
}
private static Method ToReflectedMethod(MethodID methodID, boolean isStatic) throws NoSuchMethodException {
final MethodActor methodActor = MethodID.toMethodActor(methodID);
if (methodActor == null || methodActor.isStatic() != isStatic) {
throw new NoSuchMethodException();
}
return methodActor.toJava();
}
@VM_ENTRY_POINT
private static JniHandle ToReflectedMethod(Pointer env, JniHandle javaClass, MethodID methodID, boolean isStatic) throws NoSuchMethodException {
return JniHandles.createLocalHandle(ToReflectedMethod(methodID, isStatic));
}
@VM_ENTRY_POINT
private static JniHandle GetSuperclass(Pointer env, JniHandle subType) {
return JniHandles.createLocalHandle(((Class) subType.unhand()).getSuperclass());
}
@VM_ENTRY_POINT
private static boolean IsAssignableFrom(Pointer env, JniHandle subType, JniHandle superType) {
return ClassActor.fromJava((Class) superType.unhand()).isAssignableFrom(ClassActor.fromJava((Class) subType.unhand()));
}
@VM_ENTRY_POINT
private static JniHandle ToReflectedField(Pointer env, JniHandle javaClass, FieldID fieldID, boolean isStatic) {
final FieldActor fieldActor = FieldID.toFieldActor(fieldID);
if (fieldActor == null || fieldActor.isStatic() != isStatic) {
throw new NoSuchFieldError();
}
return JniHandles.createLocalHandle(fieldActor.toJava());
}
@VM_ENTRY_POINT
private static int Throw(Pointer env, JniHandle throwable) {
VmThread.fromJniEnv(env).setJniException((Throwable) throwable.unhand());
return JNI_OK;
}
@VM_ENTRY_POINT
private static int ThrowNew(Pointer env, JniHandle throwableClass, Pointer message) throws Throwable {
final Class<Class<? extends Throwable>> type = null;
Constructor<? extends Throwable> constructor = null;
Class[] parameterTypes = null;
if (message.isZero()) {
parameterTypes = new Class[0];
} else {
parameterTypes = new Class[1];
parameterTypes[0] = String.class;
}
constructor = Utils.cast(type, throwableClass.unhand()).getConstructor(parameterTypes);
Throwable throwable = message.isZero() ? constructor.newInstance() : constructor.newInstance(CString.utf8ToJava(message));
VmThread.fromJniEnv(env).setJniException(throwable);
return JNI_OK;
}
@VM_ENTRY_POINT
private static JniHandle ExceptionOccurred(Pointer env) {
return JniHandles.createLocalHandle(VmThread.fromJniEnv(env).jniException());
}
@VM_ENTRY_POINT
private static void ExceptionDescribe(Pointer env) {
final Throwable exception = VmThread.fromJniEnv(env).jniException();
if (exception != null) {
exception.printStackTrace();
}
}
@VM_ENTRY_POINT
private static void ExceptionClear(Pointer env) {
VmThread.fromJniEnv(env).setJniException(null);
}
@VM_ENTRY_POINT
private static void FatalError(Pointer env, Pointer message) {
try {
FatalError.unexpected(CString.utf8ToJava(message));
} catch (Utf8Exception utf8Exception) {
FatalError.unexpected("fatal error with UTF8 error in message");
}
}
private static int PushLocalFrame0(Pointer env, int capacity) {
JniHandles.pushLocalFrame(capacity);
return JNI_OK;
}
@VM_ENTRY_POINT
private static int PushLocalFrame(Pointer env, int capacity) {
JniHandles.pushLocalFrame(capacity);
return JNI_OK;
}
@VM_ENTRY_POINT
private static JniHandle PopLocalFrame(Pointer env, JniHandle res) {
return JniHandles.popLocalFrame(res);
}
@VM_ENTRY_POINT
private static JniHandle NewGlobalRef(Pointer env, JniHandle handle) {
return JniHandles.createGlobalHandle(handle.unhand());
}
@VM_ENTRY_POINT
private static void DeleteGlobalRef(Pointer env, JniHandle handle) {
JniHandles.destroyGlobalHandle(handle);
}
@VM_ENTRY_POINT
private static void DeleteLocalRef(Pointer env, JniHandle handle) {
JniHandles.destroyLocalHandle(handle);
}
@VM_ENTRY_POINT
private static boolean IsSameObject(Pointer env, JniHandle object1, JniHandle object2) {
return object1.unhand() == object2.unhand();
}
@VM_ENTRY_POINT
private static JniHandle NewLocalRef(Pointer env, JniHandle object) {
return JniHandles.createLocalHandle(object.unhand());
}
@VM_ENTRY_POINT
private static int EnsureLocalCapacity(Pointer env, int capacity) {
// If this call fails, it will be with an OutOfMemoryError which will be
// set as the pending exception for the current thread
JniHandles.ensureLocalHandleCapacity(capacity);
return JNI_OK;
}
private static Object allocObject(Class javaClass) throws InstantiationException {
final ClassActor classActor = ClassActor.fromJava(javaClass);
if (classActor.isTupleClass() && !classActor.isAbstract()) {
return Heap.createTuple(classActor.dynamicHub());
}
throw new InstantiationException();
}
@VM_ENTRY_POINT
private static JniHandle AllocObject(Pointer env, JniHandle javaClass) throws InstantiationException {
return JniHandles.createLocalHandle(allocObject((Class) javaClass.unhand()));
}
@VM_ENTRY_POINT
private static native JniHandle NewObject(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native JniHandle NewObjectV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static JniHandle NewObjectA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
final ClassActor classActor = ClassActor.fromJava((Class) javaClass.unhand());
if (!(classActor instanceof TupleClassActor)) {
throw new NoSuchMethodException();
}
final TupleClassActor tupleClassActor = (TupleClassActor) classActor;
final MethodActor methodActor = MethodID.toMethodActor(methodID);
if (methodActor == null || !methodActor.isInitializer()) {
throw new NoSuchMethodException();
}
final VirtualMethodActor virtualMethodActor = tupleClassActor.findLocalVirtualMethodActor(methodActor.name, methodActor.descriptor());
if (virtualMethodActor == null) {
throw new NoSuchMethodException();
}
final SignatureDescriptor signature = virtualMethodActor.descriptor();
final Value[] argumentValues = new Value[signature.numberOfParameters()];
copyJValueArrayToValueArray(arguments, signature, argumentValues, 0);
logReflectiveInvocation(virtualMethodActor);
return JniHandles.createLocalHandle(virtualMethodActor.invokeConstructor(argumentValues).asObject());
}
@VM_ENTRY_POINT
private static JniHandle GetObjectClass(Pointer env, JniHandle object) {
final Class javaClass = object.unhand().getClass();
return JniHandles.createLocalHandle(javaClass);
}
@VM_ENTRY_POINT
private static boolean IsInstanceOf(Pointer env, JniHandle object, JniHandle javaType) {
return ((Class) javaType.unhand()).isInstance(object.unhand());
}
@VM_ENTRY_POINT
private static MethodID GetMethodID(Pointer env, JniHandle javaType, Pointer nameCString, Pointer descriptorCString) {
final ClassActor classActor = ClassActor.fromJava((Class) javaType.unhand());
Snippets.makeClassInitialized(classActor);
try {
final Utf8Constant name = SymbolTable.lookupSymbol(CString.utf8ToJava(nameCString));
final SignatureDescriptor descriptor = SignatureDescriptor.lookup(CString.utf8ToJava(descriptorCString));
if (name == null || descriptor == null) {
// The class should have been loaded (we have an instance of the class
// passed in) so the name and signature should already be in their respective canonicalization
// tables. If they're not there, the method doesn't exist.
throw new NoSuchMethodError();
}
final MethodActor methodActor = classActor.findMethodActor(name, descriptor);
if (methodActor == null || methodActor.isStatic()) {
throw new NoSuchMethodError();
}
return MethodID.fromMethodActor(methodActor);
} catch (Utf8Exception utf8Exception) {
throw new NoSuchMethodError();
}
}
@VM_ENTRY_POINT
private static native JniHandle CallObjectMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native JniHandle CallObjectMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer vaList);
/**
* Copies arguments from the native jvalue array at {@code arguments} into {@code argumentValues}. The number of
* arguments copied is equal to {@code signature.getNumberOfParameters()}.
*
* @param signature describes the kind of each parameter
* @param startIndex the index in {@code argumentValues} to start writing at
*/
private static void copyJValueArrayToValueArray(Pointer arguments, SignatureDescriptor signature, Value[] argumentValues, int startIndex) {
Pointer a = arguments;
// This is equivalent to sizeof(jvalue) in C and gives us the size of each slot in a jvalue array.
// Note that the size of the data in any given array element will be *at most* this size.
final int jvalueSize = Kind.LONG.width.numberOfBytes;
for (int i = 0; i < signature.numberOfParameters(); i++) {
final int j = startIndex + i;
switch (signature.parameterDescriptorAt(i).toKind().asEnum) {
case BYTE: {
argumentValues[j] = ByteValue.from((byte) a.readInt(0));
break;
}
case BOOLEAN: {
argumentValues[j] = (a.readInt(0) != 0) ? BooleanValue.TRUE : BooleanValue.FALSE;
break;
}
case SHORT: {
argumentValues[j] = ShortValue.from((short) a.readInt(0));
break;
}
case CHAR: {
argumentValues[j] = CharValue.from((char) a.readInt(0));
break;
}
case INT: {
argumentValues[j] = IntValue.from(a.readInt(0));
break;
}
case FLOAT: {
argumentValues[j] = FloatValue.from(a.readFloat(0));
break;
}
case LONG: {
argumentValues[j] = LongValue.from(a.readLong(0));
break;
}
case DOUBLE: {
argumentValues[j] = DoubleValue.from(a.readDouble(0));
break;
}
case WORD: {
argumentValues[j] = new WordValue(a.readWord(0));
break;
}
case REFERENCE: {
final JniHandle jniHandle = a.readWord(0).asJniHandle();
argumentValues[j] = ReferenceValue.from(jniHandle.unhand());
break;
}
default: {
throw ProgramError.unexpected();
}
}
a = a.plus(jvalueSize);
}
}
private static Value checkResult(Kind expectedReturnKind, final MethodActor methodActor, Value result) {
if (expectedReturnKind != result.kind()) {
Value zero = expectedReturnKind.zeroValue();
if (CheckJNI) {
Log.println("JNI warning: returning " + zero + " for " + expectedReturnKind + " call to " + methodActor);
}
result = zero;
}
return result;
}
private static Value CallValueMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments, Kind expectedReturnKind) throws Exception {
final MethodActor methodActor = MethodID.toMethodActor(methodID);
if (methodActor == null) {
throw new NoSuchMethodException("Invalid method ID " + methodID.asAddress().toLong());
}
if (methodActor.isStatic()) {
throw new NoSuchMethodException(methodActor.toString() + " is static");
}
if (methodActor.isInitializer()) {
throw new NoSuchMethodException(methodActor.toString() + " is an initializer");
}
final MethodActor selectedMethod;
Object receiver = object.unhand();
ClassActor holder = ObjectAccess.readClassActor(receiver);
if (!methodActor.holder().isAssignableFrom(holder)) {
throw new NoSuchMethodException(holder + " is not an instance of " + methodActor.holder());
}
selectedMethod = (MethodActor) holder.resolveMethodImpl(methodActor);
final SignatureDescriptor signature = selectedMethod.descriptor();
final Value[] argumentValues = new Value[1 + signature.numberOfParameters()];
argumentValues[0] = ReferenceValue.from(object.unhand());
copyJValueArrayToValueArray(arguments, signature, argumentValues, 1);
logReflectiveInvocation(selectedMethod);
return checkResult(expectedReturnKind, methodActor, selectedMethod.invoke(argumentValues));
}
@VM_ENTRY_POINT
private static JniHandle CallObjectMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return JniHandles.createLocalHandle(CallValueMethodA(env, object, methodID, arguments, Kind.REFERENCE).asObject());
}
@VM_ENTRY_POINT
private static native boolean CallBooleanMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native boolean CallBooleanMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer vaList);
@VM_ENTRY_POINT
private static boolean CallBooleanMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.BOOLEAN).asBoolean();
}
@VM_ENTRY_POINT
private static native byte CallByteMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native byte CallByteMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static byte CallByteMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.BYTE).asByte();
}
@VM_ENTRY_POINT
private static native char CallCharMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native char CallCharMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static char CallCharMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.CHAR).asChar();
}
@VM_ENTRY_POINT
private static native short CallShortMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native short CallShortMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static short CallShortMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.SHORT).asShort();
}
@VM_ENTRY_POINT
private static native int CallIntMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native int CallIntMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static int CallIntMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.INT).asInt();
}
@VM_ENTRY_POINT
private static native long CallLongMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native long CallLongMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static long CallLongMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.LONG).asLong();
}
@VM_ENTRY_POINT
private static native float CallFloatMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native float CallFloatMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static float CallFloatMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.FLOAT).asFloat();
}
@VM_ENTRY_POINT
private static native double CallDoubleMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native double CallDoubleMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static double CallDoubleMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
return CallValueMethodA(env, object, methodID, arguments, Kind.DOUBLE).asDouble();
}
private static Value CallNonvirtualValueMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments, Kind expectedReturnKind) throws Exception {
// Following Hotspot, the javaClass argument is ignored; we only need the methodId
final MethodActor methodActor = MethodID.toMethodActor(methodID);
if (methodActor == null || methodActor.isStatic() || methodActor.isInitializer()) {
throw new NoSuchMethodException();
}
VirtualMethodActor virtualMethodActor;
try {
virtualMethodActor = (VirtualMethodActor) methodActor;
} catch (ClassCastException ex) {
throw new NoSuchMethodException();
}
final SignatureDescriptor signature = virtualMethodActor.descriptor();
final Value[] argumentValues = new Value[1 + signature.numberOfParameters()];
argumentValues[0] = ReferenceValue.from(object.unhand());
copyJValueArrayToValueArray(arguments, signature, argumentValues, 1);
logReflectiveInvocation(virtualMethodActor);
return checkResult(expectedReturnKind, methodActor, virtualMethodActor.invoke(argumentValues));
}
@VM_ENTRY_POINT
private static native void CallVoidMethod(Pointer env, JniHandle object, MethodID methodID);
@VM_ENTRY_POINT
private static native void CallVoidMethodV(Pointer env, JniHandle object, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static void CallVoidMethodA(Pointer env, JniHandle object, MethodID methodID, Pointer arguments) throws Exception {
CallValueMethodA(env, object, methodID, arguments, Kind.VOID);
}
@VM_ENTRY_POINT
private static native JniHandle CallNonvirtualObjectMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native JniHandle CallNonvirtualObjectMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static JniHandle CallNonvirtualObjectMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return JniHandles.createLocalHandle(CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.REFERENCE).asObject());
}
@VM_ENTRY_POINT
private static native boolean CallNonvirtualBooleanMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native boolean CallNonvirtualBooleanMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static boolean CallNonvirtualBooleanMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.BOOLEAN).asBoolean();
}
@VM_ENTRY_POINT
private static native byte CallNonvirtualByteMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native byte CallNonvirtualByteMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static byte CallNonvirtualByteMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.BYTE).asByte();
}
@VM_ENTRY_POINT
private static native char CallNonvirtualCharMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native char CallNonvirtualCharMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static char CallNonvirtualCharMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.CHAR).asChar();
}
@VM_ENTRY_POINT
private static native short CallNonvirtualShortMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native short CallNonvirtualShortMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static short CallNonvirtualShortMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.SHORT).asShort();
}
@VM_ENTRY_POINT
private static native int CallNonvirtualIntMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native int CallNonvirtualIntMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static int CallNonvirtualIntMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.INT).asInt();
}
@VM_ENTRY_POINT
private static native long CallNonvirtualLongMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native long CallNonvirtualLongMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static long CallNonvirtualLongMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.LONG).asLong();
}
@VM_ENTRY_POINT
private static native float CallNonvirtualFloatMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native float CallNonvirtualFloatMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static float CallNonvirtualFloatMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.FLOAT).asFloat();
}
@VM_ENTRY_POINT
private static native double CallNonvirtualDoubleMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native double CallNonvirtualDoubleMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static double CallNonvirtualDoubleMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.DOUBLE).asDouble();
}
@VM_ENTRY_POINT
private static native void CallNonvirtualVoidMethod(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native void CallNonvirtualVoidMethodV(Pointer env, JniHandle object, JniHandle javaClass, Pointer arguments);
@VM_ENTRY_POINT
private static void CallNonvirtualVoidMethodA(Pointer env, JniHandle object, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
CallNonvirtualValueMethodA(env, object, javaClass, methodID, arguments, Kind.VOID);
}
@VM_ENTRY_POINT
private static FieldID GetFieldID(Pointer env, JniHandle javaType, Pointer nameCString, Pointer descriptorCString) {
final ClassActor classActor = ClassActor.fromJava((Class) javaType.unhand());
Snippets.makeClassInitialized(classActor);
try {
final Utf8Constant name = SymbolTable.lookupSymbol(CString.utf8ToJava(nameCString));
final TypeDescriptor descriptor = JavaTypeDescriptor.parseTypeDescriptor(CString.utf8ToJava(descriptorCString));
if (name == null || descriptor == null) {
// The class should have been loaded (we have an instance of the class
// passed in) so the name and signature should already be in their respective canonicalization
// tables. If they're not there, the field doesn't exist.
throw new NoSuchFieldError();
}
final FieldActor fieldActor = classActor.findInstanceFieldActor(name, descriptor);
if (fieldActor == null) {
throw new NoSuchFieldError(name.string);
}
return FieldID.fromFieldActor(fieldActor);
} catch (Utf8Exception utf8Exception) {
throw new NoSuchFieldError();
}
}
@VM_ENTRY_POINT
private static JniHandle GetObjectField(Pointer env, JniHandle object, FieldID fieldID) {
return JniHandles.createLocalHandle(FieldID.toFieldActor(fieldID).getObject(object.unhand()));
}
@VM_ENTRY_POINT
private static boolean GetBooleanField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getBoolean(object.unhand());
}
@VM_ENTRY_POINT
private static byte GetByteField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getByte(object.unhand());
}
@VM_ENTRY_POINT
private static char GetCharField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getChar(object.unhand());
}
@VM_ENTRY_POINT
private static short GetShortField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getShort(object.unhand());
}
@VM_ENTRY_POINT
private static int GetIntField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getInt(object.unhand());
}
@VM_ENTRY_POINT
private static long GetLongField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getLong(object.unhand());
}
@VM_ENTRY_POINT
private static float GetFloatField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getFloat(object.unhand());
}
@VM_ENTRY_POINT
private static double GetDoubleField(Pointer env, JniHandle object, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getDouble(object.unhand());
}
@VM_ENTRY_POINT
private static void SetObjectField(Pointer env, JniHandle object, FieldID fieldID, JniHandle value) {
FieldID.toFieldActor(fieldID).setObject(object.unhand(), value.unhand());
}
@VM_ENTRY_POINT
private static void SetBooleanField(Pointer env, JniHandle object, FieldID fieldID, boolean value) {
FieldID.toFieldActor(fieldID).setBoolean(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetByteField(Pointer env, JniHandle object, FieldID fieldID, byte value) {
FieldID.toFieldActor(fieldID).setByte(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetCharField(Pointer env, JniHandle object, FieldID fieldID, char value) {
FieldID.toFieldActor(fieldID).setChar(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetShortField(Pointer env, JniHandle object, FieldID fieldID, short value) {
FieldID.toFieldActor(fieldID).setShort(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetIntField(Pointer env, JniHandle object, FieldID fieldID, int value) {
FieldID.toFieldActor(fieldID).setInt(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetLongField(Pointer env, JniHandle object, FieldID fieldID, long value) {
FieldID.toFieldActor(fieldID).setLong(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetFloatField(Pointer env, JniHandle object, FieldID fieldID, float value) {
FieldID.toFieldActor(fieldID).setFloat(object.unhand(), value);
}
@VM_ENTRY_POINT
private static void SetDoubleField(Pointer env, JniHandle object, FieldID fieldID, double value) {
FieldID.toFieldActor(fieldID).setDouble(object.unhand(), value);
}
@VM_ENTRY_POINT
private static MethodID GetStaticMethodID(Pointer env, JniHandle javaType, Pointer nameCString, Pointer descriptorCString) {
final ClassActor classActor = ClassActor.fromJava((Class) javaType.unhand());
Snippets.makeClassInitialized(classActor);
try {
final Utf8Constant name = SymbolTable.lookupSymbol(CString.utf8ToJava(nameCString));
final SignatureDescriptor descriptor = SignatureDescriptor.create(CString.utf8ToJava(descriptorCString));
if (name == null || descriptor == null) {
// The class should have been loaded (we have an instance of the class
// passed in) so the name and signature should already be in their respective canonicalization
// tables. If they're not there, the method doesn't exist.
throw new NoSuchMethodError();
}
final MethodActor methodActor = classActor.findStaticMethodActor(name, descriptor);
if (methodActor == null) {
throw new NoSuchMethodError(classActor + "." + name.string);
}
return MethodID.fromMethodActor(methodActor);
} catch (Utf8Exception utf8Exception) {
throw new NoSuchMethodError();
}
}
private static Value CallStaticValueMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments, Kind expectedReturnKind) throws Exception {
final ClassActor classActor = ClassActor.fromJava((Class) javaClass.unhand());
if (!(classActor instanceof TupleClassActor)) {
throw new NoSuchMethodException(classActor + " is not a class with static methods");
}
final MethodActor methodActor = MethodID.toMethodActor(methodID);
if (methodActor == null) {
throw new NoSuchMethodException("Invalid method ID " + methodID.asAddress().toLong());
}
if (!methodActor.isStatic()) {
throw new NoSuchMethodException(methodActor + " is not static");
}
if (!javaClass.isZero() && !methodActor.holder().toJava().isAssignableFrom((Class) javaClass.unhand())) {
throw new NoSuchMethodException(javaClass.unhand() + " is not a subclass of " + methodActor.holder());
}
final SignatureDescriptor signature = methodActor.descriptor();
final Value[] argumentValues = new Value[signature.numberOfParameters()];
copyJValueArrayToValueArray(arguments, signature, argumentValues, 0);
logReflectiveInvocation(methodActor);
return checkResult(expectedReturnKind, methodActor, methodActor.invoke(argumentValues));
}
@VM_ENTRY_POINT
private static native JniHandle CallStaticObjectMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native JniHandle CallStaticObjectMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static JniHandle CallStaticObjectMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return JniHandles.createLocalHandle(CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.REFERENCE).asObject());
}
@VM_ENTRY_POINT
private static native boolean CallStaticBooleanMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native boolean CallStaticBooleanMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static boolean CallStaticBooleanMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.BOOLEAN).asBoolean();
}
@VM_ENTRY_POINT
private static native byte CallStaticByteMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native byte CallStaticByteMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static byte CallStaticByteMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.BYTE).asByte();
}
@VM_ENTRY_POINT
private static native char CallStaticCharMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native char CallStaticCharMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static char CallStaticCharMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.CHAR).asChar();
}
@VM_ENTRY_POINT
private static native short CallStaticShortMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native short CallStaticShortMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static short CallStaticShortMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.SHORT).asShort();
}
@VM_ENTRY_POINT
private static native int CallStaticIntMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native int CallStaticIntMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static int CallStaticIntMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.INT).asInt();
}
@VM_ENTRY_POINT
private static native long CallStaticLongMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native long CallStaticLongMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static long CallStaticLongMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.LONG).asLong();
}
@VM_ENTRY_POINT
private static native float CallStaticFloatMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native float CallStaticFloatMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static float CallStaticFloatMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.FLOAT).asFloat();
}
@VM_ENTRY_POINT
private static native double CallStaticDoubleMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native double CallStaticDoubleMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static double CallStaticDoubleMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
return CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.DOUBLE).asDouble();
}
@VM_ENTRY_POINT
private static native void CallStaticVoidMethod(Pointer env, JniHandle javaClass, MethodID methodID);
@VM_ENTRY_POINT
private static native void CallStaticVoidMethodV(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments);
@VM_ENTRY_POINT
private static void CallStaticVoidMethodA(Pointer env, JniHandle javaClass, MethodID methodID, Pointer arguments) throws Exception {
CallStaticValueMethodA(env, javaClass, methodID, arguments, Kind.VOID);
}
@VM_ENTRY_POINT
private static FieldID GetStaticFieldID(Pointer env, JniHandle javaType, Pointer nameCString, Pointer descriptorCString) {
final ClassActor classActor = ClassActor.fromJava((Class) javaType.unhand());
Snippets.makeClassInitialized(classActor);
try {
final Utf8Constant name = SymbolTable.lookupSymbol(CString.utf8ToJava(nameCString));
final TypeDescriptor descriptor = TypeDescriptor.lookup(CString.utf8ToJava(descriptorCString));
if (name == null || descriptor == null) {
// The class should have been loaded (we have an instance of the class
// passed in) so the name and signature should already be in their respective canonicalization
// tables. If they're not there, the field doesn't exist.
throw new NoSuchFieldError();
}
final FieldActor fieldActor = classActor.findStaticFieldActor(name, descriptor);
if (fieldActor == null) {
throw new NoSuchFieldError();
}
return FieldID.fromFieldActor(fieldActor);
} catch (Utf8Exception utf8Exception) {
throw new NoSuchFieldError();
}
}
@VM_ENTRY_POINT
private static JniHandle GetStaticObjectField(Pointer env, JniHandle javaType, FieldID fieldID) {
return JniHandles.createLocalHandle(FieldID.toFieldActor(fieldID).getObject(null));
}
@VM_ENTRY_POINT
private static boolean GetStaticBooleanField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getBoolean(null);
}
@VM_ENTRY_POINT
private static byte GetStaticByteField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getByte(null);
}
@VM_ENTRY_POINT
private static char GetStaticCharField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getChar(null);
}
@VM_ENTRY_POINT
private static short GetStaticShortField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getShort(null);
}
@VM_ENTRY_POINT
private static int GetStaticIntField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getInt(null);
}
@VM_ENTRY_POINT
private static long GetStaticLongField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getLong(null);
}
@VM_ENTRY_POINT
private static float GetStaticFloatField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getFloat(null);
}
@VM_ENTRY_POINT
private static double GetStaticDoubleField(Pointer env, JniHandle javaType, FieldID fieldID) {
return FieldID.toFieldActor(fieldID).getDouble(null);
}
@VM_ENTRY_POINT
private static void SetStaticObjectField(Pointer env, JniHandle javaType, FieldID fieldID, JniHandle value) {
FieldID.toFieldActor(fieldID).setObject(null, value.unhand());
}
@VM_ENTRY_POINT
private static void SetStaticBooleanField(Pointer env, JniHandle javaType, FieldID fieldID, boolean value) {
FieldID.toFieldActor(fieldID).setBoolean(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticByteField(Pointer env, JniHandle javaType, FieldID fieldID, byte value) {
FieldID.toFieldActor(fieldID).setByte(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticCharField(Pointer env, JniHandle javaType, FieldID fieldID, char value) {
FieldID.toFieldActor(fieldID).setChar(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticShortField(Pointer env, JniHandle javaType, FieldID fieldID, short value) {
FieldID.toFieldActor(fieldID).setShort(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticIntField(Pointer env, JniHandle javaType, FieldID fieldID, int value) {
FieldID.toFieldActor(fieldID).setInt(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticLongField(Pointer env, JniHandle javaType, FieldID fieldID, long value) {
FieldID.toFieldActor(fieldID).setLong(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticFloatField(Pointer env, JniHandle javaType, FieldID fieldID, float value) {
FieldID.toFieldActor(fieldID).setFloat(null, value);
}
@VM_ENTRY_POINT
private static void SetStaticDoubleField(Pointer env, JniHandle javaType, FieldID fieldID, double value) {
FieldID.toFieldActor(fieldID).setDouble(null, value);
}
@VM_ENTRY_POINT
private static JniHandle NewString(Pointer env, Pointer chars, int length) {
final char[] charArray = new char[length];
for (int i = 0; i < length; i++) {
charArray[i] = chars.getChar(i);
}
return JniHandles.createLocalHandle(new String(charArray));
}
@VM_ENTRY_POINT
private static int GetStringLength(Pointer env, JniHandle string) {
return ((String) string.unhand()).length();
}
@VM_ENTRY_POINT
private static Pointer GetStringChars(Pointer env, JniHandle string, Pointer isCopy) {
setCopyPointer(isCopy, true);
return copyString((String) string.unhand());
}
@VM_ENTRY_POINT
private static void ReleaseStringChars(Pointer env, JniHandle string, Pointer chars) {
Memory.deallocate(chars);
}
@VM_ENTRY_POINT
private static JniHandle NewStringUTF(Pointer env, Pointer utf) {
try {
return JniHandles.createLocalHandle(CString.utf8ToJava(utf));
} catch (Utf8Exception utf8Exception) {
return JniHandle.zero();
}
}
@VM_ENTRY_POINT
private static int GetStringUTFLength(Pointer env, JniHandle string) {
return Utf8.utf8Length((String) string.unhand());
}
@VM_ENTRY_POINT
private static Pointer GetStringUTFChars(Pointer env, JniHandle string, Pointer isCopy) {
setCopyPointer(isCopy, true);
return CString.utf8FromJava((String) string.unhand());
}
@VM_ENTRY_POINT
private static void ReleaseStringUTFChars(Pointer env, JniHandle string, Pointer chars) {
Memory.deallocate(chars);
}
@VM_ENTRY_POINT
private static int GetArrayLength(Pointer env, JniHandle array) {
return Array.getLength(array.unhand());
}
@VM_ENTRY_POINT
private static JniHandle NewObjectArray(Pointer env, int length, JniHandle elementType, JniHandle initialElementValue) {
final Object array = Array.newInstance((Class) elementType.unhand(), length);
final Object initialValue = initialElementValue.unhand();
for (int i = 0; i < length; i++) {
Array.set(array, i, initialValue);
}
return JniHandles.createLocalHandle(array);
}
@VM_ENTRY_POINT
private static JniHandle GetObjectArrayElement(Pointer env, JniHandle array, int index) {
return JniHandles.createLocalHandle(((Object[]) array.unhand())[index]);
}
@VM_ENTRY_POINT
private static void SetObjectArrayElement(Pointer env, JniHandle array, int index, JniHandle value) {
((Object[]) array.unhand())[index] = value.unhand();
}
@VM_ENTRY_POINT
private static JniHandle NewBooleanArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new boolean[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewByteArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new byte[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewCharArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new char[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewShortArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new short[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewIntArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new int[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewLongArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new long[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewFloatArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new float[length]);
}
@VM_ENTRY_POINT
private static JniHandle NewDoubleArray(Pointer env, int length) {
return JniHandles.createLocalHandle(new double[length]);
}
@VM_ENTRY_POINT
private static Pointer GetBooleanArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getBooleanArrayElements(array, isCopy);
}
private static Pointer getBooleanArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final boolean[] a = (boolean[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length);
for (int i = 0; i < a.length; i++) {
pointer.setBoolean(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetByteArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getByteArrayElements(array, isCopy);
}
private static Pointer getByteArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final byte[] a = (byte[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.BYTE.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setByte(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetCharArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getCharArrayElements(array, isCopy);
}
private static Pointer getCharArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final char[] a = (char[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.CHAR.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setChar(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetShortArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getShortArrayElements(array, isCopy);
}
private static Pointer getShortArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final short[] a = (short[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.SHORT.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setShort(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetIntArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getIntArrayElements(array, isCopy);
}
private static Pointer getIntArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final int[] a = (int[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.INT.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setInt(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetLongArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getLongArrayElements(array, isCopy);
}
private static Pointer getLongArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final long[] a = (long[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.LONG.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setLong(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetFloatArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getFloatArrayElements(array, isCopy);
}
private static Pointer getFloatArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final float[] a = (float[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.FLOAT.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setFloat(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static Pointer GetDoubleArrayElements(Pointer env, JniHandle array, Pointer isCopy) {
return getDoubleArrayElements(array, isCopy);
}
private static Pointer getDoubleArrayElements(JniHandle array, Pointer isCopy) throws OutOfMemoryError {
setCopyPointer(isCopy, true);
final double[] a = (double[]) array.unhand();
final Pointer pointer = Memory.mustAllocate(a.length * Kind.DOUBLE.width.numberOfBytes);
for (int i = 0; i < a.length; i++) {
pointer.setDouble(i, a[i]);
}
return pointer;
}
@VM_ENTRY_POINT
private static void ReleaseBooleanArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseBooleanArrayElements(array, elements, mode);
}
private static void releaseBooleanArrayElements(JniHandle array, Pointer elements, int mode) {
final boolean[] a = (boolean[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getBoolean(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseByteArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseByteArrayElements(array, elements, mode);
}
private static void releaseByteArrayElements(JniHandle array, Pointer elements, int mode) {
final byte[] a = (byte[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getByte(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseCharArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseCharArrayElements(array, elements, mode);
}
private static void releaseCharArrayElements(JniHandle array, Pointer elements, int mode) {
final char[] a = (char[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getChar(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseShortArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseShortArrayElements(array, elements, mode);
}
private static void releaseShortArrayElements(JniHandle array, Pointer elements, int mode) {
final short[] a = (short[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getShort(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseIntArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseIntArrayElements(array, elements, mode);
}
private static void releaseIntArrayElements(JniHandle array, Pointer elements, int mode) {
final int[] a = (int[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getInt(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseLongArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseLongArrayElements(array, elements, mode);
}
private static void releaseLongArrayElements(JniHandle array, Pointer elements, int mode) {
final long[] a = (long[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getLong(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseFloatArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseFloatArrayElements(array, elements, mode);
}
private static void releaseFloatArrayElements(JniHandle array, Pointer elements, int mode) {
final float[] a = (float[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getFloat(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void ReleaseDoubleArrayElements(Pointer env, JniHandle array, Pointer elements, int mode) {
releaseDoubleArrayElements(array, elements, mode);
}
private static void releaseDoubleArrayElements(JniHandle array, Pointer elements, int mode) {
final double[] a = (double[]) array.unhand();
if (mode == 0 || mode == JNI_COMMIT) {
for (int i = 0; i < a.length; i++) {
a[i] = elements.getDouble(i);
}
}
releaseElements(elements, mode);
}
@VM_ENTRY_POINT
private static void GetBooleanArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final boolean[] a = (boolean[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setBoolean(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetByteArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final byte[] a = (byte[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setByte(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetCharArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final char[] a = (char[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setChar(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetShortArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final short[] a = (short[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setShort(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetIntArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final int[] a = (int[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setInt(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetLongArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final long[] a = (long[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setLong(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetFloatArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final float[] a = (float[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setFloat(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void GetDoubleArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final double[] a = (double[]) array.unhand();
for (int i = 0; i < length; i++) {
buffer.setDouble(i, a[start + i]);
}
}
@VM_ENTRY_POINT
private static void SetBooleanArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final boolean[] a = (boolean[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getBoolean(i);
}
}
@VM_ENTRY_POINT
private static void SetByteArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final byte[] a = (byte[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getByte(i);
}
}
@VM_ENTRY_POINT
private static void SetCharArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final char[] a = (char[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getChar(i);
}
}
@VM_ENTRY_POINT
private static void SetShortArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final short[] a = (short[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getShort(i);
}
}
@VM_ENTRY_POINT
private static void SetIntArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final int[] a = (int[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getInt(i);
}
}
@VM_ENTRY_POINT
private static void SetLongArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final long[] a = (long[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getLong(i);
}
}
@VM_ENTRY_POINT
private static void SetFloatArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final float[] a = (float[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getFloat(i);
}
}
@VM_ENTRY_POINT
private static void SetDoubleArrayRegion(Pointer env, JniHandle array, int start, int length, Pointer buffer) {
final double[] a = (double[]) array.unhand();
for (int i = 0; i < length; i++) {
a[start + i] = buffer.getDouble(i);
}
}
/**
* Registers a set of native methods.
*
* For reference, this code expects the type of the {@code methods} parameter to be {@code JNINativeMethod *methods}
* where:
*
* typedef struct { char *name; char *signature; void *fnPtr; } JNINativeMethod;
*/
@VM_ENTRY_POINT
private static int RegisterNatives(Pointer env, JniHandle javaType, Pointer methods, int numberOfMethods) {
Pointer a = methods;
final int pointerSize = Word.size();
final int NAME = 0 * pointerSize;
final int SIGNATURE = 1 * pointerSize;
final int FNPTR = 2 * pointerSize;
for (int i = 0; i < numberOfMethods; i++) {
try {
final Utf8Constant name = SymbolTable.lookupSymbol(CString.utf8ToJava(a.readWord(NAME).asPointer()));
final SignatureDescriptor descriptor = SignatureDescriptor.lookup(CString.utf8ToJava(a.readWord(SIGNATURE).asPointer()));
if (name == null || descriptor == null) {
// The class should have been loaded (we have an instance of the class
// passed in) so the name and signature should already be in their respective canonicalization
// tables. If they're not there, the method doesn't exist.
throw new NoSuchMethodError();
}
final Address fnPtr = a.readWord(FNPTR).asAddress();
final ClassActor classActor = ClassActor.fromJava((Class) javaType.unhand());
final ClassMethodActor classMethodActor = classActor.findClassMethodActor(name, descriptor);
if (classMethodActor == null || !classMethodActor.isNative()) {
throw new NoSuchMethodError();
}
classMethodActor.nativeFunction.setAddress(fnPtr);
} catch (Utf8Exception e) {
throw new NoSuchMethodError();
}
// advance to next JNINativeMethod struct
a = a.plus(pointerSize * 3);
}
return 0;
}
@VM_ENTRY_POINT
private static int UnregisterNatives(Pointer env, JniHandle javaType) {
ClassActor classActor = ClassActor.fromJava((Class) javaType.unhand());
for (VirtualMethodActor method : classActor.allVirtualMethodActors()) {
method.nativeFunction.setAddress(Address.zero());
}
do {
for (StaticMethodActor method : classActor.localStaticMethodActors()) {
method.nativeFunction.setAddress(Address.zero());
}
classActor = classActor.superClassActor;
} while (classActor != null);
return 0;
}
@VM_ENTRY_POINT
private static int MonitorEnter(Pointer env, JniHandle object) {
Monitor.enter(object.unhand());
return 0;
}
@VM_ENTRY_POINT
private static int MonitorExit(Pointer env, JniHandle object) {
Monitor.exit(object.unhand());
return 0;
}
@VM_ENTRY_POINT
private static native int GetJavaVM(Pointer env, Pointer vmPointerPointer);
@VM_ENTRY_POINT
private static void GetStringRegion(Pointer env, JniHandle string, int start, int length, Pointer buffer) {
final String s = (String) string.unhand();
for (int i = 0; i < length; i++) {
buffer.setChar(i, s.charAt(i + start));
}
}
@VM_ENTRY_POINT
private static void GetStringUTFRegion(Pointer env, JniHandle string, int start, int length, Pointer buffer) {
final String s = ((String) string.unhand()).substring(start, start + length);
final byte[] utf = Utf8.stringToUtf8(s);
Memory.writeBytes(utf, utf.length, buffer);
buffer.setByte(utf.length, (byte) 0); // zero termination
}
@VM_ENTRY_POINT
private static Pointer GetPrimitiveArrayCritical(Pointer env, JniHandle array, Pointer isCopy) {
final Object arrayObject = array.unhand();
if (Heap.useDirectPointer(arrayObject)) {
setCopyPointer(isCopy, false);
return Reference.fromJava(arrayObject).toOrigin().plus(Layout.byteArrayLayout().getElementOffsetFromOrigin(0));
}
if (arrayObject instanceof boolean[]) {
return getBooleanArrayElements(array, isCopy);
} else if (arrayObject instanceof byte[]) {
return getByteArrayElements(array, isCopy);
} else if (arrayObject instanceof char[]) {
return getCharArrayElements(array, isCopy);
} else if (arrayObject instanceof short[]) {
return getShortArrayElements(array, isCopy);
} else if (arrayObject instanceof int[]) {
return getIntArrayElements(array, isCopy);
} else if (arrayObject instanceof long[]) {
return getLongArrayElements(array, isCopy);
} else if (arrayObject instanceof float[]) {
return getFloatArrayElements(array, isCopy);
} else if (arrayObject instanceof double[]) {
return getDoubleArrayElements(array, isCopy);
}
return Pointer.zero();
}
@VM_ENTRY_POINT
private static void ReleasePrimitiveArrayCritical(Pointer env, JniHandle array, Pointer elements, int mode) {
final Object arrayObject = array.unhand();
if (Heap.releasedDirectPointer(arrayObject)) {
return;
}
if (arrayObject instanceof boolean[]) {
releaseBooleanArrayElements(array, elements, mode);
} else if (arrayObject instanceof byte[]) {
releaseByteArrayElements(array, elements, mode);
} else if (arrayObject instanceof char[]) {
releaseCharArrayElements(array, elements, mode);
} else if (arrayObject instanceof short[]) {
releaseShortArrayElements(array, elements, mode);
} else if (arrayObject instanceof int[]) {
releaseIntArrayElements(array, elements, mode);
} else if (arrayObject instanceof long[]) {
releaseLongArrayElements(array, elements, mode);
} else if (arrayObject instanceof float[]) {
releaseFloatArrayElements(array, elements, mode);
} else if (arrayObject instanceof double[]) {
releaseDoubleArrayElements(array, elements, mode);
}
}
@VM_ENTRY_POINT
private static Pointer GetStringCritical(Pointer env, JniHandle string, Pointer isCopy) {
// TODO(cwi): Implement optimized version for OptimizeJNICritical if a benchmark uses it frequently
setCopyPointer(isCopy, true);
return copyString((String) string.unhand());
}
private static Pointer copyString(String string) {
final Pointer pointer = Memory.mustAllocate(string.length() * Kind.CHAR.width.numberOfBytes);
for (int i = 0; i < string.length(); i++) {
pointer.setChar(i, string.charAt(i));
}
return pointer;
}
@VM_ENTRY_POINT
private static void ReleaseStringCritical(Pointer env, JniHandle string, Pointer chars) {
Memory.deallocate(chars);
}
@VM_ENTRY_POINT
private static JniHandle NewWeakGlobalRef(Pointer env, JniHandle handle) {
return JniHandles.createWeakGlobalHandle(handle.unhand());
}
@VM_ENTRY_POINT
private static void DeleteWeakGlobalRef(Pointer env, JniHandle handle) {
JniHandles.destroyWeakGlobalHandle(handle);
}
@VM_ENTRY_POINT
private static boolean ExceptionCheck(Pointer env) {
return VmThread.fromJniEnv(env).jniException() != null;
}
private static final ClassActor DirectByteBuffer = ClassActor.fromJava(Classes.forName("java.nio.DirectByteBuffer"));
@VM_ENTRY_POINT
private static JniHandle NewDirectByteBuffer(Pointer env, Pointer address, long capacity) throws Exception {
ByteBuffer buffer = ObjectAccess.createDirectByteBuffer(address.toLong(), (int) capacity);
return JniHandles.createLocalHandle(buffer);
}
@VM_ENTRY_POINT
private static Pointer GetDirectBufferAddress(Pointer env, JniHandle buffer) throws Exception {
Object buf = buffer.unhand();
if (DirectByteBuffer.isInstance(buf)) {
long address = ClassRegistry.Buffer_address.getLong(buf);
return Pointer.fromLong(address);
}
return Pointer.zero();
}
@VM_ENTRY_POINT
private static long GetDirectBufferCapacity(Pointer env, JniHandle buffer) {
Object buf = buffer.unhand();
if (DirectByteBuffer.isInstance(buf)) {
return ((Buffer) buf).capacity();
}
return -1;
}
@VM_ENTRY_POINT
private static int GetObjectRefType(Pointer env, JniHandle obj) {
final int tag = JniHandles.tag(obj);
if (tag == JniHandles.Tag.STACK) {
return JniHandles.Tag.LOCAL;
}
return tag;
}
// Checkstyle: resume method name check
private static void setCopyPointer(Pointer isCopy, boolean bool) {
if (!isCopy.isZero()) {
isCopy.setBoolean(bool);
}
}
private static void releaseElements(Pointer elements, int mode) {
if (mode == 0 || mode == JNI_ABORT) {
Memory.deallocate(elements);
}
assert mode == 0 || mode == JNI_COMMIT || mode == JNI_ABORT;
}
}