diff options
author | bryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-10 19:02:21 +0000 |
---|---|---|
committer | bryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-10 19:02:21 +0000 |
commit | 04c95bc933562928623c859240c17a70f2a1311c (patch) | |
tree | 7b6e8c5a43f4dcb0d8d4ac926f4562a978e11786 /libjava/interpret.cc | |
parent | 5bd3d8171f767d4995706ea87092c5dc688fff21 (diff) | |
download | gcc-04c95bc933562928623c859240c17a70f2a1311c.tar.gz |
2005-03-10 Bryce McKinlay <mckinlay@redhat.com>
New Stack Trace infrastructure.
* Makefile.am (libgcj0_convenience_la_SOURCES): Add stacktrace.cc.
(gnu/gcj/runtime/StackTrace.lo): Removed.
(ordinary_java_source_files): Remove obsolete files.
(nat_source_files): Remove obsolete files. Add natVMThrowable.cc.
* configure.host (fallback_backtrace_h): Set backtrace header
for mingw and cygwin targets.
* configure.ac: Make symlink for fallback backtrace headers.
* Makefile.in, configure: Rebuilt.
* defineclass.cc (_Jv_ClassReader::read_one_code_attribute):
Read 'LineNumberTable' attribute.
(_Jv_ClassReader::read_one_class_attribute): Read 'SourceFile'
attribute.
(_Jv_ClassReader::handleCodeAttribute): Initialize method line
table fields.
* exception.cc: Remove unused include.
* interpret.cc (DIRECT_THREADED, insn_slot): Moved to java-interp.h.
(SAVE_PC): New macro. Save current PC in the interpreter frame.
(NULLCHECK, NULLARRAYCHECK): Use SAVE_PC.
(_Jv_InterpMethod::compile): Translate bytecode PC values in the line
table to direct threaded instruction values.
(_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): Removed.
(_Jv_InterpMethod::run): No longer member function. All
callers updated. Remove _Unwind calls. Call SAVE_PC whenever a call
is made or where an instruction could throw.
(_Jv_InterpMethod::get_source_line): New. Look up source line numbers
in line_table.
* prims.cc (catch_segv): Construct exception after MAKE_THROW_FRAME.
(catch_fpe): Likewise.
* stacktrace.cc: New file. Stack trace code now here.
* gnu/gcj/runtime/MethodRef.java:
* gnu/gcj/runtime/NameFinder.java: Mostly reimplemented. Now simply
calls addr2line to look up PC addresses in a given binary or shared
library.
* gnu/gcj/runtime/StackTrace.java, gnu/gcj/runtime/natNameFinder.cc,
gnu/gcj/runtime/natStackTrace.cc: Removed.
* gnu/java/lang/MainThread.java (call_main): Add comment warning that
this function name is specially recognised by the stack trace code
and shouldn't be changed.
* include/java-interp.h (DIRECT_THREADED, insn_slot): Moved here.
(struct _Jv_LineTableEntry, line_table, line_table_len): New.
(_Jv_InterpMethod::run): Update declaration.
(_Jv_StackTrace_): New friend. NameFinder and StackTrace no longer
friends.
(_Jv_InterpFrame): Renamed from _Jv_MethodChain. Add PC field.
* include/java-stack.h: New file. Declarations for stack tracing.
* include/jvm.h (_Jv_Frame_info): Removed.
* java/lang/Class.h: Update friend declarations.
* java/lang/VMClassLoader.java (getSystemClassLoader): Simplify
exception message.
* java/lang/VMThrowable.java (fillInStackTrace): Now native.
(getStackTrace): Now native.
(data): New RawDataManaged field.
* java/lang/natClass.cc: Update includes.
(forName): Use _Jv_StackTrace::GetCallingClass for
calling-classloader check.
(getClassLoader): Likewise.
* java/lang/natRuntime.cc: Update includes.
(_load): Use _Jv_StackTrace::GetFirstNonSystemClassLoader.
* java/lang/natVMSecurityManager.cc: Update includes.
(getClassContext): Use _Jv_StackTrace::GetClassContext.
* java/lang/natVMThrowable.cc: New file. Native methods for
VMThrowable.
* java/lang/reflect/natArray.cc: Update includes.
(newInstance): Use _Jv_StackTrace::GetCallingClass to implement
accessibility check.
* java/lang/reflect/natConstructor.cc: Update includes.
(newInstance): Use _Jv_StackTrace::GetCallingClass to implement
accessibility check.
* java/lang/reflect/natField.cc: Update includes.
(getAddr): Use _Jv_StackTrace::GetCallingClass to implement
accessibility check.
* java/lang/reflect/natMethod.cc: Update includes.
(invoke): Use _Jv_StackTrace::GetCallingClass to implement
accessibility check.
* java/util/natResourceBundle.cc: Update includes.
(getCallingClassLoader): Use _Jv_StackTrace::GetCallingClass.
* java/util/logging/natLogger.cc: Update includes. Use
_Jv_StackTrace::GetCallerInfo to get call-site info.
* sysdep/generic/backtrace.h: Fallback backtrace code. Stub
implementation.
* sysdep/i386/backtrace.h: New. Fallback backtrace code. i386
implementation.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@96253 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/interpret.cc')
-rw-r--r-- | libjava/interpret.cc | 159 |
1 files changed, 81 insertions, 78 deletions
diff --git a/libjava/interpret.cc b/libjava/interpret.cc index 4c547b35dd6..a2bcbb84084 100644 --- a/libjava/interpret.cc +++ b/libjava/interpret.cc @@ -13,11 +13,6 @@ details. */ #include <config.h> #include <platform.h> -// Define this to get the direct-threaded interpreter. If undefined, -// we revert to a basic bytecode interpreter. The former is faster -// but uses more memory. -#define DIRECT_THREADED - #pragma implementation "java-interp.h" #include <jvm.h> @@ -83,26 +78,6 @@ void _Jv_InitInterpreter() {} extern "C" double __ieee754_fmod (double,double); -// This represents a single slot in the "compiled" form of the -// bytecode. -union insn_slot -{ - // Address of code. - void *insn; - // An integer value used by an instruction. - jint int_val; - // A pointer value used by an instruction. - void *datum; -}; - -// The type of the PC depends on whether we're doing direct threading -// or a more ordinary bytecode interpreter. -#ifdef DIRECT_THREADED -typedef insn_slot *pc_t; -#else -typedef unsigned char *pc_t; -#endif - static inline void dupx (_Jv_word *sp, int n, int x) { // first "slide" n+x elements n to the right @@ -117,7 +92,6 @@ static inline void dupx (_Jv_word *sp, int n, int x) { sp[top-(n+x)-i] = sp[top-i]; } - } // Used to convert from floating types to integral types. @@ -248,15 +222,16 @@ static jint get4(unsigned char* loc) { | (((jint)(loc[3])) << 0); } +#define SAVE_PC() frame_desc.pc = pc #ifdef HANDLE_SEGV -#define NULLCHECK(X) -#define NULLARRAYCHECK(X) +#define NULLCHECK(X) SAVE_PC() +#define NULLARRAYCHECK(X) SAVE_PC() #else #define NULLCHECK(X) \ - do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) + do { SAVE_PC(); if ((X)==NULL) throw_null_pointer_exception (); } while (0) #define NULLARRAYCHECK(X) \ - do { if ((X)==NULL) { throw_null_pointer_exception (); } } while (0) + do { SAVE_PC(); if ((X)==NULL) { throw_null_pointer_exception (); } } while (0) #endif #define ARRAYBOUNDSCHECK(array, index) \ @@ -274,7 +249,7 @@ _Jv_InterpMethod::run_normal (ffi_cif *, void* __this) { _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this; - _this->run (ret, args); + run (ret, args, _this); } void @@ -288,7 +263,7 @@ _Jv_InterpMethod::run_synch_object (ffi_cif *, jobject rcv = (jobject) args[0].ptr; JvSynchronize mutex (rcv); - _this->run (ret, args); + run (ret, args, _this); } void @@ -299,7 +274,7 @@ _Jv_InterpMethod::run_class (ffi_cif *, { _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this; _Jv_InitClass (_this->defining_class); - _this->run (ret, args); + run (ret, args, _this); } void @@ -314,7 +289,7 @@ _Jv_InterpMethod::run_synch_class (ffi_cif *, _Jv_InitClass (sync); JvSynchronize mutex (sync); - _this->run (ret, args); + run (ret, args, _this); } #ifdef DIRECT_THREADED @@ -783,29 +758,23 @@ _Jv_InterpMethod::compile (const void * const *insn_targets) exc[i].handler_type.p = handler; } + // Translate entries in the LineNumberTable from bytecode PC's to direct + // threaded interpreter instruction values. + for (int i = 0; i < line_table_len; i++) + { + int byte_pc = line_table[i].bytecode_pc; + line_table[i].pc = &insns[pc_mapping[byte_pc]]; + } + prepared = insns; } #endif /* DIRECT_THREADED */ -// These exist so that the stack-tracing code can find the boundaries -// of the interpreter. -void *_Jv_StartOfInterpreter; -void *_Jv_EndOfInterpreter; -extern "C" void *_Unwind_FindEnclosingFunction (void *pc); - void -_Jv_InterpMethod::run (void *retp, ffi_raw *args) +_Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth) { using namespace java::lang::reflect; - // Record the address of the start of this member function in - // _Jv_StartOfInterpreter. Such a write to a global variable - // without acquiring a lock is correct iff reads and writes of words - // in memory are atomic, but Java requires that anyway. - foo: - if (_Jv_StartOfInterpreter == NULL) - _Jv_StartOfInterpreter = _Unwind_FindEnclosingFunction (&&foo); - // FRAME_DESC registers this particular invocation as the top-most // interpreter frame. This lets the stack tracing code (for // Throwable) print information about the method being interpreted @@ -813,20 +782,20 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) // destructor so it cleans up automatically when the interpreter // returns. java::lang::Thread *thread = java::lang::Thread::currentThread(); - _Jv_MethodChain frame_desc (this, - (_Jv_MethodChain **) &thread->interp_frame); + _Jv_InterpFrame frame_desc (meth, + (_Jv_InterpFrame **) &thread->interp_frame); - _Jv_word stack[max_stack]; + _Jv_word stack[meth->max_stack]; _Jv_word *sp = stack; - _Jv_word locals[max_locals]; + _Jv_word locals[meth->max_locals]; /* Go straight at it! the ffi raw format matches the internal stack representation exactly. At least, that's the idea. */ - memcpy ((void*) locals, (void*) args, args_raw_size); + memcpy ((void*) locals, (void*) args, meth->args_raw_size); - _Jv_word *pool_data = defining_class->constants.data; + _Jv_word *pool_data = meth->defining_class->constants.data; /* These three are temporaries for common code used by several instructions. */ @@ -1068,14 +1037,14 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) #define AMPAMP(label) &&label // Compile if we must. NOTE: Double-check locking. - if (prepared == NULL) + if (meth->prepared == NULL) { _Jv_MutexLock (&compile_mutex); - if (prepared == NULL) - compile (insn_target); + if (meth->prepared == NULL) + meth->compile (insn_target); _Jv_MutexUnlock (&compile_mutex); } - pc = (insn_slot *) prepared; + pc = (insn_slot *) meth->prepared; #else @@ -1132,7 +1101,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) * the corresponding bit JV_CONSTANT_ResolvedFlag in the tag * directly. For now, I don't think it is worth it. */ - rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + SAVE_PC(); + rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).rmethod; sp -= rmeth->stack_item_count; @@ -1140,7 +1110,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) // working if the method is final. So instead we do an // explicit test. if (! sp[0].o) - throw new java::lang::NullPointerException; + { + //printf("invokevirtual pc = %p/%i\n", pc, meth->get_pc_val(pc)); + throw new java::lang::NullPointerException; + } if (rmeth->vtable_index == -1) { @@ -1173,7 +1146,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) // working if the method is final. So instead we do an // explicit test. if (! sp[0].o) - throw new java::lang::NullPointerException; + { + SAVE_PC(); + throw new java::lang::NullPointerException; + } if (rmeth->vtable_index == -1) { @@ -1193,6 +1169,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) perform_invoke: { + SAVE_PC(); + /* here goes the magic again... */ ffi_cif *cif = &rmeth->cif; ffi_raw *raw = (ffi_raw*) sp; @@ -2423,7 +2401,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_getstatic: { jint fieldref_index = GET2U (); - _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); + SAVE_PC(); // Constant pool resolution could throw. + _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; if ((field->flags & Modifier::STATIC) == 0) @@ -2510,7 +2489,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_getfield: { jint fieldref_index = GET2U (); - _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; if ((field->flags & Modifier::STATIC) != 0) @@ -2626,7 +2605,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_putstatic: { jint fieldref_index = GET2U (); - _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; jclass type = field->type; @@ -2713,7 +2692,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_putfield: { jint fieldref_index = GET2U (); - _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; jclass type = field->type; @@ -2839,7 +2818,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).rmethod; sp -= rmeth->stack_item_count; @@ -2847,7 +2826,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) // We don't use NULLCHECK here because we can't rely on that // working for <init>. So instead we do an explicit test. if (! sp[0].o) - throw new java::lang::NullPointerException; + { + SAVE_PC(); + throw new java::lang::NullPointerException; + } fun = (void (*)()) rmeth->method->ncode; @@ -2868,7 +2850,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) // We don't use NULLCHECK here because we can't rely on that // working for <init>. So instead we do an explicit test. if (! sp[0].o) - throw new java::lang::NullPointerException; + { + SAVE_PC(); + throw new java::lang::NullPointerException; + } fun = (void (*)()) rmeth->method->ncode; } goto perform_invoke; @@ -2878,7 +2863,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).rmethod; sp -= rmeth->stack_item_count; @@ -2908,7 +2893,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).rmethod; sp -= rmeth->stack_item_count; @@ -2952,7 +2937,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_new: { int index = GET2U (); - jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class, + jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).clazz; jobject res = _Jv_AllocObject (klass); PUSHA (res); @@ -2986,7 +2971,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_anewarray: { int index = GET2U (); - jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class, + jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).clazz; int size = POPI(); jobject result = _Jv_NewObjectArray (size, klass, 0); @@ -3027,9 +3012,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_checkcast: { + SAVE_PC(); jobject value = POPA(); jint index = GET2U (); - jclass to = (_Jv_Linker::resolve_pool_entry (defining_class, + jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).clazz; if (value != NULL && ! to->isInstance (value)) @@ -3047,6 +3033,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) #ifdef DIRECT_THREADED checkcast_resolved: { + SAVE_PC(); jobject value = POPA (); jclass to = (jclass) AVAL (); if (value != NULL && ! to->isInstance (value)) @@ -3058,9 +3045,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_instanceof: { + SAVE_PC(); jobject value = POPA(); jint index = GET2U (); - jclass to = (_Jv_Linker::resolve_pool_entry (defining_class, + jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class, index)).clazz; PUSHI (to->isInstance (value)); @@ -3123,7 +3111,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) int dim = GET1U (); jclass type - = (_Jv_Linker::resolve_pool_entry (defining_class, + = (_Jv_Linker::resolve_pool_entry (meth->defining_class, kind_index)).clazz; jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim); @@ -3212,10 +3200,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) #else int logical_pc = pc - 1 - bytecode (); #endif - _Jv_InterpException *exc = exceptions (); + _Jv_InterpException *exc = meth->exceptions (); jclass exc_class = ex->getClass (); - for (int i = 0; i < exc_count; i++) + for (int i = 0; i < meth->exc_count; i++) { if (PCVAL (exc[i].start_pc) <= logical_pc && logical_pc < PCVAL (exc[i].end_pc)) @@ -3272,6 +3260,21 @@ throw_null_pointer_exception () } #endif +/* Look up source code line number for given bytecode (or direct threaded + interpreter) PC. */ +int +_Jv_InterpMethod::get_source_line(pc_t mpc) +{ + int line = line_table_len > 0 ? line_table[0].line : -1; + for (int i = 1; i < line_table_len; i++) + if (line_table[i].pc > mpc) + break; + else + line = line_table[i].line; + + return line; +} + /** Do static initialization for fields with a constant initializer */ void _Jv_InitField (jobject obj, jclass klass, int index) |