[kaffe] CVS kaffe (stack): More JVMPI stuff and some misc. fixes

Kaffe CVS Kaffe Mailing List <kaffe@kaffe.org>
Sat Oct 11 13:49:02 2003


PatchSet 4108 
Date: 2003/10/11 20:45:46
Author: stack
Branch: HEAD
Tag: (none) 
Log:
More JVMPI stuff and some misc. fixes

Members: 
	ChangeLog:1.1702->1.1703 
	config/i386/jit3-i386.def:1.20->1.21 
	include/jvmpi.h:1.2->1.3 
	kaffe/jvmpi/jvmpi_kaffe.c:1.2->1.3 
	kaffe/jvmpi/jvmpi_kaffe.h:1.1->1.2 
	kaffe/kaffevm/classMethod.c:1.111->1.112 
	kaffe/kaffevm/findInJar.c:1.55->1.56 
	kaffe/kaffevm/kaffe.def:1.28->1.29 
	kaffe/kaffevm/object.c:1.21->1.22 
	kaffe/kaffevm/soft.c:1.56->1.57 
	kaffe/kaffevm/soft.h:1.13->1.14 
	kaffe/kaffevm/string.c:1.27->1.28 
	kaffe/kaffevm/thread.c:1.55->1.56 
	kaffe/kaffevm/jit3/codeproto.h:1.13->1.14 
	kaffe/kaffevm/jit3/icode.c:1.33->1.34 
	kaffe/kaffevm/jit3/machine.c:1.42->1.43 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.1702 kaffe/ChangeLog:1.1703
--- kaffe/ChangeLog:1.1702	Fri Oct 10 20:05:54 2003
+++ kaffe/ChangeLog	Sat Oct 11 20:45:46 2003
@@ -1,3 +1,46 @@
+2003-10-11  Timothy S. Stack <stack@cs.utah.edu>
+
+	* config/i386/jit3-i386.def:
+	Use shorter form of some 'push' opcodes.
+	
+	* include/jvmpi.h:
+	Add JVMPI_REQUESTED_EVENT flag.
+
+	* kaffe/jvmpi/jvmpi_kaffe.h,
+	kaffe/jvmpi/jvmpi_kaffe.c:
+	Refactored some code for creating events and added support for
+	requested events.
+
+	* kaffe/kaffevm/classMethod.c,
+	kaffe/kaffevm/object.c,
+	kaffe/kaffevm/thread.c:
+	Moved code for dealing with events to jvmpi_kaffe.c
+
+	* kaffe/kaffevm/findInJar.c:
+	Correctly handle KSTAT's return value and make sure classhome is
+	non-NULL before calling discoverClasspath().
+
+	* kaffe/kaffevm/kaffe.def:
+	Don't bother calling empty methods.
+
+	* kaffe/kaffevm/soft.h,
+	kaffe/kaffevm/soft.c:
+	Add soft_null_call() for the jitters to use when a method is
+	completely empty.
+	
+	* kaffe/kaffevm/string.c:
+	Call discardErrorInfo() before returning if there was a failure.
+
+	* kaffe/kaffevm/jit3/codeproto.h,
+	kaffe/kaffevm/jit3/icode.c:
+	Add popargs_noreturn for softcalls that can't return
+	(e.g. soft_athrow).  Just saves a little bit of stack popping
+	code...
+
+	* kaffe/kaffevm/jit3/machine.c:
+	Change the internal nullCall to soft_null_call so that it can be
+	referenced in kaffe.def.
+
 2003-10-10  Alexander Kotelnikov <sacha@myxomop.com>
 
 	* config/alpha/alpha.c:
Index: kaffe/config/i386/jit3-i386.def
diff -u kaffe/config/i386/jit3-i386.def:1.20 kaffe/config/i386/jit3-i386.def:1.21
--- kaffe/config/i386/jit3-i386.def:1.20	Fri Apr 25 21:35:33 2003
+++ kaffe/config/i386/jit3-i386.def	Sat Oct 11 20:45:48 2003
@@ -1607,8 +1607,7 @@
 	if (inRegister(1, Rint|Rref)) {
 		r = rreg_int(1);
 
-		OUT = 0xFF;
-		OUT = 0xF0|r;
+		OUT = 0x50|r;
 
 		debug(("pushl %s\n", regname(r)));
 	}
@@ -1625,8 +1624,7 @@
 {
 	int r = rreg_int(1);	/* Move the float into a register */
 
-	OUT = 0xFF;
-	OUT = 0xF0|r;
+	OUT = 0x50|r;
 
 	debug(("pushl %s\n", regname(r)));
 }
Index: kaffe/include/jvmpi.h
diff -u kaffe/include/jvmpi.h:1.2 kaffe/include/jvmpi.h:1.3
--- kaffe/include/jvmpi.h:1.2	Sat Aug 30 23:57:09 2003
+++ kaffe/include/jvmpi.h	Sat Oct 11 20:45:48 2003
@@ -82,7 +82,9 @@
 	JVMPI_EVENT_GC_START = 60,
 	JVMPI_EVENT_GC_FINISH,
 	
-	JVMPI_EVENT_COUNT
+	JVMPI_EVENT_COUNT,
+	
+	JVMPI_REQUESTED_EVENT = 0x10000000
 };
 
 enum {
Index: kaffe/kaffe/jvmpi/jvmpi_kaffe.c
diff -u kaffe/kaffe/jvmpi/jvmpi_kaffe.c:1.2 kaffe/kaffe/jvmpi/jvmpi_kaffe.c:1.3
--- kaffe/kaffe/jvmpi/jvmpi_kaffe.c:1.2	Sat Aug 30 23:57:10 2003
+++ kaffe/kaffe/jvmpi/jvmpi_kaffe.c	Sat Oct 11 20:45:48 2003
@@ -1,3 +1,17 @@
+/*
+ * jvmpi_kaffe.c
+ * Routines for generating an assembly file with debugging information
+ *
+ * Copyright (c) 2003 University of Utah and the Flux Group.
+ * All rights reserved.
+ *
+ * This file is licensed under the terms of the GNU Public License.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * Contributed by the Flux Research Group, Department of Computer Science,
+ * University of Utah, http://www.cs.utah.edu/flux/
+ */
 
 #include "config.h"
 
@@ -16,6 +30,7 @@
 #include "java_lang_Thread.h"
 #include "thread.h"
 #include "stackTrace.h"
+#include "stringSupport.h"
 
 #include <assert.h>
 
@@ -25,6 +40,9 @@
 {
 	JVMPI_Interface *retval;
 
+	assert((version == JVMPI_VERSION_1) ||
+	       (version == JVMPI_VERSION_1_1));
+	
 	retval = &jvmpi_data.jk_Interface;
 	retval->version = version;
 	return( retval );
@@ -32,6 +50,7 @@
 
 void jvmpiPostEvent(JVMPI_Event *ev)
 {
+	assert(ev != NULL);
 	assert(ev->event_type >= 0);
 	assert(ev->event_type < JVMPI_EVENT_COUNT);
 
@@ -100,6 +119,117 @@
 	dst->lineno = src->line_nr;
 }
 
+void jvmpiFillObjectAlloc(JVMPI_Event *ev, struct Hjava_lang_Object *obj)
+{
+	struct Hjava_lang_Class *cl;
+	
+	assert(ev != NULL);
+	assert(obj != NULL);
+
+	cl = OBJECT_CLASS(obj);
+	ev->event_type = JVMPI_EVENT_OBJECT_ALLOC;
+	ev->u.obj_alloc.arena_id = -1;
+	ev->u.obj_alloc.class_id = cl;
+	if( CLASS_IS_ARRAY(cl) )
+	{
+		jint prim_type = 0;
+		
+		switch( CLASS_PRIM_SIG(CLASS_ELEMENT_TYPE(cl)) )
+		{
+		case 'I':
+			prim_type = JVMPI_INT;
+			break;
+		case 'Z':
+			prim_type = JVMPI_BOOLEAN;
+			break;
+		case 'S':
+			prim_type = JVMPI_SHORT;
+			break;
+		case 'B':
+			prim_type = JVMPI_BYTE;
+			break;
+		case 'C':
+			prim_type = JVMPI_CHAR;
+			break;
+		case 'F':
+			prim_type = JVMPI_FLOAT;
+			break;
+		case 'D':
+			prim_type = JVMPI_DOUBLE;
+			break;
+		case 'J':
+			prim_type = JVMPI_LONG;
+			break;
+		default:
+			assert(0);
+			break;
+		}
+		ev->u.obj_alloc.is_array = prim_type;
+	}
+	else
+	{
+		ev->u.obj_alloc.is_array = JVMPI_NORMAL_OBJECT;
+	}
+	ev->u.obj_alloc.size = GC_getObjectSize(main_collector, obj);
+	ev->u.obj_alloc.obj_id = obj;
+}
+
+void jvmpiFillThreadStart(JVMPI_Event *ev, struct Hjava_lang_Thread *tid)
+{
+	struct Hjava_lang_String *name;
+	
+	assert(ev != NULL);
+	assert(tid != NULL);
+	
+	ev->event_type = JVMPI_EVENT_THREAD_START;
+	if( (name = stringCharArray2Java(unhand_char_array(tid->name),
+					 obj_length(tid->name))) != NULL )
+	{
+		ev->u.thread_start.thread_name = stringJava2C(name);
+	}
+	else
+	{
+		ev->u.thread_start.thread_name = NULL;
+	}
+	ev->u.thread_start.group_name = stringJava2C(tid->group->name);
+	ev->u.thread_start.parent_name = NULL;
+	ev->u.thread_start.thread_id = tid;
+	ev->u.thread_start.thread_env_id =
+		&jthread_get_data((jthread_t)tid->PrivateInfo)->jniEnv;
+}
+
+void jvmpiFillClassLoad(JVMPI_Event *ev, struct Hjava_lang_Class *cl)
+{
+	int lpc;
+	
+	assert(ev != NULL);
+	assert(cl != NULL);
+
+	for( lpc = 0; lpc < CLASS_NMETHODS(cl); lpc++ )
+	{
+		jvmpiConvertMethod(&ev->u.class_load.methods[lpc],
+				   &CLASS_METHODS(cl)[lpc]);
+	}
+	for( lpc = 0; lpc < CLASS_NSFIELDS(cl); lpc++ )
+	{
+		jvmpiConvertField(&ev->u.class_load.statics[lpc],
+				  &CLASS_SFIELDS(cl)[lpc]);
+	}
+	for( lpc = 0; lpc < CLASS_NIFIELDS(cl); lpc++ )
+	{
+		jvmpiConvertField(&ev->u.class_load.statics[lpc],
+				  &CLASS_IFIELDS(cl)[lpc]);
+	}
+	ev->event_type = JVMPI_EVENT_CLASS_LOAD;
+	ev->u.class_load.class_name = CLASS_CNAME(cl);
+	ev->u.class_load.source_name = CLASS_SOURCEFILE(cl);
+	ev->u.class_load.num_interfaces = cl->interface_len;
+	ev->u.class_load.num_methods = CLASS_NMETHODS(cl);
+	ev->u.class_load.num_static_fields = CLASS_NSFIELDS(cl);
+	ev->u.class_load.num_instance_fields = CLASS_NIFIELDS(cl);
+	ev->u.class_load.class_id = cl;
+}
+
 static jint jvmpiCreateSystemThread(char *name,
 				    jint priority,
 				    void (*f)(void *))
@@ -322,8 +452,8 @@
 
 static jint jvmpiGetThreadStatus(JNIEnv *env_id)
 {
+	jint retval = 0;
 	jthread_t jt;
-	jint retval;
 
 	assert(env_id != NULL);
 
@@ -424,6 +554,62 @@
 {
 	jint retval = JVMPI_NOT_AVAILABLE;
 
+	switch( event_type )
+	{
+	case JVMPI_EVENT_HEAP_DUMP:
+		break;
+	case JVMPI_EVENT_MONITOR_DUMP:
+		break;
+	case JVMPI_EVENT_OBJECT_DUMP:
+		break;
+	case JVMPI_EVENT_CLASS_LOAD:
+		{
+			struct Hjava_lang_Class *cl;
+			JVMPI_Method *jvmpi_methods;
+			JVMPI_Field *jvmpi_fields;
+			JVMPI_Event ev;
+
+			cl = (struct Hjava_lang_Class *)arg;
+			jvmpi_methods = alloca(sizeof(JVMPI_Method) *
+					       cl->nmethods);
+			jvmpi_fields = alloca(sizeof(JVMPI_Field) *
+					      (cl->nsfields +
+					       cl->nfields));
+			ev.u.class_load.methods = jvmpi_methods;
+			ev.u.class_load.statics = &jvmpi_fields[0];
+			ev.u.class_load.instances =
+				&jvmpi_fields[cl->nsfields];
+			jvmpiFillClassLoad(&ev, cl);
+			ev.event_type |= JVMPI_REQUESTED_EVENT;
+			jvmpiPostEvent(&ev);
+		}
+		break;
+	case JVMPI_EVENT_THREAD_START:
+		{
+			struct Hjava_lang_Thread *tid;
+			JVMPI_Event ev;
+
+			tid = (struct Hjava_lang_Thread *)arg;
+			jvmpiFillThreadStart(&ev, tid);
+			ev.event_type |= JVMPI_REQUESTED_EVENT;
+			jvmpiPostEvent(&ev);
+			KFREE(ev.u.thread_start.parent_name);
+			KFREE(ev.u.thread_start.group_name);
+			KFREE(ev.u.thread_start.thread_name);
+		}
+		break;
+	case JVMPI_EVENT_OBJECT_ALLOC:
+		{
+			struct Hjava_lang_Object *obj;
+			JVMPI_Event ev;
+
+			obj = (struct Hjava_lang_Object *)arg;
+			jvmpiFillObjectAlloc(&ev, obj);
+			ev.event_type |= JVMPI_REQUESTED_EVENT;
+			jvmpiPostEvent(&ev);
+		}
+		break;
+	}
 	return( retval );
 }
 
Index: kaffe/kaffe/jvmpi/jvmpi_kaffe.h
diff -u kaffe/kaffe/jvmpi/jvmpi_kaffe.h:1.1 kaffe/kaffe/jvmpi/jvmpi_kaffe.h:1.2
--- kaffe/kaffe/jvmpi/jvmpi_kaffe.h:1.1	Sat Jul 26 16:50:47 2003
+++ kaffe/kaffe/jvmpi/jvmpi_kaffe.h	Sat Oct 11 20:45:48 2003
@@ -1,3 +1,17 @@
+/*
+ * jvmpi_kaffe.h
+ * Routines for generating an assembly file with debugging information
+ *
+ * Copyright (c) 2003 University of Utah and the Flux Group.
+ * All rights reserved.
+ *
+ * This file is licensed under the terms of the GNU Public License.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * Contributed by the Flux Research Group, Department of Computer Science,
+ * University of Utah, http://www.cs.utah.edu/flux/
+ */
 
 #ifndef _JVMPI_KAFFE_H
 #define _JVMPI_KAFFE_H
@@ -8,7 +22,7 @@
 #include "support.h"
 #include "code.h"
 
-/*
+/**
  * Implementation of a JVMPI_RawMonitor.  Just uses jmutex/jcondvar to do the
  * work.
  */
@@ -19,7 +33,10 @@
 };
 
 /*
- * Global data structure 
+ * Global structure for JVMPI data.
+ *
+ * jk_EventMask - Bitmask that indicates which events are currently active.
+ * jk_Interface - The interface to the JVMPI functions.
  */
 typedef struct jvmpi_kaffe {
 	int jk_EventMask[BITMAP_BYTE_SIZE(JVMPI_EVENT_COUNT)];
@@ -28,20 +45,94 @@
 
 #if defined(ENABLE_JVMPI)
 
+/**
+ * Global JVMPI data.
+ */
 extern jvmpi_kaffe_t jvmpi_data;
 
+/**
+ * Test if a JVMPI event is enabled.
+ *
+ * @param type The event identifier.
+ * @return True if the event has been enabled using EnableEvent() function in
+ * the interface, false otherwise.
+ */
 #define JVMPI_EVENT_ISENABLED(type) \
 	BITMAP_ISSET(jvmpi_data.jk_EventMask, (type))
 
+/**
+ * Initialize and return the JVMPI interface.
+ *
+ * @param version The requested version of the interface.
+ * @return An initialized JVMPI_Interface object of the corresponding version.
+ */
 JVMPI_Interface *jvmpiCreateInterface(jint version);
+
+/**
+ * Post a JVMPI event by filling in the 'env_id' field, optionally disabling
+ * the GC, and calling the 'NotifyEvent' function in the JVMPI_Interface.
+ *
+ * @param ev The event to post, the event_type field and any event specific
+ * data should already be filled out.
+ */
 void jvmpiPostEvent(JVMPI_Event *ev);
 
+/**
+ * Convert a Kaffe field structure to a JVMPI_Field.
+ *
+ * @param dst The destination object.
+ * @param src The source object.
+ */
 void jvmpiConvertField(JVMPI_Field *dst, fields *src);
+
+/**
+ * Convert a Kaffe method structure to a JVMPI_Method.
+ *
+ * @param dst The destination object.
+ * @param src The source object.
+ */
 void jvmpiConvertMethod(JVMPI_Method *dst, methods *src);
+
+/**
+ * Convert a Kaffe lineNumberEntry structure to a JVMPI_Lineno.
+ *
+ * @param dst The destination object.
+ * @param src The source object.
+ * @param start_pc The starting address of the method.
+ */
 void jvmpiConvertLineno(JVMPI_Lineno *dst,
 			lineNumberEntry *src,
 			void *start_pc);
 
+/**
+ * Fill in a JVMPI_Event structure with the data for a JVMPI_EVENT_OBJECT_ALLOC
+ * event.
+ *
+ * @param ev The object to fill out.
+ * @param obj The object to describe in the event.
+ */
+void jvmpiFillObjectAlloc(JVMPI_Event *ev, struct Hjava_lang_Object *obj);
+
+/**
+ * Fill in a JVMPI_Event structure with the data for a JVMPI_EVENT_THREAD_START
+ * event.  Note:  This function will KMALLOC the thread_start.parent_name,
+ * thread_start.group_name, and thread_start.thread_name fields.
+ *
+ * @param ev The object to fill out.
+ * @param obj The object to describe in the event.
+ */
+void jvmpiFillThreadStart(JVMPI_Event *ev, struct Hjava_lang_Thread *tid);
+
+/**
+ * Fill in a JVMPI_Event structure with the data for a JVMPI_EVENT_CLASS_LOAD
+ * event.  Note:  The class_load.methods, class_load.statics, and
+ * class_load.instances arrays must be allocated before calling this method.
+ *
+ * @param ev The object to fill out.
+ * @param obj The object to describe in the event.
+ */
+void jvmpiFillClassLoad(JVMPI_Event *ev, struct Hjava_lang_Class *cl);
+
 #else
 
 #define JVMPI_EVENT_ISENABLED(type) 0
@@ -50,6 +141,9 @@
 #define jvmpiConvertField(dst, src)
 #define jvmpiConvertMethod(dst, src)
 #define jvmpiConvertLineno(dst, src, start_pc)
+#define jvmpiFillObjectAlloc(ev, obj)
+#define jvmpiFillThreadStart(ev, obj)
+#define jvmpiFillClassLoad(ev, obj)
 
 #endif
 
Index: kaffe/kaffe/kaffevm/classMethod.c
diff -u kaffe/kaffe/kaffevm/classMethod.c:1.111 kaffe/kaffe/kaffevm/classMethod.c:1.112
--- kaffe/kaffe/kaffevm/classMethod.c:1.111	Mon Sep 22 15:31:24 2003
+++ kaffe/kaffe/kaffevm/classMethod.c	Sat Oct 11 20:45:49 2003
@@ -331,43 +331,17 @@
 			JVMPI_Method *jvmpi_methods;
 			JVMPI_Field *jvmpi_fields;
 			JVMPI_Event ev;
-			int lpc;
 			
 			jvmpi_methods = alloca(sizeof(JVMPI_Method) *
 					       class->nmethods);
-			for( lpc = 0; lpc < class->nmethods; lpc++ )
-			{
-				jvmpiConvertMethod(&jvmpi_methods[lpc],
-						   &class->methods[lpc]);
-			}
 			jvmpi_fields = alloca(sizeof(JVMPI_Field) *
 					      (class->nsfields +
 					       class->nfields));
-			for( lpc = 0;
-			     lpc < (class->nsfields + class->nfields);
-			     lpc++ )
-			{
-				jvmpiConvertField(&jvmpi_fields[lpc],
-						  &class->fields[lpc]);
-			}
-			ev.event_type = JVMPI_EVENT_CLASS_LOAD;
-			ev.u.class_load.class_name =
-				class->name->data;
-			ev.u.class_load.source_name =
-				class->sourcefile;
-			ev.u.class_load.num_interfaces =
-				class->interface_len;
-			ev.u.class_load.num_methods =
-				class->nmethods;
 			ev.u.class_load.methods = jvmpi_methods;
-			ev.u.class_load.num_static_fields =
-				class->nsfields;
 			ev.u.class_load.statics = &jvmpi_fields[0];
-			ev.u.class_load.num_instance_fields =
-				class->nfields;
 			ev.u.class_load.instances =
 				&jvmpi_fields[class->nsfields];
-			ev.u.class_load.class_id = class;
+			jvmpiFillClassLoad(&ev, class);
 			jvmpiPostEvent(&ev);
 		}
 #endif
Index: kaffe/kaffe/kaffevm/findInJar.c
diff -u kaffe/kaffe/kaffevm/findInJar.c:1.55 kaffe/kaffe/kaffevm/findInJar.c:1.56
--- kaffe/kaffe/kaffevm/findInJar.c:1.55	Tue Jul  8 07:33:49 2003
+++ kaffe/kaffe/kaffevm/findInJar.c	Sat Oct 11 20:45:49 2003
@@ -360,7 +360,7 @@
 		makeClasspath(writable_cp);
 		KFREE(writable_cp);
 	}
-	else {
+	else if(hm) {
 		discoverClasspath(hm);
 	}
 
@@ -553,7 +553,7 @@
 	char buf[4];
 	struct stat sbuf;
 
-	if (KSTAT(path, &sbuf) < 0) {
+	if (KSTAT(path, &sbuf)) {
 		return (CP_INVALID);
 	}
 
Index: kaffe/kaffe/kaffevm/kaffe.def
diff -u kaffe/kaffe/kaffevm/kaffe.def:1.28 kaffe/kaffe/kaffevm/kaffe.def:1.29
--- kaffe/kaffe/kaffevm/kaffe.def:1.28	Sun Aug 31 22:09:01 2003
+++ kaffe/kaffe/kaffevm/kaffe.def	Sat Oct 11 20:45:49 2003
@@ -2692,45 +2692,61 @@
 
 		check_stack_ref(idx);
 
-		if (is_virtual) {
-			/* Find dispatch table in object */
-			load_offset_ref(tmp, stack(idx), method_dtable_offset);
-
-			/* Check method table for cached entry */
-			load_offset_ref(tmp, tmp,
-				DTABLE_METHODOFFSET + 
-				method_idx() * DTABLE_METHODSIZE);
-		} else {
-			/* Explicitly check that object is non-null.
-			 * Implicitly done in the dispatch table lookup. */
-			explicit_check_null(INVOKEVIRTUAL, stack(idx), 35);
-		}
-
-		/* Push arguments & object */
-		build_call_frame(method_sig(), stack(idx), idx);
-		idx++;
-
-		if (is_virtual) {
-			slot_nowriteback(tmp);
-		}
-		pop(idx);
-		begin_func_sync();
-
-		/* Call it */
-		low = method_returntype();
-		if (is_virtual) {
-			call(tmp);
-			slot_freetmp(tmp);
-		} else {
-			call_indirect_method(method_method());
+		if( !is_virtual &&
+		    METHOD_TRANSLATED(method_method()) &&
+		    (METHOD_NATIVECODE(method_method()) == soft_null_call) )
+		{
+			idx += 1;
+			pop(idx);
 		}
-
-		/* Pop args */
-		popargs();
-
-		end_func_sync();
-		METHOD_RETURN_VALUE();
-	} 
+		else
+		{
+			if (is_virtual) {
+				/* Find dispatch table in object */
+				load_offset_ref(tmp, stack(idx),
+						method_dtable_offset);
+				
+				/* Check method table for cached entry */
+				load_offset_ref(tmp, tmp,
+						DTABLE_METHODOFFSET + 
+						method_idx() *
+						DTABLE_METHODSIZE);
+			} else {
+				/* Explicitly check that object is non-null.
+				 * Implicitly done in the dispatch table
+				 * lookup.
+				 */
+				explicit_check_null(INVOKEVIRTUAL,
+						    stack(idx),
+						    35);
+			}
+			
+			/* Push arguments & object */
+			build_call_frame(method_sig(), stack(idx), idx);
+			idx++;
+			
+			if (is_virtual) {
+				slot_nowriteback(tmp);
+			}
+			pop(idx);
+			begin_func_sync();
+			
+			/* Call it */
+			low = method_returntype();
+			if (is_virtual) {
+				call(tmp);
+				slot_freetmp(tmp);
+			} else {
+				call_indirect_method(method_method());
+			}
+			
+			/* Pop args */
+			popargs();
+			
+			end_func_sync();
+			METHOD_RETURN_VALUE();
+		}
+	}
 }
 
 define_insn(INVOKESPECIAL)
@@ -2795,23 +2811,32 @@
 
 		check_stack_ref(idx);
 
-		/* Push arguments & object */
-		build_call_frame(method_sig(), stack(idx), idx);
-		idx++;
-
-		pop(idx);
-		begin_func_sync();
-
-		/* Call it */
-		low = method_returntype();
-
-		call_indirect_method(method_method());
-
-		/* Pop args */
-		popargs();
-
-		end_func_sync();
-		METHOD_RETURN_VALUE();
+		if( METHOD_TRANSLATED(method_method()) &&
+		    (METHOD_NATIVECODE(method_method()) == soft_null_call) )
+		{
+			idx += 1;
+			pop(idx);
+		}
+		else
+		{
+			/* Push arguments & object */
+			build_call_frame(method_sig(), stack(idx), idx);
+			idx++;
+			
+			pop(idx);
+			begin_func_sync();
+			
+			/* Call it */
+			low = method_returntype();
+			
+			call_indirect_method(method_method());
+			
+			/* Pop args */
+			popargs();
+			
+			end_func_sync();
+			METHOD_RETURN_VALUE();
+		}
 	}
 }
 
@@ -2858,22 +2883,30 @@
 	else {
 		idx = method_nargs();
 
-		/* Push arguments */
-		build_call_frame(method_sig(), 0, idx);
-
-		pop(idx);
-		begin_func_sync();
-
-		/* Call it */
-		low = method_returntype();
-
-		call_indirect_method(method_method());
-
-		/* Pop args */
-		popargs();
-
-		end_func_sync();
-		METHOD_RETURN_VALUE();
+		if( METHOD_TRANSLATED(method_method()) &&
+		    (METHOD_NATIVECODE(method_method()) == soft_null_call) )
+		{
+			pop(idx);
+		}
+		else
+		{
+			/* Push arguments */
+			build_call_frame(method_sig(), 0, idx);
+			
+			pop(idx);
+			begin_func_sync();
+			
+			/* Call it */
+			low = method_returntype();
+			
+			call_indirect_method(method_method());
+			
+			/* Pop args */
+			popargs();
+			
+			end_func_sync();
+			METHOD_RETURN_VALUE();
+		}
 	}
 }
 
Index: kaffe/kaffe/kaffevm/object.c
diff -u kaffe/kaffe/kaffevm/object.c:1.21 kaffe/kaffe/kaffevm/object.c:1.22
--- kaffe/kaffe/kaffevm/object.c:1.21	Sun Aug 31 22:09:02 2003
+++ kaffe/kaffe/kaffevm/object.c	Sat Oct 11 20:45:49 2003
@@ -58,12 +58,7 @@
 	    {
 		    JVMPI_Event ev;
 		    
-		    ev.event_type = JVMPI_EVENT_OBJECT_ALLOC;
-		    ev.u.obj_alloc.arena_id = -1;
-		    ev.u.obj_alloc.class_id = class;
-		    ev.u.obj_alloc.is_array = JVMPI_NORMAL_OBJECT;
-		    ev.u.obj_alloc.size = CLASS_FSIZE(class);
-		    ev.u.obj_alloc.obj_id = obj;
+		    jvmpiFillObjectAlloc(&ev, obj);
 		    jvmpiPostEvent(&ev);
 	    }
 #endif
@@ -137,27 +132,42 @@
 	Hjava_lang_Class* class = 0;
 	Hjava_lang_Object* obj = 0;
 
-	if (CLASS_IS_PRIMITIVE(elclass) || elclass == PtrClass) {
-		size_t total_count = (TYPE_SIZE(elclass) * count) + ARRAY_DATA_OFFSET;
-		if (total_count > count) {
-			obj = gc_malloc(total_count, GC_ALLOC_PRIMARRAY);
+	if ((class = lookupArray(elclass, info)) != NULL) {
+		size_t total_count;
+		
+		if (CLASS_IS_PRIMITIVE(elclass) || elclass == PtrClass) {
+			total_count = (TYPE_SIZE(elclass) * count) +
+				ARRAY_DATA_OFFSET;
+			if (total_count > count) {
+				obj = gc_malloc(total_count,
+						GC_ALLOC_PRIMARRAY);
+			}
 		}
-	}
-	else {
-		size_t total_count = (PTR_TYPE_SIZE * count) + ARRAY_DATA_OFFSET;
-		if (total_count > count) {
-			obj = gc_malloc(total_count, GC_ALLOC_REFARRAY);
+		else {
+			total_count = (PTR_TYPE_SIZE * count) +
+				ARRAY_DATA_OFFSET;
+			if (total_count > count) {
+				obj = gc_malloc(total_count,
+						GC_ALLOC_REFARRAY);
+			}
+		}
+		if (obj != NULL) {
+			obj->dtable = class->dtable;
+			ARRAY_SIZE(obj) = count;
+
+#if defined(ENABLE_JVMPI)
+			if( JVMPI_EVENT_ISENABLED(JVMPI_EVENT_OBJECT_ALLOC) )
+			{
+				JVMPI_Event ev;
+
+				jvmpiFillObjectAlloc(&ev, obj);
+				jvmpiPostEvent(&ev);
+			}
+#endif
+			
+		} else {
+			postOutOfMemory(info);
 		}
-	}
-	if (obj) {
-		class = lookupArray(elclass, info);
-	} else {
-		postOutOfMemory(info);
-	}
-
-	if (class) {
-		obj->dtable = class->dtable;
-		ARRAY_SIZE(obj) = count;
 	}
 DBG(NEWOBJECT,
 	dprintf("newArray %p class %s count %d\n", obj,
Index: kaffe/kaffe/kaffevm/soft.c
diff -u kaffe/kaffe/kaffevm/soft.c:1.56 kaffe/kaffe/kaffevm/soft.c:1.57
--- kaffe/kaffe/kaffevm/soft.c:1.56	Sun Aug 31 22:09:02 2003
+++ kaffe/kaffe/kaffevm/soft.c	Sat Oct 11 20:45:49 2003
@@ -38,6 +38,11 @@
 #include "fp.h"
 #include "jvmpi_kaffe.h"
 
+void
+soft_null_call(void)
+{
+}
+
 /*
  * soft_new
  */
Index: kaffe/kaffe/kaffevm/soft.h
diff -u kaffe/kaffe/kaffevm/soft.h:1.13 kaffe/kaffe/kaffevm/soft.h:1.14
--- kaffe/kaffe/kaffevm/soft.h:1.13	Sun Aug 31 22:09:02 2003
+++ kaffe/kaffe/kaffevm/soft.h	Sat Oct 11 20:45:49 2003
@@ -16,6 +16,7 @@
 struct Hjava_lang_Class;
 struct Hjava_lang_Object;
 
+void	soft_null_call(void);
 void*	soft_new(struct Hjava_lang_Class*);
 void*	soft_newarray(jint, jint);
 void*	soft_anewarray(struct Hjava_lang_Class*, jint);
Index: kaffe/kaffe/kaffevm/string.c
diff -u kaffe/kaffe/kaffevm/string.c:1.27 kaffe/kaffe/kaffevm/string.c:1.28
--- kaffe/kaffe/kaffevm/string.c:1.27	Mon Sep 22 15:31:24 2003
+++ kaffe/kaffe/kaffevm/string.c	Sat Oct 11 20:45:49 2003
@@ -119,7 +119,10 @@
 	/* Get new array object */
 	ary = (HArrayOfChar*)newArrayChecked(TYPE_CLASS(TYPE_Char),
 					     len, &info);
-	if (!ary) return 0;
+	if (!ary) {
+		discardErrorInfo(&info);
+		return 0;
+	}
 	
 	/* Convert C chars to Java chars */
 	for (k = 0; k < len; k++) {
@@ -465,11 +468,17 @@
 	/* Create a new String object */
 	ary = (HArrayOfChar*)newArrayChecked(charClass, len,
 					     &info);
-	if (!ary) return 0;
+	if (!ary) {
+		discardErrorInfo(&info);
+		return 0;
+	}
 	
 	memcpy(ARRAY_DATA(ary), data, len * sizeof(jchar));
 	string = (Hjava_lang_String*)newObjectChecked(StringClass, &info);
-	if (!string) return 0;
+	if (!string) {
+		discardErrorInfo(&info);
+		return 0;
+	}
 	unhand(string)->value = ary;
 	unhand(string)->count = len;
 
Index: kaffe/kaffe/kaffevm/thread.c
diff -u kaffe/kaffe/kaffevm/thread.c:1.55 kaffe/kaffe/kaffevm/thread.c:1.56
--- kaffe/kaffe/kaffevm/thread.c:1.55	Sun Aug 31 22:09:02 2003
+++ kaffe/kaffe/kaffevm/thread.c	Sat Oct 11 20:45:49 2003
@@ -377,13 +377,7 @@
 	{
 		JVMPI_Event ev;
 
-		ev.event_type = JVMPI_EVENT_THREAD_START;
-		ev.u.thread_start.thread_name = // XXX stringJava2C(tid->name);
-		ev.u.thread_start.group_name = stringJava2C(tid->group->name);
-		ev.u.thread_start.parent_name = NULL;
-			// XXX stringJava2C(tid->parent->name);
-		ev.u.thread_start.thread_id = tid;
-		ev.u.thread_start.thread_env_id = THREAD_JNIENV();
+		jvmpiFillThreadStart(&ev, tid);
 		jvmpiPostEvent(&ev);
 		KFREE(ev.u.thread_start.parent_name);
 		KFREE(ev.u.thread_start.group_name);
Index: kaffe/kaffe/kaffevm/jit3/codeproto.h
diff -u kaffe/kaffe/kaffevm/jit3/codeproto.h:1.13 kaffe/kaffe/kaffevm/jit3/codeproto.h:1.14
--- kaffe/kaffe/kaffevm/jit3/codeproto.h:1.13	Sun Aug 31 22:09:04 2003
+++ kaffe/kaffe/kaffevm/jit3/codeproto.h	Sat Oct 11 20:45:50 2003
@@ -117,7 +117,9 @@
 void pusharg_string_const(void*, int);
 void pusharg_class_const(struct Hjava_lang_Class*, int);
 void pusharg_utf8_const(Utf8Const*, int);
-void popargs(void);
+void popargs_internal(int does_return);
+#define popargs() popargs_internal(1)
+#define popargs_noreturn() popargs_internal(0)
 
 void return_int(SlotInfo*);
 void return_ref(SlotInfo*);
Index: kaffe/kaffe/kaffevm/jit3/icode.c
diff -u kaffe/kaffe/kaffevm/jit3/icode.c:1.33 kaffe/kaffe/kaffevm/jit3/icode.c:1.34
--- kaffe/kaffe/kaffevm/jit3/icode.c:1.33	Sun Sep 21 18:18:19 2003
+++ kaffe/kaffe/kaffevm/jit3/icode.c	Sat Oct 11 20:45:50 2003
@@ -3503,12 +3503,15 @@
 }
 
 void
-popargs(void)
+popargs_internal(int does_return)
 {
  	if (argcount != 0) {
+		if( does_return )
+		{
 #if defined(HAVE_popargs)
-		slot_slot_const(0, 0, argcount, HAVE_popargs, Tnull);
+			slot_slot_const(0, 0, argcount, HAVE_popargs, Tnull);
 #endif
+		}
 		if (argcount > maxPush) {
 			maxPush = argcount;
 		}
@@ -4839,7 +4842,7 @@
 	begin_func_sync();
 	pusharg_utf8_const(name, 0);
 	call_soft(soft_nosuchclass);
-	popargs();
+	popargs_noreturn();
 	end_func_sync();
 }
 
@@ -4857,7 +4860,7 @@
 	pusharg_class_const(cls, 0);
 #endif
 	call_soft(soft_nosuchmethod);
-	popargs();
+	popargs_noreturn();
 	end_func_sync();
 }
 
@@ -4873,7 +4876,7 @@
 	pusharg_utf8_const(cls, 0);
 #endif
 	call_soft(soft_nosuchfield);
-	popargs();
+	popargs_noreturn();
 	end_func_sync();

*** Patch too long, truncated ***