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 [13/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/elf.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/elf.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/elf.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/elf.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,884 @@
+
+/*
+ * 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: elf.c,v 1.5 2005/02/23 22:48:16 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static jint _jc_elf_load_link(_jc_env *env, _jc_elf *elf,
+ char **vaddrp, Elf_Off *vsizep);
+static void _jc_elf_destroy_link_info(_jc_elf_info **infop);
+static jint _jc_elf_resolve(_jc_env *env, _jc_elf *elf,
+ _jc_elf_resolver *resolver, void *arg);
+static jint _jc_elf_resolve_sym(_jc_env *env, _jc_elf *elf,
+ _jc_elf_loadable *loadable,
+ const Elf_Rela *rela,
+ _jc_elf_resolver *resolver, void *arg);
+static jint _jc_elf_process(_jc_env *env, _jc_elf *elf);
+
+/* Internal variables */
+static const u_char elf_magic[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
+
+/*
+ * Load an ELF object file, resolve all symbols that can be resolved
+ * locally within the file, and do some initial processing. The ELF file
+ * is returned with one reference.
+ *
+ * If unsuccessful an exception is stored.
+ */
+_jc_elf *
+_jc_elf_load(_jc_env *env, _jc_class_loader *loader, const char *path)
+{
+ _jc_jvm *const vm = env->vm;
+ const size_t pathlen = strlen(path);
+ _jc_elf *elf;
+
+ /* Lock loader */
+ _JC_MUTEX_LOCK(env, loader->mutex);
+
+ /* Initialize new 'elf' structure */
+ if ((elf = _jc_cl_alloc(env, loader,
+ sizeof(*elf) + pathlen + 1)) == NULL) {
+ _JC_MUTEX_UNLOCK(env, loader->mutex);
+ return NULL;
+ }
+
+ /* Unlock loader */
+ _JC_MUTEX_UNLOCK(env, loader->mutex);
+
+ /* Initialize ELF structure */
+ memset(elf, 0, sizeof(*elf));
+ elf->refs = 1;
+ elf->loader = loader;
+ memcpy(elf->pathname, path, pathlen + 1);
+ _jc_splay_init(&elf->types, _jc_type_cmp, _JC_OFFSETOF(_jc_type, node));
+
+ /* Verbosity */
+ if (loader == vm->boot.loader)
+ VERBOSE(OBJ, vm, "trying `%s' (via bootstrap loader)", path);
+ else {
+ VERBOSE(OBJ, vm, "trying `%s' (via %s@%p)",
+ path, loader->instance->type->name, loader->instance);
+ }
+
+ /* Load object file */
+ if (_jc_elf_load_link(env, elf,
+ &elf->vaddr, &elf->vsize) == JNI_ERR)
+ goto fail;
+
+ /* Verbosity */
+ if (loader == vm->boot.loader) {
+ VERBOSE(OBJ, vm, "processing `%s' (via bootstrap loader)",
+ path);
+ } else {
+ VERBOSE(OBJ, vm, "processing `%s' (via %s@%p)",
+ path, loader->instance->type->name, loader->instance);
+ }
+
+ /* Do initial linking */
+ if (_jc_elf_resolve(env, elf, NULL, NULL) != JNI_OK)
+ goto fail;
+
+ /* Do initial processing */
+ if (_jc_elf_process(env, elf) != JNI_OK)
+ goto fail;
+
+ /* Done */
+ return elf;
+
+fail:
+ VERBOSE(OBJ, vm, "failed: %s: %s",
+ _jc_vmex_names[env->ex.num], env->ex.msg);
+ _jc_elf_unref(&elf);
+ return NULL;
+}
+
+/*
+ * Increment reference count on an ELF object.
+ */
+void
+_jc_elf_addref(_jc_elf *elf)
+{
+ _jc_word old_refs;
+
+ /* Increment ref count */
+ _JC_ASSERT(elf->refs > 0);
+ do
+ old_refs = elf->refs;
+ while (!_jc_compare_and_swap(&elf->refs, old_refs, old_refs + 1));
+}
+
+/*
+ * Unreference an ELF object.
+ */
+void
+_jc_elf_unref(_jc_elf **elfp)
+{
+ _jc_class_loader *loader;
+ _jc_elf *elf = *elfp;
+ _jc_word old_refs;
+
+ /* Sanity check */
+ if (elf == NULL)
+ return;
+ *elfp = NULL;
+
+ /* Decrement ref count */
+ _JC_ASSERT(elf->refs > 0);
+ do
+ old_refs = elf->refs;
+ while (!_jc_compare_and_swap(&elf->refs, old_refs, old_refs - 1));
+ if (elf->refs > 0)
+ return;
+
+ /* Destroy ELF link info */
+ _jc_elf_destroy_link_info(&elf->info);
+
+ /* Lock loader */
+ loader = elf->loader;
+ _JC_MUTEX_LOCK(_jc_get_current_env(), loader->mutex);
+
+ /* Try to give back class loader memory */
+ _jc_cl_unalloc(loader, &elf->vaddr, elf->vsize);
+ _jc_cl_unalloc(loader, &elf, sizeof(*elf) + strlen(elf->pathname) + 1);
+
+ /* Unlock loader */
+ _JC_MUTEX_UNLOCK(_jc_get_current_env(), loader->mutex);
+}
+
+/*
+ * Link a loaded ELF file and flush the instruction cache.
+ *
+ * It is assumed that internally resolvable symbols have already
+ * been resolved.
+ */
+jint
+_jc_elf_link(_jc_env *env, _jc_elf *elf, _jc_elf_resolver *resolver, void *arg)
+{
+ _jc_elf_info *const info = elf->info;
+ int i;
+
+ /* Sanity check */
+ _JC_ASSERT(resolver != NULL);
+ _JC_ASSERT(elf->info != NULL);
+
+ /* Resolve external references */
+ if (_jc_elf_resolve(env, elf, resolver, arg) != JNI_OK)
+ return JNI_ERR;
+
+ /* Flush the i-cache for executable sections */
+ for (i = 0; i < info->num_loadables; i++) {
+ _jc_elf_loadable *const loadable = &info->loadables[i];
+ const Elf_Shdr *const shdr = loadable->shdr;
+
+ if ((shdr->sh_flags & SHF_EXECINSTR) != 0)
+ _jc_iflush(loadable->vaddr, shdr->sh_size);
+ }
+
+ /* Done */
+ return JNI_OK;
+}
+
+/*
+ * Free up memory used by the linking and symbol resolution process.
+ */
+void
+_jc_elf_link_cleanup(_jc_elf *elf)
+{
+ _jc_elf_destroy_link_info(&elf->info);
+}
+
+/*
+ * Load and ELF file but don't do anything much with it.
+ *
+ * The object is loaded using class loader memory, in a region
+ * described upon return by *vaddrp and *vsizep.
+ *
+ * If unsuccessful an exception is stored.
+ */
+static jint
+_jc_elf_load_link(_jc_env *env, _jc_elf *elf, char **vaddrp, Elf_Off *vsizep)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_class_loader *const loader = elf->loader;
+ const Elf_Ehdr *ehdr;
+ const Elf_Shdr *symtab = NULL;
+ const Elf_Shdr *strtab = NULL;
+ const Elf_Shdr *stabstr = NULL;
+ const char *shdr_strings;
+ char *aligned_vaddr;
+ _jc_elf_info *info;
+ Elf_Off max_align;
+ char *vaddr = NULL;
+ Elf_Off vsize = 0;
+ Elf_Off offset;
+ struct stat sb;
+ int esave;
+ int fd;
+ int i;
+
+ /* Sanity check */
+ _JC_ASSERT(elf->info == NULL);
+
+ /* Initialize new ELF linkage structure */
+ if ((info = _jc_vm_zalloc(env, sizeof(*info))) == NULL)
+ return JNI_ERR;
+
+ /* Open the ELF file and mmap() it in read-only */
+ if ((fd = open(elf->pathname, O_RDONLY)) == -1 || fstat(fd, &sb) == -1)
+ goto fail_errno;
+ (void)fcntl(fd, F_SETFD, 1);
+ info->map_size = sb.st_size;
+ info->map_base = mmap(NULL, info->map_size,
+ PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+ esave = errno;
+ close(fd);
+ if (info->map_base == MAP_FAILED) {
+ errno = esave;
+ goto fail_errno;
+ }
+ ehdr = info->ehdr = (const Elf_Ehdr *)info->map_base;
+
+ /* Check that we're looking at the right kind of file */
+ if (memcmp(ehdr, elf_magic, sizeof(elf_magic)) != 0) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' is not an ELF object file", elf->pathname);
+ goto fail_errmsg;
+ }
+ if (ehdr->e_ident[EI_CLASS] != _JC_ELF_CLASS
+ || ehdr->e_ident[EI_DATA] != _JC_ELF_DATA
+ || ehdr->e_machine != _JC_ELF_MACHINE
+ || ehdr->e_shentsize != sizeof(Elf_Shdr)) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' has an unsupported ELF format", elf->pathname);
+ goto fail_errmsg;
+ }
+ if (ehdr->e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr->e_version != EV_CURRENT) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' has an unsupported ELF version", elf->pathname);
+ goto fail_errmsg;
+ }
+ if (ehdr->e_type != ET_REL) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' is not a relocatable object", elf->pathname);
+ goto fail_errmsg;
+ }
+ if (ehdr->e_shoff == 0 || ehdr->e_shstrndx == SHN_UNDEF) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' is missing required section header info",
+ elf->pathname);
+ goto fail_errmsg;
+ }
+
+ /* Initialize pointers to section header table and its strings */
+ info->shdrs = (const Elf_Shdr *)(info->map_base + ehdr->e_shoff);
+ shdr_strings = info->map_base + info->shdrs[ehdr->e_shstrndx].sh_offset;
+
+ /* Create array of loadable sections */
+ if ((info->loadables = _jc_vm_zalloc(env,
+ ehdr->e_shnum * sizeof(*info->loadables))) == NULL)
+ goto fail;
+
+ /* Create array that maps section index back to loadable section */
+ if ((info->shdr2section = _jc_vm_alloc(env,
+ ehdr->e_shnum * sizeof(*info->shdr2section))) == NULL)
+ goto fail;
+
+ /* Scan the section header entries for loadable sections */
+ offset = 0;
+ max_align = _JC_FULL_ALIGNMENT;
+ for (info->num_loadables = i = 0; i < ehdr->e_shnum; i++) {
+ const Elf_Shdr *const shdr = &info->shdrs[i];
+ const char *const sname = shdr_strings + shdr->sh_name;
+ _jc_elf_loadable *const loadable
+ = &info->loadables[info->num_loadables];
+
+ /* Ignore non-loadable sections from this point on */
+ if ((shdr->sh_flags & SHF_ALLOC) == 0)
+ continue;
+
+ /* Sanity check */
+ if (shdr->sh_addr != 0) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "section `%s' in `%s' has non-zero section"
+ " load address", sname, elf->pathname);
+ goto fail_errmsg;
+ }
+
+ /* Initialize new loadable section */
+ memset(loadable, 0, sizeof(*loadable));
+ loadable->name = sname;
+ loadable->shdr = shdr;
+ loadable->bytes = info->map_base + shdr->sh_offset;
+ info->shdr2section[i] = loadable;
+
+ /* Keep track of maximum alignment for all loadable sections */
+ if (shdr->sh_addralign > max_align)
+ max_align = shdr->sh_addralign;
+
+ /* Align the load offset for this section */
+ if (shdr->sh_addralign > _JC_FULL_ALIGNMENT)
+ offset = _JC_ROUNDUP2(offset, shdr->sh_addralign);
+ loadable->offset = offset;
+
+ /*
+ * Update offset to account for this section's length.
+ * Keep all sections aligned at least to _JC_FULL_ALIGNMENT.
+ */
+ offset = _JC_ROUNDUP2(offset + shdr->sh_size,
+ _JC_FULL_ALIGNMENT);
+
+ /* Continue */
+ info->num_loadables++;
+ }
+
+ /* Scan section header entries for debug, symbol and string sections */
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ const Elf_Shdr *const shdr = &info->shdrs[i];
+ const char *const sname = shdr_strings + shdr->sh_name;
+ _jc_elf_debug_lines *const dlines = &info->debug_lines;
+
+ /* Remember symbol and string sections */
+ if (strcmp(sname, ".symtab") == 0) {
+ symtab = shdr;
+ continue;
+ }
+ if (strcmp(sname, ".strtab") == 0) {
+ strtab = shdr;
+ continue;
+ }
+ if (strcmp(sname, ".stabstr") == 0) {
+ stabstr = shdr; /* stabs strings */
+ continue;
+ }
+
+ /* Remember debug sections containing line number info */
+ if (!vm->line_numbers)
+ continue;
+ if (strcmp(sname, ".debug_line") == 0)
+ dlines->type = _JC_LINE_DEBUG_DWARF2;
+ else if (strcmp(sname, ".stab") == 0)
+ dlines->type = _JC_LINE_DEBUG_STABS;
+ else
+ continue;
+ dlines->loadable.name = sname;
+ dlines->loadable.shdr = shdr;
+ dlines->loadable.bytes = info->map_base + shdr->sh_offset;
+ dlines->loadable.vaddr = info->map_base + shdr->sh_offset;
+ info->shdr2section[i] = &dlines->loadable;
+ }
+
+ /* Get pointers to symbols and strings */
+ if (symtab == NULL || strtab == NULL) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' is missing a symbol or string table",
+ elf->pathname);
+ goto fail_errmsg;
+ }
+ info->symbols = (const Elf_Sym *)(info->map_base + symtab->sh_offset);
+ info->num_symbols = symtab->sh_size / sizeof(*info->symbols);
+ info->strings = info->map_base + strtab->sh_offset;
+
+ /* If debug section was found get other associated info */
+ switch (info->debug_lines.type) {
+ case _JC_LINE_DEBUG_DWARF2:
+ {
+ _jc_elf_debug_lines *const dlines = &info->debug_lines;
+
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ const Elf_Shdr *const shdr = &info->shdrs[i];
+ const char *const sname = shdr_strings + shdr->sh_name;
+
+ if (strcmp(sname, ".rel.debug_line") == 0)
+ dlines->loadable.rel = shdr;
+ else if (strcmp(sname, ".rela.debug_line") == 0)
+ dlines->loadable.rela = shdr;
+ }
+ break;
+ }
+ case _JC_LINE_DEBUG_STABS:
+ {
+ _jc_elf_debug_lines *const dlines = &info->debug_lines;
+
+ if (stabstr == NULL) {
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "`%s' has no .stabstr section", elf->pathname);
+ goto fail_errmsg;
+ }
+ dlines->strings = info->map_base + stabstr->sh_offset;
+ break;
+ }
+ case _JC_LINE_DEBUG_NONE:
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ }
+
+ /* Find relocation sections for all loadable sections */
+ for (i = 0; i < info->num_loadables; i++) {
+ _jc_elf_loadable *const loadable = &info->loadables[i];
+ char relaname[64];
+ char relname[64];
+ int j;
+
+ snprintf(relname, sizeof(relname), ".rel%s", loadable->name);
+ snprintf(relaname, sizeof(relaname), ".rela%s", loadable->name);
+ for (j = 0; j < ehdr->e_shnum; j++) {
+ const Elf_Shdr *const shdr = &info->shdrs[j];
+ const char *sname = shdr_strings + shdr->sh_name;
+
+ if (strcmp(sname, relname) == 0)
+ loadable->rel = shdr;
+ else if (strcmp(sname, relaname) == 0)
+ loadable->rela = shdr;
+ }
+ }
+
+ /*
+ * Allocate memory for the loadable sections. Ensure that we can
+ * align ourselves to 'max_align' by allocating a little extra.
+ */
+ offset += max_align - _JC_FULL_ALIGNMENT;
+ vsize = offset;
+ _JC_MUTEX_LOCK(env, loader->mutex);
+ vaddr = _jc_cl_alloc(env, loader, vsize);
+ _JC_MUTEX_UNLOCK(env, loader->mutex);
+ if (vaddr == NULL)
+ goto fail;
+ aligned_vaddr = (void *)_JC_ROUNDUP2((Elf_Off)vaddr, max_align);
+
+ /* Load the loadable sections */
+ for (i = 0; i < info->num_loadables; i++) {
+ _jc_elf_loadable *const loadable = &info->loadables[i];
+ const Elf_Shdr *const shdr = loadable->shdr;
+
+ loadable->vaddr = aligned_vaddr + loadable->offset;
+ if (shdr->sh_type != SHT_NOBITS)
+ memcpy(loadable->vaddr, loadable->bytes, shdr->sh_size);
+ else
+ memset(loadable->vaddr, 0, shdr->sh_size);
+ }
+
+ /* Done */
+ *vaddrp = vaddr;
+ *vsizep = vsize;
+ elf->info = info;
+ return JNI_OK;
+
+fail_errno:
+ snprintf(env->ex.msg, sizeof(env->ex.msg),
+ "%s: %s", elf->pathname, strerror(errno));
+
+fail_errmsg:
+ env->ex.num = _JC_LinkageError;
+
+fail:
+ /* Clean up after failure */
+ _JC_MUTEX_LOCK(env, loader->mutex);
+ _jc_cl_unalloc(loader, &vaddr, vsize);
+ _jc_elf_destroy_link_info(&info);
+ _JC_MUTEX_UNLOCK(env, loader->mutex);
+ return JNI_ERR;
+}
+
+/*
+ * Destroy an ELF linking structure.
+ *
+ * NOTE: This assume the associated class loader mutex is locked.
+ */
+static void
+_jc_elf_destroy_link_info(_jc_elf_info **infop)
+{
+ _jc_elf_info *info = *infop;
+
+ /* Sanity check */
+ if (info == NULL)
+ return;
+ *infop = NULL;
+
+ /* Destroy structure */
+ _JC_ASSERT(info->resolver == NULL);
+ munmap((void *)info->map_base, info->map_size);
+ _jc_vm_free(&info->shdr2section);
+ _jc_vm_free(&info->loadables);
+ _jc_vm_free(&info);
+}
+
+/*
+ * Resolve a symbol in an ELF object. There are two cases here.
+ *
+ * If 'resolver' is NULL, only symbols resolvable internally are
+ * resolved, and exceptions are stored, not posted. Otherwise,
+ * only symbols resolvable externally are resolved, 'resolver' is
+ * used to resolve them, and exceptions are posted.
+ */
+static inline jint
+_jc_elf_resolve_sym(_jc_env *env, _jc_elf *elf, _jc_elf_loadable *loadable,
+ const Elf_Rela *rela, _jc_elf_resolver *resolver, void *arg)
+{
+ const Elf_Word type = ELF_R_TYPE(rela->r_info);
+ _jc_elf_info *const info = elf->info;
+ const Elf_Sym *const sym = &info->symbols[ELF_R_SYM(rela->r_info)];
+ const char *name = info->strings + sym->st_name;
+
+ switch (sym->st_shndx) {
+ case SHN_ABS:
+ if (resolver != NULL)
+ break;
+ if (_jc_elf_arch_reloc(env, elf->pathname,
+ loadable->vaddr, rela->r_offset, type,
+ sym->st_value, rela->r_addend) != JNI_OK)
+ return JNI_ERR;
+ break;
+ case SHN_UNDEF:
+ {
+ Elf_Addr value;
+
+ if (resolver == NULL)
+ break;
+ if ((*resolver)(env, arg,
+ info->strings + sym->st_name, &value) != JNI_OK)
+ return JNI_ERR;
+ if (_jc_elf_arch_reloc(env, elf->pathname, loadable->vaddr,
+ rela->r_offset, type, value, rela->r_addend) != JNI_OK) {
+ _jc_post_exception_info(env);
+ return JNI_ERR;
+ }
+ break;
+ }
+ case SHN_COMMON:
+ _JC_ASSERT(resolver == NULL);
+ _JC_EX_STORE(env, LinkageError,
+ "%s: ELF symbol `%s' is common (not supported)",
+ elf->pathname, name);
+ return JNI_ERR;
+ default:
+ {
+ const _jc_elf_loadable *sym_section;
+
+ /* Skip if only resolving externals */
+ if (resolver != NULL)
+ break;
+
+ /* Sanity check the symbol's section */
+ if (sym->st_shndx >= info->ehdr->e_shnum
+ || (sym_section
+ = info->shdr2section[sym->st_shndx]) == NULL) {
+ _JC_EX_STORE(env, LinkageError,
+ "%s: invalid section index %d for symbol `%s'",
+ elf->pathname, sym->st_shndx, name);
+ return JNI_ERR;
+ }
+
+ /* Apply relocation */
+ if (_jc_elf_arch_reloc(env, elf->pathname,
+ loadable->vaddr, rela->r_offset, type,
+ (Elf_Addr)(sym_section->vaddr + sym->st_value),
+ rela->r_addend) != JNI_OK)
+ return JNI_ERR;
+ break;
+ }
+ }
+
+ /* Done */
+ return JNI_OK;
+}
+
+/*
+ * Resolve symbols in an ELF file.
+ *
+ * If 'resolver' is NULL, only symbols resolvable internally are
+ * resolved. Otherwise, only symbols resolvable externally are
+ * resolved, and 'resolver' is used to resolve them.
+ *
+ * Exceptions are posted if resolver != NULL, otherwise stored.
+ */
+static jint
+_jc_elf_resolve(_jc_env *env, _jc_elf *elf,
+ _jc_elf_resolver *resolver, void *arg)
+{
+ _jc_elf_info *const info = elf->info;
+ _jc_elf_debug_lines *const dlines = &info->debug_lines;
+ int i;
+
+ /* Resolve normal relocations for loadable sections */
+ for (i = 0; i < info->num_loadables; i++) {
+ _jc_elf_loadable *const section = &info->loadables[i];
+ const Elf_Shdr *const rsect = section->rel;
+ const Elf_Rel *rels;
+ int num_rels;
+ int j;
+
+ /* If no relocations, skip this section */
+ if (rsect == NULL)
+ continue;
+
+ /* Get pointer to relocations and count */
+ rels = (const Elf_Rel *)(info->map_base + rsect->sh_offset);
+ num_rels = rsect->sh_size / sizeof(*rels);
+
+ /* Process normal relocations */
+ for (j = 0; j < num_rels; j++) {
+ const Elf_Rel *const rel = &rels[j];
+ Elf_Rela rela;
+
+ rela.r_offset = rel->r_offset;
+ rela.r_info = rel->r_info;
+ rela.r_addend = 0;
+ if (_jc_elf_resolve_sym(env, elf,
+ section, &rela, resolver, arg) != JNI_OK)
+ return JNI_ERR;
+ }
+ }
+
+ /* Resolve addend relocations for loadable sections */
+ for (i = 0; i < info->num_loadables; i++) {
+ _jc_elf_loadable *const section = &info->loadables[i];
+ const Elf_Shdr *const rsect = section->rela;
+ const Elf_Rela *relas;
+ int num_relas;
+ int j;
+
+ /* If no relocations, skip this section */
+ if (rsect == NULL)
+ continue;
+
+ /* Get pointer to relocations and count */
+ relas = (const Elf_Rela *)(info->map_base + rsect->sh_offset);
+ num_relas = rsect->sh_size / sizeof(*relas);
+
+ /* Process addend relocations */
+ for (j = 0; j < num_relas; j++) {
+ if (_jc_elf_resolve_sym(env, elf,
+ section, &relas[j], resolver, arg) != JNI_OK)
+ return JNI_ERR;
+ }
+ }
+
+ /* Resolve normal relocations for debug line section, if any */
+ if (resolver == NULL && dlines->loadable.rel != NULL) {
+ _jc_elf_loadable *const section = &dlines->loadable;
+ const Elf_Shdr *const rsect = section->rel;
+ const Elf_Rel *rels;
+ int num_rels;
+ int j;
+
+ /* Get pointer to relocations and count */
+ rels = (const Elf_Rel *)(info->map_base + rsect->sh_offset);
+ num_rels = rsect->sh_size / sizeof(*rels);
+
+ /* Process normal relocations */
+ for (j = 0; j < num_rels; j++) {
+ const Elf_Rel *const rel = &rels[j];
+ Elf_Rela rela;
+
+ rela.r_offset = rel->r_offset;
+ rela.r_info = rel->r_info;
+ rela.r_addend = 0;
+ if (_jc_elf_resolve_sym(env, elf,
+ section, &rela, NULL, NULL) != JNI_OK)
+ return JNI_ERR;
+ }
+ }
+
+ /* Resolve addend relocations for debug line section, if any */
+ if (resolver == NULL && dlines->loadable.rela != NULL) {
+ _jc_elf_loadable *const section = &dlines->loadable;
+ const Elf_Shdr *const rsect = section->rela;
+ const Elf_Rela *relas;
+ int num_relas;
+ int j;
+
+ /* Get pointer to relocations and count */
+ relas = (const Elf_Rela *)(info->map_base + rsect->sh_offset);
+ num_relas = rsect->sh_size / sizeof(*relas);
+
+ /* Process addend relocations */
+ for (j = 0; j < num_relas; j++) {
+ if (_jc_elf_resolve_sym(env, elf,
+ section, &relas[j], NULL, NULL) != JNI_OK)
+ return JNI_ERR;
+ }
+ }
+
+ /* Done */
+ return JNI_OK;
+}
+
+/*
+ * Scan a newly loaded ELF file and do the following:
+ *
+ * - Find all _jc_type definitions therein by scanning the symbol table
+ * and put them in the ELF file's unloaded types tree.
+ *
+ * - Compute the ending address of all method functions, which is
+ * computed using the 'size' attribute of the corresponding ELF symbol
+ *
+ * - Create the PC -> Java line number table index mapping, which is
+ * computed using line number information in the ELF debug section
+ *
+ * This assumes that the initial intra-file ELF linking has been done.
+ *
+ * If unsuccessful, an exception is stored.
+ */
+static jint
+_jc_elf_process(_jc_env *env, _jc_elf *elf)
+{
+ _jc_elf_info *const info = elf->info;
+ _jc_method_node *node;
+ _jc_method_node key;
+ _jc_splay_tree methods;
+ _jc_method *method;
+ _jc_uni_mem uni;
+ int i;
+
+ /* Initialize temporary method info tree */
+ _jc_splay_init(&methods, _jc_method_node_compare,
+ _JC_OFFSETOF(_jc_method_node, node));
+
+ /* Create temporary uni-allocator to hold _jc_method_node's */
+ _jc_uni_alloc_init(&uni, 0, NULL);
+
+ /* Scan symbol table and gather information about types & methods */
+ for (i = 0; i < info->num_symbols; i++) {
+ const Elf_Sym *const sym = &info->symbols[i];
+ const char *sym_name = info->strings + sym->st_name;
+ const _jc_elf_loadable *sym_section = NULL;
+ const char *s;
+ void *addr;
+
+ /* Check symbol type */
+ switch (sym->st_shndx) {
+ case SHN_ABS:
+ break;
+ case SHN_UNDEF:
+ case SHN_COMMON:
+ continue;
+ default:
+ /* Sanity check the symbol's section */
+ if (sym->st_shndx >= info->ehdr->e_shnum
+ || (sym_section
+ = info->shdr2section[sym->st_shndx]) == NULL)
+ continue;
+ break;
+ }
+
+ /* Check if symbol is a JC symbol */
+ if (strncmp(sym_name, "_jc_", 4) != 0
+ || (s = strchr(sym_name + 4, '$')) == NULL)
+ continue;
+
+ /* Get symbol's value */
+ switch (sym->st_shndx) {
+ case SHN_ABS: /* not likely! */
+ addr = (void *)sym->st_value;
+ break;
+ default:
+ addr = sym_section->vaddr + sym->st_value;
+ break;
+ }
+
+ /* Check if symbol is for a _jc_type */
+ if (strcmp(s + 1, "type") == 0) {
+ _jc_type *const type = addr;
+
+ _jc_splay_insert(&elf->types, type);
+ type->loader = elf->loader;
+ type->u.nonarray.u.elf = elf;
+ continue;
+ }
+
+ /* Check if symbol is for a _jc_method or method function */
+ if (strncmp(s + 1, "method", 6) != 0)
+ continue;
+ key.cname = sym_name + 4;
+ key.clen = s - key.cname;
+ s += 7; /* skip "$method" */
+ if (*s == '$') { /* function symbol */
+ key.mname = s + 1;
+ method = NULL;
+ } else if (strncmp(s, "_info$", 6) == 0) {
+ key.mname = s + 6; /* _jc_method symbol */
+ method = (_jc_method *)addr;
+ } else
+ continue; /* shouldn't happen */
+ key.mlen = strlen(key.mname);
+
+ /* Find/create method info node in tree */
+ if ((node = _jc_splay_find(&methods, &key)) == NULL) {
+
+ /* Don't create nodes for non-concrete methods */
+ if (method != NULL && method->function == NULL)
+ continue;
+
+ /* Create new node */
+ if ((node = _jc_uni_zalloc(env,
+ &uni, sizeof(*node))) == NULL)
+ goto fail;
+ node->cname = key.cname;
+ node->clen = key.clen;
+ node->mname = key.mname;
+ node->mlen = key.mlen;
+ _jc_splay_insert(&methods, node);
+ }
+
+ /* Update node with method function size or method pointer */
+ if (method == NULL) {
+ _JC_ASSERT(node->size == 0);
+ _JC_ASSERT(sym->st_size > 0);
+ node->size = sym->st_size;
+ } else {
+ _JC_ASSERT(node->method == NULL);
+ node->method = method;
+ }
+
+ /* Compute function ending address if we have all the info */
+ if (node->method != NULL && node->size > 0) {
+ _JC_ASSERT(node->method->function != NULL);
+ _JC_ASSERT(!_JC_ACC_TEST(node->method, INTERP));
+ node->method->u.exec.function_end
+ = (const char *)node->method->function + node->size;
+ }
+ }
+
+ /* Process any debug section containing line number info */
+ switch (info->debug_lines.type) {
+ case _JC_LINE_DEBUG_DWARF2:
+ if (_jc_debug_line_dwarf2(env, elf, &methods) != JNI_OK)
+ goto fail;
+ break;
+ case _JC_LINE_DEBUG_STABS:
+ if (_jc_debug_line_stabs(env, elf, &methods) != JNI_OK)
+ goto fail;
+ break;
+ default:
+ break;
+ }
+
+ /* Done */
+ _jc_uni_alloc_free(&uni);
+ return JNI_OK;
+
+fail:
+ /* Clean up after failure */
+ _jc_uni_alloc_free(&uni);
+ return JNI_ERR;
+}
+
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/exception.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/exception.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/exception.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/exception.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,539 @@
+
+/*
+ * 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: exception.c,v 1.15 2005/03/16 15:31:12 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static void _jc_bootstrap_exception(_jc_env *env, int num, const char *msg);
+
+/*
+ * Post one of the special, pre-instatiated VM exceptions.
+ *
+ * 'env' may be NULL.
+ */
+void
+_jc_post_exception(_jc_env *env, int num)
+{
+ _jc_post_exception_msg(env, num, NULL);
+}
+
+/*
+ * Post an exception using an exception info structure.
+ */
+void
+_jc_post_exception_info(_jc_env *env)
+{
+ _JC_ASSERT(env->ex.num >= 0 && env->ex.num < _JC_VMEXCEPTION_MAX);
+ if (*env->ex.msg != '\0')
+ _jc_post_exception_msg(env, env->ex.num, "%s", env->ex.msg);
+ else
+ _jc_post_exception_msg(env, env->ex.num, NULL);
+#ifndef NDEBUG
+ env->ex.num = -1;
+#endif
+}
+
+/*
+ * Post one of the special VM exceptions with the optional message string.
+ *
+ * 'env' may be NULL.
+ */
+void
+_jc_post_exception_msg(_jc_env *env, int num, const char *fmt, ...)
+{
+ _jc_jvm *const vm = env->vm;
+ jobject sref = NULL;
+ char *msgbuf = NULL;
+ _jc_word param;
+ va_list args;
+
+ /* Sanity check */
+ _JC_ASSERT(num >= 0 && num < _JC_VMEXCEPTION_MAX);
+
+ /* Format the message string */
+ if (fmt != NULL) {
+ va_start(args, fmt);
+ msgbuf = _JC_FORMAT_STRINGV(env, fmt, args);
+ va_end(args);
+ }
+
+ /* Handle an exception thrown during the bootstrap process */
+ if (vm == NULL || vm->initialization != NULL) {
+ if (vm == NULL || !vm->initialization->may_execute) {
+ _jc_bootstrap_exception(env, num, msgbuf);
+ return;
+ }
+ if (vm->boot.objects.vmex[num] == NULL) {
+ _JC_ASSERT(vm->initialization != NULL);
+ _jc_fatal_error(vm, "%s thrown during bootstrap",
+ _jc_vmex_names[num]);
+ return;
+ }
+ }
+
+ /* Create message String object */
+ if (msgbuf != NULL) {
+ if ((sref = _jc_new_local_native_ref(env,
+ _jc_new_string(env, msgbuf, strlen(msgbuf)))) == NULL)
+ return;
+ param = (_jc_word)*sref;
+ } else
+ param = (_jc_word)NULL;
+
+ /* Create and post the exception */
+ _jc_post_exception_params(env, num, ¶m);
+
+ /* Clean up */
+ _jc_free_local_native_ref(&sref);
+}
+
+/*
+ * Instantiate and post one of the special VM exceptions with the
+ * supplied constructor parameters. The parameters must match the
+ * constructor resolved for this exception during bootstrapping.
+ *
+ * This assumes env != NULL and that we are past the point during
+ * bootstrap where code execution is enabled.
+ *
+ * If we are already trying to post it, use one the pre-instantiated
+ * one to avoid infinite recursion.
+ */
+void
+_jc_post_exception_params(_jc_env *env, int num, _jc_word *params)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_method *const cons = vm->boot.methods.vmex[num].init;
+ _jc_object *e;
+
+ /* Sanity check */
+ _JC_ASSERT(env != NULL);
+ _JC_ASSERT(env->head.pending == NULL);
+ _JC_ASSERT(num >= 0 && num < _JC_VMEXCEPTION_MAX);
+ _JC_ASSERT(vm->initialization == NULL
+ || vm->initialization->may_execute);
+
+ /* Don't recursively try throw the same exception */
+ if ((env->in_vmex & (1 << num)) != 0) {
+
+ /* Pre-instantiated exception may not exist during bootstrap */
+ if ((e = vm->boot.objects.vmex[num]) == NULL) {
+ _JC_ASSERT(vm->initialization != NULL);
+ _jc_fatal_error(vm, "%s recursively thrown"
+ " during bootstrap", _jc_vmex_names[num]);
+ return;
+ }
+
+ /* Print verbose message */
+ if ((env->vm->verbose_flags
+ & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: %s recursively thrown]\n",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS],
+ _jc_vmex_names[num]);
+ }
+
+ /* Just post the pre-instantiated version of this exception */
+ goto post_it;
+ }
+
+ /* Enable recursion detection */
+ env->in_vmex |= (1 << num);
+
+ /* Verbosity */
+ if ((env->vm->verbose_flags & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ char *buf = NULL;
+ size_t len;
+
+ /* Decode first paramater if it's a message string */
+ if (strncmp(cons->signature, "(Ljava/lang/String;", 19) == 0
+ && params[0] != (_jc_word)NULL) {
+ _jc_object *const string = (_jc_object *)params[0];
+
+ len = _jc_decode_string_utf8(env, string, NULL);
+ if ((buf = _jc_vm_alloc(env, len + 1)) != NULL)
+ _jc_decode_string_utf8(env, string, buf);
+ }
+
+ /* Print verbose message */
+ _jc_printf(vm, "[verbose %s: posting in thread %p: %s%s%s]\n",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS], env,
+ _jc_vmex_names[num], buf != NULL ? ": " : "",
+ buf != NULL ? buf : "");
+ _jc_vm_free(&buf);
+ }
+
+ /* Create new exception object */
+ if ((e = _jc_new_object(env, vm->boot.types.vmex[num])) == NULL)
+ goto done;
+
+ /* Invoke constructor with supplied parameters */
+ if (_jc_invoke_nonvirtual_a(env, cons, e, params) != JNI_OK)
+ goto done;
+
+post_it:
+ /* Post the exception to this thread */
+ env->head.pending = e;
+
+done:
+ /* Clean up */
+ env->in_vmex &= ~(1 << num);
+}
+
+/*
+ * Post an exception using an already-instatiated Throwable object.
+ *
+ * Any previously posted exception overrides 'exception'.
+ */
+void
+_jc_post_exception_object(_jc_env *env, _jc_object *exception)
+{
+ _jc_jvm *const vm = env->vm;
+
+ /* Sanity check */
+ _JC_ASSERT(_jc_subclass_of(exception, env->vm->boot.types.Throwable));
+
+ /* Verbosity */
+ if ((env->vm->verbose_flags & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: posting in thread %p: ",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS], env);
+ _jc_fprint_exception_headline(env, stdout, exception);
+ _jc_printf(vm, "]\n");
+ }
+
+ /* Post the exception to this thread */
+ _JC_ASSERT(env->head.pending == NULL);
+ env->head.pending = exception;
+}
+
+/*
+ * Handle an exception during VM creation. Instead of trying to create
+ * an actual Throwable object, we just store the exception type, message,
+ * and stack trace in the vm->initialization structure.
+ */
+static void
+_jc_bootstrap_exception(_jc_env *env, int num, const char *msg)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_initialization *const init = vm->initialization;
+ int num_frames;
+
+ /* Sanity check */
+ _JC_ASSERT(vm == NULL || vm->initialization != NULL);
+
+ /* Discard any previous bootstrap exception */
+ init->ex.num = -1;
+ init->num_frames = 0;
+ _jc_vm_free(&init->frames);
+
+ /* "Post" new exception */
+ init->ex.num = num;
+
+ /* Verbosity */
+ VERBOSE(EXCEPTIONS, env->vm, "bootstrap exception: %s: %s",
+ _jc_vmex_names[num], msg);
+
+ /* Avoid infinite recursion */
+ if ((env->in_vmex & (1 << _JC_OutOfMemoryError)) != 0)
+ return;
+
+ /* Save message */
+ if (msg != NULL) {
+ strncpy(init->ex.msg, msg, sizeof(init->ex.msg) - 1);
+ init->ex.msg[sizeof(init->ex.msg) - 1] = '\0';
+ } else
+ *init->ex.msg = '\0';
+
+ /* Save stack trace */
+ num_frames = _jc_save_stack_frames(env, env, 0, NULL);
+ if ((init->frames = _jc_vm_alloc(env,
+ num_frames * sizeof(*init->frames))) == NULL)
+ return;
+ init->num_frames = num_frames;
+ _jc_save_stack_frames(env, env, init->num_frames, init->frames);
+}
+
+/*
+ * Throw an exception.
+ *
+ * It must have already been posted.
+ */
+void
+_jc_throw_exception(_jc_env *env)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_stack_crawl crawl;
+ _jc_catch_frame *catch;
+ int target_index = 1;
+
+ /* Sanity check */
+ _JC_ASSERT(env->status == _JC_THRDSTAT_RUNNING_NORMAL
+ || env->status == _JC_THRDSTAT_HALTING_NORMAL);
+ _JC_ASSERT(vm->initialization == NULL
+ || vm->initialization->may_execute);
+ _JC_ASSERT(env->head.pending != NULL);
+
+ /* Retrieve and un-post the exception */
+ env->head.caught = _jc_retrieve_exception(env, NULL);
+
+ /* Verbosity */
+ if ((env->vm->verbose_flags & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: throwing in thread %p: ",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS], env);
+ _jc_fprint_exception_headline(env, stdout, env->head.caught);
+ _jc_printf(vm, "]\n");
+ }
+
+ /* Lock VM */
+ _JC_MUTEX_LOCK(env, vm->mutex);
+
+ /*
+ * Crawl up the stack, searching for a method that:
+ *
+ * (a) Matches the current catch frame (i.e., same method); and
+ * (b) Has a matching trap table entry for the exception
+ *
+ * If we find a method that satisfies (a) but not (b) then
+ * the current catch frame is discarded, as it corresponds to
+ * a frame that might have caught the exception but didn't.
+ * The corresponding method must be (indirectly) recursive.
+ */
+ catch = env->head.catch_list;
+ for (_jc_stack_crawl_first(env, &crawl);
+ JNI_TRUE; _jc_stack_crawl_next(vm, &crawl)) {
+ _jc_method *const method = crawl.method;
+ int i;
+
+ /* We should never run out of stack or catch frames */
+ _JC_ASSERT(method != NULL);
+ _JC_ASSERT(catch != NULL);
+ _JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+
+ /* Does this frame's method correspond to the catch frame? */
+ if (method != catch->method)
+ continue;
+
+ /*
+ * If the method doesn't have a trap table, it must be
+ * _jc_invoke_jcni_a(), which catches all exceptions.
+ */
+ if (method->u.exec.trap_table_len == 0) {
+ _JC_ASSERT(method == &vm->invoke_method);
+ if ((env->vm->verbose_flags
+ & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: caught via %s()"
+ " in thread %p: ",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS],
+ method->name, env);
+ _jc_fprint_exception_headline(env,
+ stdout, env->head.caught);
+ _jc_printf(vm, "]\n");
+ }
+ break;
+ }
+ _JC_ASSERT(method->class != NULL);
+
+ /* If not within any trap region, skip the trap scan */
+ if (catch->region == 0)
+ goto not_caught;
+
+ /* Search trap table for a matching range and exception */
+ for (i = 0; i < method->u.exec.trap_table_len; i++) {
+ _jc_trap_info *const trap
+ = &method->u.exec.trap_table[i];
+
+ /* Sanity check */
+ _JC_ASSERT(trap->start > 0 && trap->end > trap->start);
+
+ /* Did the exception happen within the trap region? */
+ if (catch->region < trap->start
+ || catch->region >= trap->end)
+ continue;
+
+ /* Does the exception type match what's caught? */
+ if (trap->type != NULL
+ && !_jc_subclass_of(env->head.caught, trap->type))
+ continue;
+
+ /* Derive trap target index from trap table index */
+ target_index = i + 1;
+
+ /* Verbosity */
+ if ((env->vm->verbose_flags
+ & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: caught via trap"
+ " %d (%d-%d) in %s.%s%s in thread %p: ",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS],
+ target_index - 1, trap->start, trap->end,
+ method->class->name, method->name,
+ method->signature, env);
+ _jc_fprint_exception_headline(env,
+ stdout, env->head.caught);
+ _jc_printf(vm, "]\n");
+ }
+
+ /* Unwind the stack */
+ goto found;
+ }
+
+not_caught:
+ /* Exception not caught; discard the current catch frame */
+ catch = catch->next;
+ }
+
+found:
+ /* Unlock VM */
+ _JC_MUTEX_UNLOCK(env, vm->mutex);
+
+ /* Unlink all catch frames added after the target catch frame */
+ env->head.catch_list = catch;
+
+ /* Reset the top Java stack frame */
+ env->java_stack = crawl.stack;
+ _JC_ASSERT(env->java_stack == NULL || !env->java_stack->interp);
+ ((_jc_exec_stack *)env->java_stack)->pc = NULL;
+#ifndef NDEBUG
+ _jc_stack_frame_init(&((_jc_exec_stack *)env->java_stack)->frame);
+#endif
+
+ /* Jump back to the catching method, supplying the target trap index */
+ _JC_ASSERT(target_index > 0);
+ siglongjmp(catch->context, target_index);
+}
+
+/*
+ * Retrieve this thread's pending exception and un-post it, if any.
+ *
+ * If "type" is not NULL, only retrieve the exception if it is an
+ * instance of the type (otherwise return NULL and leave it posted).
+ */
+_jc_object *
+_jc_retrieve_exception(_jc_env *env, _jc_type *type)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_object *const e = env->head.pending;
+
+ /* Sanity check */
+ _JC_ASSERT(env == _jc_get_current_env());
+ _JC_ASSERT(e != NULL);
+
+ /* If type doesn't match, return NULL and leave it posted */
+ if (type != NULL && !_jc_subclass_of(e, type))
+ return NULL;
+
+ /* Verbosity */
+ if ((env->vm->verbose_flags & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: unposting in thread %p: ",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS], env);
+ _jc_fprint_exception_headline(env, stdout, e);
+ _jc_printf(vm, "]\n");
+ }
+
+ /* Un-post the exception and return it */
+ env->head.pending = NULL;
+ return e;
+}
+
+/*
+ * Atomically retrieve the cross-posted exception, if any.
+ */
+_jc_object *
+_jc_retrieve_cross_exception(_jc_env *env)
+{
+ _jc_object *e;
+
+ /*
+ * Check for an exception posted by another thread.
+ * Retrieve it atomically so as to not lose any.
+ */
+ while ((e = env->cross_exception) != NULL) {
+ if (_jc_compare_and_swap((_jc_word *)&env->cross_exception,
+ (_jc_word)e, (_jc_word)NULL))
+ break;
+ }
+ return e;
+}
+
+/*
+ * Version of _jc_retrieve_exception() suitable for use by code
+ * in the bootstrap path, when the exception may not be a real object.
+ * The exeception is not retrieved, it's only unposted.
+ */
+jboolean
+_jc_unpost_exception(_jc_env *env, int num)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_initialization *const init = vm->initialization;
+
+ /* Are we no longer doing special bootstrap exceptions? */
+ if (vm->initialization == NULL || vm->initialization->may_execute) {
+ return _jc_retrieve_exception(env,
+ vm->boot.types.vmex[num]) != NULL;
+ }
+
+ /* Does "posted" exception type match? */
+ if (init->ex.num != num)
+ return JNI_FALSE;
+
+ /* Verbosity */
+ VERBOSE(EXCEPTIONS, env->vm, "unposting bootstrap exception: %s%s%s",
+ _jc_vmex_names[init->ex.num], *init->ex.msg != '\0' ? ": " : "",
+ init->ex.msg);
+
+ /* Unpost exception */
+ _jc_vm_free(&init->frames);
+ init->ex.num = -1;
+ init->num_frames = 0;
+ return JNI_TRUE;
+}
+
+/*
+ * Extract headline from an exception object.
+ */
+void
+_jc_fprint_exception_headline(_jc_env *env, FILE *fp, _jc_object *e)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_object *message;
+ char *msg_buf;
+ size_t msg_len;
+
+ /* Sanity check */
+ _JC_ASSERT(e != NULL);
+ _JC_ASSERT(_jc_subclass_of(e, vm->boot.types.Throwable));
+
+ /* Print exception class */
+ _jc_fprint_noslash(vm, fp, e->type->name);
+
+ /* Any detail message? */
+ if ((message = *_JC_VMFIELD(vm, e,
+ Throwable, detailMessage, _jc_object *)) == NULL)
+ return;
+
+ /* Print exception detail message, if any */
+ msg_len = _jc_decode_string_utf8(env, message, NULL);
+ if ((msg_buf = _JC_STACK_ALLOC(env, msg_len + 1)) == NULL) {
+ _jc_fprintf(vm, fp, ": [error displaying message: %s%s%s]",
+ _jc_vmex_names[env->ex.num],
+ env->ex.msg != '\0' ? ": " : "", env->ex.msg);
+ } else {
+ _jc_decode_string_utf8(env, message, msg_buf);
+ _jc_fprintf(vm, fp, ": %s", msg_buf);
+ }
+}
+
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/fatal.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/fatal.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/fatal.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/fatal.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,58 @@
+
+/*
+ * 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: fatal.c,v 1.1.1.1 2004/02/20 05:15:34 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+void
+_jc_fatal_error(_jc_jvm *vm, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ _jc_fatal_error_v(vm, fmt, args);
+ /* va_end(args); */
+}
+
+void
+_jc_fatal_error_v(_jc_jvm *vm, const char *fmt, va_list args)
+{
+ int (*printer)(FILE *, const char *, va_list);
+ void (*aborter)(void);
+
+ /* Print message */
+ if (vm != NULL) {
+ printer = vm->vfprintf;
+ aborter = vm->abort;
+ } else {
+ printer = vfprintf;
+ aborter = abort;
+ }
+ (*printer)(stderr, "jc: ", args);
+ (*printer)(stderr, fmt, args);
+ (*printer)(stderr, "\n", args);
+
+ /* Die */
+ (*aborter)();
+
+ /* Should never get here */
+ fprintf(stderr, "jc: abort() function returned!\n");
+ abort();
+}
+
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_final.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_final.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_final.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_final.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,138 @@
+
+/*
+ * 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: gc_final.c,v 1.3 2005/03/16 15:31:12 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Do a periodic check after scanning this many objects */
+#define _JC_FINALIZE_CHECK 16
+
+/*
+ * Finalize finalizable objects and enqueue enqueable references.
+ */
+jint
+_jc_gc_finalize(_jc_env *env)
+{
+ _jc_jvm *const vm = env->vm;
+ _jc_heap *const heap = &vm->heap;
+ _jc_heap_sweep sweep;
+ _jc_object *obj;
+ int i = 0;
+
+start_over:
+ _jc_heap_sweep_init(heap, &sweep);
+ while ((obj = _jc_heap_sweep_next(&sweep, JNI_FALSE)) != NULL) {
+ _jc_word lockword = obj->lockword;
+ jint gc_cycles;
+ jobject ref;
+
+ /* Sanity check */
+ _JC_ASSERT((lockword & _JC_LW_KEEP_BIT) != 0);
+
+ /* Check for live, enqueable references */
+ if ((lockword & (_JC_LW_SPECIAL_BIT|_JC_LW_LIVE_BIT))
+ == (_JC_LW_SPECIAL_BIT|_JC_LW_LIVE_BIT)
+ && _jc_subclass_of(obj, vm->boot.types.Reference)
+ && *_JC_VMFIELD(vm, obj,
+ Reference, queue, _jc_object *) != NULL) {
+ _jc_object *referent;
+
+ /* Get referent */
+ referent = *_JC_VMFIELD(vm, obj,
+ Reference, referent, _jc_object *);
+
+ /* Sanity check: non-null referent should be kept */
+ _JC_ASSERT(referent == NULL
+ || _JC_LW_TEST(referent->lockword, KEEP));
+
+ /* References are enqueable if the referent is null */
+ if (referent == NULL) {
+
+ /* Add native reference to reference */
+ ref = _jc_new_local_native_ref(env, obj);
+ _JC_ASSERT(ref != NULL);
+
+ /* Invoke enqueue(), ignoring any exception */
+ gc_cycles = vm->gc_cycles;
+ if (_jc_invoke_virtual(env,
+ vm->boot.methods.Reference.enqueue, obj)
+ != JNI_OK)
+ _jc_retrieve_exception(env, NULL);
+
+ /* Free local native reference */
+ _jc_free_local_native_ref(&ref);
+
+ /* If a GC cycle happened, start over */
+ if (gc_cycles != vm->gc_cycles)
+ goto start_over;
+
+ /* Sanity check queue field is now null */
+ _JC_ASSERT(*_JC_VMFIELD(vm, obj,
+ Reference, queue, _jc_object *) == NULL);
+ }
+ }
+
+ /* Check for unreachable but finalizable objects */
+ if ((lockword & (_JC_LW_LIVE_BIT|_JC_LW_FINALIZE_BIT))
+ != _JC_LW_FINALIZE_BIT)
+ goto next_object;
+
+ /* Add native reference to object */
+ ref = _jc_new_local_native_ref(env, obj);
+ _JC_ASSERT(ref != NULL);
+
+ /* Mark object as no longer finalizable */
+ while (!_jc_compare_and_swap(&obj->lockword,
+ lockword, lockword & ~_JC_LW_FINALIZE_BIT))
+ lockword = obj->lockword;
+
+ /*
+ * Finalize object, ignoring any exceptions. Note that a GC
+ * cycle can happen here; our native reference keeps this
+ * object (and any objects it references) alive.
+ */
+ gc_cycles = vm->gc_cycles;
+ if (_jc_invoke_virtual(env,
+ vm->boot.methods.Object.finalize, obj) != JNI_OK)
+ _jc_retrieve_exception(env, NULL);
+
+ /* Free local native reference */
+ _jc_free_local_native_ref(&ref);
+
+ /*
+ * If a GC cycle happened, more objects may have become
+ * finalizable, so start over.
+ */
+ if (gc_cycles != vm->gc_cycles)
+ goto start_over;
+
+ /* Do a periodic check after finalization */
+ i = -1;
+
+next_object:
+ /* Periodic check */
+ if ((++i % _JC_FINALIZE_CHECK) == 0
+ && _jc_thread_check(env) != JNI_OK)
+ return JNI_ERR;
+ }
+
+ /* Done */
+ return JNI_OK;
+}
+
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_root.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_root.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_root.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/gc_root.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,452 @@
+
+/*
+ * 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: gc_root.c,v 1.12 2005/03/20 23:05:31 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal definitions */
+#define _JC_NUM_REGISTER_OFFS \
+ (sizeof(_jc_register_offs) / sizeof(*_jc_register_offs))
+
+/* Internal functions */
+static _jc_object *_jc_locate_object(_jc_jvm *vm,
+ const _jc_word *info, const void *ptr);
+static int _jc_root_walk_thread(_jc_env *thread,
+ const _jc_word *info, _jc_object ***refsp);
+static int _jc_root_walk_native_refs(_jc_native_frame_list *list,
+ _jc_object ***refsp);
+static int _jc_scan_exec_stack(_jc_jvm *vm, _jc_exec_stack *stack,
+ const _jc_word *info, _jc_object ***refsp);
+static int _jc_scan_interp_stack(_jc_jvm *vm,
+ _jc_interp_stack *stack, const _jc_word *info,
+ _jc_object ***refsp);
+
+/* Internal variables */
+static const int _jc_register_offs[] = _JC_REGISTER_OFFS;
+
+/*
+ * Find the head of the object given a pointer into its interior.
+ * This is used for conservative GC scan.
+ */
+static _jc_object *
+_jc_locate_object(_jc_jvm *vm, const _jc_word *info, const void *ptr)
+{
+ _jc_heap *const heap = &vm->heap;
+ _jc_word word;
+ char *page;
+ int pnum;
+
+ /* Does pointer point into the heap? */
+ if (!_JC_IN_HEAP(heap, ptr)) {
+ _jc_class_loader *loader;
+
+ /* Handle a common case */
+ if (ptr == NULL)
+ return NULL;
+
+ /* Check each class loader (except boot loader) */
+ LIST_FOREACH(loader, &vm->class_loaders, link) {
+ if (loader == vm->boot.loader)
+ continue;
+ if (_jc_uni_contains(&loader->uni, ptr))
+ return loader->instance;
+ }
+
+ /* Done */
+ return NULL;
+ }
+
+ /* Get page number */
+ pnum = ((char *)ptr - (char *)heap->pages) / _JC_PAGE_SIZE;
+ _JC_ASSERT(pnum >= 0 && pnum < heap->num_pages);
+
+ /* If page is an interior page, find the first page */
+ while ((info[pnum / _JC_BITS_PER_WORD]
+ & (1 << (pnum % _JC_BITS_PER_WORD))) != 0)
+ pnum--;
+ page = (char *)heap->pages + pnum * _JC_PAGE_SIZE;
+
+ /* Examine page type to find start of object memory block */
+ word = *((_jc_word *)page);
+ switch (_JC_HEAP_EXTRACT(word, PTYPE)) {
+ case _JC_HEAP_PAGE_FREE:
+ return NULL;
+ case _JC_HEAP_PAGE_SMALL:
+ {
+ char *const first_block = page + _JC_HEAP_BLOCK_OFFSET;
+ _jc_heap_size *size;
+ int block_num;
+
+ /* Get block size in this page */
+ size = &heap->sizes[_JC_HEAP_EXTRACT(word, BSI)];
+
+ /* Find block into which pointer is pointing */
+ block_num = ((char *)ptr - first_block) / size->size;
+ if (block_num < 0 || block_num >= size->num_blocks)
+ return NULL;
+
+ /* Point to start of block */
+ ptr = first_block + block_num * size->size;
+
+ /* See if there really is an object in there */
+ word = *((_jc_word *)ptr);
+ _JC_ASSERT(word != _JC_HEAP_BLOCK_ALLOC);
+ if (word == _JC_HEAP_BLOCK_FREE)
+ return NULL;
+ break;
+ }
+ case _JC_HEAP_PAGE_LARGE:
+ ptr = page + _JC_HEAP_BLOCK_OFFSET;
+ break;
+ default:
+ _JC_ASSERT(0);
+ }
+
+ /*
+ * If we could assume all references really pointed to the
+ * head of the object, then we could optimize further here.
+ */
+
+ /* Find object head */
+ return _jc_find_object_head(ptr);
+}
+
+/*
+ * Compute the root set of references. Returns the number of references,
+ * or -1 if there was an error. The caller must free the returned array.
+ * Ths stack of the current thread must be clipped.
+ *
+ * If unsuccessful an exception is stored.
+ *
+ * NOTE: This assumes the VM mutex is locked and the world is stopped.
+ */
+int
+_jc_root_walk(_jc_env *env, _jc_object ***refsp)
+{
+ const int nrefs_slop = 32;
+ _jc_jvm *const vm = env->vm;
+ _jc_heap *const heap = &vm->heap;
+ _jc_object **refs_start = NULL;
+ _jc_object **refs = NULL;
+ _jc_env *thread;
+ _jc_word *info;
+ int max_nrefs = 0;
+ int nrefs = 0;
+ int pnum;
+
+ /* Sanity check */
+ _JC_MUTEX_ASSERT(env, vm->mutex);
+ _JC_ASSERT(vm->world_stopped);
+
+ /* Allocate heap page info bit array */
+ if ((info = _jc_vm_zalloc(env, sizeof(_jc_word)
+ * _JC_HOWMANY(heap->num_pages, _JC_BITS_PER_WORD))) == NULL)
+ return -1;
+
+ /* Mark heap pages which are interior pages of a large object */
+ for (pnum = 0; pnum < heap->num_pages; ) {
+ _jc_word word;
+
+ word = *((_jc_word *)((char *)heap->pages
+ + pnum * _JC_PAGE_SIZE));
+ switch (_JC_HEAP_EXTRACT(word, PTYPE)) {
+ case _JC_HEAP_PAGE_ALLOC:
+ _JC_ASSERT(0);
+ case _JC_HEAP_PAGE_FREE:
+ case _JC_HEAP_PAGE_SMALL:
+ pnum++;
+ break;
+ case _JC_HEAP_PAGE_LARGE:
+ {
+ const int npages = _JC_HEAP_EXTRACT(word, NPAGES);
+ int i;
+
+ for (i = pnum + 1; i < pnum + npages; i++) {
+ info[i / _JC_BITS_PER_WORD]
+ |= 1 << (i % _JC_BITS_PER_WORD);
+ }
+ pnum += npages;
+ break;
+ }
+ }
+ _JC_ASSERT(pnum <= heap->num_pages);
+ }
+
+again:
+ /* First count the references, then allocate array and record them */
+ nrefs = 0;
+
+ /* Walk threads */
+ LIST_FOREACH(thread, &vm->threads.alive_list, link)
+ nrefs += _jc_root_walk_thread(thread, info, &refs);
+
+ /* Walk global native references */
+ nrefs += _jc_root_walk_native_refs(&vm->native_globals, &refs);
+
+ /*
+ * After counting references, allocate array and walk them again.
+ * Because the current thread's stack may change, allow some slop.
+ */
+ if (refs == NULL) {
+ max_nrefs = nrefs + nrefs_slop;
+ if ((refs = _jc_vm_alloc(env,
+ max_nrefs * sizeof(*refs))) == NULL) {
+ nrefs = -1;
+ goto done;
+ }
+ refs_start = refs;
+ goto again;
+ }
+
+ /* Sanity check we didn't somehow get a bunch more refs */
+ _JC_ASSERT(nrefs <= max_nrefs);
+
+done:
+ /* Done */
+ _jc_vm_free(&info);
+ *refsp = refs_start;
+ return nrefs;
+}
+
+/*
+ * Walk all objects in one thread's root set. The thread's Java stack
+ * must already be clipped.
+ *
+ * NOTE: This assumes caller has acquired the VM mutex.
+ */
+static int
+_jc_root_walk_thread(_jc_env *thread, const _jc_word *info, _jc_object ***refsp)
+{
+ _jc_jvm *const vm = thread->vm;
+ _jc_object **refs = *refsp;
+ _jc_java_stack *jstack;
+ _jc_stack_crawl crawl;
+ int count = 0;
+
+ /* Sanity check */
+ _JC_ASSERT(thread->java_stack == NULL
+ || thread->java_stack->interp
+ || ((_jc_exec_stack *)thread->java_stack)->pc != NULL);
+
+ /* Scan each contiguous Java stack segment */
+ for (jstack = thread->java_stack;
+ jstack != NULL; jstack = jstack->next) {
+ count += jstack->interp ?
+ _jc_scan_interp_stack(vm,
+ (_jc_interp_stack *)jstack, info, &refs) :
+ _jc_scan_exec_stack(vm,
+ (_jc_exec_stack *)jstack, info, &refs);
+ }
+
+ /* Get implicit references from Java methods to their classes */
+ for (_jc_stack_crawl_first(thread, &crawl);
+ crawl.method != NULL; _jc_stack_crawl_next(vm, &crawl)) {
+
+ /* Skip _jc_invoke_jcni_a() */
+ if (crawl.method->class == NULL) {
+ _JC_ASSERT(crawl.method == &vm->invoke_method);
+ continue;
+ }
+
+ /* Add the Class instance */
+ _JC_ASSERT(crawl.method->class->instance != NULL);
+ if (refs != NULL)
+ *refs++ = crawl.method->class->instance;
+ count++;
+ }
+
+ /* Walk thread's local native references */
+ count += _jc_root_walk_native_refs(&thread->native_locals, &refs);
+
+ /* Walk thread's Thread instance (if any) */
+ if (thread->instance != NULL) {
+ if (refs != NULL)
+ *refs++ = thread->instance;
+ count++;
+ }
+
+ /* Walk thread's pending exception (if any) */
+ if (thread->head.pending != NULL) {
+ if (refs != NULL)
+ *refs++ = thread->head.pending;
+ count++;
+ }
+
+ /* Walk any exception posted in this thread by another thread */
+ if (thread->cross_exception != NULL) {
+ if (refs != NULL)
+ *refs++ = thread->cross_exception;
+ count++;
+ }
+
+ /* Done */
+ *refsp = refs;
+ return count;
+}
+
+/*
+ * Scan an interpreter stack frame.
+ */
+static int
+_jc_scan_interp_stack(_jc_jvm *vm, _jc_interp_stack *stack,
+ const _jc_word *info, _jc_object ***refsp)
+{
+ _jc_method *const method = stack->method;
+ _jc_method_code *const code = &method->u.code;
+ _jc_object **refs = *refsp;
+ _jc_object *obj;
+ int count = 0;
+ int i;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, INTERP));
+
+ /* Any state in this method yet? */
+ if (stack->locals == NULL)
+ return 0;
+
+ /* Scan stack frame's locals and Java operand stack */
+ for (i = 0; i < code->max_locals + code->max_stack; i++) {
+ _jc_object *const ref = (_jc_object *)stack->locals[i];
+
+ /* Find object pointed to, if any */
+ if ((obj = _jc_locate_object(vm, info, ref)) == NULL)
+ continue;
+
+ /* Add object to list */
+ if (refs != NULL)
+ *refs++ = obj;
+ count++;
+ }
+
+ /* Done */
+ *refsp = refs;
+ return count;
+}
+
+/*
+ * Scan a contiguous executable stack chunk.
+ */
+static int
+_jc_scan_exec_stack(_jc_jvm *vm, _jc_exec_stack *stack,
+ const _jc_word *info, _jc_object ***refsp)
+{
+ const size_t stack_step = (_JC_STACK_ALIGN < sizeof(void *)) ?
+ _JC_STACK_ALIGN : sizeof(void *);
+ _jc_object **refs = *refsp;
+ const char *stack_bot = NULL;
+ const char *stack_top = NULL;
+ _jc_stack_crawl crawl;
+ _jc_object *obj;
+ const char *ptr;
+ int count = 0;
+ int regnum;
+
+ /* Get references from saved registers */
+ for (regnum = 0; regnum < _JC_NUM_REGISTER_OFFS; regnum++) {
+
+ /* Find object pointed to by register, if any */
+ if ((obj = _jc_locate_object(vm, info,
+ *(_jc_word **)((char *)&stack->regs
+ + _jc_register_offs[regnum]))) == NULL)
+ continue;
+
+ /* Add object to list */
+ if (refs != NULL)
+ *refs++ = obj;
+ count++;
+ }
+
+ /* Compute the top of this Java stack segment */
+ stack_top = _jc_mcontext_sp(&stack->regs);
+
+ /* Find the bottom of this Java stack segment */
+ memset(&crawl, 0, sizeof(crawl));
+ crawl.frame = stack->frame;
+ crawl.pc = stack->pc;
+ while (crawl.method != &vm->invoke_method) {
+ _jc_stack_frame_next(&crawl.frame, &crawl.pc);
+ _jc_stack_crawl_skip(vm, &crawl);
+ }
+ stack_bot = _jc_stack_frame_sp(crawl.frame);
+
+ /* Sanity check stack alignment */
+ _JC_ASSERT(((_jc_word)stack_top & (_JC_STACK_ALIGN - 1)) == 0);
+ _JC_ASSERT(((_jc_word)stack_bot & (_JC_STACK_ALIGN - 1)) == 0);
+
+ /* Conservatively find references in this Java stack segment */
+#if _JC_DOWNWARD_STACK
+ for (ptr = stack_top; ptr < stack_bot; ptr += stack_step)
+#else
+ for (ptr = stack_bot; ptr < stack_top; ptr += stack_step)
+#endif
+ {
+ /* Find object pointed into, if any */
+ if ((obj = _jc_locate_object(vm,
+ info, *(_jc_word **)ptr)) == NULL)
+ continue;
+
+ /* Add object to list */
+ if (refs != NULL)
+ *refs++ = obj;
+ count++;
+ }
+
+ /* Done */
+ *refsp = refs;
+ return count;
+}
+
+/*
+ * Walk all objects in a native reference list.
+ */
+static int
+_jc_root_walk_native_refs(_jc_native_frame_list *list, _jc_object ***refsp)
+{
+ _jc_object **refs = *refsp;
+ _jc_native_frame *frame;
+ int count = 0;
+ int i;
+
+ /* Iterate through each frame */
+ SLIST_FOREACH(frame, list, link) {
+
+ /* Skip empty frames */
+ if (!_JC_NATIVE_REF_ANY_USED(frame))
+ continue;
+
+ /* Iterate references in this frame */
+ for (i = 0; i < _JC_NATIVE_REFS_PER_FRAME; i++) {
+ if (!_JC_NATIVE_REF_IS_FREE(frame, i)) {
+ _jc_object *const obj = frame->refs[i];
+
+ if (obj != NULL) {
+ if (refs != NULL)
+ *refs++ = obj;
+ count++;
+ }
+ }
+ }
+ }
+
+ /* Done */
+ *refsp = refs;
+ return count;
+}
+