Commit 262fa8a4 by Tom Tromey Committed by Tom Tromey

re PR java/29812 (env->klass value is not updated during the native calls)

	PR java/29812:
	* testsuite/libjava.jni/pr29812.java: New file.
	* testsuite/libjava.jni/pr29812_injar.java: New file.
	* testsuite/libjava.jni/pr29812_injar.jar: New file.
	* testsuite/libjava.jni/pr29812.out: New file.
	* testsuite/libjava.jni/pr29812_injar.c: New file.
	* testsuite/libjava.jni/pr29812_injar.h: New file.
	* testsuite/libjava.jni/pr29812.jar: New file.
	* testsuite/libjava.jni/pr29812.c: New file.
	* testsuite/libjava.jni/pr29812.h: New file.
	* testsuite/libjava.jni/jni.exp (gcj_jni_get_cxxflags_invocation):
	New proc.
	(gcj_jni_invocation_test_one): Use it.
	(gcj_jni_pr29812): New proc.
	(gcj_jni_run): Use it.
	* java/lang/natRuntime.cc (_load): Push a new system frame before
	calling JNI_OnLoad.
	* include/jvm.h (_Jv_JNI_PopSystemFrame): Declare.
	(_Jv_GetJNIEnvNewFrameWithLoader): Likewise.
	* jni.cc (struct _Jv_JNI_LocalFrame) <marker>: Now unsigned char.
	<allocated_p>: Now bool.
	<loader>: New field.
	(_Jv_JNI_EnsureLocalCapacity): Updated.
	(_Jv_JNI_NewLocalRef): Likewise.
	(_Jv_JNI_NewLocalRef): Likewise.
	(_Jv_JNI_PopLocalFrame): Likewise.
	(_Jv_JNI_FindClass): Likewise.
	(_Jv_GetJNIEnvNewFrame): Likewise.
	(_Jv_JNI_AttachCurrentThread): Likewise.
	(_Jv_GetJNIEnvNewFrameWithLoader): New function.
	(_Jv_GetJNIEnvNewFrame): Use it.
	* include/jni_md.h (_CLASSPATH_JNIENV_CONTENTS): Removed 'klass'.

From-SVN: r121064
parent c8832aae
2007-01-22 Tom Tromey <tromey@redhat.com> 2007-01-22 Tom Tromey <tromey@redhat.com>
PR java/29812:
* testsuite/libjava.jni/pr29812.java: New file.
* testsuite/libjava.jni/pr29812_injar.java: New file.
* testsuite/libjava.jni/pr29812_injar.jar: New file.
* testsuite/libjava.jni/pr29812.out: New file.
* testsuite/libjava.jni/pr29812_injar.c: New file.
* testsuite/libjava.jni/pr29812_injar.h: New file.
* testsuite/libjava.jni/pr29812.jar: New file.
* testsuite/libjava.jni/pr29812.c: New file.
* testsuite/libjava.jni/pr29812.h: New file.
* testsuite/libjava.jni/jni.exp (gcj_jni_get_cxxflags_invocation):
New proc.
(gcj_jni_invocation_test_one): Use it.
(gcj_jni_pr29812): New proc.
(gcj_jni_run): Use it.
* java/lang/natRuntime.cc (_load): Push a new system frame before
calling JNI_OnLoad.
* include/jvm.h (_Jv_JNI_PopSystemFrame): Declare.
(_Jv_GetJNIEnvNewFrameWithLoader): Likewise.
* jni.cc (struct _Jv_JNI_LocalFrame) <marker>: Now unsigned char.
<allocated_p>: Now bool.
<loader>: New field.
(_Jv_JNI_EnsureLocalCapacity): Updated.
(_Jv_JNI_NewLocalRef): Likewise.
(_Jv_JNI_NewLocalRef): Likewise.
(_Jv_JNI_PopLocalFrame): Likewise.
(_Jv_JNI_FindClass): Likewise.
(_Jv_GetJNIEnvNewFrame): Likewise.
(_Jv_JNI_AttachCurrentThread): Likewise.
(_Jv_GetJNIEnvNewFrameWithLoader): New function.
(_Jv_GetJNIEnvNewFrame): Use it.
* include/jni_md.h (_CLASSPATH_JNIENV_CONTENTS): Removed 'klass'.
2007-01-22 Tom Tromey <tromey@redhat.com>
* libtool-version: Bump current to 9. * libtool-version: Bump current to 9.
2007-01-22 Andrew Haley <aph@redhat.com> 2007-01-22 Andrew Haley <aph@redhat.com>
......
/* jni_md.h /* jni_md.h
Copyright (C) 2001, 2005 Free Software Foundation, Inc. Copyright (C) 2001, 2005, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -58,9 +58,6 @@ typedef struct _Jv_JavaVM JavaVM; ...@@ -58,9 +58,6 @@ typedef struct _Jv_JavaVM JavaVM;
/* The current exception. */ \ /* The current exception. */ \
jthrowable ex; \ jthrowable ex; \
\ \
/* The class of the current native method. */ \
jclass klass; \
\
/* The chain of local frames. */ \ /* The chain of local frames. */ \
struct _Jv_JNI_LocalFrame *locals; \ struct _Jv_JNI_LocalFrame *locals; \
\ \
......
...@@ -592,8 +592,8 @@ void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *); ...@@ -592,8 +592,8 @@ void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *);
/* Free a JNIEnv. */ /* Free a JNIEnv. */
void _Jv_FreeJNIEnv (_Jv_JNIEnv *); void _Jv_FreeJNIEnv (_Jv_JNIEnv *);
/* Free a JNIEnv. */ extern "C" void _Jv_JNI_PopSystemFrame (_Jv_JNIEnv *);
void _Jv_FreeJNIEnv (_Jv_JNIEnv *); _Jv_JNIEnv *_Jv_GetJNIEnvNewFrameWithLoader (::java::lang::ClassLoader *);
struct _Jv_JavaVM; struct _Jv_JavaVM;
_Jv_JavaVM *_Jv_GetJavaVM (); _Jv_JavaVM *_Jv_GetJavaVM ();
......
...@@ -207,7 +207,14 @@ java::lang::Runtime::_load (jstring path, jboolean do_search) ...@@ -207,7 +207,14 @@ java::lang::Runtime::_load (jstring path, jboolean do_search)
// FIXME: what? // FIXME: what?
return; return;
} }
// Push a new frame so that JNI_OnLoad will get the right class
// loader if it calls FindClass.
::java::lang::ClassLoader *loader
= _Jv_StackTrace::GetFirstNonSystemClassLoader();
JNIEnv *env = _Jv_GetJNIEnvNewFrameWithLoader (loader);
jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL); jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL);
_Jv_JNI_PopSystemFrame (env);
if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2 if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
&& vers != JNI_VERSION_1_4) && vers != JNI_VERSION_1_4)
{ {
......
...@@ -85,16 +85,18 @@ extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions; ...@@ -85,16 +85,18 @@ extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
// This structure is used to keep track of local references. // This structure is used to keep track of local references.
struct _Jv_JNI_LocalFrame struct _Jv_JNI_LocalFrame
{ {
// This is true if this frame object represents a pushed frame (eg // This is one of the MARK_ constants.
// from PushLocalFrame). unsigned char marker;
int marker;
// Flag to indicate some locals were allocated. // Flag to indicate some locals were allocated.
int allocated_p; bool allocated_p;
// Number of elements in frame. // Number of elements in frame.
int size; int size;
// The class loader of the JNI method that allocated this frame.
::java::lang::ClassLoader *loader;
// Next frame in chain. // Next frame in chain.
_Jv_JNI_LocalFrame *next; _Jv_JNI_LocalFrame *next;
...@@ -311,8 +313,9 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) ...@@ -311,8 +313,9 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size)
frame->marker = MARK_NONE; frame->marker = MARK_NONE;
frame->size = size; frame->size = size;
frame->allocated_p = 0; frame->allocated_p = false;
memset (&frame->vec[0], 0, size * sizeof (jobject)); memset (&frame->vec[0], 0, size * sizeof (jobject));
frame->loader = env->locals->loader;
frame->next = env->locals; frame->next = env->locals;
env->locals = frame; env->locals = frame;
...@@ -350,7 +353,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj) ...@@ -350,7 +353,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
set = true; set = true;
done = true; done = true;
frame->vec[i] = obj; frame->vec[i] = obj;
frame->allocated_p = 1; frame->allocated_p = true;
break; break;
} }
} }
...@@ -368,7 +371,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj) ...@@ -368,7 +371,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
_Jv_JNI_EnsureLocalCapacity (env, 16); _Jv_JNI_EnsureLocalCapacity (env, 16);
// We know the first element of the new frame will be ok. // We know the first element of the new frame will be ok.
env->locals->vec[0] = obj; env->locals->vec[0] = obj;
env->locals->allocated_p = 1; env->locals->allocated_p = true;
} }
mark_for_gc (obj, local_ref_table); mark_for_gc (obj, local_ref_table);
...@@ -397,7 +400,7 @@ _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop) ...@@ -397,7 +400,7 @@ _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
{ {
if (rf->allocated_p) if (rf->allocated_p)
memset (&rf->vec[0], 0, rf->size * sizeof (jobject)); memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
rf->allocated_p = 0; rf->allocated_p = false;
rf = NULL; rf = NULL;
break; break;
} }
...@@ -541,8 +544,8 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name) ...@@ -541,8 +544,8 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name)
jstring n = JvNewStringUTF (s); jstring n = JvNewStringUTF (s);
java::lang::ClassLoader *loader = NULL; java::lang::ClassLoader *loader = NULL;
if (env->klass != NULL) if (env->locals->loader != NULL)
loader = env->klass->getClassLoaderInternal (); loader = env->locals->loader;
if (loader == NULL) if (loader == NULL)
{ {
...@@ -2087,18 +2090,14 @@ mangled_name (jclass klass, _Jv_Utf8Const *func_name, ...@@ -2087,18 +2090,14 @@ mangled_name (jclass klass, _Jv_Utf8Const *func_name,
buf[here] = '\0'; buf[here] = '\0';
} }
// Return the current thread's JNIEnv; if one does not exist, create JNIEnv *
// it. Also create a new system frame for use. This is `extern "C"' _Jv_GetJNIEnvNewFrameWithLoader (::java::lang::ClassLoader *loader)
// because the compiler calls it.
extern "C" JNIEnv *
_Jv_GetJNIEnvNewFrame (jclass klass)
{ {
JNIEnv *env = _Jv_GetCurrentJNIEnv (); JNIEnv *env = _Jv_GetCurrentJNIEnv ();
if (__builtin_expect (env == NULL, false)) if (__builtin_expect (env == NULL, false))
{ {
env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
env->p = &_Jv_JNIFunctions; env->p = &_Jv_JNIFunctions;
env->klass = klass;
env->locals = NULL; env->locals = NULL;
// We set env->ex below. // We set env->ex below.
...@@ -2107,11 +2106,12 @@ _Jv_GetJNIEnvNewFrame (jclass klass) ...@@ -2107,11 +2106,12 @@ _Jv_GetJNIEnvNewFrame (jclass klass)
_Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ (FRAME_SIZE + (FRAME_SIZE
* sizeof (jobject))); * sizeof (jobject)));
env->bottom_locals->marker = MARK_SYSTEM; env->bottom_locals->marker = MARK_SYSTEM;
env->bottom_locals->size = FRAME_SIZE; env->bottom_locals->size = FRAME_SIZE;
env->bottom_locals->next = NULL; env->bottom_locals->next = NULL;
env->bottom_locals->allocated_p = 0; env->bottom_locals->allocated_p = false;
// We set the klass field below.
memset (&env->bottom_locals->vec[0], 0, memset (&env->bottom_locals->vec[0], 0,
env->bottom_locals->size * sizeof (jobject)); env->bottom_locals->size * sizeof (jobject));
...@@ -2123,23 +2123,25 @@ _Jv_GetJNIEnvNewFrame (jclass klass) ...@@ -2123,23 +2123,25 @@ _Jv_GetJNIEnvNewFrame (jclass klass)
// built, above. // built, above.
if (__builtin_expect (env->locals == NULL, true)) if (__builtin_expect (env->locals == NULL, true))
env->locals = env->bottom_locals; {
env->locals = env->bottom_locals;
env->locals->loader = loader;
}
else else
{ {
// Alternatively, we might be re-entering JNI, in which case we can't // Alternatively, we might be re-entering JNI, in which case we can't
// reuse the bottom_locals frame, because it is already underneath // reuse the bottom_locals frame, because it is already underneath
// us. So we need to make a new one. // us. So we need to make a new one.
_Jv_JNI_LocalFrame *frame _Jv_JNI_LocalFrame *frame
= (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ (FRAME_SIZE + (FRAME_SIZE
* sizeof (jobject))); * sizeof (jobject)));
frame->marker = MARK_SYSTEM; frame->marker = MARK_SYSTEM;
frame->size = FRAME_SIZE; frame->size = FRAME_SIZE;
frame->allocated_p = 0; frame->allocated_p = false;
frame->next = env->locals; frame->next = env->locals;
frame->loader = loader;
memset (&frame->vec[0], 0, memset (&frame->vec[0], 0,
frame->size * sizeof (jobject)); frame->size * sizeof (jobject));
...@@ -2152,6 +2154,15 @@ _Jv_GetJNIEnvNewFrame (jclass klass) ...@@ -2152,6 +2154,15 @@ _Jv_GetJNIEnvNewFrame (jclass klass)
return env; return env;
} }
// Return the current thread's JNIEnv; if one does not exist, create
// it. Also create a new system frame for use. This is `extern "C"'
// because the compiler calls it.
extern "C" JNIEnv *
_Jv_GetJNIEnvNewFrame (jclass klass)
{
return _Jv_GetJNIEnvNewFrameWithLoader (klass->getClassLoaderInternal());
}
// Destroy the env's reusable resources. This is called from the thread // Destroy the env's reusable resources. This is called from the thread
// destructor "finalize_native" in natThread.cc // destructor "finalize_native" in natThread.cc
void void
...@@ -2392,7 +2403,6 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, ...@@ -2392,7 +2403,6 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv,
return JNI_ERR; return JNI_ERR;
env->p = &_Jv_JNIFunctions; env->p = &_Jv_JNIFunctions;
env->ex = NULL; env->ex = NULL;
env->klass = NULL;
env->bottom_locals env->bottom_locals
= (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ (FRAME_SIZE + (FRAME_SIZE
...@@ -2404,9 +2414,10 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, ...@@ -2404,9 +2414,10 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv,
return JNI_ERR; return JNI_ERR;
} }
env->locals->allocated_p = 0; env->locals->allocated_p = false;
env->locals->marker = MARK_SYSTEM; env->locals->marker = MARK_SYSTEM;
env->locals->size = FRAME_SIZE; env->locals->size = FRAME_SIZE;
env->locals->loader = NULL;
env->locals->next = NULL; env->locals->next = NULL;
for (int i = 0; i < env->locals->size; ++i) for (int i = 0; i < env->locals->size; ++i)
......
...@@ -101,7 +101,8 @@ proc gcj_jni_test_one {file} { ...@@ -101,7 +101,8 @@ proc gcj_jni_test_one {file} {
# The base name. We use it for several purposes. # The base name. We use it for several purposes.
set main [file rootname [file tail $file]] set main [file rootname [file tail $file]]
if {! [runtest_file_p $runtests $main]} { if {! [runtest_file_p $runtests $main]
|| $main == "pr29812" || $main == "pr29812_injar"} {
# Simply skip it. # Simply skip it.
return 1 return 1
} }
...@@ -235,6 +236,33 @@ proc gcj_jni_invocation_compile_c_to_binary {file {options {}}} { ...@@ -235,6 +236,33 @@ proc gcj_jni_invocation_compile_c_to_binary {file {options {}}} {
return 1 return 1
} }
proc gcj_jni_get_cxxflags_invocation {} {
# Darwin needs -liconv linked, otherwise we get some unresolved.
# If you're building the compiler with --prefix set to a place
# where it's not yet installed, then the linker won't be able to
# find the libgcc used by libffi.dylib. We could pass the
# -dylib_file option, but that's complicated, and it's much easier
# to just make the linker find libgcc using -L options.
# Similar logic applies to libgcj.
if { [istarget "*-*-darwin*"] } {
set cxxflags "-L../.libs -shared-libgcc -ljvm -lgcj -liconv"
} else {
global LIBJAVA
if [info exists LIBJAVA] {
set libjava $LIBJAVA;
} else {
set libjava [libjava_find_lib libjava gcj]
}
set cxxflags "$libjava -ljvm"
}
if { [istarget "*-*-solaris*"] } {
lappend cxxflags "-lsocket"
}
return $cxxflags
}
# Do all the work for a single invocation API test. Return 0 on # Do all the work for a single invocation API test. Return 0 on
# failure. # failure.
proc gcj_jni_invocation_test_one {file} { proc gcj_jni_invocation_test_one {file} {
...@@ -259,29 +287,8 @@ proc gcj_jni_invocation_test_one {file} { ...@@ -259,29 +287,8 @@ proc gcj_jni_invocation_test_one {file} {
# pass "bytecompile $file" # pass "bytecompile $file"
set cfile [file rootname $file].c set cfile [file rootname $file].c
# Darwin needs -liconv linked, otherwise we get some unresolved.
# If you're building the compiler with --prefix set to a place
# where it's not yet installed, then the linker won't be able to
# find the libgcc used by libffi.dylib. We could pass the
# -dylib_file option, but that's complicated, and it's much easier
# to just make the linker find libgcc using -L options.
# Similar logic applies to libgcj.
if { [istarget "*-*-darwin*"] } {
set cxxflags "-L../.libs -shared-libgcc -ljvm -lgcj -liconv"
} else {
global LIBJAVA
if [info exists LIBJAVA] {
set libjava $LIBJAVA;
} else {
set libjava [libjava_find_lib libjava gcj]
}
set cxxflags "$libjava -ljvm"
}
if { [istarget "*-*-solaris*"] } {
lappend cxxflags "-lsocket"
}
set cxxflags [gcj_jni_get_cxxflags_invocation]
if {! [gcj_jni_invocation_compile_c_to_binary $cfile $cxxflags]} { if {! [gcj_jni_invocation_compile_c_to_binary $cfile $cxxflags]} {
# FIXME # FIXME
return 0 return 0
...@@ -309,6 +316,40 @@ proc gcj_jni_invocation_test_one {file} { ...@@ -309,6 +316,40 @@ proc gcj_jni_invocation_test_one {file} {
return 1 return 1
} }
proc gcj_jni_pr29812 {} {
global srcdir subdir
global INTERPRETER runtests
# Set up a global we need.
libjava_arguments
set b ${srcdir}/${subdir}
if {! [runtest_file_p $runtests pr29812]} {
# Simply skip it.
return 1
}
if {! [gcj_jni_compile_c_to_so $b/pr29812.c ""]} {
return 0
}
if {! [gcj_jni_compile_c_to_so $b/pr29812_injar.c ""]} {
return 0
}
set gij [libjava_find_gij]
if {$INTERPRETER == "yes" && $gij != ""} {
if {! [libjava_invoke pr29812 "gij test" opts $gij \
"" $b/pr29812.out "" \
-classpath $b/pr29812.jar pr29812 $b/pr29812_injar.jar]} {
return 0
}
}
# When we succeed we remove all our clutter.
eval gcj_cleanup [glob -nocomplain -- *pr29812*]
}
# Run the JNI tests. # Run the JNI tests.
proc gcj_jni_run {} { proc gcj_jni_run {} {
global srcdir subdir global srcdir subdir
...@@ -328,6 +369,8 @@ proc gcj_jni_run {} { ...@@ -328,6 +369,8 @@ proc gcj_jni_run {} {
foreach x $srcfiles { foreach x $srcfiles {
gcj_jni_invocation_test_one $x gcj_jni_invocation_test_one $x
} }
gcj_jni_pr29812
} else { } else {
verbose "JNI tests not run in cross-compilation environment" verbose "JNI tests not run in cross-compilation environment"
} }
......
#include <pr29812.h>
void
Java_pr29812_baseN (JNIEnv *env, jclass barf)
{
/* nothing */
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#ifndef __pr29812__
#define __pr29812__
#ifdef __cplusplus
extern "C"
{
#endif
JNIEXPORT void JNICALL Java_pr29812_baseN (JNIEnv *env, jclass);
#ifdef __cplusplus
}
#endif
#endif /* __pr29812__ */
import java.io.File;
import java.net.*;
import java.lang.reflect.Method;
public class pr29812
{
static {
System.loadLibrary("pr29812");
}
public static native void baseN();
public static void main(String[] args) throws Throwable
{
// Make sure JNI environment is initialized.
baseN();
File jar = new File(args[0]);
URL u = jar.toURL();
URLClassLoader uc = new URLClassLoader(new URL[] { u });
Class k = uc.loadClass("pr29812_injar");
Method m = k.getMethod("doit", (Class[]) null);
m.invoke(null, (Object[]) null);
}
}
#include <stdlib.h>
#include <assert.h>
#include <pr29812_injar.h>
JNIEXPORT jint JNICALL
JNI_OnLoad (JavaVM *vm, void *nothing)
{
JNIEnv *env;
jint r;
jclass k;
r = (*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_2);
assert (r == JNI_OK);
k = (*env)->FindClass (env, "pr29812_injar$inner");
assert (k != NULL);
return JNI_VERSION_1_2;
}
void
Java_pr29812_1injar_doit (JNIEnv *env, jclass b)
{
jclass k = (*env)->FindClass(env, "pr29812_injar$inner");
assert (k != NULL);
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#ifndef __pr29812_1injar__
#define __pr29812_1injar__
#ifdef __cplusplus
extern "C"
{
#endif
JNIEXPORT void JNICALL Java_pr29812_1injar_doit (JNIEnv *env, jclass);
#ifdef __cplusplus
}
#endif
#endif /* __pr29812_1injar__ */
public class pr29812_injar
{
public class inner
{
}
static {
System.loadLibrary("pr29812_injar");
}
public static native void doit();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment