blob: b857949d193c83d41b47dd4a8c1ace1003e4c182 [file] [log] [blame]
/*
* jato - Java JIT compiler and VM
* Copyright (C) 2009 Vegard Nossum <vegardno@ifi.uio.no>
*
* This file is released under the GPL version 2 with the following
* clarification and special exception:
*
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under terms
* of your choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module. An
* independent module is a module which is not derived from or based on
* this library. If you modify this library, you may extend this exception
* to your version of the library, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
* Please refer to the file LICENSE for details.
*/
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <stdio.h>
#include <time.h>
#include "valgrind/valgrind.h"
#include "cafebabe/access.h"
#include "cafebabe/attribute_info.h"
#include "cafebabe/class.h"
#include "cafebabe/constant_pool.h"
#include "cafebabe/error.h"
#include "cafebabe/field_info.h"
#include "cafebabe/method_info.h"
#include "cafebabe/stream.h"
#include "runtime/stack-walker.h"
#include "runtime/runtime.h"
#include "jit/compiler.h"
#include "jit/cu-mapping.h"
#include "jit/gdb.h"
#include "jit/exception.h"
#include "jit/inline-cache.h"
#include "jit/perf-map.h"
#include "jit/debug.h"
#include "jit/text.h"
#include "lib/options.h"
#include "lib/string.h"
#include "lib/parse.h"
#include "lib/list.h"
#include "vm/fault-inject.h"
#include "vm/verifier.h"
#include "vm/classloader.h"
#include "vm/stack-trace.h"
#include "vm/reflection.h"
#include "vm/natives.h"
#include "vm/preload.h"
#include "vm/version.h"
#include "vm/interp.h"
#include "vm/itable.h"
#include "vm/method.h"
#include "vm/object.h"
#include "vm/reference.h"
#include "vm/signal.h"
#include "vm/static.h"
#include "vm/string.h"
#include "vm/system.h"
#include "vm/thread.h"
#include "vm/class.h"
#include "vm/call.h"
#include "vm/utf8.h"
#include "vm/jar.h"
#include "vm/jni.h"
#include "vm/gc.h"
#include "vm/vm.h"
#include "vm/java-version.h"
#include "arch/init.h"
#include "runtime/gnu_java_lang_management_VMThreadMXBeanImpl.h"
#include "runtime/java_lang_reflect_VMMethod.h"
#include "runtime/java_lang_reflect_VMField.h"
#include "runtime/java_lang_VMClassLoader.h"
#include "runtime/java_lang_VMString.h"
#include "runtime/java_lang_VMSystem.h"
#include "runtime/java_lang_VMThread.h"
#include "runtime/java_lang_VMClass.h"
#include "runtime/sun_misc_Unsafe.h"
static const char *bootclasspath_append;
static bool dump_maps;
static bool perf_enabled;
static char *program_name;
/* Arguments passed to the main class. */
static unsigned int nr_java_args;
static char **java_args;
static bool use_system_classloader = true;
/*
* Enable SSA optimizations.
*/
bool opt_ssa_enable;
static bool opt_interp_only;
/*
* Enable JIT workarounds for valgrind.
*/
bool running_on_valgrind;
static void vm_atexit(void)
{
classloader_destroy();
}
static void __attribute__((noreturn)) vm_exit(int status)
{
clear_exception();
vm_call_method(vm_java_lang_System_exit, status);
if (exception_occurred())
vm_print_exception(exception_occurred());
error("System.exit() returned");
}
static void vm_properties_set_property(struct vm_object *p,
const char *key, const char *value)
{
struct vm_object *(*trampoline)(struct vm_object *,
struct vm_object *, struct vm_object *);
assert(key != NULL);
assert(value != NULL);
trampoline
= vm_method_trampoline_ptr(vm_java_util_Properties_setProperty);
struct vm_object *key_obj = vm_object_alloc_string_from_c(key);
struct vm_object *value_obj = vm_object_alloc_string_from_c(value);
trampoline(p, key_obj, value_obj);
}
struct system_properties_entry {
char *key;
char *value;
struct list_head list_node;
};
static struct list_head system_properties_list;
static struct system_properties_entry *find_system_property(const char *key)
{
struct system_properties_entry *this;
list_for_each_entry(this, &system_properties_list, list_node) {
if (strcmp(this->key, key) == 0)
return this;
}
return NULL;
}
static void add_system_property(char *key, char *value)
{
struct system_properties_entry *ent;
assert(key && value);
ent = find_system_property(key);
if (ent) {
free(ent->value);
free(key);
ent->value = value;
return;
}
ent = malloc(sizeof *ent);
if (!ent)
error("out of memory");
ent->key = key;
ent->value = value;
list_add(&ent->list_node, &system_properties_list);
}
static void add_system_property_const(const char *key, const char *value)
{
char *key_d;
char *value_d;
if (value == NULL)
value = "";
key_d = strdup(key);
value_d = strdup(value);
if (!key_d || !value_d)
error("out of memory");
add_system_property(key_d, value_d);
}
static void system_property_append_path(const char *key, const char *path)
{
struct system_properties_entry *ent;
ent = find_system_property(key);
if (!ent) {
add_system_property_const(key, path);
return;
}
if (asprintf(&ent->value, "%s:%s", ent->value, path) < 0)
error("out of memory");
}
static char *system_property_get(const char *key)
{
struct system_properties_entry *ent;
ent = find_system_property(key);
if (!ent)
return NULL;
return ent->value;
}
struct system_property {
const char *key;
const char *value;
};
static struct system_property system_properties[] = {
{ "java.vm.name", "jato" },
{ "java.vm.vendor", "Pekka Enberg" },
{ "java.vm.vendor.url", "http://www.jatovm.org/" },
{ "java.io.tmpdir", "/tmp" },
{ "java.home", "/usr" },
{ "file.separator", "/" },
{ "path.separator", ":" },
{ "line.separator", "\n" },
{ "java.runtime.name", "GNU Classpath" },
{ "java.version", JAVA_VERSION },
{ "java.vendor", "GNU Classpath" },
{ "java.vendor.url", "http://www.classpath.org/" },
{ "java.vm.specification.version", JAVA_VM_SPEC_VERSION },
{ "java.vm.specification.vendor", "Sun Microsystems, Inc." },
{ "java.vm.specification.name", "Java Virtual Machine Specification"},
{ "java.specification.version", JAVA_SPEC_VERSION },
{ "java.specification.vendor", "Sun Microsystems, Inc." },
{ "java.specification.name", "Java Platform API Specification"},
{ "java.class.version", CLASSFILE_VERSION },
{ "java.compiler", "jato" },
{ "java.ext.dirs", "" },
};
/*
* This sets default values of system properties. It should be called
* before command line arguments are parsed because these properties
* can be overriden by -Dkey=value option.
*/
static void init_system_properties(void)
{
INIT_LIST_HEAD(&system_properties_list);
for (unsigned int i = 0; i < ARRAY_SIZE(system_properties); i++) {
struct system_property *p = &system_properties[i];
add_system_property_const(p->key, p->value);
}
add_system_property_const("java.library.path",
getenv("LD_LIBRARY_PATH"));
char *cwd = get_current_dir_name();
add_system_property_const("user.dir", cwd);
free(cwd);
add_system_property_const("user.name", getenv("USER"));
add_system_property_const("user.home", getenv("HOME"));
struct utsname info;
uname(&info);
add_system_property_const("os.arch", ARCH_NAME);
add_system_property_const("os.name", info.sysname);
add_system_property_const("os.version", info.release);
add_system_property_const("gnu.cpu.endian", "little");
}
static void native_vmsystemproperties_preinit(struct vm_object *p)
{
struct system_properties_entry *this, *t;
list_for_each_entry(this, &system_properties_list, list_node)
vm_properties_set_property(p, this->key, this->value);
/* dealloc system properties list */
list_for_each_entry_safe(this, t, &system_properties_list, list_node) {
free(this->key);
free(this->value);
list_del(&this->list_node);
free(this);
}
}
static void native_vmruntime_println(struct vm_object *message)
{
if (!message) {
printf("null\n");
return;
}
char *cstr = vm_string_to_cstr(message);
if (cstr)
printf("%s\n", cstr);
free(cstr);
}
static struct vm_object *
native_vmobject_clone(struct vm_object *object)
{
if (!object) {
signal_new_exception(vm_java_lang_NullPointerException, NULL);
return NULL;
}
return vm_object_clone(object);
}
static struct vm_object *
native_vmobject_getclass(struct vm_object *object)
{
if (!object) {
signal_new_exception(vm_java_lang_NullPointerException, NULL);
return NULL;
}
assert(object->class);
return object->class->object;
}
static int
native_vmfile_is_directory(struct vm_object *dirpath)
{
char *dirpath_str;
struct stat buf;
if (!dirpath) {
signal_new_exception(vm_java_lang_NullPointerException, NULL);
return false;
}
dirpath_str = vm_string_to_cstr(dirpath);
if (!dirpath_str)
return false;
if (stat(dirpath_str, &buf)) {
free(dirpath_str);
return false;
}
free(dirpath_str);
return S_ISDIR(buf.st_mode);
}
static void
native_vm_throw_null_pointer_exception(void)
{
signal_new_exception(vm_java_lang_NullPointerException, NULL);
}
static void native_vmobject_notify(struct vm_object *obj)
{
vm_object_notify(obj);
if (exception_occurred())
return;
}
static void native_vmobject_notify_all(struct vm_object *obj)
{
vm_object_notify_all(obj);
if (exception_occurred())
return;
}
static void native_vmobject_wait(struct vm_object *object, jlong ms, jint ns)
{
if (ms == 0 && ns == 0)
vm_object_wait(object);
else
vm_object_timed_wait(object, ms, ns);
}
static jint native_atomiclong_vm_supports_cs8(void)
{
return false;
}
static struct vm_native natives[] = {
DEFINE_NATIVE("gnu/java/lang/management/VMThreadMXBeanImpl", "getThreadInfoForId", gnu_java_lang_management_VMThreadMXBeanImpl_getThreadInfoForId),
DEFINE_NATIVE("gnu/classpath/VMStackWalker", "getClassContext", native_vmstackwalker_getclasscontext),
DEFINE_NATIVE("gnu/classpath/VMStackWalker", "getClassLoader", java_lang_VMClass_getClassLoader),
DEFINE_NATIVE("gnu/classpath/VMSystemProperties", "preInit", native_vmsystemproperties_preinit),
DEFINE_NATIVE("jato/internal/VM", "disableFault", native_vm_disable_fault),
DEFINE_NATIVE("jato/internal/VM", "enableFault", native_vm_enable_fault),
DEFINE_NATIVE("jato/internal/VM", "exit", native_vmruntime_exit),
DEFINE_NATIVE("jato/internal/VM", "println", native_vmruntime_println),
DEFINE_NATIVE("jato/internal/VM", "throwNullPointerException", native_vm_throw_null_pointer_exception),
DEFINE_NATIVE("java/lang/reflect/VMArray", "createObjectArray", native_vmarray_createobjectarray),
DEFINE_NATIVE("java/io/VMFile", "isDirectory", native_vmfile_is_directory),
DEFINE_NATIVE("java/lang/VMClass", "forName", java_lang_VMClass_forName),
DEFINE_NATIVE("java/lang/VMClass", "getClassLoader", java_lang_VMClass_getClassLoader),
DEFINE_NATIVE("java/lang/VMClass", "getComponentType", java_lang_VMClass_getComponentType),
DEFINE_NATIVE("java/lang/VMClass", "getDeclaredAnnotations", java_lang_VMClass_getDeclaredAnnotations),
DEFINE_NATIVE("java/lang/VMClass", "getDeclaredClasses", java_lang_VMClass_getDeclaredClasses),
DEFINE_NATIVE("java/lang/VMClass", "getDeclaredConstructors", java_lang_VMClass_getDeclaredConstructors),
DEFINE_NATIVE("java/lang/VMClass", "getDeclaredFields", java_lang_VMClass_getDeclaredFields),
DEFINE_NATIVE("java/lang/VMClass", "getDeclaredMethods", java_lang_VMClass_getDeclaredMethods),
DEFINE_NATIVE("java/lang/VMClass", "getDeclaringClass", java_lang_VMClass_getDeclaringClass),
DEFINE_NATIVE("java/lang/VMClass", "getEnclosingClass", java_lang_VMClass_getEnclosingClass),
DEFINE_NATIVE("java/lang/VMClass", "getInterfaces", java_lang_VMClass_getInterfaces),
DEFINE_NATIVE("java/lang/VMClass", "getModifiers", java_lang_VMClass_getModifiers),
DEFINE_NATIVE("java/lang/VMClass", "getName", java_lang_VMClass_getName),
DEFINE_NATIVE("java/lang/VMClass", "getSuperclass", java_lang_VMClass_getSuperclass),
DEFINE_NATIVE("java/lang/VMClass", "isAnonymousClass", java_lang_VMClass_isAnonymousClass),
DEFINE_NATIVE("java/lang/VMClass", "isArray", java_lang_VMClass_isArray),
DEFINE_NATIVE("java/lang/VMClass", "isAssignableFrom", java_lang_VMClass_isAssignableFrom),
DEFINE_NATIVE("java/lang/VMClass", "isInstance", java_lang_VMClass_isInstance),
DEFINE_NATIVE("java/lang/VMClass", "isInterface", java_lang_VMClass_isInterface),
DEFINE_NATIVE("java/lang/VMClass", "isLocalClass", java_lang_VMClass_isLocalClass),
DEFINE_NATIVE("java/lang/VMClass", "isMemberClass", java_lang_VMClass_isMemberClass),
DEFINE_NATIVE("java/lang/VMClass", "isPrimitive", java_lang_VMClass_isPrimitive),
DEFINE_NATIVE("java/lang/VMClassLoader", "defineClass", java_lang_VMClassLoader_defineClass),
DEFINE_NATIVE("java/lang/VMClassLoader", "findLoadedClass", java_lang_VMClassLoader_findLoadedClass),
DEFINE_NATIVE("java/lang/VMClassLoader", "getPrimitiveClass", java_lang_VMClassLoader_getPrimitiveClass),
DEFINE_NATIVE("java/lang/VMClassLoader", "loadClass", java_lang_VMClassLoader_loadClass),
DEFINE_NATIVE("java/lang/VMClassLoader", "resolveClass", java_lang_VMClassLoader_resolveClass),
DEFINE_NATIVE("java/lang/VMObject", "clone", native_vmobject_clone),
DEFINE_NATIVE("java/lang/VMObject", "getClass", native_vmobject_getclass),
DEFINE_NATIVE("java/lang/VMObject", "notify", native_vmobject_notify),
DEFINE_NATIVE("java/lang/VMObject", "notifyAll", native_vmobject_notify_all),
DEFINE_NATIVE("java/lang/VMObject", "wait", native_vmobject_wait),
DEFINE_NATIVE("java/lang/VMRuntime", "freeMemory", native_vmruntime_free_memory),
DEFINE_NATIVE("java/lang/VMRuntime", "totalMemory", native_vmruntime_total_memory),
DEFINE_NATIVE("java/lang/VMRuntime", "maxMemory", native_vmruntime_max_memory),
DEFINE_NATIVE("java/lang/VMRuntime", "availableProcessors", native_vmruntime_available_processors),
DEFINE_NATIVE("java/lang/VMRuntime", "exit", native_vmruntime_exit),
DEFINE_NATIVE("java/lang/VMRuntime", "gc", native_vmruntime_gc),
DEFINE_NATIVE("java/lang/VMRuntime", "mapLibraryName", native_vmruntime_maplibraryname),
DEFINE_NATIVE("java/lang/VMRuntime", "nativeLoad", native_vmruntime_native_load),
DEFINE_NATIVE("java/lang/VMRuntime", "runFinalizationForExit", native_vmruntime_run_finalization_for_exit),
DEFINE_NATIVE("java/lang/VMRuntime", "runFinalization", java_lang_VMRuntime_runFinalization),
DEFINE_NATIVE("java/lang/VMRuntime", "traceInstructions", native_vmruntime_trace_instructions),
DEFINE_NATIVE("java/lang/VMRuntime", "traceMethodCalls", native_vmruntime_trace_method_calls),
DEFINE_NATIVE("java/lang/VMString", "intern", java_lang_VMString_intern),
DEFINE_NATIVE("java/lang/VMSystem", "arraycopy", java_lang_VMSystem_arraycopy),
DEFINE_NATIVE("java/lang/VMSystem", "identityHashCode", java_lang_VMSystem_identityHashCode),
DEFINE_NATIVE("java/lang/VMThread", "currentThread", java_lang_VMThread_currentThread),
DEFINE_NATIVE("java/lang/VMThread", "interrupt", java_lang_VMThread_interrupt),
DEFINE_NATIVE("java/lang/VMThread", "interrupted", java_lang_VMThread_interrupted),
DEFINE_NATIVE("java/lang/VMThread", "isInterrupted", java_lang_VMThread_isInterrupted),
DEFINE_NATIVE("java/lang/VMThread", "nativeSetPriority", java_lang_VMThread_setPriority),
DEFINE_NATIVE("java/lang/VMThread", "start", java_lang_VMThread_start),
DEFINE_NATIVE("java/lang/VMThread", "yield", java_lang_VMThread_yield),
DEFINE_NATIVE("java/lang/VMThrowable", "fillInStackTrace", native_vmthrowable_fill_in_stack_trace),
DEFINE_NATIVE("java/lang/VMThrowable", "getStackTrace", native_vmthrowable_get_stack_trace),
DEFINE_NATIVE("java/lang/reflect/Constructor", "constructNative", native_constructor_construct_native),
DEFINE_NATIVE("java/lang/reflect/Constructor", "getModifiersInternal", native_constructor_get_modifiers_internal),
DEFINE_NATIVE("java/lang/reflect/Constructor", "getParameterTypes", native_constructor_get_parameter_types),
DEFINE_NATIVE("java/lang/reflect/Constructor", "getExceptionTypes", native_vmconstructor_get_exception_types),
DEFINE_NATIVE("java/lang/reflect/VMConstructor", "construct", native_vmconstructor_construct),
DEFINE_NATIVE("java/lang/reflect/VMConstructor", "getParameterTypes", native_constructor_get_parameter_types),
DEFINE_NATIVE("java/lang/reflect/VMConstructor", "getModifiersInternal", native_constructor_get_modifiers_internal),
DEFINE_NATIVE("java/lang/reflect/VMConstructor", "getExceptionTypes", native_vmconstructor_get_exception_types),
DEFINE_NATIVE("java/lang/reflect/Field", "get", java_lang_reflect_VMField_get),
DEFINE_NATIVE("java/lang/reflect/Field", "getInt", java_lang_reflect_VMField_getInt),
DEFINE_NATIVE("java/lang/reflect/Field", "getLong", java_lang_reflect_VMField_getLong),
DEFINE_NATIVE("java/lang/reflect/Field", "getShort", java_lang_reflect_VMField_getShort),
DEFINE_NATIVE("java/lang/reflect/Field", "getFloat", java_lang_reflect_VMField_getFloat),
DEFINE_NATIVE("java/lang/reflect/Field", "getDouble", java_lang_reflect_VMField_getDouble),
DEFINE_NATIVE("java/lang/reflect/Field", "getChar", java_lang_reflect_VMField_getChar),
DEFINE_NATIVE("java/lang/reflect/Field", "getByte", java_lang_reflect_VMField_getByte),
DEFINE_NATIVE("java/lang/reflect/Field", "getBoolean", java_lang_reflect_VMField_getBoolean),
DEFINE_NATIVE("java/lang/reflect/Field", "getModifiersInternal", java_lang_reflect_VMField_getModifiersInternal),
DEFINE_NATIVE("java/lang/reflect/Field", "getType", java_lang_reflect_VMField_getType),
DEFINE_NATIVE("java/lang/reflect/Field", "set", java_lang_reflect_VMField_set),
DEFINE_NATIVE("java/lang/reflect/VMField", "get", java_lang_reflect_VMField_get),
DEFINE_NATIVE("java/lang/reflect/VMField", "getLong", java_lang_reflect_VMField_getLong),
DEFINE_NATIVE("java/lang/reflect/VMField", "getInt", java_lang_reflect_VMField_getInt),
DEFINE_NATIVE("java/lang/reflect/VMField", "getShort", java_lang_reflect_VMField_getShort),
DEFINE_NATIVE("java/lang/reflect/VMField", "getFloat", java_lang_reflect_VMField_getFloat),
DEFINE_NATIVE("java/lang/reflect/VMField", "getDouble", java_lang_reflect_VMField_getDouble),
DEFINE_NATIVE("java/lang/reflect/VMField", "getChar", java_lang_reflect_VMField_getChar),
DEFINE_NATIVE("java/lang/reflect/VMField", "getByte", java_lang_reflect_VMField_getByte),
DEFINE_NATIVE("java/lang/reflect/VMField", "getBoolean", java_lang_reflect_VMField_getBoolean),
DEFINE_NATIVE("java/lang/reflect/VMField", "getModifiersInternal", java_lang_reflect_VMField_getModifiersInternal),
DEFINE_NATIVE("java/lang/reflect/VMField", "getType", java_lang_reflect_VMField_getType),
DEFINE_NATIVE("java/lang/reflect/VMField", "getAnnotation", java_lang_reflect_VMField_getAnnotation),
DEFINE_NATIVE("java/lang/reflect/VMField", "getDeclaredAnnotations", java_lang_reflect_VMField_getDeclaredAnnotations),
DEFINE_NATIVE("java/lang/reflect/VMField", "set", java_lang_reflect_VMField_set),
DEFINE_NATIVE("java/lang/reflect/Method", "getModifiersInternal", native_method_get_modifiers_internal),
DEFINE_NATIVE("java/lang/reflect/Method", "getParameterTypes", native_method_get_parameter_types),
DEFINE_NATIVE("java/lang/reflect/Method", "getReturnType", native_method_getreturntype),
DEFINE_NATIVE("java/lang/reflect/Method", "invokeNative", native_method_invokenative),
DEFINE_NATIVE("java/lang/reflect/Method", "getExceptionTypes", native_method_get_exception_types),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getAnnotation", java_lang_reflect_VMMethod_getAnnotation),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getDeclaredAnnotations", java_lang_reflect_VMMethod_getDeclaredAnnotations),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getParameterAnnotations", java_lang_reflect_VMMethod_getParameterAnnotations),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getDefaultValue", native_method_get_default_value),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getExceptionTypes", native_method_get_exception_types),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getModifiersInternal", native_method_get_modifiers_internal),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getParameterTypes", native_method_get_parameter_types),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "invoke", native_vmmethod_invoke),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getReturnType", native_method_getreturntype),
DEFINE_NATIVE("java/lang/reflect/VMMethod", "getExceptionTypes", native_method_get_exception_types),
DEFINE_NATIVE("java/util/concurrent/atomic/AtomicLong", "VMSupportsCS8", native_atomiclong_vm_supports_cs8),
DEFINE_NATIVE("sun/misc/Unsafe", "arrayBaseOffset", sun_misc_Unsafe_arrayBaseOffset),
DEFINE_NATIVE("sun/misc/Unsafe", "arrayIndexScale", sun_misc_Unsafe_arrayIndexScale),
DEFINE_NATIVE("sun/misc/Unsafe", "compareAndSwapInt", native_unsafe_compare_and_swap_int),
DEFINE_NATIVE("sun/misc/Unsafe", "compareAndSwapLong", native_unsafe_compare_and_swap_long),
DEFINE_NATIVE("sun/misc/Unsafe", "compareAndSwapObject", native_unsafe_compare_and_swap_object),
DEFINE_NATIVE("sun/misc/Unsafe", "getIntVolatile", sun_misc_Unsafe_getIntVolatile),
DEFINE_NATIVE("sun/misc/Unsafe", "getLongVolatile", sun_misc_Unsafe_getLongVolatile),
DEFINE_NATIVE("sun/misc/Unsafe", "getObjectVolatile", sun_misc_Unsafe_getObjectVolatile),
DEFINE_NATIVE("sun/misc/Unsafe", "objectFieldOffset", sun_misc_Unsafe_objectFieldOffset),
DEFINE_NATIVE("sun/misc/Unsafe", "park", native_unsafe_park),
DEFINE_NATIVE("sun/misc/Unsafe", "putIntVolatile", sun_misc_Unsafe_putIntVolatile),
DEFINE_NATIVE("sun/misc/Unsafe", "putLong", sun_misc_Unsafe_putLong),
DEFINE_NATIVE("sun/misc/Unsafe", "putLongVolatile", sun_misc_Unsafe_putLongVolatile),
DEFINE_NATIVE("sun/misc/Unsafe", "putObject", sun_misc_Unsafe_putObject),
DEFINE_NATIVE("sun/misc/Unsafe", "putObjectVolatile", sun_misc_Unsafe_putObjectVolatile),
DEFINE_NATIVE("sun/misc/Unsafe", "unpark", native_unsafe_unpark),
};
static void jit_init_natives(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(natives); i++)
vm_register_native(&natives[i]);
}
#define USAGE_TEXT \
"Usage: %s [-options] class [arg1 arg2 ...]\n" \
" (to run a class file)\n" \
" or %s [-options] -jar jarfile [arg1 arg2 ...]\n" \
" (to run a standalone jar file)\n" \
"where options include:\n" \
" -client compatibility (ignored)\n" \
" -server compatibility (ignored)\n" \
"\n" \
" -cp <jar/zip files and directories separated by :>\n" \
" -classpath <jar/zip files and directories separated by :>\n" \
" locations where to find application classes\n" \
" -D<name>=<value> set a system property\n" \
" -verbose[:gc]\n" \
" :gc print out results of garbage collection\n" \
" -version print out version number and copyright information\n" \
"\n" \
" -Xint operate in interpreter-only mode\n" \
" -XX:+PrintCompilation Print a message when a method is compiled\n"
static void usage(FILE *f, int retval)
{
fprintf(f, USAGE_TEXT, program_name, program_name);
exit(retval);
}
static void handle_version(void)
{
fprintf(stdout, "java version \"%s\"\n", JAVA_VERSION);
fprintf(stdout, "Jato VM version %s\n", JATO_VERSION);
exit(EXIT_SUCCESS);
}
static void handle_help(void)
{
usage(stdout, EXIT_SUCCESS);
}
static void handle_client(void)
{
/* Ignore */
}
static void handle_server(void)
{
/* Ignore */
}
static void handle_classpath(const char *arg)
{
system_property_append_path("java.class.path", arg);
}
static void bootclasspath_parse_and_append(const void *arg)
{
static const char delim[] = ":;";
char *cp = strdup(arg);
char *path = strtok(cp, delim);
while (path) {
classloader_add_to_classpath(path);
system_property_append_path("java.boot.class.path", path);
path = strtok(NULL, delim);
}
}
static void handle_bootclasspath(const char *arg)
{
bootclasspath_parse_and_append(arg);
}
static void handle_bootclasspath_append(const char *arg)
{
bootclasspath_append = arg;
}
enum operation {
OPERATION_MAIN_CLASS,
OPERATION_JAR_FILE,
};
static enum operation operation = OPERATION_MAIN_CLASS;
static char *classname;
static struct vm_jar *jar_file;
static void handle_jar(const char *arg)
{
operation = OPERATION_JAR_FILE;
/* Can't specify more than one jar file */
if (jar_file)
usage(stderr, EXIT_FAILURE);
jar_file = vm_jar_open(arg);
if (!jar_file) {
fprintf(stdout, "Unable to open JAR file %s\n", arg);
exit(EXIT_FAILURE);
}
const char *main_class = vm_jar_get_main_class(jar_file);
if (!main_class) {
fprintf(stdout, "Unable to look up main class in JAR file %s\n", arg);
exit(EXIT_FAILURE);
}
classname = dots_to_slash(main_class);
if (!classname)
die("out of memory");
/* XXX: Cheap solution. This can give funny results depending on where
* you put the -jar relative to the -classpath(s). Besides, we should
* save some memory and only open the zip file once. */
system_property_append_path("java.class.path", arg);
}
static void handle_nogc(void)
{
dont_gc = 1;
}
static void handle_no_system_classloader(void)
{
use_system_classloader = false;
}
static void handle_newgc(void)
{
newgc_enabled = true;
}
static void handle_maps(void)
{
dump_maps = true;
}
static void handle_perf(void)
{
perf_enabled = true;
}
static void handle_ssa(void)
{
opt_ssa_enable = true;
}
static void handle_no_ic(void)
{
opt_ic_enabled = false;
}
static void handle_int(void)
{
opt_interp_only = true;
}
static void regex_compile(regex_t *regex, const char *arg)
{
int err = regcomp(regex, arg, REG_EXTENDED | REG_NOSUB);
if (err) {
unsigned int size = regerror(err, regex, NULL, 0);
char *errbuf = malloc(size);
regerror(err, regex, errbuf, size);
fprintf(stderr, "error: regcomp: %s\n", errbuf);
free(errbuf);
exit(EXIT_FAILURE);
}
}
/* @arg must be in the format package/name/Class.method(Lsignature;)V */
static void handle_trace_method(const char *arg)
{
opt_trace_method = true;
regex_compile(&method_trace_regex, arg);
}
static void handle_trace_gate(const char *arg)
{
opt_trace_gate = true;
regex_compile(&method_trace_gate_regex, arg);
}
static void handle_debug_stack(void)
{
opt_debug_stack = true;
}
static void handle_trace_asm(void)
{
opt_trace_machine_code = true;
opt_trace_compile = true;
}
static void handle_trace_bytecode_offset(void)
{
opt_trace_bytecode_offset = true;
}
static void handle_trace_verifier(void)
{
opt_trace_verifier = true;
}
static void handle_trace_classloader(void)
{
opt_trace_classloader = true;
}
static void handle_trace_compile(void)
{
opt_trace_compile = true;
}
static void handle_trace_exceptions(void)
{
opt_trace_exceptions = true;
}
static void handle_trace_invoke(void)
{
opt_trace_invoke = true;
}
static void handle_trace_invoke_verbose(void)
{
opt_trace_invoke = true;
opt_trace_invoke_verbose = true;
}
static void handle_trace_itable(void)
{
opt_trace_itable = true;
}
static void handle_trace_liveness(void)
{
opt_trace_liveness = true;
}
static void handle_trace_jit(void)
{
opt_trace_ssa = true;
opt_trace_cfg = true;
opt_trace_tree_ir = true;
opt_trace_lir = true;
opt_trace_regalloc = true;
opt_trace_machine_code = true;
opt_trace_magic_trampoline = true;
opt_trace_bytecode_offset = true;
opt_trace_compile = true;
}
static void handle_trace_bytecode(void)
{
opt_trace_bytecode = true;
opt_trace_compile = true;
}
static void handle_trace_trampoline(void)
{
opt_trace_magic_trampoline = true;
}
static void handle_trace_vtable(void)
{
opt_trace_vtable = true;
}
static void handle_define(const char *arg)
{
char *str, *ptr, *key, *value;
str = strdup(arg);
if (!str)
error("out of memory");
key = strtok_r(str, "=", &ptr);
value = strtok_r(NULL, "=", &ptr);
if (!key || !*key)
goto out;
key = strdup(key);
if (value)
value = strdup(value);
else
value = strdup("");
if (!key || !value)
error("out of memory");
add_system_property(key, value);
out:
free(str);
}
static void handle_verbose_gc(void)
{
verbose_gc = true;
}
static void handle_max_heap_size(const char *arg)
{
max_heap_size = parse_long(arg);
if (!max_heap_size) {
fprintf(stderr, "%s: unparseable heap size '%s'\n", program_name, arg);
usage(stderr, EXIT_FAILURE);
}
}
static void handle_thread_stack_size(const char *arg)
{
/* Ignore */
}
static void handle_print_compilation(void)
{
opt_print_compilation = true;
}
const struct option options[] = {
DEFINE_OPTION("version", handle_version),
DEFINE_OPTION("h", handle_help),
DEFINE_OPTION("help", handle_help),
DEFINE_OPTION("client", handle_client),
DEFINE_OPTION("server", handle_server),
DEFINE_OPTION("verbose:gc", handle_verbose_gc),
DEFINE_OPTION("Xmaps", handle_maps),
DEFINE_OPTION("Xnewgc", handle_newgc),
DEFINE_OPTION("Xnogc", handle_nogc),
DEFINE_OPTION("Xnosystemclassloader", handle_no_system_classloader),
DEFINE_OPTION("Xperf", handle_perf),
DEFINE_OPTION("Xssa", handle_ssa),
DEFINE_OPTION("Xnoic", handle_no_ic),
DEFINE_OPTION("Xint", handle_int),
DEFINE_OPTION("Xdebug:stack", handle_debug_stack),
DEFINE_OPTION("Xtrace:asm", handle_trace_asm),
DEFINE_OPTION("Xtrace:bytecode", handle_trace_bytecode),
DEFINE_OPTION("Xtrace:bytecode-offset", handle_trace_bytecode_offset),
DEFINE_OPTION("Xtrace:classloader", handle_trace_classloader),
DEFINE_OPTION("Xtrace:compile", handle_trace_compile),
DEFINE_OPTION("Xtrace:exceptions", handle_trace_exceptions),
DEFINE_OPTION("Xtrace:invoke", handle_trace_invoke),
DEFINE_OPTION("Xtrace:invoke-verbose", handle_trace_invoke_verbose),
DEFINE_OPTION("Xtrace:itable", handle_trace_itable),
DEFINE_OPTION("Xtrace:jit", handle_trace_jit),
DEFINE_OPTION("Xtrace:liveness", handle_trace_liveness),
DEFINE_OPTION("Xtrace:trampoline", handle_trace_trampoline),
DEFINE_OPTION("Xtrace:verifier", handle_trace_verifier),
DEFINE_OPTION("Xtrace:vtable", handle_trace_vtable),
DEFINE_OPTION_ARG("classpath", handle_classpath),
DEFINE_OPTION_ARG("bootclasspath", handle_bootclasspath),
DEFINE_OPTION_ARG("cp", handle_classpath),
DEFINE_OPTION_ARG("jar", handle_jar),
DEFINE_OPTION_ARG("Xtrace:method", handle_trace_method),
DEFINE_OPTION_ARG("Xtrace:gate", handle_trace_gate),
DEFINE_OPTION_ADJACENT_ARG("Xbootclasspath/a:", handle_bootclasspath_append),
DEFINE_OPTION_ADJACENT_ARG("D", handle_define),
DEFINE_OPTION_ADJACENT_ARG("Xmx", handle_max_heap_size),
DEFINE_OPTION_ADJACENT_ARG("Xss", handle_thread_stack_size),
DEFINE_OPTION("XX:+PrintCompilation", handle_print_compilation),
};
static void parse_options(int argc, char *argv[])
{
int optind;
for (optind = 1; optind < argc; ++optind) {
if (argv[optind][0] != '-')
break;
const struct option *opt = get_option(options, ARRAY_SIZE(options), argv[optind] + 1);
if (!opt) {
fprintf(stderr, "%s: unrecognized option '%s'\n", program_name, argv[optind]);
usage(stderr, EXIT_FAILURE);
}
if (!opt->arg) {
opt->handler.func();
continue;
}
if (opt->arg_is_adjacent) {
opt->handler.func_arg(argv[optind] + strlen(opt->name)
+ 1);
continue;
}
/* We wanted an argument, but there was none */
if (optind + 1 >= argc)
usage(stderr, EXIT_FAILURE);
opt->handler.func_arg(argv[++optind]);
if (strcmp(argv[optind - 1], "-jar") == 0) {
optind++;
break;
}
}
if (operation == OPERATION_MAIN_CLASS) {
if (optind >= argc)
usage(stderr, EXIT_FAILURE);
classname = dots_to_slash(argv[optind++]);
}
if (optind < argc) {
nr_java_args = argc - optind;
java_args = &argv[optind];
}
}
static int
do_main_class(void)
{
struct vm_object *loader = NULL;
if (use_system_classloader) {
loader = get_system_class_loader();
if (!loader)
return -1;
}
if (exception_occurred()) {
return -1;
}
struct vm_class *vmc = classloader_load(loader, classname);
if (!vmc) {
fprintf(stderr, "error: %s: could not load\n", classname);
return -1;
}
if (vm_class_ensure_init(vmc)) {
fprintf(stderr, "error: %s: couldn't initialize\n", classname);
return -1;
}
struct vm_method *vmm = vm_class_get_method_recursive(vmc,
"main", "([Ljava/lang/String;)V");
if (!vmm) {
fprintf(stderr, "error: %s: no main method\n", classname);
return -1;
}
if (!vm_method_is_static(vmm)) {
fprintf(stderr, "error: %s: main method not static\n",
classname);
return -1;
}
struct vm_object *args;
args = vm_object_alloc_array(vm_array_of_java_lang_String, nr_java_args);
if (!args)
die("out of memory");
for (unsigned int i = 0; i < nr_java_args; i++) {
struct vm_object *arg;
arg = vm_object_alloc_string_from_c(java_args[i]);
array_set_field_object(args, i, arg);
}
if (opt_interp_only) {
vm_interp_method(vmm, args);
} else {
void (*java_main)(void *);
java_main = vm_method_trampoline_ptr(vmm);
java_main(args);
}
return 0;
}
static int
do_jar_file(void)
{
/* XXX: This stub should be expanded in the future; see comment in
* handle_jar(). */
return do_main_class();
}
struct gnu_classpath_config {
const char *glibj;
const char *lib;
};
struct gnu_classpath_config gnu_classpath_configs[] = {
{
"/usr/local/classpath/share/classpath/glibj.zip",
"/usr/local/classpath/lib/classpath"
},
{
"/usr/share/classpath/glibj.zip",
"/usr/lib/classpath/"
},
};
static bool gnu_classpath_autodiscovery(void)
{
for (unsigned int i = 0; i < ARRAY_SIZE(gnu_classpath_configs); i++) {
struct gnu_classpath_config *config = &gnu_classpath_configs[i];
if (try_to_add_zip_to_classpath(config->glibj) < 0)
continue;
system_property_append_path("java.boot.class.path", config->glibj);
system_property_append_path("java.library.path", config->lib);
return true;
}
return false;
}
static bool init_classpath(void)
{
if (!system_property_get("java.boot.class.path")) {
if (!gnu_classpath_autodiscovery())
return false;
}
const char *boot_cp = system_property_get("java.boot.class.path");
add_system_property_const("sun.boot.class.path", boot_cp);
if (bootclasspath_append)
bootclasspath_parse_and_append(bootclasspath_append);
/* Search $CLASSPATH last. */
char *classpath = getenv("CLASSPATH");
if (classpath)
system_property_append_path("java.class.path", classpath);
if (!find_system_property("java.class.path")) {
const char *cwd = system_property_get("user.dir");
system_property_append_path("java.class.path", cwd);
}
return true;
}
static void print_proc_maps(void)
{
char cmd[32];
pid_t self;
self = getpid();
snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", self);
if (system(cmd) != 0)
die("system");
}
int
main(int argc, char *argv[])
{
int status = EXIT_FAILURE;
program_name = argv[0];
atexit(vm_atexit);
#ifndef NDEBUG
/* Make stdout/stderr unbuffered; it really helps debugging! */
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#endif
if (RUNNING_ON_VALGRIND) {
printf("JIT: Enabling workarounds for valgrind.\n");
running_on_valgrind = true;
}
arch_init();
init_string_intern();
init_literals_hash_map();
init_system_properties();
parse_options(argc, argv);
if (dump_maps)
print_proc_maps();
gc_init();
init_exec_env();
vm_reference_init();
classloader_init();
init_vm_objects();
jit_text_init();
gdb_init();
if (perf_enabled)
perf_map_open();
setup_signal_handlers();
init_cu_mapping();
init_exceptions();
jit_init_natives();
static_fixup_init();
vm_jni_init();
if (!init_classpath()) {
fprintf(stderr, "Unable to locate GNU Classpath. Please specify 'java.boot.class.path' and 'java.library.path' manually.\n");
exit(EXIT_FAILURE);
}
if (preload_vm_classes()) {
fprintf(stderr, "Unable to preload system classes\n");
exit(EXIT_FAILURE);
}
init_stack_trace_printing();
if (init_threading()) {
fprintf(stderr, "could not initialize threading\n");
goto out_check_exception;
}
switch (operation) {
case OPERATION_MAIN_CLASS:
status = do_main_class();
break;
case OPERATION_JAR_FILE:
status = do_jar_file();
break;
default:
break;
}
out_check_exception:
if (exception_occurred()) {
vm_print_exception(exception_occurred());
status = EXIT_FAILURE;
goto out;
}
vm_thread_wait_for_non_daemons();
out:
vm_exit(status);
/* XXX: We should not get there */
return EXIT_FAILURE;
}