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, ¶m, sizeof(param));
+ pi++;
+ break;
+ }
+ case _JC_TYPE_LONG:
+ {
+ const jlong param = value.j;
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_DOUBLE:
+ {
+ const jdouble param = value.d;
+
+ memcpy(params + pi, ¶m, 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, ¶m);
+ 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;
+}
+