Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is the Object class implemented (methods like hashCode and internal fields)?

Tags:

java

object

jvm

I am curious how is the Object class implemented. For example

  1. a method hashCode() or wait()
  2. How is the internal state represented. For instance, an instrinsic lock or the data structure for storing threads that called object's wait().

In order to find these out, I have downloaded a source of OpenJDK and started to dig in. First thing, I came across was \openjdksrc\jdk\src\share\native\java\lang\Object.c file, containing, among others:

static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
{
    if (this == NULL) {
        JNU_ThrowNullPointerException(env, NULL);
        return 0;
    } else {
        return (*env)->GetObjectClass(env, this);
    }
}

and to my understanding, methods[] array defines a mapping between the native implementations of Object's methods. So for example, Object's hashCode() is mapped to JVM_IHashCode function. The JVM_IHashCode is implemented in \openjdksrc\hotspot\src\share\vm\prims\jvm.cpp. And here is my first question. Why this is already a part of VM itself (it is defined already in \openjdksrc\hotspot\src\share\vm)? But lets move to the code of JVM_IHashCode:

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_IHashCode");
  // as implemented in the classic virtual machine; return 0 if object is NULL
  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END

Why if object is null we return here 0? I guess an NPE should be thrown. Otherwise, the FastHashCode is called from \openjdksrc\hotspot\src\share\vm\runtime\synchronizer.cpp and eventually at some point of time, the get_next_hash is called that calculates the real value. Once it is calculated the question is where it is stored?

    intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {

...CUT...

      ObjectMonitor* monitor = NULL;
      markOop temp, test;
      intptr_t hash;
      markOop mark = ReadStableMark (obj);

...CUT...

      if (mark->is_neutral()) {
        hash = mark->hash();              // this is a normal header
        if (hash) {                       // if it has hash, just return it
          return hash;
        }
        hash = get_next_hash(Self, obj);  // allocate a new hash code
        temp = mark->copy_set_hash(hash); // merge the hash code into header
        // use (machine word version) atomic operation to install the hash
        test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
        if (test == mark) {
          return hash;
        }
        // If atomic operation failed, we must inflate the header
        // into heavy weight monitor. We could add more code here
        // for fast path, but it does not worth the complexity.
      } 
...CUT...
      return hash;
    }

So the oop class/struct (?) has a markOop class/struct (?) where the hash value is stored. Funilly I can't locate these classes/structs. All I was able to find was:

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
...CUT...

in \openjdksrc\hotspot\src\share\vm\oops\oop.hpp which seems to have markOop in a private field. But then what really is "oop" which is refered in the rest of the code? And where to find markOop definition? I have found a corresponding:

class markOopDesc: public oopDesc 
...CUT...

in \openjdksrc\hotspot\src\share\vm\oops\markOop.hpp but it is only full of enums and can't find a field where the hash value can be stored. If someone could answer at least a part of my questions I would be very grateful. Thanks!

like image 588
Janek Avatar asked Dec 08 '12 13:12

Janek


1 Answers

Java object's hash code is stored in object header, once it's calculated.

http://www.javamex.com/tutorials/memory/object_memory_usage.shtml

http://hunmr.blogspot.com/2012/08/java-performance-tunning.html

from hotspot/src/share/vm/oops/markOop.hpp

// The markOop describes the header of an object.
//
// Note that the mark is not a real oop but just a word.
// It is placed in the oop hierarchy for historical reasons.
//
// Bit-format of an object header (most significant first, big endian layout below):
//
//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
like image 189
whunmr Avatar answered Oct 23 '22 09:10

whunmr