📄 natobject.cc
字号:
// natObject.cc - Implementation of the Object class./* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation This file is part of libgcj.This software is copyrighted work licensed under the terms of theLibgcj License. Please consult the file "LIBGCJ_LICENSE" fordetails. */#include <config.h>#include <platform.h>#include <string.h>#pragma implementation "Object.h"#include <gcj/cni.h>#include <jvm.h>#include <java/lang/Object.h>#include <java-threads.h>#include <java-signal.h>#include <java/lang/CloneNotSupportedException.h>#include <java/lang/IllegalArgumentException.h>#include <java/lang/IllegalMonitorStateException.h>#include <java/lang/InterruptedException.h>#include <java/lang/NullPointerException.h>#include <java/lang/Class.h>#include <java/lang/Cloneable.h>#include <java/lang/Thread.h>#ifdef LOCK_DEBUG# include <stdio.h>#endifusing namespace java::lang;// This is used to represent synchronization information.struct _Jv_SyncInfo{#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) // We only need to keep track of initialization state if we can // possibly finalize this object. bool init;#endif _Jv_ConditionVariable_t condition; _Jv_Mutex_t mutex;};jclassjava::lang::Object::getClass (void){ _Jv_VTable **dt = (_Jv_VTable **) this; return (*dt)->clas;}jintjava::lang::Object::hashCode (void){ return _Jv_HashCode (this);}jobjectjava::lang::Object::clone (void){ jclass klass = getClass (); jobject r; jint size; // We also clone arrays here. If we put the array code into // __JArray, then we'd have to figure out a way to find the array // vtbl when creating a new array class. This is easier, if uglier. if (klass->isArray()) { __JArray *array = (__JArray *) this; jclass comp = getClass()->getComponentType(); jint eltsize; if (comp->isPrimitive()) { r = _Jv_NewPrimArray (comp, array->length); eltsize = comp->size(); } else { r = _Jv_NewObjectArray (array->length, comp, NULL); eltsize = sizeof (jobject); } // We can't use sizeof on __JArray because we must account for // alignment of the element type. size = (_Jv_GetArrayElementFromElementType (array, comp) - (char *) array + array->length * eltsize); } else { if (! java::lang::Cloneable::class$.isAssignableFrom(klass)) throw new CloneNotSupportedException; size = klass->size(); r = _Jv_AllocObject (klass); } memcpy ((void *) r, (void *) this, size);#ifndef JV_HASH_SYNCHRONIZATION // Guarantee that the locks associated to the two objects are // distinct. r->sync_info = NULL;#endif return r;}void_Jv_FinalizeObject (jobject obj){ // Ignore exceptions. From section 12.6 of the Java Language Spec. try { obj->finalize (); } catch (java::lang::Throwable *t) { // Ignore. }}//// Synchronization code.//#ifndef JV_HASH_SYNCHRONIZATION// This global is used to make sure that only one thread sets an// object's `sync_info' field.static _Jv_Mutex_t sync_mutex;// This macro is used to see if synchronization initialization is// needed.#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy)# define INIT_NEEDED(Obj) (! (Obj)->sync_info \ || ! ((_Jv_SyncInfo *) ((Obj)->sync_info))->init)#else# define INIT_NEEDED(Obj) (! (Obj)->sync_info)#endif#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy)// If we have to run a destructor for a sync_info member, then this// function is registered as a finalizer for the sync_info.static voidfinalize_sync_info (jobject obj){ _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj;#if defined (_Jv_HaveCondDestroy) _Jv_CondDestroy (&si->condition);#endif#if defined (_Jv_HaveMutexDestroy) _Jv_MutexDestroy (&si->mutex);#endif si->init = false;}#endif// This is called to initialize the sync_info element of an object.voidjava::lang::Object::sync_init (void){ _Jv_MutexLock (&sync_mutex); // Check again to see if initialization is needed now that we have // the lock. if (INIT_NEEDED (this)) { // We assume there are no pointers in the sync_info // representation. _Jv_SyncInfo *si; // We always create a new sync_info, even if there is already // one available. Any given object can only be finalized once. // If we get here and sync_info is not null, then it has already // been finalized. So if we just reinitialize the old one, // we'll never be able to (re-)destroy the mutex and/or // condition variable. si = (_Jv_SyncInfo *) _Jv_AllocBytes (sizeof (_Jv_SyncInfo)); _Jv_MutexInit (&si->mutex); _Jv_CondInit (&si->condition);#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) // Register a finalizer. si->init = true; _Jv_RegisterFinalizer (si, finalize_sync_info);#endif sync_info = (jobject) si; } _Jv_MutexUnlock (&sync_mutex);}voidjava::lang::Object::notify (void){ if (__builtin_expect (INIT_NEEDED (this), false)) sync_init (); _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; if (__builtin_expect (_Jv_CondNotify (&si->condition, &si->mutex), false)) throw new IllegalMonitorStateException(JvNewStringLatin1 ("current thread not owner"));}voidjava::lang::Object::notifyAll (void){ if (__builtin_expect (INIT_NEEDED (this), false)) sync_init (); _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; if (__builtin_expect (_Jv_CondNotifyAll (&si->condition, &si->mutex), false)) throw new IllegalMonitorStateException(JvNewStringLatin1 ("current thread not owner"));}voidjava::lang::Object::wait (jlong timeout, jint nanos){ if (__builtin_expect (INIT_NEEDED (this), false)) sync_init (); if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, false)) throw new IllegalArgumentException; _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; switch (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos)) { case _JV_NOT_OWNER: throw new IllegalMonitorStateException (JvNewStringLatin1 ("current thread not owner")); case _JV_INTERRUPTED: if (Thread::interrupted ()) throw new InterruptedException; }}//// Some runtime code.//// This function is called at system startup to initialize the// `sync_mutex'.void_Jv_InitializeSyncMutex (void){ _Jv_MutexInit (&sync_mutex);}void_Jv_MonitorEnter (jobject obj){#ifndef HANDLE_SEGV if (__builtin_expect (! obj, false)) throw new java::lang::NullPointerException;#endif if (__builtin_expect (INIT_NEEDED (obj), false)) obj->sync_init (); _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; _Jv_MutexLock (&si->mutex); // FIXME: In the Windows case, this can return a nonzero error code. // We should turn that into some exception ...}void_Jv_MonitorExit (jobject obj){ JvAssert (obj); JvAssert (! INIT_NEEDED (obj)); _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; if (__builtin_expect (_Jv_MutexUnlock (&si->mutex), false)) throw new java::lang::IllegalMonitorStateException;}bool_Jv_ObjectCheckMonitor (jobject obj){ if (__builtin_expect (INIT_NEEDED (obj), false)) obj->sync_init (); _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; return _Jv_MutexCheckMonitor (&si->mutex);}#else /* JV_HASH_SYNCHRONIZATION */// FIXME: We shouldn't be calling GC_register_finalizer directly.#ifndef HAVE_BOEHM_GC# error Hash synchronization currently requires boehm-gc// That's actually a bit of a lie: It should also work with the null GC,// probably even better than the alternative.// To really support alternate GCs here, we would need to widen the// interface to finalization, since we sometimes have to register a// second finalizer for an object that already has one.// We might also want to move the GC interface to a .h file, since// the number of procedure call levels involved in some of these// operations is already ridiculous, and would become worse if we// went through the proper intermediaries.#else# ifdef LIBGCJ_GC_DEBUG# define GC_DEBUG# endif# include "gc.h"#endif// What follows currenly assumes a Linux-like platform.// Some of it specifically assumes X86 or IA64 Linux, though that// should be easily fixable.// A Java monitor implemention based on a table of locks.// Each entry in the table describes// locks held for objects that hash to that location.// This started out as a reimplementation of the technique used in SGIs JVM,// for which we obtained permission from SGI.// But in fact, this ended up quite different, though some ideas are// still shared with the original.// It was also influenced by some of the published IBM work,// though it also differs in many ways from that.// We could speed this up if we had a way to atomically update// an entire cache entry, i.e. 2 contiguous words of memory.// That would usually be the case with a 32 bit ABI on a 64 bit processor.// But we don't currently go out of our way to target those.// I don't know how to do much better with a N bit ABI on a processor// that can atomically update only N bits at a time.// Author: Hans-J. Boehm (Hans_Boehm@hp.com, boehm@acm.org)#include <limits.h>#include <unistd.h> // for usleep, sysconf.#include <gcj/javaprims.h>#include <sysdep/locks.h>#include <java/lang/Thread.h>// Try to determine whether we are on a multiprocessor, i.e. whether// spinning may be profitable.// This should really use a suitable autoconf macro.// False is the conservative answer, though the right one is much better.static boolis_mp(){#ifdef _SC_NPROCESSORS_ONLN long nprocs = sysconf(_SC_NPROCESSORS_ONLN); return (nprocs > 1);#else return false;#endif}// A call to keep_live(p) forces p to be accessible to the GC// at this point.inline static voidkeep_live(obj_addr_t p){ __asm__ __volatile__("" : : "rm"(p) : "memory");}// Each hash table entry holds a single preallocated "lightweight" lock.// In addition, it holds a chain of "heavyweight" locks. Lightweight// locks do not support Object.wait(), and are converted to heavyweight// status in response to contention. Unlike the SGI scheme, both// ligtweight and heavyweight locks in one hash entry can be simultaneously// in use. (The SGI scheme requires that we be able to acquire a heavyweight// lock on behalf of another thread, and can thus convert a lock we don't// hold to heavyweight status. Here we don't insist on that, and thus// let the original holder of the lighweight lock keep it.)struct heavy_lock { void * reserved_for_gc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -