_jc_env * _jc_support_init() { _jc_mutex_init(&phoney_env, &phoney_loader.mutex); _jc_mutex_init(&phoney_env, &phoney_jvm.mutex); _jc_uni_alloc_init(&phoney_loader.uni, 0, NULL); phoney_jvm.boot.loader = &phoney_loader; phoney_env.vm = &phoney_jvm; return &phoney_env; }
/* * Allocate and link a new classloader structure into a VM. * * An exception is stored if unsuccessful. * * NOTE: The global VM mutex must be held when calling this function. */ _jc_class_loader * _jc_create_loader(_jc_env *env) { _jc_jvm *const vm = env->vm; _jc_class_loader *loader; /* Sanity check */ _JC_MUTEX_ASSERT(env, vm->mutex); /* Create and initialize new structure */ if ((loader = _jc_vm_zalloc(env, sizeof(*loader) + vm->object_path_len * sizeof(*loader->objects_loaded))) == NULL) return NULL; loader->objects_loaded = (jboolean *)(loader + 1); /* Initialize class loader memory manager */ _jc_uni_alloc_init(&loader->uni, _JC_CL_ALLOC_MIN_PAGES, &vm->avail_loader_pages); /* Initialize mutex and condition variable */ if (_jc_mutex_init(env, &loader->mutex) != JNI_OK) goto fail1; if (_jc_cond_init(env, &loader->cond) != JNI_OK) goto fail2; /* Initialize initiated, defining, and partially derived type trees */ _jc_splay_init(&loader->initiated_types, _jc_node_cmp, _JC_OFFSETOF(_jc_type_node, node)); _jc_splay_init(&loader->deriving_types, _jc_node_cmp, _JC_OFFSETOF(_jc_type_node, node)); _jc_splay_init(&loader->defined_types, _jc_type_cmp, _JC_OFFSETOF(_jc_type, node)); /* Initialize native library list */ STAILQ_INIT(&loader->native_libs); /* Link new class loader into the VM */ LIST_INSERT_HEAD(&vm->class_loaders, loader, link); /* Done */ return loader; /* Clean up after failure */ fail2: _jc_mutex_destroy(&loader->mutex); fail1: _jc_uni_alloc_free(&loader->uni); _jc_vm_free(&loader); return NULL; }
/* * 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; }