/* * static final native String mapLibraryName(String) */ _jc_object * _JC_JCNI_ATTR JCNI_java_lang_VMRuntime_mapLibraryName(_jc_env *env, _jc_object *string) { size_t name_len; char *fname; char *name; /* Check for null */ if (string == NULL) { _jc_post_exception(env, _JC_NullPointerException); _jc_throw_exception(env); } /* Decode string */ name_len = _jc_decode_string_utf8(env, string, NULL); if ((name = _JC_STACK_ALLOC(env, name_len + 1)) == NULL) { _jc_post_exception_info(env); _jc_throw_exception(env); } _jc_decode_string_utf8(env, string, name); /* Format filename */ if ((fname = _JC_FORMAT_STRING(env, _JC_LIBRARY_FMT, name)) == NULL) { _jc_post_exception_info(env); _jc_throw_exception(env); } /* Create new String object */ if ((string = _jc_new_string(env, fname, strlen(fname))) == NULL) _jc_throw_exception(env); /* Done */ return string; }
/* * static final native void gc() */ void _JC_JCNI_ATTR JCNI_java_lang_VMRuntime_gc(_jc_env *env) { if (_jc_gc(env, JNI_FALSE) != JNI_OK) { _jc_post_exception_info(env); _jc_throw_exception(env); } }
/* * Create a subdirectory under 'root' if it doesn't already exist. * The pathname is the name of any file in the subdirectory. */ jint _jc_create_subdir(_jc_env *env, const char *root, const char *pathname) { const size_t rlen = strlen(root); const char *error_path; struct stat info; char *next; char *buf; char *s; /* The root directory must exist */ error_path = root; if (stat(root, &info) == -1) goto io_err; if ((info.st_mode & S_IFMT) != S_IFDIR) { errno = ENOTDIR; goto io_err; } /* Check successive subdirectories */ if ((buf = _JC_FORMAT_STRING(env, "%s%s%s", root, _JC_FILE_SEPARATOR, pathname)) == NULL) { _jc_post_exception_info(env); return JNI_ERR; } error_path = buf; for (s = buf + rlen + 1; ; s = next) { /* Another directory in path? If not, we're done */ if ((next = strstr(s, _JC_FILE_SEPARATOR)) == NULL) return JNI_OK; /* Check directory status; create if not found */ *next = '\0'; if (stat(buf, &info) == -1) { if (errno != ENOENT) goto io_err; if (mkdir(buf, 0755) == -1) goto io_err; } else if ((info.st_mode & S_IFMT) != S_IFDIR) { errno = ENOTDIR; goto io_err; } strcpy(next, _JC_FILE_SEPARATOR); next += strlen(_JC_FILE_SEPARATOR); } io_err: /* Failed; throw an error */ _jc_post_exception_msg(env, _JC_InternalError, "%s: %s", error_path, strerror(errno)); return JNI_ERR; }
/* * static final native int nativeLoad(String, ClassLoader) */ jint _JC_JCNI_ATTR JCNI_java_lang_VMRuntime_nativeLoad(_jc_env *env, _jc_object *string, _jc_object *clobj) { _jc_jvm *const vm = env->vm; _jc_class_loader *loader; char *filename; size_t len; /* Check for null */ if (string == NULL) { _jc_post_exception(env, _JC_NullPointerException); _jc_throw_exception(env); } /* Convert String to UTF-8 */ len = _jc_decode_string_utf8(env, string, NULL); if ((filename = _JC_STACK_ALLOC(env, len + 1)) == NULL) { _jc_post_exception_info(env); _jc_throw_exception(env); } _jc_decode_string_utf8(env, string, filename); /* Get class loader */ if (clobj == NULL) loader = vm->boot.loader; else if ((loader = _jc_get_loader(env, clobj)) == NULL) _jc_throw_exception(env); /* Open native library */ if (_jc_load_native_library(env, loader, filename) != JNI_OK) { _jc_post_exception_info(env); _jc_throw_exception(env); } /* OK */ return 1; }
/* * public static final native boolean compileClasses(String) */ jboolean _JC_JCNI_ATTR JCNI_java_lang_VMCompiler_compileClasses(_jc_env *env, _jc_object *string) { _jc_jvm *const vm = env->vm; size_t slen; char *name; /* Decode string */ slen = _jc_decode_string_utf8(env, string, NULL); if ((name = _JC_STACK_ALLOC(env, slen + 1)) == NULL) { _jc_post_exception_info(env); _jc_throw_exception(env); } _jc_decode_string_utf8(env, string, name); /* XXX we are supposed to do some kind of pattern matching... */ /* Generate ELF object */ if (_jc_generate_object(env, vm->boot.loader, name) != JNI_OK) _jc_throw_exception(env); return JNI_TRUE; }
/* * 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; }
/* * Find the internal _jc_class_loader structure corresponding to * a ClassLoader object. Create one if it doesn't already exist, * but do so atomically. * * Posts an exception on failure. */ _jc_class_loader * _jc_get_loader(_jc_env *env, _jc_object *obj) { _jc_jvm *const vm = env->vm; jboolean vm_locked = JNI_FALSE; _jc_class_loader *loader; _jc_resolve_info info; /* Check for null */ if (obj == NULL) { _jc_post_exception(env, _JC_NullPointerException); return NULL; } _JC_ASSERT(_jc_subclass_of(obj, vm->boot.types.ClassLoader)); /* Lock VM */ _JC_MUTEX_LOCK(env, vm->mutex); vm_locked = JNI_TRUE; /* See if loader structure already exists */ if ((loader = _jc_get_vm_pointer(vm, obj, vm->boot.fields.ClassLoader.vmdata)) != NULL) goto done; /* Create a new loader structure */ if ((loader = _jc_create_loader(env)) == NULL) { _jc_post_exception_info(env); goto done; } loader->instance = obj; /* Set the ClassLoader.vmdata field */ if (_jc_set_vm_pointer(env, obj, vm->boot.fields.ClassLoader.vmdata, loader) != JNI_OK) { _jc_destroy_loader(vm, &loader); goto done; } /* Unlock VM */ _JC_MUTEX_UNLOCK(env, vm->mutex); vm_locked = JNI_FALSE; /* Create reference list with one reference */ memset(&info, 0, sizeof(info)); info.loader = loader, info.implicit_refs = &loader->instance; info.num_implicit_refs = 1; /* Put ClassLoader object on implicit reference list */ if (_jc_merge_implicit_refs(env, &info) != JNI_OK) { _jc_destroy_loader(vm, &loader); _jc_post_exception_info(env); goto done; } done: /* Unlock VM */ if (vm_locked) _JC_MUTEX_UNLOCK(env, vm->mutex); /* Done */ return loader; }
/* * Search for a class file node in the VM class file tree. If not found, * actively retrieve it by trying to load it with the supplied class loader. * * Because user class loaders control finding and loading their classes, * the only way for us to force the acquisition of a classfile is to try to * load the type. In general this may cause ClassCircularityErrors, but we * don't care about them because by the time one is thrown, the class file * has already been seen by us and its node stored in the class file tree. * * If successful, the node is returned with an extra reference. * * This function is used only if vm->without_classfiles is false. */ _jc_class_node * _jc_get_class_node(_jc_env *env, _jc_class_loader *loader, const char *name) { _jc_jvm *const vm = env->vm; _jc_class_save class_save; _jc_class_node *node; _jc_class_node key; _jc_type *type; /* Sanity check */ _JC_ASSERT(name[0] != '['); _JC_ASSERT(!vm->without_classfiles); /* Lock VM */ _JC_MUTEX_LOCK(env, vm->mutex); /* Search for existing class file node */ key.name = name; if ((node = _jc_splay_find(&vm->classfiles, &key)) != NULL && node->bytes != NULL) { node->refs++; _JC_MUTEX_UNLOCK(env, vm->mutex); return node; } node = NULL; /* Unlock VM */ _JC_MUTEX_UNLOCK(env, vm->mutex); /* If loader is the boot loader, we can get the class file directly */ if (loader == vm->boot.loader) { _jc_classbytes *cbytes; /* Find the class file bytes in the filesystem */ if ((cbytes = _jc_bootcl_find_classbytes(env, name, NULL)) == NULL) { _jc_post_exception_info(env); goto done; } /* Try to add class file to class file tree */ _JC_MUTEX_LOCK(env, vm->mutex); node = _jc_ref_class_node(env, name, cbytes->hash, cbytes); _JC_MUTEX_UNLOCK(env, vm->mutex); /* Free class file bytes */ _jc_free_classbytes(&cbytes); /* Post stored exception if failed */ if (node == NULL) _jc_post_exception_info(env); /* Done */ goto done; } /* Initialize our class file save structure */ class_save.name = name; class_save.bytes = NULL; class_save.next = env->class_save; env->class_save = &class_save; /* * Attempt to load the type in order to acquire the class file. * If we succeeded, then the class file node must have been added. */ if ((type = _jc_load_type(env, loader, name)) != NULL) { /* Lock VM */ _JC_MUTEX_LOCK(env, vm->mutex); /* Find node and add reference */ node = _jc_splay_find(&vm->classfiles, &key); _JC_ASSERT(node != NULL); node->refs++; /* Unlock VM */ _JC_MUTEX_UNLOCK(env, vm->mutex); /* Done */ goto done; } /* Ignore LinkageError's but bail out if any other exception */ if (!_jc_unpost_exception(env, _JC_LinkageError)) goto done; /* Lock VM */ _JC_MUTEX_LOCK(env, vm->mutex); /* * Look for class file in our class file save structure; if found, * copy its info to VM tree and grab a reference to the new node. */ if (class_save.bytes != NULL) { /* Add node */ node = _jc_ref_class_node(env, name, class_save.bytes->hash, class_save.bytes); _JC_MUTEX_UNLOCK(env, vm->mutex); /* Post exception if failed */ if (node == NULL) _jc_post_exception_info(env); /* Done */ goto done; } /* Unlock VM */ _JC_MUTEX_UNLOCK(env, vm->mutex); done: /* Destroy class save structure if we added one */ if (env->class_save == &class_save) { _jc_free_classbytes(&class_save.bytes); env->class_save = class_save.next; } /* Done */ return node; }