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
This commit is contained in:
Tom Tromey 2007-01-22 23:04:16 +00:00 committed by Tom Tromey
parent c8832aae41
commit 262fa8a4b5
15 changed files with 255 additions and 54 deletions

View File

@ -1,3 +1,38 @@
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> 2007-01-22 Tom Tromey <tromey@redhat.com>
* libtool-version: Bump current to 9. * libtool-version: Bump current to 9.

View File

@ -1,5 +1,5 @@
/* 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;
/* 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; \
\ \

View File

@ -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 ();

View File

@ -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)
{ {

View File

@ -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)
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)
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)
_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)
{ {
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)
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,
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.
@ -2111,7 +2110,8 @@ _Jv_GetJNIEnvNewFrame (jclass klass)
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,14 +2123,15 @@ _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
@ -2138,8 +2139,9 @@ _Jv_GetJNIEnvNewFrame (jclass klass)
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)
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,
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,
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)

View 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 {}}} {
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} {
# 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} {
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 {} {
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"
} }

View File

@ -0,0 +1,7 @@
#include <pr29812.h>
void
Java_pr29812_baseN (JNIEnv *env, jclass barf)
{
/* nothing */
}

View File

@ -0,0 +1,19 @@
/* 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__ */

Binary file not shown.

View File

@ -0,0 +1,25 @@
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);
}
}

View File

@ -0,0 +1,26 @@
#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);
}

View File

@ -0,0 +1,19 @@
/* 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__ */

Binary file not shown.

View File

@ -0,0 +1,12 @@
public class pr29812_injar
{
public class inner
{
}
static {
System.loadLibrary("pr29812_injar");
}
public static native void doit();
}