You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/10/05 04:20:10 UTC

svn commit: r294974 [21/25] - in /incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm: ./ jchevm/ jchevm/doc/ jchevm/etc/ jchevm/include/ jchevm/java/ jchevm/java/org/ jchevm/java/org/dellroad/ jchevm/java/org/dellroad/jc/ jchevm/java/org/dellroad...

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/properties.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/properties.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/properties.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/properties.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,527 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ * $Id: properties.c,v 1.17 2005/05/15 01:48:31 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* List of fixed default properties */
+static const _jc_property _jc_fixed_properties[] = {
+{ "java.version",			"1.4" },
+{ "java.vendor",			"JC virtual machine project" },
+{ "java.vendor.url",			"http://jcvm.sourceforge.net/" },
+{ "java.home",				_AC_DATADIR "/jc" },
+{ "java.vm.name",			"JC virtual machine" },
+{ "java.vm.vendor",			"JC virtual machine project" },
+{ "java.vm.version",			PACKAGE_VERSION },
+{ "java.vm.specification.name",		"Java Virtual Machine Specification" },
+{ "java.vm.specification.vendor",	"Sun Microsystems Inc." },
+{ "java.vm.specification.version",	"1.0" },
+{ "java.specification.name",		"Java Platform API Specification" },
+{ "java.specification.vendor",		"Sun Microsystems Inc." },
+{ "java.specification.version",		"1.4" },
+{ "java.class.version",			"46.0" },
+{ "java.io.tmpdir",			_JC_TEMP_DIR },
+{ "file.separator",			_JC_FILE_SEPARATOR },
+{ "line.separator",			_JC_LINE_SEPARATOR },
+{ "path.separator",			_JC_PATH_SEPARATOR },
+{ "java.library.path",			_JC_LIBRARY_PATH },
+{ "java.boot.class.path",		_JC_BOOT_CLASS_PATH },
+#if _JC_BIG_ENDIAN
+{ "gnu.cpu.endian",			"big" },
+#else
+{ "gnu.cpu.endian",			"little" },
+#endif
+#if _JC_THREAD_LOCAL_SUPPORT
+{ "jc.thread.local",			"true" },
+#else
+{ "jc.thread.local",			"false" },
+#endif
+{ "jc.stack.minimum",			_JC_STACK_MINIMUM },
+{ "jc.stack.maximum",			_JC_STACK_MAXIMUM },
+{ "jc.stack.default",			_JC_STACK_DEFAULT },
+{ "jc.heap.size",			_JC_DEFAULT_HEAP_SIZE },
+{ "jc.loader.size",			_JC_DEFAULT_LOADER_SIZE },
+{ "jc.heap.granularity",		_JC_DEFAULT_HEAP_GRANULARITY },
+{ "jc.gnu.compiler",			_JC_GNU_COMPILER },
+{ "jc.include.dir",			_JC_INCLUDE_DIR },
+{ "jc.object.generator",	"org.dellroad.jc.cgen.JCObjectGenerator" },
+{ "jc.method.optimizer",	"org.dellroad.jc.cgen.DefaultMethodOptimizer" },
+{ "jc.gen.inline.max.expansion",	"2.5" },
+{ "jc.gen.inline.max.caller",		"5000" },
+{ "jc.gen.inline.max.callee",		"12" },
+{ "jc.gen.inline.min.caller",		"20" },
+{ "jc.gen.inline.min.callee",		"3" },
+{ "jc.gen.inline.verbose",		"false" },
+{ "jc.include.line.numbers",		"true" },
+{ "jc.object.generation.enabled",	"true" },
+{ "jc.object.loader.enabled",		"true" },
+{ "jc.without.classfiles",		"false" },
+{ "jc.ignore.resolution.failures",	"false" },
+{ "jc.resolve.native.directly",		"false" },
+{ NULL,					NULL }
+};
+
+/* Internal functions */
+static jint		_jc_digest_size(_jc_env *env, size_t *ptr,
+				_jc_property *prop, size_t max);
+static _jc_property	*_jc_property_get(_jc_jvm *vm, const char *name);
+static int		_jc_property_cmp(const void *item1, const void *item2);
+
+/*
+ * Set the default system properties.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_set_system_properties(_jc_env *env)
+{
+	const char *home_dir;
+	struct utsname uts;
+	struct passwd *pw;
+	time_t now;
+	char *buf;
+	char *s;
+	int i;
+
+	/* Set fixed properties */
+	for (i = 0; _jc_fixed_properties[i].name != NULL; i++) {
+		const _jc_property *const prop = &_jc_fixed_properties[i];
+
+		if (_jc_set_property(env, prop->name, prop->value) != JNI_OK)
+			return JNI_ERR;
+	}
+
+	/* Set current working directory */
+	for (s = NULL, i = 64; JNI_TRUE; i *= 2) {
+		if (i < 0)
+			return JNI_ERR;
+		_jc_vm_free(&s);
+		if ((s = _jc_vm_zalloc(env, i)) == NULL)
+			return JNI_ERR;
+		if (getcwd(s, i) != NULL)
+			break;
+		if (errno != ERANGE) {
+			_JC_EX_STORE(env, InternalError, "%s: %s",
+			    "getcwd", strerror(errno));
+			return JNI_ERR;
+		}
+	}
+	if (_jc_set_property(env, "user.dir", s) != JNI_OK) {
+		_jc_vm_free(&s);
+		return JNI_ERR;
+	}
+	_jc_vm_free(&s);
+
+	/* Set user name and home directory */
+	if ((pw = getpwuid(getuid())) == NULL) {
+		_JC_EX_STORE(env, InternalError, "%s: %s",
+		    "getpwuid", strerror(errno));
+		return JNI_ERR;
+	}
+	if (_jc_set_property(env, "user.name", pw->pw_name) != JNI_OK)
+		return JNI_ERR;
+	if ((home_dir = getenv("HOME")) == NULL)
+		home_dir = pw->pw_dir;
+	if (_jc_set_property(env, "user.home", home_dir) != JNI_OK)
+		return JNI_ERR;
+
+	/* Set user timezone */
+	now = time(NULL);
+	if (_jc_set_property(env,
+	    "user.timezone", localtime(&now)->tm_zone) != JNI_OK)
+		return JNI_ERR;
+
+	/* Set source and object directory paths */
+	if ((buf = _JC_FORMAT_STRING(env, "%s%s.jc_src%s%s",
+	    home_dir, _JC_FILE_SEPARATOR, _JC_PATH_SEPARATOR,
+	    _JC_BOOT_SOURCE_DIR)) == NULL)
+		return JNI_ERR;
+	if (_jc_set_property(env, "jc.source.path", buf) != JNI_OK)
+		return JNI_ERR;
+	if ((buf = _JC_FORMAT_STRING(env, "%s%s.jc_obj%s%s",
+	    home_dir, _JC_FILE_SEPARATOR, _JC_PATH_SEPARATOR,
+	    _JC_BOOT_OBJECT_DIR)) == NULL)
+		return JNI_ERR;
+	if (_jc_set_property(env, "jc.object.path", buf) != JNI_OK)
+		return JNI_ERR;
+
+	/* Set operating system info */
+	if (uname(&uts) == -1) {
+		_JC_EX_STORE(env, InternalError, "%s: %s",
+		    "uname", strerror(errno));
+		return JNI_ERR;
+	}
+	if (strcmp(uts.machine, "i486") == 0
+	    || strcmp(uts.machine, "i586") == 0
+	    || strcmp(uts.machine, "i686") == 0)
+		strcpy(uts.machine, "i386");
+	if (_jc_set_property(env, "os.arch", uts.machine) != JNI_OK)
+		return JNI_ERR;
+	if (_jc_set_property(env, "os.name", uts.sysname) != JNI_OK)
+		return JNI_ERR;
+	if (_jc_set_property(env, "os.version", uts.release) != JNI_OK)
+		return JNI_ERR;
+
+	/* Done */
+	endpwent();
+	return JNI_OK;
+}
+
+/*
+ * Set a system property.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_set_property(_jc_env *env, const char *name, const char *value)
+{
+	return _jc_set_property2(env, name, strlen(name), value);
+}
+
+/*
+ * Set a system property, where the name does not have to be
+ * nul-terminated.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_set_property2(_jc_env *env, const char *name,
+	size_t name_len, const char *value)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_properties *const props = &vm->system_properties;
+	_jc_property *prop;
+	char *new_value;
+	char *new_name;
+	int i;
+
+	/* Replace property if it already exists */
+	for (i = 0; i < props->length; i++) {
+		prop = &props->elems[i];
+		if (strncmp(prop->name, name, name_len) == 0
+		    && prop->name[name_len] == '\0') {
+			if ((new_value = _jc_vm_strdup(env, value)) == NULL)
+				return JNI_ERR;
+			_jc_vm_free(&prop->value);
+			prop->value = new_value;
+			return JNI_OK;
+		}
+	}
+
+	/* Extend properties list if necessary */
+	if (props->length == props->allocated) {
+		u_int new_alloc = props->allocated + 128;
+		_jc_property *new_elems;
+
+		if ((new_elems = _jc_vm_realloc(env, props->elems,
+		    new_alloc * sizeof(*new_elems))) == NULL)
+			return JNI_ERR;
+		props->elems = new_elems;
+		props->allocated = new_alloc;
+	}
+
+	/* Add property to list */
+	prop = &props->elems[props->length];
+	memset(prop, 0, sizeof(*prop));
+	if ((new_name = _jc_vm_strndup(env, name, name_len)) == NULL)
+		return JNI_ERR;
+	if ((new_value = _jc_vm_strdup(env, value)) == NULL) {
+		_jc_vm_free(&new_name);
+		return JNI_ERR;
+	}
+	prop->name = new_name;
+	prop->value = new_value;
+
+	/* Done */
+	props->length++;
+	return JNI_OK;
+}
+
+/*
+ * Process system properties that have special meanings.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_digest_properties(_jc_env *env)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_property *prop;
+	size_t loader_size;
+	int len;
+	int i;
+
+	/* Sort properties for faster searching */
+	qsort(vm->system_properties.elems, vm->system_properties.length,
+	    sizeof(*vm->system_properties.elems), _jc_property_cmp);
+
+	/* Get whether object generation is enabled */
+	prop = _jc_property_get(vm, "jc.object.generation.enabled");
+	_JC_ASSERT(prop != NULL);
+	vm->generation_enabled = strcmp(prop->value, "true") == 0;
+
+	/* Get line number support */
+	prop = _jc_property_get(vm, "jc.include.line.numbers");
+	_JC_ASSERT(prop != NULL);
+	vm->line_numbers = strcmp(prop->value, "true") == 0;
+
+	/* Sanity check */
+	_JC_ASSERT(vm->boot.class_path == NULL);
+	_JC_ASSERT(vm->boot.class_path_len == 0);
+
+	/* Get boot loader class search path prepends */
+	prop = _jc_property_get(vm, "java.boot.class.path.prepend");
+	if (prop != NULL && _jc_parse_classpath(env, prop->value,
+	    &vm->boot.class_path, &vm->boot.class_path_len) == JNI_ERR)
+		return JNI_ERR;
+
+	/* Get boot loader class search path */
+	prop = _jc_property_get(vm, "java.boot.class.path");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_parse_classpath(env, prop->value,
+	    &vm->boot.class_path, &vm->boot.class_path_len) == JNI_ERR)
+		return JNI_ERR;
+
+	/* Get boot loader class search path appends */
+	prop = _jc_property_get(vm, "java.boot.class.path.append");
+	if (prop != NULL && _jc_parse_classpath(env, prop->value,
+	    &vm->boot.class_path, &vm->boot.class_path_len) == JNI_ERR)
+		return JNI_ERR;
+
+	/* Get object file search path */
+	prop = _jc_property_get(vm, "jc.object.path");
+	_JC_ASSERT(prop != NULL);
+
+	/* Sanity check */
+	_JC_ASSERT(vm->object_path == NULL);
+	_JC_ASSERT(vm->object_path_len == 0);
+
+	/* Parse object path */
+	if ((len = _jc_parse_objpath(env, prop->value, &vm->object_path)) == -1)
+		return JNI_ERR;
+	vm->object_path_len = len;
+
+	/* Get source and object directory paths */
+	prop = _jc_property_get(vm, "jc.source.path");
+	_JC_ASSERT(prop != NULL);
+	if ((vm->source_path = _jc_parse_searchpath(env, prop->value)) == NULL)
+		return JNI_ERR;
+
+	/* Get thread stack minimum, maximum, and default */
+	prop = _jc_property_get(vm, "jc.stack.minimum");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_digest_size(env, &vm->threads.stack_minimum, prop, 0) != JNI_OK)
+		return JNI_ERR;
+	prop = _jc_property_get(vm, "jc.stack.maximum");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_digest_size(env, &vm->threads.stack_maximum, prop, 0) != JNI_OK)
+		return JNI_ERR;
+	prop = _jc_property_get(vm, "jc.stack.default");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_digest_size(env, &vm->threads.stack_default, prop, 0) != JNI_OK)
+		return JNI_ERR;
+
+	/* Get heap size and granularity factor */
+	prop = _jc_property_get(vm, "jc.heap.size");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_digest_size(env, &vm->heap.size, prop, 0) != JNI_OK)
+		return JNI_ERR;
+	prop = _jc_property_get(vm, "jc.heap.granularity");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_digest_size(env, &vm->heap.granularity, prop, 99) != JNI_OK)
+		return JNI_ERR;
+	prop = _jc_property_get(vm, "jc.loader.size");
+	_JC_ASSERT(prop != NULL);
+	if (_jc_digest_size(env, &loader_size, prop, 0) != JNI_OK)
+		return JNI_ERR;
+	vm->max_loader_pages = _JC_HOWMANY(loader_size, _JC_PAGE_SIZE);
+	vm->avail_loader_pages = vm->max_loader_pages;
+
+	/* Check for native resolution optimization */
+	prop = _jc_property_get(vm, "jc.resolve.native.directly");
+	_JC_ASSERT(prop != NULL);
+	vm->resolve_native_directly = strcmp(prop->value, "true") == 0;
+
+	/* Check whether we really need classfiles */
+	prop = _jc_property_get(vm, "jc.without.classfiles");
+	_JC_ASSERT(prop != NULL);
+	vm->without_classfiles = strcmp(prop->value, "true") == 0;
+
+	/* Check whether to enable the ELF loader */
+	prop = _jc_property_get(vm, "jc.object.loader.enabled");
+	_JC_ASSERT(prop != NULL);
+	vm->loader_enabled = strcmp(prop->value, "true") == 0;
+
+	/* Check whether we should ignore class resolution failures */
+	prop = _jc_property_get(vm, "jc.ignore.resolution.failures");
+	_JC_ASSERT(prop != NULL);
+	vm->ignore_resolution_failures = strcmp(prop->value, "true") == 0;
+
+	/* Without classfiles or loader implies no object generation */
+	if (vm->without_classfiles || !vm->loader_enabled)
+		vm->generation_enabled = JNI_FALSE;
+
+	/* Check stack parameters */
+	if (vm->threads.stack_minimum > vm->threads.stack_default
+	    || (vm->threads.stack_maximum > 0
+	      && (vm->threads.stack_default > vm->threads.stack_maximum
+	       || vm->threads.stack_maximum < PTHREAD_STACK_MIN))) {
+		_JC_EX_STORE(env, InternalError,
+		    "invalid/incompatible values for properties"
+		    " `%s' (%d), `%s' (%d), and/or `%s' (%d)",
+		    "jc.stack.minimum", vm->threads.stack_minimum,
+		    "jc.stack.maximum", vm->threads.stack_maximum,
+		    "jc.stack.default", vm->threads.stack_default);
+		return JNI_ERR;
+	}
+
+	/* Set verbose properties from verbose flags */
+	for (i = 0; i < _JC_VERBOSE_MAX; i++) {
+		const char *const flag = _jc_verbose_names[i];
+		char name[128];
+
+		snprintf(name, sizeof(name), "jc.verbose.%s", flag);
+		if (_jc_set_property(env, name, ((vm->verbose_flags
+		    & (1 << i)) != 0) ? "true" : "false") != JNI_OK)
+			return JNI_ERR;
+	}
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Free all system properties.
+ */
+void
+_jc_destroy_properties(_jc_jvm *vm)
+{
+	int i;
+
+	for (i = 0; i < vm->system_properties.length; i++) {
+		_jc_property *const prop = &vm->system_properties.elems[i];
+
+		_jc_vm_free(&prop->name);
+		_jc_vm_free(&prop->value);
+	}
+	_jc_vm_free(&vm->system_properties.elems);
+	vm->system_properties.allocated = 0;
+	vm->system_properties.length = 0;
+}
+
+/*
+ * Digest an unsigned numerical property. Recognize suffixes for
+ * kilobytes, megabytes, etc. and convert the property if found.
+ */
+static jint
+_jc_digest_size(_jc_env *env, size_t *ptr, _jc_property *prop, size_t max)
+{
+	const char *value = prop->value;
+	size_t vlen = strlen(value);
+	unsigned long long size;
+	unsigned int units = 1;
+	char buf[64];
+	char *eptr;
+
+	/* Get units, if any */
+	if (vlen > 0) {
+		switch (value[vlen - 1]) {
+		case 'K':
+		case 'k':
+			units = 1024;
+			break;
+		case 'M':
+		case 'm':
+			units = 1024 * 1024;
+			break;
+		case 'G':
+		case 'g':
+			units = 1024 * 1024 * 1024;
+			break;
+		default:
+			break;
+		}
+		if (units != 1) {
+			if (vlen > sizeof(buf))
+				vlen = sizeof(buf);
+			strncpy(buf, value, vlen - 1);
+			buf[vlen - 1] = '\0';
+			value = buf;
+		}
+	}
+
+	/* Parse units */
+	if (((size = strtoull(value, &eptr, 0)) == ULLONG_MAX
+	      && errno == ERANGE)
+	    || (eptr == value || *eptr != '\0')) {
+		_JC_EX_STORE(env, InternalError,
+		    "invalid value `%s' for property `%s'",
+		    prop->value, prop->name);
+		return JNI_ERR;
+	}
+
+	/* Multiply by units and update property */
+	if (units > 1) {
+		size *= units;
+		snprintf(buf, sizeof(buf), "%llu", size);
+		if ((value = _jc_vm_strdup(env, buf)) == NULL)
+			return JNI_ERR;
+		_jc_vm_free(&prop->value);
+		prop->value = value;
+	}
+
+	/* Check upper bound */
+	if (size > SIZE_T_MAX || (max != 0 && size > max)) {
+		_JC_EX_STORE(env, InternalError,
+		    "value `%s' for property `%s' is too large",
+		    prop->value, prop->name);
+		return JNI_ERR;
+	}
+
+	/* Done */
+	*ptr = (size_t)size;
+	return JNI_OK;
+}
+
+/*
+ * Find a property in the sorted list.
+ */
+static _jc_property *
+_jc_property_get(_jc_jvm *vm, const char *name)
+{
+	_jc_property key;
+
+	key.name = name;
+	return bsearch(&key, vm->system_properties.elems,
+	    vm->system_properties.length, sizeof(*vm->system_properties.elems),
+	    _jc_property_cmp);
+}
+
+/*
+ * Compare two properties for sorting by name.
+ */
+static int
+_jc_property_cmp(const void *item1, const void *item2)
+{
+	const _jc_property *const prop1 = item1;
+	const _jc_property *const prop2 = item2;
+
+	return strcmp(prop1->name, prop2->name);
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/reflect.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/reflect.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/reflect.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/reflect.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,837 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ * $Id: reflect.c,v 1.25 2005/07/10 21:03:54 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static _jc_object	*_jc_get_reflected(_jc_env *env, _jc_method *constr,
+				_jc_type *type, const char *name, jint slot);
+
+/*
+ * Resolve a field declared in a specific class.
+ *
+ * If unsuccessful a NoSuchFieldError exception is stored.
+ */
+_jc_field *
+_jc_get_declared_field(_jc_env *env, _jc_type *type, const char *name,
+	const char *sig, int is_static)
+{
+	_jc_field key_data;
+	_jc_field *const key = &key_data;
+	_jc_field **fieldp;
+	_jc_field *field;
+
+	/* Only normal reference types have declared fields */
+	if ((type->flags & (_JC_TYPE_ARRAY|_JC_TYPE_MASK))
+	    != _JC_TYPE_REFERENCE)
+		goto fail;
+
+	/* Binary search for field */
+	key->name = name;
+	key->signature = sig;
+	key->access_flags = is_static ? _JC_ACC_STATIC : 0;
+	if ((fieldp = bsearch(&key, type->u.nonarray.fields,
+	    type->u.nonarray.num_fields, sizeof(*type->u.nonarray.fields),
+	    _jc_field_compare)) == NULL)
+	      	goto fail;
+	field = *fieldp;
+
+	/* Done */
+	return field;
+
+fail:
+	/* Not found */
+	_JC_EX_STORE(env, NoSuchFieldError, "%s.%s (type `%s', %sstatic)",
+	    type->name, name, sig, is_static ? "" : "non-");
+	return NULL;
+}
+
+/*
+ * Resolve a method declared in a specific class.
+ *
+ * The method's access flags in 'flags_mask' must match 'flags'.
+ *
+ * If unsuccessful a NoSuchMethodError exception is stored.
+ */
+_jc_method *
+_jc_get_declared_method(_jc_env *env, _jc_type *type, const char *name,
+	const char *sig, int flags_mask, int flags)
+{
+	_jc_method key_data;
+	_jc_method *const key = &key_data;
+	_jc_method **methodp;
+	_jc_method *method;
+
+	/* Only normal reference types have declared methods */
+	if ((type->flags & (_JC_TYPE_ARRAY|_JC_TYPE_MASK))
+	    != _JC_TYPE_REFERENCE)
+		goto fail;
+
+	/* Binary search for method */
+	key->name = name;
+	key->signature = sig;
+	if ((methodp = bsearch(&key, type->u.nonarray.methods,
+	    type->u.nonarray.num_methods, sizeof(*type->u.nonarray.methods),
+	    _jc_method_compare)) == NULL)
+	      	goto fail;
+	method = *methodp;
+
+	/* Check access flags */
+	if ((method->access_flags & flags_mask) != flags)
+		goto fail;
+
+	/* Done */
+	return method;
+
+fail:
+	/* Not found */
+	_JC_EX_STORE(env, NoSuchMethodError, "%s.%s%s", type->name, name, sig);
+	return NULL;
+}
+
+/*
+ * Get the java.lang.reflect.Field object corresponding to 'field'.
+ */
+_jc_object *
+_jc_get_reflected_field(_jc_env *env, _jc_field *field)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_type *const dclass = field->class;
+	int slot;
+
+	/* Determine slot */
+	for (slot = 0; slot < dclass->u.nonarray.num_fields; slot++) {
+		if (dclass->u.nonarray.fields[slot] == field)
+			break;
+	}
+	_JC_ASSERT(slot < dclass->u.nonarray.num_fields);
+
+	/* Return reflection object */
+	return _jc_get_reflected(env, vm->boot.methods.Field.init,
+	    dclass, field->name, slot);
+}
+
+/*
+ * Get the java.lang.reflect.Method object corresponding to 'method'.
+ */
+_jc_object *
+_jc_get_reflected_method(_jc_env *env, _jc_method *method)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_type *const dclass = method->class;
+	int slot;
+
+	/* Sanity check */
+	_JC_ASSERT(*method->name != '<');
+
+	/* Determine slot */
+	for (slot = 0; slot < dclass->u.nonarray.num_methods; slot++) {
+		if (dclass->u.nonarray.methods[slot] == method)
+			break;
+	}
+	_JC_ASSERT(slot < dclass->u.nonarray.num_methods);
+
+	/* Return reflection object */
+	return _jc_get_reflected(env, vm->boot.methods.Method.init,
+	    dclass, method->name, slot);
+}
+
+/*
+ * Get the java.lang.reflect.Constructor object corresponding to 'method'.
+ */
+_jc_object *
+_jc_get_reflected_constructor(_jc_env *env, _jc_method *method)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_type *const dclass = method->class;
+	int slot;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_ACC_TEST(method, STATIC) && *method->name == '<');
+
+	/* Determine slot */
+	for (slot = 0; slot < dclass->u.nonarray.num_methods; slot++) {
+		if (dclass->u.nonarray.methods[slot] == method)
+			break;
+	}
+	_JC_ASSERT(slot < dclass->u.nonarray.num_methods);
+
+	/* Return reflection object */
+	return _jc_get_reflected(env, vm->boot.methods.Constructor.init,
+	    dclass, NULL, slot);
+}
+
+/*
+ * Get a java.lang.reflect object. We create a new one each time,
+ * because these objects are mutable (they inherit AccessibleObject).
+ */
+static _jc_object *
+_jc_get_reflected(_jc_env *env, _jc_method *constr,
+	_jc_type *type, const char *name, jint slot)
+{
+	_jc_object *rtn = NULL;
+	jobject rref = NULL;
+	_jc_word params[3];
+	int nparam = 0;
+
+	/* Create the new reflection instance */
+	if ((rref = _jc_new_local_native_ref(env,
+	    _jc_new_object(env, constr->class))) == NULL)
+		goto done;
+
+	/* Prepare constructor parameters */
+	params[nparam++] = (_jc_word)type->instance;
+	if (name != NULL) {
+		_jc_object *string;
+
+		if ((string = _jc_new_string(env, name, strlen(name))) == NULL)
+			goto done;
+		params[nparam++] = (_jc_word)string;
+	}
+	params[nparam++] = (_jc_word)slot;
+
+	/* Initialize it */
+	if (_jc_invoke_nonvirtual_a(env, constr, *rref, params) != JNI_OK)
+		goto done;
+
+	/* Done */
+	rtn = *rref;
+
+done:
+	/* Free local native refs */
+	_jc_free_local_native_ref(&rref);
+
+	/* Done */
+	return rtn;
+}
+
+/*
+ * Find the _jc_method structure corresponding to a Method object.
+ */
+_jc_method *
+_jc_get_method(_jc_env *env, _jc_object *obj)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_method *method;
+	_jc_object *cl;
+	_jc_type *type;
+	jint slot;
+
+	/* Sanity check */
+	_JC_ASSERT(obj != NULL && obj->type == vm->boot.types.Method);
+
+	/* Locate declaring class */
+	cl = *_JC_VMFIELD(vm, obj, Method, declaringClass, _jc_object *);
+	type = _jc_get_vm_pointer(cl, vm->boot.fields.Class.vmdata);
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+
+	/* Locate method */
+	slot = *_JC_VMFIELD(vm, obj, Method, slot, jint);
+	_JC_ASSERT(slot >= 0 && slot < type->u.nonarray.num_methods);
+	method = type->u.nonarray.methods[slot];
+
+	/* Sanity check */
+	_JC_ASSERT(*method->name != '<');
+
+	/* Done */
+	return method;
+}
+
+/*
+ * Find the _jc_method structure corresponding to a Constructor object.
+ */
+_jc_method *
+_jc_get_constructor(_jc_env *env, _jc_object *obj)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_method *method;
+	_jc_object *cl;
+	_jc_type *type;
+	jint slot;
+
+	/* Sanity check */
+	_JC_ASSERT(obj != NULL && obj->type == vm->boot.types.Constructor);
+
+	/* Locate declaring class */
+	cl = *_JC_VMFIELD(vm, obj, Constructor, clazz, _jc_object *);
+	type = _jc_get_vm_pointer(cl, vm->boot.fields.Class.vmdata);
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+
+	/* Locate constructor method */
+	slot = *_JC_VMFIELD(vm, obj, Constructor, slot, jint);
+	_JC_ASSERT(slot >= 0 && slot < type->u.nonarray.num_methods);
+	method = type->u.nonarray.methods[slot];
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_ACC_TEST(method, STATIC) && *method->name == '<');
+
+	/* Done */
+	return method;
+}
+
+/*
+ * Find the _jc_field structure corresponding to a Field object.
+ */
+_jc_field *
+_jc_get_field(_jc_env *env, _jc_object *obj)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_object *cl;
+	_jc_type *type;
+	jint slot;
+
+	/* Sanity check */
+	_JC_ASSERT(obj != NULL && obj->type == vm->boot.types.Field);
+
+	/* Locate declaring class */
+	cl = *_JC_VMFIELD(vm, obj, Field, declaringClass, _jc_object *);
+	type = _jc_get_vm_pointer(cl, vm->boot.fields.Class.vmdata);
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+
+	/* Locate field */
+	slot = *_JC_VMFIELD(vm, obj, Field, slot, jint);
+	_JC_ASSERT(slot >= 0 && slot < type->u.nonarray.num_fields);
+	return type->u.nonarray.fields[slot];
+}
+
+
+/*
+ * Invoke a method or constructor via reflection.
+ *
+ * This function is used by both Method.invoke() and Constructor.newInstance().
+ */
+jint
+_jc_reflect_invoke(_jc_env *env, _jc_method *method,
+	_jc_object *this, _jc_object_array *pobjs)
+{
+	const jboolean is_static = _JC_ACC_TEST(method, STATIC);
+	const jboolean is_constructor = !is_static && *method->name == '<';
+	_jc_method *imethod = NULL;
+	jobject this_ref = NULL;
+	_jc_word *params;
+	jint status;
+	int nwords;
+	int pi;
+	int i;
+
+	/* Check class is instantiable (if constructor) */
+	if (is_constructor
+	   && (method->class->access_flags
+	    & (_JC_ACC_ABSTRACT|_JC_ACC_INTERFACE)) != 0) {
+		_jc_post_exception(env, _JC_InstantiationException);
+		goto fail;
+	}
+
+	/* Check for null 'this' */
+	if (!is_static && !is_constructor && this == NULL) {
+		_jc_post_exception(env, _JC_NullPointerException);
+		goto fail;
+	}
+
+	/* Check that 'this' is the right kind of instance */
+	if (!is_static && !is_constructor) {
+		switch (_jc_instance_of(env, this, method->class)) {
+		case 1:
+			break;
+		case 0:
+			_jc_post_exception_msg(env,
+			    _JC_IllegalArgumentException,
+			    "`%s' object is not an instance of `%s'",
+			    this->type->name, method->class->name);
+			goto fail;
+		case -1:
+			goto fail;
+		default:
+			_JC_ASSERT(JNI_FALSE);
+		}
+	}
+
+	/* Resolve interface methods using hash table lookup */
+	if (!is_static && !is_constructor
+	    && _JC_ACC_TEST(method->class, INTERFACE)) {
+	      	const jlong sig_hash = method->signature_hash;
+		_jc_type *const type = this->type;
+		const int bucket = (int)sig_hash & (_JC_IMETHOD_HASHSIZE - 1);
+		_jc_method *const *methodp;
+
+		_JC_ASSERT(type->imethod_hash_table != NULL);
+		for (methodp = type->imethod_hash_table[bucket];
+		    *methodp != NULL; methodp++) {
+			if ((*methodp)->signature_hash == sig_hash) {
+				imethod = method;
+				method = *methodp;
+				break;
+			}
+		}
+		_JC_ASSERT(*methodp != NULL);
+	}
+
+	/* Check for exceptions */
+	if (method->num_parameters > 0 && pobjs == NULL) {
+		_jc_post_exception(env, _JC_NullPointerException);
+		goto fail;
+	}
+	if (pobjs != NULL && pobjs->length != method->num_parameters) {
+		_jc_post_exception_msg(env, _JC_IllegalArgumentException,
+		    "number of parameters (%d) does not match method (%d)",
+		    pobjs->length, method->num_parameters);
+		goto fail;
+	}
+
+	/* Count parameter words */
+	nwords = method->num_parameters;
+	for (i = 0; i < method->num_parameters; i++) {
+		if (_jc_dword_type[method->param_ptypes[i]])
+			nwords++;
+	}
+
+	/* Allocate parameter array */
+	if ((params = _JC_STACK_ALLOC(env, nwords * sizeof(*params))) == NULL) {
+		_jc_post_exception_info(env);
+		goto fail;
+	}
+
+	/* Convert parameters */
+	for (pi = i = 0; i < method->num_parameters; i++) {
+		_jc_type *const ptype = method->param_types[i];
+		const int dtype = (ptype->flags & _JC_TYPE_MASK);
+		_jc_value value;
+
+		/* Convert parameter object into a _jc_value */
+		if (dtype == _JC_TYPE_REFERENCE) {
+			_jc_object *const obj = pobjs->elems[~i];
+
+			/* Check parameter has the proper type */
+			if (obj != NULL) {
+				switch (_jc_instance_of(env, obj, ptype)) {
+				case 1:
+					break;
+				case 0:
+					_jc_post_exception(env,
+					    _JC_IllegalArgumentException);
+					goto fail;
+				case -1:
+					goto fail;
+				default:
+					_JC_ASSERT(JNI_FALSE);
+				}
+			}
+			value.l = obj;
+		} else {
+			int stype;
+
+			if ((stype = _jc_unwrap_primitive(env,
+			    pobjs->elems[~i], &value)) == _JC_TYPE_INVALID)
+				goto fail;
+			if (_jc_convert_primitive(env,
+			    dtype, stype, &value) != JNI_OK)
+				goto fail;
+		}
+
+		/* Add value to parameter list */
+		switch (dtype) {
+		case _JC_TYPE_BOOLEAN:
+			params[pi++] = (jint)value.z;
+			break;
+		case _JC_TYPE_BYTE:
+			params[pi++] = (jint)value.b;
+			break;
+		case _JC_TYPE_CHAR:
+			params[pi++] = (jint)value.c;
+			break;
+		case _JC_TYPE_SHORT:
+			params[pi++] = (jint)value.s;
+			break;
+		case _JC_TYPE_INT:
+			params[pi++] = value.i;
+			break;
+		case _JC_TYPE_FLOAT:
+		    {
+			const jfloat param = value.f;
+
+			memcpy(params + pi, &param, sizeof(param));
+			pi++;
+			break;
+		    }
+		case _JC_TYPE_LONG:
+		    {
+			const jlong param = value.j;
+
+			memcpy(params + pi, &param, sizeof(param));
+			pi += 2;
+			break;
+		    }
+		case _JC_TYPE_DOUBLE:
+		    {
+			const jdouble param = value.d;
+
+			memcpy(params + pi, &param, sizeof(param));
+			pi += 2;
+			break;
+		    }
+		case _JC_TYPE_REFERENCE:
+			params[pi++] = (_jc_word)value.l;
+			break;
+		default:
+			_JC_ASSERT(JNI_FALSE);
+			break;
+		}
+	}
+
+	/* Create new instance (if constructor) */
+	if (is_constructor) {
+		if ((this_ref = _jc_new_local_native_ref(env,
+		    _jc_new_object(env, method->class))) == NULL)
+			goto fail;
+		this = *this_ref;
+	}
+
+	/* For JDK compatibility, interface methods cause initialization */
+	if (imethod != NULL
+	    && !_JC_FLG_TEST(imethod->class, INITIALIZED)
+	    && _jc_initialize_type(env, imethod->class) != JNI_OK)
+		goto fail;
+
+	/* Invoke method */
+	if (is_static) {
+		if (!_JC_FLG_TEST(method->class, INITIALIZED)
+		    && _jc_initialize_type(env, method->class) != JNI_OK)
+			goto fail;
+		status = _jc_invoke_static_a(env, method, params);
+	} else if (is_constructor)
+		status = _jc_invoke_nonvirtual_a(env, method, this, params);
+	else
+		status = _jc_invoke_virtual_a(env, method, this, params);
+
+	/* Handle exception thrown by method */
+	if (status != JNI_OK) {
+		_jc_object *e;
+		_jc_word param;
+
+		/* Get thrown exception */
+		e = _jc_retrieve_exception(env, NULL);
+		_JC_ASSERT(e != NULL);
+		param = (_jc_word)e;
+
+		/* Wrap it in a InvocationTargetException */
+		_jc_post_exception_params(env,
+		    _JC_InvocationTargetException, &param);
+		goto fail;
+	}
+
+	/* For constructors, return value is new object */
+	if (is_constructor) {
+		_JC_ASSERT(this != NULL);
+		env->retval.l = this;
+	}
+
+	/* Done */
+	_jc_free_local_native_ref(&this_ref);
+	return JNI_OK;
+
+fail:
+	/* Clean up after failure */
+	_jc_free_local_native_ref(&this_ref);
+	return JNI_ERR;
+}
+
+/*
+ * Return the parameter types of a method or constructor as a Class[] array.
+ */
+_jc_object_array *
+_jc_get_parameter_types(_jc_env *env, _jc_method *method)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_object_array *array;
+	int i;
+
+	/* Create Class[] array */
+	if ((array = (_jc_object_array *)_jc_new_array(env,
+	    vm->boot.types.Class_array, method->num_parameters)) == NULL)
+		return NULL;
+
+	/* Fill array */
+	for (i = 0; i < method->num_parameters; i++)
+		array->elems[~i] = method->param_types[i]->instance;
+
+	/* Done */
+	return array;
+}
+
+/*
+ * Return the exception types of a method or constructor as a Class[] array.
+ */
+_jc_object_array *
+_jc_get_exception_types(_jc_env *env, _jc_method *method)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_object_array *array;
+	int i;
+
+	/* Create Class[] array */
+	if ((array = (_jc_object_array *)_jc_new_array(env,
+	    vm->boot.types.Class_array, method->num_exceptions)) == NULL)
+		return NULL;
+
+	/* Fill array */
+	for (i = 0; i < method->num_exceptions; i++)
+		array->elems[~i] = method->exceptions[i]->instance;
+
+	/* Done */
+	return array;
+}
+
+/*
+ * Wrap a primitive value in an instance of the corresponding
+ * java.lang.X wrapper class.
+ *
+ * Returns NULL and posts an exception on error.
+ */
+_jc_object *
+_jc_wrap_primitive(_jc_env *env, int ptype, _jc_value *value)
+{
+	_jc_jvm *const vm = env->vm;
+	jobject ref;
+
+	/* Sanity check */
+	_JC_ASSERT(ptype >= _JC_TYPE_BOOLEAN && ptype <= _JC_TYPE_DOUBLE);
+
+	/* Create new wrapper object */
+	if ((ref = _jc_new_local_native_ref(env,
+	    _jc_new_object(env, vm->boot.types.prim_wrapper[ptype]))) == NULL)
+		return NULL;
+
+	/* Invoke constructor */
+	if (_jc_invoke_nonvirtual_a(env,
+	    vm->boot.methods.prim_wrapper[ptype].init,
+	    *ref, (_jc_word *)value) != JNI_OK) {
+		_jc_free_local_native_ref(&ref);
+		return NULL;
+	}
+
+	/* Done */
+	return _jc_free_local_native_ref(&ref);
+}
+
+/*
+ * Extract the primitive value from a wrapper class object,
+ * put the result in *value, and return the primitive type.
+ *
+ * If an exception is thrown, _JC_TYPE_INVALID is returned.
+ */
+int
+_jc_unwrap_primitive(_jc_env *env, _jc_object *obj, _jc_value *value)
+{
+	_jc_jvm *const vm = env->vm;
+	jint status;
+	int ptype;
+
+	/* Check for null */
+	if (obj == NULL) {
+		_jc_post_exception(env, _JC_IllegalArgumentException);
+		return _JC_TYPE_INVALID;
+	}
+
+	/* Check that wrapper object is really a wrapper object */
+	for (ptype = _JC_TYPE_BOOLEAN;
+	    ptype <= _JC_TYPE_DOUBLE
+	      && obj->type != vm->boot.types.prim_wrapper[ptype];
+	    ptype++);
+	if (ptype > _JC_TYPE_DOUBLE) {
+		_jc_post_exception_msg(env, _JC_IllegalArgumentException,
+		    "not a primitive wrapper class instance");
+		return _JC_TYPE_INVALID;
+	}
+
+	/* Extract the primitive value from the wrapper object */
+	if ((status = _jc_invoke_virtual(env,
+	    vm->boot.methods.prim_wrapper[ptype].value, obj)) != JNI_OK)
+		return status;
+	*value = env->retval;
+
+	/* Done */
+	return ptype;
+}
+
+/*
+ * Convert one primitive type to another by a widening conversion.
+ * If the conversion is illegal, throw an IllegalArgumentException.
+ */
+jint
+_jc_convert_primitive(_jc_env *env, int dtype, int stype, _jc_value *value)
+{
+	static const void *const
+	    convert_table[_JC_TYPE_DOUBLE + 1][_JC_TYPE_DOUBLE + 1] = {
+		[_JC_TYPE_SHORT]= {
+			[_JC_TYPE_BYTE]=	&&b2s,
+		},
+		[_JC_TYPE_INT]= {
+			[_JC_TYPE_BYTE]=	&&b2i,
+			[_JC_TYPE_CHAR]=	&&c2i,
+			[_JC_TYPE_SHORT]=	&&s2i,
+		},
+		[_JC_TYPE_LONG]= {
+			[_JC_TYPE_BYTE]=	&&b2j,
+			[_JC_TYPE_CHAR]=	&&c2j,
+			[_JC_TYPE_SHORT]=	&&s2j,
+			[_JC_TYPE_INT]=		&&i2j,
+		},
+		[_JC_TYPE_FLOAT]= {
+			[_JC_TYPE_BYTE]=	&&b2f,
+			[_JC_TYPE_CHAR]=	&&c2f,
+			[_JC_TYPE_SHORT]=	&&s2f,
+			[_JC_TYPE_INT]=		&&i2f,
+			[_JC_TYPE_LONG]=	&&j2f,
+		},
+		[_JC_TYPE_DOUBLE]= {
+			[_JC_TYPE_BYTE]=	&&b2d,
+			[_JC_TYPE_CHAR]=	&&c2d,
+			[_JC_TYPE_SHORT]=	&&s2d,
+			[_JC_TYPE_INT]=		&&i2d,
+			[_JC_TYPE_LONG]=	&&j2d,
+			[_JC_TYPE_FLOAT]=	&&f2d,
+		},
+	};
+	const void *target;
+	_jc_value svalue;
+
+	/* Sanity check */
+	_JC_ASSERT(dtype >= _JC_TYPE_BOOLEAN && dtype <= _JC_TYPE_DOUBLE);
+	_JC_ASSERT(stype >= _JC_TYPE_BOOLEAN && stype <= _JC_TYPE_DOUBLE);
+
+	/* Handle the trivial case */
+	if (dtype == stype)
+		return JNI_OK;
+
+	/* Check that the conversion is allowed */
+	if ((target = convert_table[dtype][stype]) == NULL) {
+		_jc_post_exception_msg(env, _JC_IllegalArgumentException,
+		    "illegal widening conversion");
+		return JNI_ERR;
+	}
+
+	/* Convert the value by a widening conversion */
+	svalue = *value;		/* XXX is this step necessary? */
+	goto *target;
+
+b2s:	value->s = svalue.b; return JNI_OK;
+b2i:	value->i = svalue.b; return JNI_OK;
+c2i:	value->i = svalue.c; return JNI_OK;
+s2i:	value->i = svalue.s; return JNI_OK;
+b2j:	value->j = svalue.b; return JNI_OK;
+c2j:	value->j = svalue.c; return JNI_OK;
+s2j:	value->j = svalue.s; return JNI_OK;
+i2j:	value->j = svalue.i; return JNI_OK;
+b2f:	value->f = svalue.b; return JNI_OK;
+c2f:	value->f = svalue.c; return JNI_OK;
+s2f:	value->f = svalue.s; return JNI_OK;
+i2f:	value->f = svalue.i; return JNI_OK;
+j2f:	value->f = svalue.j; return JNI_OK;
+b2d:	value->d = svalue.b; return JNI_OK;
+c2d:	value->d = svalue.c; return JNI_OK;
+s2d:	value->d = svalue.s; return JNI_OK;
+i2d:	value->d = svalue.i; return JNI_OK;
+j2d:	value->d = svalue.j; return JNI_OK;
+f2d:	value->d = svalue.f; return JNI_OK;
+}
+
+/*
+ * Determine whether a class member is accessible from the calling method.
+ * The "calling method" is the first non-reflection method on the stack.
+ *
+ * Returns:
+ *	 1	Yes
+ *	 0	No (and *calling_classp points to the calling class)
+ *	-1	Exception posted
+ */
+int
+_jc_reflect_accessible(_jc_env *env, _jc_type *member_class,
+	uint16_t access, _jc_type **calling_classp)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_type *calling_class = NULL;
+	_jc_stack_crawl crawl;
+	int rtn;
+
+	/* If member is public, we're done */
+	if ((access & _JC_ACC_PUBLIC) != 0)
+		return 1;
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+
+	/* Crawl the stack until we see a non-bootstrap ClassLoader */
+	for (_jc_stack_crawl_first(env, &crawl);
+	    crawl.method != NULL; _jc_stack_crawl_next(vm, &crawl)) {
+
+		/* Skip _jc_invoke_jcni_a() and java.lang.reflect methods */
+		if (crawl.method->class == NULL
+		    || strncmp(crawl.method->class->name, "java/lang/reflect/",
+		      sizeof("java/lang/reflect/") - 1) == 0)
+			continue;
+
+		/* Found calling class */
+		calling_class = crawl.method->class;
+		*calling_classp = calling_class;
+		break;
+	}
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Sanity check */
+	_JC_ASSERT(calling_class != NULL);
+
+	/* Compare calling class with member class and flags */
+	switch (access & (_JC_ACC_PRIVATE|_JC_ACC_PROTECTED)) {
+	case _JC_ACC_PRIVATE:
+		return calling_class == member_class;
+		break;
+	case _JC_ACC_PROTECTED:
+		if ((rtn = _jc_assignable_from(env,
+		    calling_class, member_class)) != 0)
+			return rtn;
+		/* FALLTHROUGH */
+	case 0:				/* package access */
+	    {
+		int calling_plen = 0;
+		int member_plen = 0;
+		const char *s;
+
+		/*
+		 * Check for same package.
+		 * XXX We should not say classes loaded by different
+		 * XXX class loaders are in the same package.
+		 */
+		if ((s = strrchr(member_class->name, '/')) != NULL)
+			member_plen = s - member_class->name;
+		if ((s = strrchr(calling_class->name, '/')) != NULL)
+			calling_plen = s - calling_class->name;
+		return calling_plen == member_plen
+		    && strncmp(calling_class->name,
+		      member_class->name, member_plen) == 0;
+	    }
+	default:
+		_JC_ASSERT(JNI_FALSE);
+		return -1;			/* silence compiler warning */
+	}
+}
+
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/resolve.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/resolve.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/resolve.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/resolve.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,888 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ * $Id: resolve.c,v 1.18 2005/05/10 17:21:07 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static void		_jc_resolve_vtable(_jc_jvm *vm, _jc_type *type);
+static jint		_jc_resolve_exec(_jc_env *env, _jc_type *type,
+				_jc_resolve_info *info);
+static jint		_jc_resolve_java_symbol(_jc_env *env,
+				_jc_resolve_info *info, const char *name,
+				Elf_Addr *result, jboolean *found);
+
+static _jc_elf_resolver	_jc_resolve_symbol;
+
+/* Empty interface method lookup tables */
+const void		*_jc_empty_quick_table[_JC_IMETHOD_HASHSIZE];
+_jc_method		**_jc_empty_imethod_table[_JC_IMETHOD_HASHSIZE];
+
+/*
+ * Resolve a type.
+ *
+ * This means resolving all symbolic references to other types,
+ * methods, etc. In addition, update the list of implicit references
+ * from this class' class loader to other types' Class objects.
+ *
+ * This function synchronizes on the type's Class object.
+ * The type must not be an array type.
+ */
+jint
+_jc_resolve_type(_jc_env *env, _jc_type *type)
+{
+	_jc_class_loader *const loader = type->loader;
+	_jc_object *const obj = type->instance;
+	jboolean class_locked = JNI_FALSE;
+	_jc_resolve_info info;
+	jint status = JNI_ERR;
+	int i;
+
+	/* Optimization for array types */
+	if (_JC_FLG_TEST(type, ARRAY)) {
+		_JC_ASSERT(_JC_FLG_TEST(type, RESOLVED));
+		return JNI_OK;
+	}
+
+	/* Initialize resolve info */
+	memset(&info, 0, sizeof(info));
+	info.type = type;
+	info.loader = loader;
+
+	/* Lock class object (except during initial bootstrap) */
+	if (obj != NULL) {
+		if (_jc_lock_object(env, obj) != JNI_OK)
+			goto fail;
+		class_locked = JNI_TRUE;
+	}
+
+	/* Already resolved? */
+	if (_JC_FLG_TEST(type, RESOLVED)) {
+		_JC_ASSERT(_JC_FLG_TEST(type, LOADED));
+		_JC_ASSERT(_JC_FLG_TEST(type, VERIFIED));
+		_JC_ASSERT(_JC_FLG_TEST(type, PREPARED));
+		goto done;
+	}
+
+	/* Prepare class first */
+	if (!_JC_FLG_TEST(type, PREPARED)
+	    && _jc_prepare_type(env, type) != JNI_OK)
+		goto fail;
+
+	/* For ELF types, resolve type by resolving all ELF symbols */
+	if (!_JC_ACC_TEST(type, INTERP)
+	    && _jc_resolve_exec(env, type, &info) != JNI_OK)
+	    	goto fail;
+
+	/* Ensure superclass and superinterfaces are resolved */
+	if (type->superclass != NULL
+	    && !_JC_FLG_TEST(type->superclass, RESOLVED)
+	    && _jc_resolve_type(env, type->superclass) != JNI_OK)
+		goto fail;
+	for (i = 0; i < type->num_interfaces; i++) {
+		_jc_type *const iftype = type->interfaces[i];
+
+		if (!_JC_FLG_TEST(iftype, RESOLVED)
+		    && _jc_resolve_type(env, iftype) != JNI_OK)
+			goto fail;
+	}
+
+	/* Compute vtable and mtable for this class (as needed) */
+	if (!_JC_ACC_TEST(type, INTERFACE)) {
+		_jc_jvm *const vm = env->vm;
+
+		if (!vm->loader_enabled || !vm->generation_enabled)
+			_jc_resolve_vtable(vm, type);
+	}
+
+	/* Resolve interpreted types */
+	if (_JC_ACC_TEST(type, INTERP)
+	    && _jc_resolve_interp(env, type, &info) != JNI_OK)
+	    	goto fail;
+
+	/* Merge in type's implicit references into class loader's list */
+	if (_jc_merge_implicit_refs(env, &info) != JNI_OK) {
+		_jc_post_exception_info(env);
+		goto fail;
+	}
+
+	/* Mark type as resolved */
+	type->flags |= _JC_TYPE_RESOLVED;
+
+	/* Free temporary supers info */
+	_jc_vm_free(&type->u.nonarray.supers);
+
+done:
+	_JC_ASSERT(_JC_FLG_TEST(type, LOADED));
+	_JC_ASSERT(_JC_FLG_TEST(type, RESOLVED));
+	status = JNI_OK;
+	goto out;
+
+fail:
+	/* Failed */
+	status = JNI_ERR;
+
+out:
+	/* Unlock class object */
+	if (class_locked) {
+		jint status2;
+
+		if ((status2 = _jc_unlock_object(env, obj)) != JNI_OK)
+			status = status2;
+	}
+
+	/* Clean up and return */
+	_jc_vm_free(&info.implicit_refs);
+	return status;
+}
+
+/*
+ * Resolve vtable and mtable (as needed).
+ */
+static void
+_jc_resolve_vtable(_jc_jvm *vm, _jc_type *type)
+{
+	_jc_nonarray_type *const ntype = &type->u.nonarray;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_ACC_TEST(type, INTERFACE)
+	    && (!vm->loader_enabled || !vm->generation_enabled));
+
+	/*
+	 * Copy superclass' vtable and mtable. At this point these tables
+	 * are correct except for overridden superclass methods.
+	 */
+	if (type->superclass != NULL) {
+		_jc_type *const stype = type->superclass;
+		_jc_nonarray_type *const sntype = &stype->u.nonarray;
+
+		/*
+		 * For interpreted types, copy superclass vtable.
+		 * For ELF types, the vtable should already be correct.
+		 */
+		if (_JC_ACC_TEST(type, INTERP)) {
+			memcpy(type->vtable, stype->vtable,
+			    sntype->num_vmethods * sizeof(*type->vtable));
+		}
+
+		/* Copy superclass mtable (if needed) */
+		memcpy(ntype->mtable, sntype->mtable,
+		    sntype->num_vmethods * sizeof(*ntype->mtable));
+	}
+
+	/* Handle overridden methods */
+	for (i = 0; i < ntype->num_methods; i++) {
+		_jc_method *const method = ntype->methods[i];
+		_jc_type *stype;
+
+		/* Ignore non-virtual methods */
+		if (_JC_ACC_TEST(method, STATIC) || *method->name == '<')
+			continue;
+
+		/* Override overridden methods */
+		_JC_ASSERT(method->function != NULL);
+		for (stype = type->superclass;
+		    stype != NULL; stype = stype->superclass) {
+			_jc_method *orm;
+
+			/* Is this method overridden? */
+			if ((orm = _jc_method_lookup(stype, method)) == NULL)
+				continue;
+
+			/* Override in vtable */
+			if (_JC_ACC_TEST(type, INTERP)) {
+				type->vtable[orm->vtable_index]
+				    = method->function;
+			} else {
+				_JC_ASSERT(type->vtable[orm->vtable_index]
+				    == method->function);
+			}
+
+			/* Override in mtable */
+			ntype->mtable[orm->vtable_index] = method;
+		}
+	}
+}
+
+/*
+ * Resolve a non-interpreted type, i.e., an ELF-loaded type.
+ */
+static jint
+_jc_resolve_exec(_jc_env *env, _jc_type *type, _jc_resolve_info *info)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_class_loader *const loader = type->loader;
+	_jc_elf *const elf = type->u.nonarray.u.elf;
+	jint status;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_ACC_TEST(type, INTERP));
+
+	/* Lock loader */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+
+retry:
+	/* Is this type defined in an ELF file that's already resolved? */
+	if (elf->info == NULL) {
+		_JC_MUTEX_UNLOCK(env, loader->mutex);
+		return JNI_OK;
+	}
+
+	/* Is another thread currently resolving this ELF object? */
+	if (elf->info->resolver != NULL) {
+
+		/* If recursively resolving, something wierd is happening */
+		if (elf->info->resolver == env) {
+			_JC_MUTEX_UNLOCK(env, loader->mutex);
+			_jc_post_exception_msg(env, _JC_LinkageError,
+			    "recursively resolving `%s'", elf->pathname);
+			return JNI_ERR;
+		}
+
+		/* Wait for the other thread to finish */
+		_jc_loader_wait(env, loader);
+		goto retry;
+	}
+
+	/* Mark this thread as resolving */
+	elf->info->resolver = env;
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Verbosity */
+	if (loader == vm->boot.loader) {
+		VERBOSE(RESOLUTION, vm,
+		    "resolving `%s' (via bootstrap loader)", type->name);
+	} else {
+		VERBOSE(RESOLUTION, vm,
+		    "resolving `%s' (via %s@%p)", type->name,
+		    loader->instance->type->name, loader->instance);
+	}
+
+	/*
+	 * Resolve all external symbols in the ELF image. As we resolve
+	 * symbols that refer to other types, update the list of implicit
+	 * references from this type to other types.
+	 */
+	status = _jc_elf_link(env, elf, _jc_resolve_symbol, info);
+
+	/* Lock loader */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+
+	/* Mark this thread as no longer resolving */
+	_JC_ASSERT(elf->info->resolver == env);
+	elf->info->resolver = NULL;
+
+	/* Free ELF linking info; this signals that the ELF file is resolved */
+	if (status == JNI_OK) {
+		_jc_elf_link_cleanup(elf);
+		_JC_ASSERT(elf->info == NULL);
+	}
+
+	/* Wake up other threads waiting on us */
+	if (loader->waiters) {
+		loader->waiters = JNI_FALSE;
+		_JC_COND_BROADCAST(loader->cond);
+	}
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Done */
+	return status;
+}
+
+/*
+ * Resolve a field per JVMS section 5.4.3.2.
+ * Note the static-ness of the field is not checked.
+ *
+ * Returns NULL and stores a NoSuchFieldError upon failure.
+ */
+_jc_field *
+_jc_resolve_field(_jc_env *env, _jc_type *type,
+	const char *name, const char *sig, int is_static)
+{
+	_jc_field *field;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+
+	/* Search for field in class */
+	if ((field = _jc_get_declared_field(env,
+	    type, name, sig, is_static)) != NULL)
+		return field;
+
+	/* Search for field in superinterfaces */
+	for (i = 0; i < type->num_interfaces; i++) {
+		_jc_type *itype;
+
+		itype = (!_JC_FLG_TEST(type, RESOLVED)
+		      && !_JC_ACC_TEST(type, INTERP)) ?
+		    type->u.nonarray.supers->interfaces[i] :
+		    type->interfaces[i];
+		if ((field = _jc_resolve_field(env,
+		    itype, name, sig, is_static)) != NULL)
+			return field;
+	}
+
+	/* Search for field in superclasses */
+	while (JNI_TRUE) {
+		type = (!_JC_FLG_TEST(type, RESOLVED)
+		      && !_JC_ACC_TEST(type, INTERP)) ?
+		    type->u.nonarray.supers->superclass : type->superclass;
+		if (type == NULL)
+			break;
+		if ((field = _jc_get_declared_field(env,
+		    type, name, sig, is_static)) != NULL)
+			return field;
+	}
+
+	/* Not found */
+	return NULL;
+}
+
+/*
+ * Resolve a method per JVMS section 5.4.3.3 and 5.4.3.4.
+ * Note the static-ness of the method is not checked.
+ *
+ * Returns NULL and stores an exception upon failure.
+ */
+_jc_method *
+_jc_resolve_method(_jc_env *env, _jc_type *type,
+	const char *name, const char *sig)
+{
+	_jc_method *method;
+	_jc_type *stype;
+	jboolean clinit;
+	int i;
+
+	/* Special case for <clinit> (don't recurse) */
+	clinit = strcmp(name, "<clinit>") == 0;
+
+	/* Search for method in class and superclasses */
+	for (stype = type; stype != NULL; ) {
+		if ((method = _jc_get_declared_method(env,
+		    stype, name, sig, 0, 0)) != NULL)
+			return method;
+		if (clinit)
+			return NULL;
+		stype = (!_JC_FLG_TEST(stype, RESOLVED)
+		      && !_JC_ACC_TEST(stype, INTERP)) ?
+		    stype->u.nonarray.supers->superclass : stype->superclass;
+	}
+
+	/* Search for method in superinterfaces */
+	for (i = 0; i < type->num_interfaces; i++) {
+		_jc_type *itype;
+
+		itype = (!_JC_FLG_TEST(type, RESOLVED)
+		      && !_JC_ACC_TEST(type, INTERP)) ?
+		    type->u.nonarray.supers->interfaces[i] :
+		    type->interfaces[i];
+		if ((method = _jc_resolve_method(env,
+		    itype, name, sig)) != NULL)
+			return method;
+	}
+
+	/* Not found */
+	return NULL;
+}
+
+/*
+ * Resolve an unresolved external reference in an ELF file.
+ *
+ * This function is used as a callback from the ELF linker code.
+ */
+static jint
+_jc_resolve_symbol(_jc_env *env, void *arg, const char *name, Elf_Addr *result)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_resolve_info *const info = arg;
+	_jc_native_lib *lib;
+	const void *func;
+	jboolean found;
+
+	/* If not a symbol we know about? */
+	if (strncmp(name, "_jc_", 4) != 0)
+		goto search_external;
+
+	/* Handle "_jc_check_address" */
+	if (strcmp(name, "_jc_check_address") == 0) {
+		*result = (Elf_Addr)vm->check_address;
+		return JNI_OK;
+	}
+
+	/* Handle empty interface method tables */
+	if (strcmp(name, "_jc_empty_quick_table") == 0) {
+		*result = (Elf_Addr)_jc_empty_quick_table;
+		return JNI_OK;
+	}
+	if (strcmp(name, "_jc_empty_imethod_table") == 0) {
+		*result = (Elf_Addr)_jc_empty_imethod_table;
+		return JNI_OK;
+	}
+
+	/* Search C support functions, which all have "_jc_cs_" prefix */
+	if (strncmp(name, "_jc_cs_", 7) == 0) {
+		if ((func = dlsym(NULL, name)) != NULL) {
+			*result = (Elf_Addr)func;
+			return JNI_OK;
+		}
+	}
+
+	/* Try to parse a Java type, method, etc. symbol */
+	if (_jc_resolve_java_symbol(env, info, name, result, &found) != JNI_OK)
+		return JNI_ERR;
+	if (found)
+		return JNI_OK;
+
+	/*
+	 * If symbol started with "_jc_" but was not found, then
+	 * generate an error. Alternately, we could try to search
+	 * for it in external libraries, but that is likely to not
+	 * be correct and means a less clear namespace separation.
+	 */
+	goto not_found;
+
+search_external:
+	/*
+	 * If we get here, the symbol is not a Java symbol.
+	 * Search for it first in the shared libraries associated with
+	 * the class loader, then in the shared C libraries that are
+	 * loaded on behalf of this process by the normal runtime linker.
+	 */
+
+	/* Search the loader's shared libraries */
+	STAILQ_FOREACH(lib, &info->loader->native_libs, link) {
+		if ((func = dlsym(lib->handle, name)) != NULL) {
+			*result = (Elf_Addr)func;
+			return JNI_OK;
+		}
+	}
+
+	/* Search normally loaded shared libraries */
+	if ((func = dlsym(RTLD_DEFAULT, name)) != NULL) {
+		*result = (Elf_Addr)func;
+		return JNI_OK;
+	}
+
+#ifdef __linux__
+    {
+    	static void *kludge;
+
+	/* Stupid Linux. dlsym() won't retrieve GCC helper functions */
+	if ((kludge != NULL
+	      || (kludge = dlopen("/lib/libgcc_s.so.1", RTLD_NOW)) != NULL)
+	    && (func = dlsym(kludge, name)) != NULL) {
+		*result = (Elf_Addr)func;
+		return JNI_OK;
+	}
+    }
+#endif
+
+not_found:
+	/* Symbol not found */
+	_jc_post_exception_msg(env, _JC_LinkageError,
+	    "can't resolve symbol `%s' in ELF object `%s'",
+	    name, info->type->u.nonarray.u.elf->pathname);
+	return JNI_ERR;
+}
+
+/*
+ * Resolve a symbol that refers to a Java type, method, etc.
+ *
+ * Sets *found to true or false depending on the outcome.
+ * If not found, *result will not be modified and JNI_OK
+ * is returned.
+ *
+ * An error is returned only if an exception is thrown.
+ */
+static jint
+_jc_resolve_java_symbol(_jc_env *env, _jc_resolve_info *info,
+	const char *name, Elf_Addr *result, jboolean *found)
+{
+	_jc_jvm *const vm = env->vm;
+	int ptype = _JC_TYPE_INVALID;
+	char *class_name;
+	const char *s;
+	_jc_type *type;
+	int dims = 0;
+	char *p;
+	int i;
+
+	/* Find dollar sign */
+	if (strncmp(name, "_jc_", 4) != 0)
+		goto unknown;
+	name += 4;
+	if ((s = strchr(name, '$')) == NULL)
+		goto unknown;
+	s++;
+
+	/* Check for an array type and get dimensions if so */
+	if (strncmp(s, "array", 5) == 0) {
+		s += 5;
+		for (i = 0; i < 3; i++) {
+			if (!isdigit(s[i]))
+				break;
+			if (dims == 0 && s[i] == '0')
+				break;
+			dims = dims * 10 + (s[i] - '0');
+			if (dims < 0 || dims > 255)
+				goto unknown;
+		}
+		if (dims == 0)		/* "$array$x" abbreviates "$array1$x" */
+			dims = 1;
+		if (s[i] != '$')
+			goto unknown;
+		s += i + 1;
+	}
+
+	/* Check for a primitive base type */
+	if (strncmp(s, "prim$", 5) == 0) {
+		s += 5;				/* advance past the "prim$" */
+		switch (*name) {
+		case 'b':			/* boolean or byte */
+			if (strncmp(name, "boolean$", 8) == 0)
+				ptype = _JC_TYPE_BOOLEAN;
+			else if (strncmp(name, "byte$", 5) == 0)
+				ptype = _JC_TYPE_BYTE;
+			break;
+		case 'c':			/* char */
+			if (strncmp(name, "char$", 5) == 0)
+				ptype = _JC_TYPE_CHAR;
+			break;
+		case 's':			/* short */
+			if (strncmp(name, "short$", 6) == 0)
+				ptype = _JC_TYPE_SHORT;
+			break;
+		case 'i':			/* int */
+			if (strncmp(name, "int$", 4) == 0)
+				ptype = _JC_TYPE_INT;
+			break;
+		case 'l':			/* long */
+			if (strncmp(name, "long$", 5) == 0)
+				ptype = _JC_TYPE_LONG;
+			break;
+		case 'f':			/* float */
+			if (strncmp(name, "float$", 6) == 0)
+				ptype = _JC_TYPE_FLOAT;
+			break;
+		case 'd':			/* double */
+			if (strncmp(name, "double$", 7) == 0)
+				ptype = _JC_TYPE_DOUBLE;
+			break;
+		case 'v':			/* void */
+			if (strncmp(name, "void$", 5) == 0)
+				ptype = _JC_TYPE_VOID;
+			break;
+		default:
+			break;
+		}
+
+		/* Bail out if none matched */
+		if (ptype == _JC_TYPE_INVALID)
+			goto unknown;
+
+		/* Handle zero and one dimensional types directly */
+		switch (dims) {
+		case 0:
+			type = vm->boot.types.prim[ptype];
+			goto got_type;
+		case 1:
+			if (ptype == _JC_TYPE_VOID)
+				goto unknown;		/* no void[] type */
+			type = vm->boot.types.prim_array[ptype];
+			goto got_type;
+		default:
+			break;
+		}
+
+		/* Generate multi-dimensional array type name */
+		if ((class_name = _JC_STACK_ALLOC(env, dims + 2)) == NULL) {
+			_jc_post_exception_info(env);
+			return JNI_ERR;
+		}
+		memset(class_name, '[', dims);
+		class_name[dims] = _jc_prim_chars[ptype];
+		class_name[dims + 1] = '\0';
+		goto resolve_type;
+	}
+
+	/* Generate (possibly array) type name */
+	if ((class_name = _JC_STACK_ALLOC(env,
+	    dims + (s - name) + 3)) == NULL) {
+		_jc_post_exception_info(env);
+		return JNI_ERR;
+	}
+	p = class_name;
+	if (dims > 0) {
+		memset(p, '[', dims);
+		p += dims;
+		*p++ = 'L';
+	}
+	if ((p = _jc_name_decode(name, p)) == NULL)
+		goto unknown;
+	if (dims > 0)
+		*p++ = ';';
+	*p = '\0';
+
+resolve_type:
+	/*
+	 * Resolve the type. If we can't, but "jc.ignore.resolution.failures"
+	 * is set to true, then ignore the failure and just return zero.
+	 */
+	if ((type = _jc_load_type(env, info->loader, class_name)) == NULL) {
+		if (vm->ignore_resolution_failures
+		    && _jc_unpost_exception(env, _JC_LinkageError)) {
+			*result = (Elf_Addr)0;
+			goto found;
+		}
+		return JNI_ERR;
+	}
+
+got_type:
+	/* Sanity check */
+	_JC_ASSERT(type->instance != NULL);
+
+	/* Add a reference to the resolved type's class loader */
+	if (_jc_resolve_add_loader_ref(env, info, type->loader) != JNI_OK) {
+		_jc_post_exception_info(env);
+		return JNI_ERR;
+	}
+
+	/* Is just the type needed? */
+	if (strcmp(s, "type") == 0) {
+		*result = (Elf_Addr)type;
+		goto found;
+	}
+
+	/* Is the type's Class instance needed? */
+	if (strcmp(s, "class_object") == 0) {
+		*result = (Elf_Addr)type->instance;
+		_JC_ASSERT(*result != 0);
+		goto found;
+	}
+
+	/* Is the type's static fields structure needed? */
+	if (strcmp(s, "class_fields") == 0) {
+		if (_JC_FLG_TEST(type, ARRAY)
+		    || type->u.nonarray.class_fields == NULL)
+			goto unknown;
+		*result = (Elf_Addr)type->u.nonarray.class_fields;
+		_JC_ASSERT(*result != 0);
+		goto found;
+	}
+
+	/* Is one of the type's methods or method info structures needed? */
+	if (strncmp(s, "method$", 7) == 0
+	    || strncmp(s, "method_info$", 12) == 0) {
+		const int is_info = (s[6] == '_');
+		size_t name_len;
+		jlong sig_hash;
+		char *buf;
+
+		/* Sanity check */
+		if (_JC_FLG_TEST(type, ARRAY))
+			goto unknown;
+
+		/* Parse out and decode method name */
+		name = s + (is_info ? 12 : 7);
+		if ((s = strchr(name, '$')) == NULL)
+			goto unknown;
+		name_len = s - name;
+		s++;
+		if (strncmp(name, "_init", 5) == 0)
+			name = "<init>";
+		else if (strncmp(name, "_clinit", 7) == 0)
+			name = "<clinit>";
+		else {
+			if ((buf = _JC_STACK_ALLOC(env,
+			    name_len + 1)) == NULL) {
+				_jc_post_exception_info(env);
+				return JNI_ERR;
+			}
+			if (_jc_name_decode(name, buf) == NULL)
+				goto unknown;
+			name = buf;
+		}
+
+		/* Parse out method signature hash */
+		for (sig_hash = 0, i = 0; i < 16 && s[i] != '\0'; i++) {
+			if (!isxdigit(s[i]))
+				goto unknown;
+			sig_hash = (sig_hash << 4) | _JC_HEXVAL(s[i]);
+		}
+
+		/* Intpreted types must be resolved here */
+		if (_JC_ACC_TEST(type, INTERP)
+		    && _jc_resolve_type(env, type) != JNI_OK)
+			return JNI_ERR;
+
+		/* Search for method */
+		for (i = 0; i < type->u.nonarray.num_methods; i++) {
+			_jc_method *const method = type->u.nonarray.methods[i];
+
+			/* Is this the method? */
+			if (method->signature_hash != sig_hash
+			    || strcmp(method->name, name) != 0)
+				continue;
+
+			/* Return method info if desired */
+			if (is_info) {
+				*result = (Elf_Addr)method;
+				_JC_ASSERT(*result != 0);
+				goto found;
+			}
+
+			/*
+			 * If method is native, JCNI, and resolved,
+			 * optimize by linking directly to it if enabled.
+			 */
+			if (_JC_ACC_TEST(method, NATIVE)
+			    && vm->resolve_native_directly) {
+
+				/* Resolve native method if not already */
+				if (method->native_function == NULL) {
+					if (_jc_resolve_native_method(env,
+					      method) != JNI_OK
+					    && !_jc_unpost_exception(env,
+					      _JC_UnsatisfiedLinkError))
+						return JNI_ERR;
+				}
+
+				/* Method must be resolved and a JCNI method */
+				if (method->native_function != NULL
+				    && _JC_ACC_TEST(method, JCNI)) {
+					*result = (Elf_Addr)
+					    method->native_function;
+					_JC_ASSERT(*result != 0);
+					goto found;
+				}
+			}
+
+			/* Resolve normally to method's C function */
+			*result = (Elf_Addr)method->function;
+			_JC_ASSERT(*result != 0);
+			goto found;
+		}
+
+		/* Not found */
+		goto unknown;
+	}
+
+unknown:
+	/* Not a recognized symbol */
+	*found = JNI_FALSE;
+	return JNI_OK;
+
+found:
+	/* Found it */
+	*found = JNI_TRUE;
+	return JNI_OK;
+}
+
+/*
+ * Add an implicit reference from one class loader to another.
+ *
+ * If the two loaders are the same, or the other loader is the boot
+ * loader (which is never GC'd), then don't bother adding the reference.
+ *
+ * If the other loader is already in the list, don't bother adding it.
+ *
+ * Stores an exception on failure.
+ */
+jint
+_jc_resolve_add_loader_ref(_jc_env *env, _jc_resolve_info *info,
+	_jc_class_loader *loader)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_object *ref;
+
+	/* Avoid unecessary references */
+	if (loader == info->loader || loader == vm->boot.loader)
+		return JNI_OK;
+
+	/*
+	 * Sanity check: the boot loader should never reference other
+	 * class loaders directly, because the boot loader has no parent.
+	 */
+	_JC_ASSERT(info->loader != vm->boot.loader);
+
+	/* Sanity check: non-boot loaders have associated ClassLoader objects */
+	_JC_ASSERT(loader->instance != NULL);
+
+	/* Get reference to the ClassLoader object */
+	ref = loader->instance;
+
+	/* Add reference to loader instance */
+	return _jc_resolve_add_ref(env, info, ref);
+}
+
+/*
+ * Add an implicit reference from one class loader to an object.
+ *
+ * Stores an exception on failure.
+ */
+jint
+_jc_resolve_add_ref(_jc_env *env, _jc_resolve_info *info, _jc_object *ref)
+{
+	int lim;
+	int i;
+
+	/* Sanity check */
+	if (ref == NULL)
+		return JNI_OK;
+
+	/* See if reference already exists in list (via binary search) */
+	for (i = 0, lim = info->num_implicit_refs; lim != 0; lim >>= 1) {
+		const int j = i + (lim >> 1);
+
+		if (ref == info->implicit_refs[j])
+			return JNI_OK;
+		if (ref > info->implicit_refs[j]) {
+			i = j + 1;
+			lim--;
+		}
+	}
+
+	/* Make room in the array for the new reference */
+	if (info->num_implicit_refs == info->num_implicit_alloc) {
+		const int new_alloc = info->num_implicit_alloc
+		    + _JC_CL_ALLOC_IMPLICIT_REFS;
+		_jc_object **new_refs;
+
+		if ((new_refs = _jc_vm_realloc(env, info->implicit_refs,
+		    new_alloc * sizeof(*new_refs))) == NULL)
+			return JNI_ERR;
+		info->implicit_refs = new_refs;
+		info->num_implicit_alloc = new_alloc;
+	}
+
+	/* Shift higher references over by one */
+	memmove(info->implicit_refs + i + 1, info->implicit_refs + i,
+	    (info->num_implicit_refs++ - i) * sizeof(*info->implicit_refs));
+
+	/* Insert the new reference in its proper place */
+	info->implicit_refs[i] = ref;
+	return JNI_OK;
+}
+