[vmkit-commits] [PATCH] Implement a number of Java.sun.misc.Unsafe.* methods.
Will Dietz
wdietz2 at illinois.edu
Sun Nov 6 18:50:01 PST 2011
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;
+
+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);
+ }
+
+ /// getStaticInstance - Get the static instance contained in this object
+ ///
+ void * 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
More information about the vmkit-commits
mailing list