[vmkit-commits] [PATCH] Implement a number of Java.sun.misc.Unsafe.* methods.

Nicolas Geoffray nicolas.geoffray at gmail.com
Tue Nov 8 07:57:28 PST 2011


Almost good to go :)

On Mon, Nov 7, 2011 at 3:50 AM, Will Dietz <wdietz2 at illinois.edu> wrote:

> On Fri, Nov 4, 2011 at 4:06 PM, Nicolas Geoffray
> <nicolas.geoffray at gmail.com> wrote:
> > Thanks Will for the new change. I have a few comments that I'd like you
> to
> > take into account before moving forward.
> [snip]
>
> Thank you for your comments!  Updated patch inlined below :).
>
> ~Will
>
> From 64c05c78614b4036e40dc915926f590b82f60966 Mon Sep 17 00:00:00 2001
> From: Will Dietz <w at wdtz.org>
> Date: Fri, 14 Oct 2011 06:07:15 -0500
> Subject: [PATCH 6/8] Implement a number of Java.sun.misc.Unsafe.* methods.
>
> Of particular interest is the addition of VMStaticInstance, used to
> enable us to return a reference to a static instance, even though a
> static instance isn't a heap object (and prevents the underlying
> static instance from being GC'd while this reference is live).
>
> This is required for us to support staticFieldBase/staticFieldOffset.
> ---
>  lib/J3/ClassLib/Classpath.inc       |  195
> ++++++++++++++++++++++++++++++++++-
>  lib/J3/ClassLib/VMStaticInstance.h  |   82 +++++++++++++++
>  lib/J3/Compiler/JavaAOTCompiler.cpp |    5 +-
>  lib/J3/Compiler/Makefile            |    2 +-
>  lib/J3/VMCore/Jnjvm.cpp             |    5 +
>  lib/J3/VMCore/Makefile              |    2 +-
>  lib/J3/VMCore/VirtualTables.cpp     |   11 ++-
>  7 files changed, 296 insertions(+), 6 deletions(-)
>  create mode 100644 lib/J3/ClassLib/VMStaticInstance.h
>
> diff --git a/lib/J3/ClassLib/Classpath.inc b/lib/J3/ClassLib/Classpath.inc
> index ccb9607..c81e26b 100644
> --- a/lib/J3/ClassLib/Classpath.inc
> +++ b/lib/J3/ClassLib/Classpath.inc
> @@ -15,12 +15,23 @@
>  #include "JavaThread.h"
>  #include "JavaUpcalls.h"
>  #include "Jnjvm.h"
> +#include "Reader.h"
> +#include "VMStaticInstance.h"
>
>
>  using namespace j3;
>
>  extern "C" {
>
> +// Convert a 'base' JavaObject to its pointer representation.
> +// Handles our special VMStaticInstance wrapper.
> +static inline uint8 *baseToPtr(JavaObject *base) {
> +  if (VMStaticInstance::isVMStaticInstance(base))
> +    return (uint8*)((VMStaticInstance*)base)->getStaticInstance();
> +  else
> +    return (uint8*)base;
> +}
> +
>  // Define hasClassInitializer because of a buggy implementation in
> Classpath.
>  JNIEXPORT bool JNICALL
> Java_java_io_VMObjectStreamClass_hasClassInitializer(
>  #ifdef NATIVE_JNI
> @@ -359,6 +370,186 @@ JavaObject* unsafe, JavaObject* obj, jlong
> offset, JavaObject* value) {
>   mvm::Collector::objectReferenceWriteBarrier((gc*)obj, (gc**)ptr,
> (gc*)value);
>  }
>
> +JNIEXPORT jlong JNICALL Java_sun_misc_Unsafe_allocateMemory(
> +JavaObject* unsafe, jlong size) {
> +  // TODO: Invalid size/OOM/etc handling!
> +  jlong res = 0;
> +  BEGIN_NATIVE_EXCEPTION(0)
> +  res = (jlong)malloc(size);
> +  END_NATIVE_EXCEPTION
> +  return res;
> +}
> +
> +JNIEXPORT void JNICALL Java_sun_misc_Unsafe_freeMemory(
> +JavaObject* unsafe, jlong ptr) {
> +  // TODO: Exception handling...
> +  BEGIN_NATIVE_EXCEPTION(0)
> +  free((void*)ptr);
> +  END_NATIVE_EXCEPTION
> +}
> +
> +JNIEXPORT void JNICALL Java_sun_misc_Unsafe_putLong__JJ(
> +JavaObject* unsafe, jlong ptr, jlong value) {
> +  BEGIN_NATIVE_EXCEPTION(0)
> +  *(jlong*)ptr = value;
> +  END_NATIVE_EXCEPTION
> +}
> +
> +JNIEXPORT jbyte JNICALL Java_sun_misc_Unsafe_getByte__J(
> +JavaObject* unsafe, jlong ptr) {
> +  jbyte res = 0;
> +  BEGIN_NATIVE_EXCEPTION(0)
> +  res =  *(jbyte*)ptr;
> +  END_NATIVE_EXCEPTION
> +
> +  return res;
> +}
> +
> +JNIEXPORT void JNICALL Java_sun_misc_Unsafe_ensureClassInitialized(
> +JavaObject* unsafe, JavaObject* clazz) {
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(clazz, 0);
> +  BEGIN_NATIVE_EXCEPTION(0)
> +
> +  Jnjvm* vm = JavaThread::get()->getJVM();
> +
> +  CommonClass * cl = JavaObject::getClass(clazz);
> +  assert(cl && cl->isClass());
> +  cl->asClass()->resolveClass();
> +  cl->asClass()->initialiseClass(vm);
> +
> +  END_NATIVE_EXCEPTION;
> +}
> +
> +JNIEXPORT jlong JNICALL Java_sun_misc_Unsafe_staticFieldOffset(
> +JavaObject* unsafe, JavaObjectField* _field) {
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(_field, 0);
> +
> +  jlong res = 0;
> +  BEGIN_NATIVE_EXCEPTION(0)
> +
> +  JavaField * field = JavaObjectField::getInternalField(_field);
> +  assert(field);
> +
> +  res = field->ptrOffset;
> +
> +  END_NATIVE_EXCEPTION;
> +
> +  return res;
> +}
> +
> +JNIEXPORT JavaObject* JNICALL Java_sun_misc_Unsafe_staticFieldBase(
> +JavaObject* unsafe, JavaObjectField* _field) {
> +  JavaObject* res = 0;
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(_field, 0);
> +  llvm_gcroot(res, 0);
> +  BEGIN_NATIVE_EXCEPTION(0)
> +
> +  JavaField * field = JavaObjectField::getInternalField(_field);
> +  assert(field);
> +  field->classDef->initialiseClass(JavaThread::get()->getJVM());
> +
> +  res = VMStaticInstance::allocate(
> +    (JavaObjectClass*)field->classDef->getDelegatee());
> +
> +  END_NATIVE_EXCEPTION;
> +
> +  return res;
> +}
> +
> +JNIEXPORT JavaObject* JNICALL Java_sun_misc_Unsafe_getObjectVolatile(
> +JavaObject* unsafe, JavaObject* base, jlong offset) {
> +  JavaObject * res = 0;
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(base, 0);
> +  llvm_gcroot(res, 0);
> +
> +  BEGIN_NATIVE_EXCEPTION(0)
> +  JavaObject** ptr = (JavaObject**) (baseToPtr(base) + offset);
> +  res = *ptr;
> +  END_NATIVE_EXCEPTION;
> +
> +  return res;
> +}
> +
> +JNIEXPORT jlong JNICALL Java_sun_misc_Unsafe_arrayBaseOffset(
> +JavaObject* unsafe, JavaObject* clazz) {
> +  UNIMPLEMENTED();
> +  return 0;
> +}
> +
> +JNIEXPORT jlong JNICALL Java_sun_misc_Unsafe_arrayIndexScale(
> +#ifdef NATIVE_JNI
> +JNIEnv *env,
> +#endif
> +JavaObject* unsafe, JavaObject* clazz) {
> +  UNIMPLEMENTED();
> +  return 0;
> +}
> +
> +JNIEXPORT JavaObject* JNICALL
>
> Java_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoader_2Ljava_security_ProtectionDomain_2(
> +JavaObject* unsafe, JavaString *name, ArrayObject * bytesArr, jint
> off, jint len, JavaObject * loader, JavaObject * pd) {
> +  JavaObject* res = 0;
> +  llvm_gcroot(res, 0);
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(name, 0);
> +  llvm_gcroot(bytesArr, 0);
> +  llvm_gcroot(loader, 0);
> +  llvm_gcroot(pd, 0);
> +  BEGIN_NATIVE_EXCEPTION(0)
> +
> +  Jnjvm* vm = JavaThread::get()->getJVM();
> +  JnjvmClassLoader* JCL = NULL;
> +  JCL = JnjvmClassLoader::getJnjvmLoaderFromJavaObject(loader, vm);
> +
> +  jint last = off + len;
> +  if (last < bytesArr->size) {
> +    assert(0 && "What exception to throw here?");
> +  }
> +  ClassBytes * bytes = new (JCL->allocator, len) ClassBytes(len);
> +  memcpy(bytes->elements, JavaArray::getElements(bytesArr)+off, len);
> +  const UTF8* utfName = JavaString::javaToInternal(name, JCL->hashUTF8);
> +  UserClass *cl = JCL->constructClass(utfName, bytes);
> +
> +  if (cl) res = (JavaObject*)cl->getClassDelegatee(vm);
> +
> +  END_NATIVE_EXCEPTION;
> +
> +  return res;
> +}
> +
> +JNIEXPORT JavaObject* JNICALL
> Java_sun_misc_Unsafe_allocateInstance__Ljava_lang_Class_2(
> +JavaObject* unsafe, JavaObjectClass * clazz) {
> +  JavaObject* res = 0;
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(clazz, 0);
> +  llvm_gcroot(res, 0);
> +
> +  BEGIN_NATIVE_EXCEPTION(0)
> +
> +  JavaThread* th = JavaThread::get();
> +  Jnjvm* vm = th->getJVM();
> +
> +  UserCommonClass* cl = UserCommonClass::resolvedImplClass(vm, clazz,
> true);
> +  if (cl->isClass())
> +    res = cl->asClass()->doNew(vm);
> +
> +  END_NATIVE_EXCEPTION;
> +
> +  return res;
> +}
> +
> +
> +JNIEXPORT void JNICALL Java_sun_misc_Unsafe_throwException(
> +JavaObject* unsafe, JavaObject * obj) {
> +  llvm_gcroot(unsafe, 0);
> +  llvm_gcroot(obj, 0);
> +
> +  JavaThread::get()->throwException(obj);
> +}
> +
>  JNIEXPORT void JNICALL Java_sun_misc_Unsafe_registerNatives(JavaObject*) {
>   // Nothing
>  }
> @@ -369,7 +560,7 @@ JNIEXPORT jtype JNICALL Java_sun_misc_Unsafe_get
> ## Type ## __Ljava_lang_Object_
>  JavaObject* unsafe, JavaObject* base, jlong offset) { \
>   jtype res = 0; \
>   BEGIN_NATIVE_EXCEPTION(0) \
> -  jtype* ptr = (jtype*) (((uint8 *) base) + offset); \
> +  jtype* ptr = (jtype*) (baseToPtr(base) + offset); \
>   res = *ptr; \
>   END_NATIVE_EXCEPTION \
>  \
> @@ -379,7 +570,7 @@ JavaObject* unsafe, JavaObject* base, jlong offset) { \
>  JNIEXPORT void JNICALL Java_sun_misc_Unsafe_put ## Type ##
> __Ljava_lang_Object_2J ## shorttype( \
>  JavaObject* unsafe, JavaObject* base, jlong offset, jtype val) { \
>   BEGIN_NATIVE_EXCEPTION(0) \
> -  jtype* ptr = (jtype*) (((uint8 *) base) + offset); \
> +  jtype* ptr = (jtype*) (baseToPtr(base) + offset); \
>   *ptr = val; \
>   END_NATIVE_EXCEPTION \
>  }
> diff --git a/lib/J3/ClassLib/VMStaticInstance.h
> b/lib/J3/ClassLib/VMStaticInstance.h
> new file mode 100644
> index 0000000..f2ca906
> --- /dev/null
> +++ b/lib/J3/ClassLib/VMStaticInstance.h
> @@ -0,0 +1,82 @@
> +//===-------- VMStaticInstance.h - Java wrapper for a static
> instance------===//
> +//
> +//                            The VMKit project
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef JNJVM_VMSTATICINSTANCE_H
> +#define JNJVM_VMSTATICINSTANCE_H
> +
> +#include "ClasspathReflect.h"
> +#include "JavaObject.h"
> +#include "MvmGC.h"
> +
> +namespace j3 {
> +
> +/// VMStaticInstance - Used as a placeholder for a staticInstance,
> tracing to
> +/// the corresponding Class to ensure it doesn't get improperly GC'd.
> +/// This placeholder is used solely in getStaticFieldBase and the various
> +/// put/get methods in sun.misc.Unsafe, any other use is invalid.
> +/// Largely inspired by VMClassLoader.
> +///
> +class VMStaticInstance : public JavaObject {
> +private:
> +
> +  /// OwningClass - The Class this is represents a static instance of.
> +  JavaObjectClass * OwningClass;
>

You should use the Class* instead of the JavaObjectClass. This makes it
less brittle for the GC.

+
> +public:
> +
> +  static VMStaticInstance* allocate(JavaObjectClass * Class) {
> +    VMStaticInstance* res = 0;
> +    llvm_gcroot(res, 0);
> +    llvm_gcroot(Class, 0);
> +    res = (VMStaticInstance*)gc::operator new(sizeof(VMStaticInstance),
> &VT);
> +    res->OwningClass = Class;
> +
> +    return res;
> +  }
> +
> +  /// VT - The VirtualTable for this GC-class.
> +  ///
> +  static VirtualTable VT;
> +
> +  /// Is the object a VMStaticInstance object?
> +  ///
> +  static bool isVMStaticInstance(JavaObject* obj) {
> +    llvm_gcroot(obj, 0);
> +    return obj->getVirtualTable() == &VT;
> +  }
> +
> +  /// ~VMStaticInstance - Nothing. Placeholder method
> +  /// to give the VirtualTable.
> +  ///
> +  static void staticDestructor(VMStaticInstance* obj) {
> +    llvm_gcroot(obj, 0);
> +    // Nothing to do here
> +  }
> +
> +  /// staticTracer - Trace through to our Class
> +  ///
> +  static void staticTracer(VMStaticInstance* obj, word_t closure) {
> +    llvm_gcroot(obj, 0);
> +    if (obj->OwningClass != NULL) obj->OwningClass->tracer(closure);
>

That's a bug if it's null. Maybe assert that it's not. Also, by replacing
OwningClass to a Class*, you should do
obj->OwningClass->JCL->tracer(closure);

+  }
> +
> +  /// getStaticInstance - Get the static instance contained in this object
> +  ///
> +  void * getStaticInstance() {
>

Just change it to OwningClass->getStaticInstance();


> +    assert(OwningClass);
> +    UserCommonClass * Cl = JavaObjectClass::getClass(OwningClass);
> +    assert(Cl && Cl->isClass());
> +    return Cl->asClass()->getStaticInstance();
> +  }
> +
> +};
> +
> +}
> +
> +#endif // JNJVM_VMSTATICINSTANCE_H
> diff --git a/lib/J3/Compiler/JavaAOTCompiler.cpp
> b/lib/J3/Compiler/JavaAOTCompiler.cpp
> index d16d57c..1a4d2e4 100644
> --- a/lib/J3/Compiler/JavaAOTCompiler.cpp
> +++ b/lib/J3/Compiler/JavaAOTCompiler.cpp
> @@ -32,6 +32,7 @@
>  #include "JavaUpcalls.h"
>  #include "Jnjvm.h"
>  #include "Reader.h"
> +#include "VMStaticInstance.h"
>  #include "Zip.h"
>
>  #include <cstdio>
> @@ -2545,7 +2546,9 @@ CommonClass*
> JavaAOTCompiler::getUniqueBaseClass(CommonClass* cl) {
>
>   for (; I != E; ++I) {
>     JavaObject* obj = (JavaObject*)(*I);
> -    if (!VMClassLoader::isVMClassLoader(obj) &&
> JavaObject::instanceOf(obj, cl)) {
> +    if (!VMClassLoader::isVMClassLoader(obj) &&
> +        !VMStaticInstance::isVMStaticInstance(obj) &&
> +        JavaObject::instanceOf(obj, cl)) {
>       if (currentClass != NULL) {
>         if (JavaObject::getClass(obj) != currentClass) {
>           return 0;
> diff --git a/lib/J3/Compiler/Makefile b/lib/J3/Compiler/Makefile
> index 58bb2e1..99c46db 100644
> --- a/lib/J3/Compiler/Makefile
> +++ b/lib/J3/Compiler/Makefile
> @@ -14,4 +14,4 @@ MODULE_WITH_GC = J3Compiler
>
>  include $(LEVEL)/Makefile.common
>
> -CXX.Flags += -I$(PROJ_OBJ_DIR)/../LLVMRuntime
> -I$(PROJ_SRC_DIR)/../ClassLib/$(CLASSPATH_DIR)
> -I$(PROJ_SRC_DIR)/../VMCore
> +CXX.Flags += -I$(PROJ_OBJ_DIR)/../LLVMRuntime
> -I$(PROJ_SRC_DIR)/../ClassLib/$(CLASSPATH_DIR)
> -I$(PROJ_SRC_DIR)/../ClassLib/ -I$(PROJ_SRC_DIR)/../VMCore
> diff --git a/lib/J3/VMCore/Jnjvm.cpp b/lib/J3/VMCore/Jnjvm.cpp
> index 4961694..5165b88 100644
> --- a/lib/J3/VMCore/Jnjvm.cpp
> +++ b/lib/J3/VMCore/Jnjvm.cpp
> @@ -35,6 +35,7 @@
>  #include "LockedMap.h"
>  #include "Reader.h"
>  #include "ReferenceQueue.h"
> +#include "VMStaticInstance.h"
>  #include "Zip.h"
>
>  using namespace j3;
> @@ -1394,6 +1395,8 @@ size_t Jnjvm::getObjectSize(gc* object) {
>   JavaObject* src = (JavaObject*)object;
>   if (VMClassLoader::isVMClassLoader(src)) {
>     size = sizeof(VMClassLoader);
> +  } else if (VMStaticInstance::isVMStaticInstance(src)) {
> +    size = sizeof(VMStaticInstance);
>   } else {
>     CommonClass* cl = JavaObject::getClass(src);
>     if (cl->isArray()) {
> @@ -1416,6 +1419,8 @@ const char* Jnjvm::getObjectTypeName(gc* object) {
>   JavaObject* src = (JavaObject*)object;
>   if (VMClassLoader::isVMClassLoader(src)) {
>     return "VMClassLoader";
> +  } else if (VMStaticInstance::isVMStaticInstance(src)) {
> +    return "VMStaticInstance";
>   } else {
>     CommonClass* cl = JavaObject::getClass(src);
>     // This code is only used for debugging on a fatal error. It is fine to
> diff --git a/lib/J3/VMCore/Makefile b/lib/J3/VMCore/Makefile
> index fc07061..987919a 100644
> --- a/lib/J3/VMCore/Makefile
> +++ b/lib/J3/VMCore/Makefile
> @@ -14,4 +14,4 @@ MODULE_WITH_GC = J3
>
>  include $(LEVEL)/Makefile.common
>
> -CXX.Flags += -I$(PROJ_OBJ_DIR)/../ClassLib
> -I$(PROJ_OBJ_DIR)/../LLVMRuntime
> -I$(PROJ_SRC_DIR)/../ClassLib/$(CLASSPATH_DIR)
> -I$(PROJ_SRC_DIR)/../../../include/j3
> +CXX.Flags += -I$(PROJ_OBJ_DIR)/../ClassLib
> -I$(PROJ_OBJ_DIR)/../LLVMRuntime
> -I$(PROJ_SRC_DIR)/../ClassLib/$(CLASSPATH_DIR)
> -I$(PROJ_SRC_DIR)/../../../include/j3 -I$(PROJ_SRC_DIR)/../ClassLib
> diff --git a/lib/J3/VMCore/VirtualTables.cpp
> b/lib/J3/VMCore/VirtualTables.cpp
> index 68774b7..6b3b999 100644
> --- a/lib/J3/VMCore/VirtualTables.cpp
> +++ b/lib/J3/VMCore/VirtualTables.cpp
> @@ -32,6 +32,7 @@
>  #include "JnjvmClassLoader.h"
>  #include "LockedMap.h"
>  #include "ReferenceQueue.h"
> +#include "VMStaticInstance.h"
>  #include "Zip.h"
>
>  using namespace j3;
> @@ -44,7 +45,7 @@ using namespace j3;
>  // Having many GC classes gives more work to the GC for the scanning phase
>  // and for the relocation phase (for copying collectors).
>  //
> -// In J3, there is only one internal gc object, the class loader.
> +// In J3, there is only one primary internal gc object, the class loader.
>  // We decided that this was the best solution because
>  // otherwise it would involve hacks on the java.lang.Classloader class.
>  // Therefore, we create a new GC class with a finalize method that will
> @@ -52,12 +53,20 @@ using namespace j3;
>  // not reachable anymore. This also relies on the java.lang.Classloader
> class
>  // referencing an object of type VMClassLoader (this is the case in GNU
>  // Classpath with the vmdata field).
> +// In addition, to handle support for sun.misc.Unsafe, we have a similar
> +// second clsas VMStaticInstance that wraps static instances for use
> +// in staticFieldBase and traces the owning ClassLoader to make sure
> +// the underlying instance and class don't get GC'd improperly.
>
>  //===----------------------------------------------------------------------===//
>
>  VirtualTable VMClassLoader::VT((word_t)VMClassLoader::staticDestructor,
>                                (word_t)VMClassLoader::staticDestructor,
>                                (word_t)VMClassLoader::staticTracer);
>
> +VirtualTable
> VMStaticInstance::VT((word_t)VMStaticInstance::staticDestructor,
> +
>  (word_t)VMStaticInstance::staticDestructor,
> +                                  (word_t)VMStaticInstance::staticTracer);
> +
>
>  //===----------------------------------------------------------------------===//
>  // Trace methods for Java objects. There are four types of objects:
>  // (1) java.lang.Object and primitive arrays: no need to trace anything.
> --
> 1.7.5.1
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/vmkit-commits/attachments/20111108/0804f968/attachment.html>


More information about the vmkit-commits mailing list