/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This source file is part of SableVM. * * * * See the file "LICENSE" for the copyright information and for * * the terms and conditions for copying, distribution and * * modification of this source file. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ---------------------------------------------------------------------- Java_java_lang_VMObject_notify ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: notify * Signature: (Ljava/lang/Object;)V */ JNIEXPORT static void JNICALL Java_java_lang_VMObject_notify (JNIEnv *_env, jclass class SVM_UNUSED, jobject o) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; _svmm_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; /* < head is thin > */ if (_svmf_lockword_is_thin (lockword)) { /* < thin head is ours > */ if (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* It's a thinlock; no other thread is possibly waiting on * this object's monitor. No need to notify. */ goto end; } /* Head is fat - look at the main body. */ { _svmt_word body_index = _svmf_lockword_get_fatlock_index (lockword); _svmt_JNIEnv *main_body = vm->threads.array[body_index]; /* < main body is ours > */ if (main_body->body.owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* [ * acquire main body mutex ] */ _svmm_mutex_lock_v (main_body->body.mutex); /* < any waiting threads > */ if (!_svmm_dll_empty (main_body, wait)) { /* [ * signal a waiting thread via main body cond. var. ] */ _svmm_cond_signal_v (env, main_body->body.wait_cond); } /* [ * release main body mutex ] */ _svmm_mutex_unlock_v (); } } end: _svmm_stopping_java (env); } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_notifyAll ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: notifyAll * Signature: (Ljava/lang/Object;)V */ JNIEXPORT static void JNICALL Java_java_lang_VMObject_notifyAll (JNIEnv *_env, jclass class SVM_UNUSED, jobject o) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; _svmm_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; /* < head is thin > */ if (_svmf_lockword_is_thin (lockword)) { /* < thin head is ours > */ if (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* It's a thinlock; no other thread is possibly waiting on * this object's monitor. No need to notify. */ goto end; } /* Head is fat - look at the main body. */ { _svmt_word body_index = _svmf_lockword_get_fatlock_index (lockword); _svmt_JNIEnv *main_body = vm->threads.array[body_index]; /* < main body is ours > */ if (main_body->body.owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* [ * acquire main body mutex ] */ _svmm_mutex_lock_v (main_body->body.mutex); /* < any waiting threads > */ if (!_svmm_dll_empty (main_body, wait)) { /* [ * signal all waiting threads via main body cond. var. ] */ _svmm_cond_broadcast_v (env, main_body->body.wait_cond); } /* [ * release main body mutex ] */ _svmm_mutex_unlock_v (); } } end: _svmm_stopping_java (env); } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_wait ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: wait * Signature: (Ljava/lang/Object;JI)V */ JNIEXPORT static void JNICALL Java_java_lang_VMObject_wait (JNIEnv *_env, jclass class SVM_UNUSED, jobject o, jlong ms, jint ns) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; jint recursive_count, body_index; _svmt_JNIEnv *main_body = NULL; jboolean acquire_body_needed = JNI_FALSE; jboolean error_occured = JNI_FALSE; _svmm_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; _svmt_JNIEnv *target_thread; _svmm_mutex_new_name (main_body_mutex); _svmm_assert_not_encloser (instance); /* < head is thin > */ if (_svmf_lockword_is_thin (lockword)) { /* ! < thin head is ours > */ if (__unlikely (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id)) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* "Compulsory" contention handling */ /* [ * acquire own thread mutex ] */ _svmm_mutex_lock_v (env->locking.thread_mutex); /* < contention flag set > */ if (env->contention.flag) { /* [ CONTENTION HANDLING ] */ _svmf_contention_handling (env, NULL); goto inflate_in_own_cell; } /* < head is still thin > */ if (__likely (_svmf_lockword_is_thin (instance->lockword))) { inflate_in_own_cell: /* [ * use enclosed free body to create new main body ] */ main_body = env->locking.encloses; _svmm_assert_free_body (main_body); /* [ * set new main body owner to self ] */ main_body->body.owner = env; /* [ * fill in recursive count ] */ main_body->body.recursive_count = _svmf_lockword_get_thinlock_recursive_count (lockword) + 1; /* [ * fill in reference to the object new main body ] * [ will be attached to ] */ *main_body->body.jobject = instance; /* [ * set new main body "attached" flag to true ] */ main_body->body.attached = JNI_TRUE; /* [ * make the head fat and pointing to the new body ] */ instance->lockword = _svmf_lockword_fatlock (main_body->thread.id, _svmf_lockword_get_extra_bits (lockword)); } else { body_index = _svmf_lockword_get_fatlock_index (instance->lockword); main_body = vm->threads.array[body_index]; assert (instance == *main_body->body.jobject); } /* [ * release own thread mutex ] */ _svmm_mutex_unlock_v (); } else /* is fat already */ { body_index = _svmf_lockword_get_fatlock_index (lockword); main_body = vm->threads.array[body_index]; /* ! < main body is ours > */ if (__unlikely (main_body->body.owner != env)) { _svmf_error_IllegalMonitorStateException (env); goto end; } } assert (main_body != NULL); main_body_mutex = &main_body->body.mutex; /* [ * acquire main body mutex ] */ _svmm_mutex_lock_name (main_body_mutex); /* [ * add self to the list of waiting threads ] */ _svmm_dll_append (main_body, wait, env); /* [ * save recursive count ] */ recursive_count = main_body->body.recursive_count; /* < blocked list empty > */ if (_svmm_dll_empty (main_body, blocked)) { /* [ * set "waiting on object" reference to the object ] * [ current thread will be waiting on ] */ *env->locking.waiting_on = instance; /* Optimization: try to cheaply switch to not running java. */ if (__unlikely (_svmm_stopping_java_noblock (env) != JNI_OK)) { /* [ ? release main body mutex ] */ _svmm_mutex_unlock_name (main_body_mutex); /* [ + transition to "not running java" ] */ _svmm_stopping_java (env); /* [ ? acquire main body mutex ] */ _svmm_mutex_lock_name (main_body_mutex); } /* < blocked list still empty > */ if (__likely (_svmm_dll_empty (main_body, blocked))) { goto ready_to_wait; } else { if (__unlikely (_svmm_resuming_java_noblock (env) != JNI_OK)) { /* [ ? release main body mutex ] */ _svmm_mutex_unlock_name (main_body_mutex); /* [ + transition to "running java" ] */ _svmm_resuming_java (env); /* [ ? acquire main body mutex ] */ _svmm_mutex_lock_name (main_body_mutex); /* [ * re-read instance and lockword, nullify waiting_on ] */ instance = *env->locking.waiting_on; lockword = instance->lockword; } /* [ * unset "waiting on object" reference (opt.) ] */ *env->locking.waiting_on = NULL; /* [ * pick the first blocked thread as Target ] */ target_thread = _svmm_dll_first (main_body, blocked); goto transfer_main_body; } } else /* blocked list not empty */ { /* < main body is enclosed by the first blocked thread > */ /* [ * pick the first blocked thread as Target ] */ target_thread = _svmm_dll_first (main_body, blocked); if (__unlikely (target_thread != main_body->body.encloser)) { transfer_main_body: /* [ * exchange encloseness of: ] * [ - the free body Target encloses with ] * [ - the main body; ] * [ update enclosers locations in bodies ] */ _svmm_assert_free_body (target_thread->locking.encloses); _svmm_swap_thread_bodies (main_body->body.encloser, target_thread); } /* [ * set "waiting on object" reference to the object ] * [ current thread will be waiting on ] */ *env->locking.waiting_on = instance; } /* Optimized change to not running java */ if (__unlikely (_svmm_stopping_java_noblock (env) != JNI_OK)) { /* [ ? release main_body mutex ] */ _svmm_mutex_unlock_name (main_body_mutex); /* [ + transition to "not running java" ] */ _svmm_stopping_java (env); /* [ ? acquire main body mutex ] */ _svmm_mutex_lock_name (main_body_mutex); } /* [ * signal the thread enclosing main body ] */ _svmm_cond_signal_v (main_body, main_body->body.encloser->locking.thread_cond); ready_to_wait: /* [ * set main body owner to null ] */ main_body->body.owner = NULL; /* ! < interrupted flag set > */ if (__likely (!env->locking.interrupted)) { if (__likely (ms == 0 && ns == 0)) { _svmm_cond_wait_v (main_body->body.wait_cond, *main_body_mutex); } else { /* The following code is unforunately platform dependent. You will have to find some function like gettimeofday() that returns the current time as precisely as possible. In the worst case, simply use the quite imprecise ISO C time() function. */ struct timeval now; struct timespec timeout; gettimeofday (&now, NULL); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = now.tv_usec * 1000; timeout.tv_sec = timeout.tv_sec + (ms / 1000); timeout.tv_nsec = timeout.tv_nsec + (ms % 1000) * 1000 * 1000 + ns; /* Watch for overflow of timeout.tv_nsec... OK; I assume that tv_nsec has at least 32 bits (signed or not, I don't care), a reasonable assumption given that it must be able to hold the value 999999999. */ if (timeout.tv_nsec >= 1000000000L) { timeout.tv_sec++; timeout.tv_nsec -= 1000000000L; } /* I don't care about overflow of timeout.tv_sec. */ #if 0 /* FIXME: this is for benchmarking only!!! remove!!! */ if ((ms != 0xcafe) && (ns != 0xbabe)) { _svmm_cond_timedwait (main_body->body.wait_cond, *main_body_mutex, timeout); } else { sched_yield (); } #else _svmm_cond_timedwait (main_body->body.wait_cond, *main_body_mutex, timeout); #endif } } /* Optimization: try to cheaply switch to running java. */ if (__unlikely (_svmm_resuming_java_noblock (env) != JNI_OK)) { /* [ * release main body mutex ] */ _svmm_mutex_unlock_name (main_body_mutex); /* [ * transition to "running java" ] */ _svmm_resuming_java (env); /* [ * acquire main body mutex ] */ _svmm_mutex_lock_name (main_body_mutex); } /* [ * re-read instance and lockword, nullify waiting_on ] */ instance = *env->locking.waiting_on; /* [ * unset "waiting on object" reference ] */ *env->locking.waiting_on = NULL; /* < interrupted flag set > */ if (__unlikely (env->locking.interrupted)) { /* [ * clear "interrupted" flag ] * [ * create InterruptedException ] */ env->locking.interrupted = JNI_FALSE; _svmf_error_InterruptedException (env); } /* [ * remove self from the wait list of main body ] */ _svmm_dll_remove (main_body, wait, env); /* < can acquire main body ownership > */ if (main_body->body.owner == NULL) { /* [ * set main body owner to self ] */ main_body->body.owner = env; /* [ * restore saved recursive count ] */ main_body->body.recursive_count = recursive_count; /* { DEFLATE OR TRANSFER } ] */ if (__unlikely (_svmf_deflate_or_transfer (env, main_body) != JNI_OK)) { error_occured = JNI_TRUE; } } else { /* [ * append self to the list of blocked threads ] */ _svmm_dll_append (main_body, blocked, env); acquire_body_needed = JNI_TRUE; } /* [ * release main body mutex ] */ _svmm_mutex_unlock_name (main_body_mutex); if (__unlikely (error_occured)) { _svmf_error_OutOfMemoryError (env); goto end; } if (acquire_body_needed) { /* [ * transition to "not running java" ] */ _svmm_stopping_java (env); /* XXX: this could be better optimized */ _svmm_mutex_lock_name (main_body_mutex); if (__unlikely (_svmf_acquire_body (env, 1, main_body) != JNI_OK)) { _svmf_error_OutOfMemoryError (env); } _svmm_mutex_unlock_name (main_body_mutex); /* Yes, we will need to stop java again, because * _svmf_acquire_body resumed it. */ } } end: _svmm_stopping_java (env); } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_clone ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: clone * Signature: (Ljava/lang/Cloneable;)Ljava/lang/Object; */ JNIEXPORT static jobject JNICALL Java_java_lang_VMObject_clone (JNIEnv *_env, jclass class SVM_UNUSED, jobject obj) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); jobject clone = NULL; _svmm_resuming_java (env); { clone = _svmf_get_jni_frame_native_local (env); _svmf_clone_instance (env, obj, clone); } _svmm_stopping_java (env); return clone; } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_getClass ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: getClass * Signature: ()Ljava/lang/Class; */ JNIEXPORT static jclass JNICALL Java_java_lang_VMObject_getClass (JNIEnv *_env, jclass c SVM_UNUSED, jobject this) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); jclass class; _svmm_resuming_java (env); { class = _svmf_get_jni_frame_native_local (env); *class = *((*this)->vtable->type->class_instance); } _svmm_stopping_java (env); return class; }