diff -r a97f753cfb7a src/mm/gc-boehm.cpp --- a/src/mm/gc-boehm.cpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/mm/gc-boehm.cpp Mon Jan 14 22:44:36 2013 +0100 @@ -63,6 +63,8 @@ static bool in_gc_out_of_memory = false; /* is GC out of memory? */ static size_t gc_max_heap_size = 0; +static int pagesize; + /* prototype static functions *************************************************/ @@ -115,6 +117,8 @@ if (heapstartsize > heapcurrentsize) GC_expand_hp(heapstartsize - heapcurrentsize); + + pagesize = os::getpagesize(); } @@ -150,6 +154,22 @@ struct timespec time_start, time_end; #endif + threadobject *t = thread_get_current(); + // bdwgc accesses quite a lot of stack on its own + if ((uintptr_t) &p - 16*pagesize < (uintptr_t) t->stack_guard) + { + if (!t->stack_guard_hit) { + t->stack_guard_hit = true; + exceptions_throw_stackoverflowerror(); + return 0; + } + else { + p = malloc(size); + MSET(p, 0, uint8_t, size); + return p; + } + } + RT_TIMING_GET_TIME(time_start); /* We can't use a bool here for references, as it's passed as a diff -r a97f753cfb7a src/threads/posix/thread-posix.cpp --- a/src/threads/posix/thread-posix.cpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/threads/posix/thread-posix.cpp Mon Jan 14 22:44:36 2013 +0100 @@ -489,6 +489,7 @@ t->es = NULL; #endif + t->stack_guard_hit = false; // Simply reuse the existing dump memory. } diff -r a97f753cfb7a src/threads/posix/thread-posix.hpp --- a/src/threads/posix/thread-posix.hpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/threads/posix/thread-posix.hpp Mon Jan 14 22:44:36 2013 +0100 @@ -106,6 +106,8 @@ s4 suspend_reason; /* reason for suspending */ u1 *pc; /* current PC (used for profiling) */ + void *stack_guard; + bool stack_guard_hit; java_object_t *_exceptionptr; /* current exception */ struct stackframeinfo_t *_stackframeinfo; /* current native stackframeinfo */ diff -r a97f753cfb7a src/vm/exceptions.cpp --- a/src/vm/exceptions.cpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/exceptions.cpp Mon Jan 14 22:44:36 2013 +0100 @@ -1133,6 +1133,18 @@ } +/* exceptions_throw_stackoverflowerror ***************************************** + + Generates and throws an java.lang.StackOverflowError for the VM. + +*******************************************************************************/ + +void exceptions_throw_stackoverflowerror(void) +{ + exceptions_throw_utf(utf_java_lang_StackOverflowError); +} + + /* exceptions_throw_unsatisfiedlinkerror *************************************** Generates and throws a java.lang.UnsatisfiedLinkError for the @@ -1565,6 +1577,21 @@ return o; } +/* exceptions_new_stackoverflowerror ******************************************* + + Generates a java.lang.StackOverflowError for the VM system. + +*******************************************************************************/ + +java_handle_t *exceptions_new_stackoverflowerror(void) +{ + java_handle_t *o; + + o = exceptions_new_utf(utf_java_lang_StackOverflowError); + + return o; +} + /* exceptions_throw_nullpointerexception *************************************** diff -r a97f753cfb7a src/vm/exceptions.hpp --- a/src/vm/exceptions.hpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/exceptions.hpp Mon Jan 14 22:44:36 2013 +0100 @@ -68,6 +68,7 @@ void exceptions_throw_instantiationerror(classinfo *c); void exceptions_throw_internalerror(const char *message, ...); void exceptions_throw_outofmemoryerror(void); +void exceptions_throw_stackoverflowerror(void); void exceptions_throw_verifyerror(methodinfo *m, const char *message, ...); void exceptions_throw_verifyerror_for_stack(methodinfo *m, int type); void exceptions_throw_unsatisfiedlinkerror(utf *name); @@ -91,6 +92,7 @@ void exceptions_throw_negativearraysizeexception(void); java_handle_t *exceptions_new_nullpointerexception(void); +java_handle_t *exceptions_new_stackoverflowerror(void); void exceptions_throw_nullpointerexception(void); void exceptions_throw_privilegedactionexception(java_handle_t *cause); void exceptions_throw_stringindexoutofboundsexception(void); diff -r a97f753cfb7a src/vm/jit/builtin.cpp --- a/src/vm/jit/builtin.cpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/jit/builtin.cpp Mon Jan 14 22:44:36 2013 +0100 @@ -851,8 +851,10 @@ o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS, c->finalizer, true); - if (!o) + if (!o) { + thread_get_current()->stack_guard_hit = false; return NULL; + } #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) /* XXX this is only a dirty hack to make Boehm work with handles */ @@ -933,8 +935,10 @@ c->finalizer, true); } - if (!o) + if (!o) { + thread_get_current()->stack_guard_hit = false; return NULL; + } # if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) /* XXX this is only a dirty hack to make Boehm work with handles */ @@ -1018,8 +1022,10 @@ o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS, c->finalizer, false); - if (!o) + if (!o) { + thread_get_current()->stack_guard_hit = false; return NULL; + } o->vftbl = c->vftbl; @@ -2143,8 +2149,10 @@ co = (java_handle_t*) heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true); - if (co == NULL) + if (co == NULL) { + thread_get_current()->stack_guard_hit = false; return NULL; + } #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) /* XXX this is only a dirty hack to make Boehm work with handles */ diff -r a97f753cfb7a src/vm/jit/trap.cpp --- a/src/vm/jit/trap.cpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/jit/trap.cpp Mon Jan 14 22:44:36 2013 +0100 @@ -163,6 +163,11 @@ return; } + if (thread_get_current()->stack_guard_hit) { + es.pc += 8; + md_executionstate_write(&es, context); + return; + } // We have a problem... vm_abort_disassemble(xpc, 1, "trap_handle: Unknown trap instruction at %p", xpc); } @@ -242,6 +247,10 @@ p = exceptions_new_nullpointerexception(); break; + case TRAP_StackOverflowError: + p = exceptions_new_stackoverflowerror(); + break; + case TRAP_ArithmeticException: p = exceptions_new_arithmeticexception(); break; @@ -407,6 +416,8 @@ es.intregs[REG_ITMP2_XPC] = (uintptr_t) xpc; es.pc = (uint8_t *) (uintptr_t) asm_handle_exception; #endif + + thread_get_current()->stack_guard_hit = false; } } diff -r a97f753cfb7a src/vm/jit/x86_64/codegen.c --- a/src/vm/jit/x86_64/codegen.c Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/jit/x86_64/codegen.c Mon Jan 14 22:44:36 2013 +0100 @@ -89,7 +89,6 @@ registerdata* rd = jd->rd; /* create stack frame (if necessary) */ - if (cd->stackframesize) M_ASUB_IMM(cd->stackframesize * 8, REG_SP); @@ -153,6 +152,10 @@ } } } + + if (!code_is_leafmethod(jd->code)) + /* stack probe */ + M_LLD(REG_ITMP1, REG_SP, -4096 * 8); } diff -r a97f753cfb7a src/vm/jit/x86_64/md-trap.h --- a/src/vm/jit/x86_64/md-trap.h Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/jit/x86_64/md-trap.h Mon Jan 14 22:44:36 2013 +0100 @@ -52,13 +52,14 @@ /* Don't use 4 (could be a normal load offset). */ TRAP_ClassCastException = 5, - TRAP_CHECK_EXCEPTION = 6, - TRAP_PATCHER = 7, + TRAP_StackOverflowError = 6, + TRAP_CHECK_EXCEPTION = 7, /* Don't use 8 (could be a normal load offset). */ - TRAP_COMPILER = 9, - TRAP_COUNTDOWN = 10, + TRAP_PATCHER = 9, + TRAP_COMPILER = 10, + TRAP_COUNTDOWN = 11, TRAP_END }; diff -r a97f753cfb7a src/vm/jit/x86_64/md.c --- a/src/vm/jit/x86_64/md.c Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/jit/x86_64/md.c Mon Jan 14 22:44:36 2013 +0100 @@ -194,12 +194,21 @@ // Default case is a normal NullPointerException. else { - trp->type = TRAP_NullPointerException; + threadobject *t = thread_get_current(); + uint64_t sp = (uint64_t) es->sp; + uint64_t guard = (uint64_t) t->stack_guard; + if ((uint64_t) sp < guard + 12*4096) { + if (t->stack_guard_hit) + return false; + trp->type = TRAP_StackOverflowError; + t->stack_guard_hit = true; + } else + trp->type = TRAP_NullPointerException; trp->value = 0; return true; } } - + default: return false; } diff -r a97f753cfb7a src/vm/utf8.c --- a/src/vm/utf8.c Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/utf8.c Mon Jan 14 22:44:36 2013 +0100 @@ -86,6 +86,7 @@ utf *utf_java_lang_NoSuchFieldError; utf *utf_java_lang_NoSuchMethodError; utf *utf_java_lang_OutOfMemoryError; +utf *utf_java_lang_StackOverflowError; utf *utf_java_lang_UnsatisfiedLinkError; utf *utf_java_lang_UnsupportedClassVersionError; utf *utf_java_lang_VerifyError; @@ -303,6 +304,8 @@ utf_java_lang_OutOfMemoryError = utf_new_char("java/lang/OutOfMemoryError"); + utf_java_lang_StackOverflowError = utf_new_char("java/lang/StackOverflowError"); + utf_java_lang_UnsatisfiedLinkError = utf_new_char("java/lang/UnsatisfiedLinkError"); diff -r a97f753cfb7a src/vm/utf8.h --- a/src/vm/utf8.h Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/utf8.h Mon Jan 14 22:44:36 2013 +0100 @@ -83,6 +83,7 @@ extern utf *utf_java_lang_NoSuchFieldError; extern utf *utf_java_lang_NoSuchMethodError; extern utf *utf_java_lang_OutOfMemoryError; +extern utf *utf_java_lang_StackOverflowError; extern utf *utf_java_lang_UnsatisfiedLinkError; extern utf *utf_java_lang_UnsupportedClassVersionError; extern utf *utf_java_lang_VerifyError; diff -r a97f753cfb7a src/vm/vm.cpp --- a/src/vm/vm.cpp Sun Jan 06 19:28:42 2013 +0100 +++ b/src/vm/vm.cpp Mon Jan 14 22:44:36 2013 +0100 @@ -580,6 +580,31 @@ static void vm_compile_method(char* mainname); #endif +/* +void *growstack_(int n, char *p) +{ + char buf[4000]; + for (int i=0; i<4000; i++) + buf[i] = *p + 1; + if (n>0) + return growstack_(n-1, buf); + else + return buf; +} + +void *growstack() +{ + char buf[4000]; + void *bottom, *aligned; + memset(buf, 0, 4000); + bottom = growstack_(256, buf); + + int pagesize = os::getpagesize(); + aligned = (void*)(((uint64_t)(((u1*) bottom)-32000)) & ~(pagesize-1)); + (void) os::mmap_anonymous(aligned, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED); + return aligned; +} +// */ /** * Implementation for JNI_CreateJavaVM. This function creates a VM @@ -1402,6 +1427,16 @@ threads_init(); #endif + threadobject *t = thread_get_current(); + + int pagesize = os::getpagesize(); + // just an arbitrarily chosen stack size of 512k + void *aligned = (void*) MEMORY_ALIGN((uintptr_t) ((void*) &t) - 512 * 1024, pagesize); + (void) os::mmap_anonymous(aligned, pagesize*4, PROT_NONE, MAP_PRIVATE | MAP_FIXED); + + t->stack_guard = aligned; + t->stack_guard_hit = false; + /* Initialize the native VM subsystem. */ /* AFTER: threads_init (at least for SUN's classes) */