[vmkit-commits] [vmkit] r198210 - First version of stack locking algorithm. Inflation is not yet tested.

Gael Thomas gael.thomas at lip6.fr
Mon Dec 30 03:34:19 PST 2013


Author: gthomas
Date: Mon Dec 30 05:34:18 2013
New Revision: 198210

URL: http://llvm.org/viewvc/llvm-project?rev=198210&view=rev
Log:
First version of stack locking algorithm. Inflation is not yet tested.

Modified:
    vmkit/branches/mcjit/include/j3/j3.h
    vmkit/branches/mcjit/include/j3/j3codegen.h
    vmkit/branches/mcjit/include/j3/j3meta.def
    vmkit/branches/mcjit/include/j3/j3monitor.h
    vmkit/branches/mcjit/include/j3/j3object.h
    vmkit/branches/mcjit/include/j3/j3thread.h
    vmkit/branches/mcjit/lib/j3/vm/j3.cc
    vmkit/branches/mcjit/lib/j3/vm/j3codegen.cc
    vmkit/branches/mcjit/lib/j3/vm/j3object.cc

Modified: vmkit/branches/mcjit/include/j3/j3.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/include/j3/j3.h?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/include/j3/j3.h (original)
+++ vmkit/branches/mcjit/include/j3/j3.h Mon Dec 30 05:34:18 2013
@@ -92,6 +92,7 @@ namespace j3 {
 		llvm::Type* typeJ3Object;
 		llvm::Type* typeJ3ObjectPtr;
 		llvm::Type* typeJ3ObjectHandlePtr;
+		llvm::Type* typeJ3LockRecord;
 		llvm::Type* typeGXXException;
 
 		J3Options*                 options() { return &_options; }

Modified: vmkit/branches/mcjit/include/j3/j3codegen.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/include/j3/j3codegen.h?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/include/j3/j3codegen.h (original)
+++ vmkit/branches/mcjit/include/j3/j3codegen.h Mon Dec 30 05:34:18 2013
@@ -81,6 +81,7 @@ namespace j3 {
 		uint32_t           wideReadU1();
 		uint32_t           wideReadS1();
 
+		llvm::Value*       spToCurrentThread(llvm::Value* sp);
 		llvm::Value*       currentThread();
 
 		llvm::Value*       nullCheck(llvm::Value* obj);
@@ -100,6 +101,9 @@ namespace j3 {
 		llvm::Value*       vt(llvm::Value* obj);
 		void               initialiseJ3Type(J3Type* cl);
 
+		void               monitorEnter(llvm::Value* obj);
+		void               monitorExit(llvm::Value* obj);
+
 		llvm::Value*       isAssignableTo(llvm::Value* obj, J3Type* type);
 		void               instanceof(llvm::Value* obj, J3Type* type);
 		void               checkCast(llvm::Value* obj, J3Type* type);

Modified: vmkit/branches/mcjit/include/j3/j3meta.def
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/include/j3/j3meta.def?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/include/j3/j3meta.def (original)
+++ vmkit/branches/mcjit/include/j3/j3meta.def Mon Dec 30 05:34:18 2013
@@ -8,6 +8,8 @@ _x(funcJ3ClassStringAt,          "j3::J3
 _x(funcJ3ObjectTypeJavaClass,    "j3::J3ObjectType::javaClass()")
 _x(funcJniEnv,                   "j3::J3::jniEnv()")
 _x(funcJ3ObjectAllocate,         "j3::J3Object::allocate(j3::J3VirtualTable*, unsigned long)")
+_x(funcJ3ObjectMonitorEnter,     "j3::J3Object::monitorEnter(j3::J3Object*)")
+_x(funcJ3ObjectMonitorExit,      "j3::J3Object::monitorExit(j3::J3Object*)")
 _x(funcThrowException,           "vmkit::VMKit::throwException(void*)")
 _x(funcClassCastException,       "j3::J3::classCastException()")
 _x(funcNullPointerException,     "j3::J3::nullPointerException()")

Modified: vmkit/branches/mcjit/include/j3/j3monitor.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/include/j3/j3monitor.h?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/include/j3/j3monitor.h (original)
+++ vmkit/branches/mcjit/include/j3/j3monitor.h Mon Dec 30 05:34:18 2013
@@ -12,6 +12,15 @@ namespace j3 {
 	class J3Thread;
 	class J3Object;
 
+	class J3LockRecord {
+	public:
+		static const uint32_t gepHeader = 0;
+		static const uint32_t gepLockCount = 1;
+
+		uintptr_t header;
+		uint32_t  lockCount;
+	};
+
 	class J3Monitor {
 		friend class J3MonitorManager;
 

Modified: vmkit/branches/mcjit/include/j3/j3object.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/include/j3/j3object.h?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/include/j3/j3object.h (original)
+++ vmkit/branches/mcjit/include/j3/j3object.h Mon Dec 30 05:34:18 2013
@@ -92,15 +92,18 @@ namespace j3 {
 		J3VirtualTable* _vt;
 		uintptr_t       _header;
 		/* 
-		 *     biased (not yet implemented):  0         | epoch | age        | 101
-		 *                                    thread_id | epoch | age        | 101
-		 *     not locked:                    hash-code 24 bits | age 5 bits | 001
-		 *     stack locked:                      pointer to lock record      | 00
-		 *     inflated:                          pointer to monitor          | 01
+		 *     biasable (not yet implemented):  0         | epoch | age        | 101
+		 *     biased (not yet implemented):    thread_id | epoch | age        | 101
+		 *     not locked:                      hash-code 24 bits | age 5 bits | 001
+		 *     stack locked:                        pointer to lock record      | 00
+		 *     inflated:                            pointer to monitor          | 10
 		 */
 
 		J3Object(); /* never directly allocate an object */
 
+		static void monitorEnter(J3Object* obj);
+		static void monitorExit(J3Object* obj);
+
 		static J3Object* allocate(J3VirtualTable* vt, size_t n);
 		static J3Object* doNewNoInit(J3Class* cl);
 		static J3Object* doNew(J3Class* cl);

Modified: vmkit/branches/mcjit/include/j3/j3thread.h
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/include/j3/j3thread.h?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/include/j3/j3thread.h (original)
+++ vmkit/branches/mcjit/include/j3/j3thread.h Mon Dec 30 05:34:18 2013
@@ -15,12 +15,11 @@ namespace j3 {
 
 	class J3Thread : public vmkit::Thread {
 		friend class J3Monitor;
+		friend class J3CodeGen;
 
-	public:
 		static const uint32_t gepInterfaceMethodIndex = 1;
+		uint32_t              _interfaceMethodIndex;
 
-	private:
-		uint32_t                   _interfaceMethodIndex;
 		vmkit::BumpAllocator*      _allocator;
 		JNIEnv                     _jniEnv;
 		J3LocalReferences          _localReferences;

Modified: vmkit/branches/mcjit/lib/j3/vm/j3.cc
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/lib/j3/vm/j3.cc?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/lib/j3/vm/j3.cc (original)
+++ vmkit/branches/mcjit/lib/j3/vm/j3.cc Mon Dec 30 05:34:18 2013
@@ -58,6 +58,7 @@ void J3::introspect() {
 	typeJ3Object            = introspectType("class.j3::J3Object");
 	typeJ3ObjectPtr         = llvm::PointerType::getUnqual(typeJ3Object);
 	typeJ3ObjectHandlePtr   = llvm::PointerType::getUnqual(introspectType("class.j3::J3ObjectHandle"));
+	typeJ3LockRecord        = introspectType("class.j3::J3LockRecord");
 
 	typeGXXException        = llvm::StructType::get(llvm::Type::getInt8Ty(llvmContext())->getPointerTo(), 
 																									llvm::Type::getInt32Ty(llvmContext()), NULL);
@@ -229,6 +230,7 @@ void J3::printStackTrace() {
 
 void J3::forceSymbolDefinition() {
 	J3ArrayObject a; a.length(); /* J3ArrayObject */
+	J3LockRecord* l = new J3LockRecord(); /* J3LockRecord */
 	try {
 		throw (void*)0;
 	} catch(void* e) {

Modified: vmkit/branches/mcjit/lib/j3/vm/j3codegen.cc
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/lib/j3/vm/j3codegen.cc?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/lib/j3/vm/j3codegen.cc (original)
+++ vmkit/branches/mcjit/lib/j3/vm/j3codegen.cc Mon Dec 30 05:34:18 2013
@@ -158,15 +158,116 @@ llvm::Value* J3CodeGen::unflatten(llvm::
 	}
 }
 
-llvm::Value* J3CodeGen::currentThread() {
-	llvm::Type* type = vm->dataLayout()->getIntPtrType(module()->getContext());
+llvm::Value* J3CodeGen::spToCurrentThread(llvm::Value* sp) {
+	llvm::Type* type = builder->getIntPtrTy(vm->dataLayout());
 
-	return builder->CreateIntToPtr(builder->CreateAnd(builder->CreatePtrToInt(builder->CreateCall(frameAddress, builder->getInt32(0)),
-																																						type),
+	return builder->CreateIntToPtr(builder->CreateAnd(builder->CreatePtrToInt(sp, type),
 																										llvm::ConstantInt::get(type, vmkit::Thread::getThreadMask())),
 																 vm->typeJ3Thread);
 }
 
+llvm::Value* J3CodeGen::currentThread() {
+	return spToCurrentThread(builder->CreateCall(frameAddress, builder->getInt32(0)));
+}
+
+void J3CodeGen::monitorEnter(llvm::Value* obj) {
+	llvm::Type* uintPtrTy = builder->getIntPtrTy(vm->dataLayout());
+	llvm::Type* recordTy = vm->typeJ3LockRecord;
+	llvm::Type* recordPtrTy = vm->typeJ3LockRecord->getPointerTo();
+
+	llvm::AllocaInst* recordPtr = builder->CreateAlloca(recordPtrTy);
+
+	llvm::BasicBlock* ok = forwardBranch("lock-ok", codeReader->tell(), 0, 0);
+	llvm::BasicBlock* stackLocked = newBB("stack-locked");
+	llvm::BasicBlock* tryStackLock = newBB("try-stack-lock");
+	llvm::BasicBlock* stackFail = newBB("stack-lock-fail");
+
+	/* already stack locked by myself? */
+	llvm::Value* gepH[] = { builder->getInt32(0), builder->getInt32(J3Object::gepHeader) };
+	llvm::Value* headerPtr = builder->CreateGEP(obj, gepH);
+	llvm::Value* header = builder->CreateLoad(headerPtr);
+	
+	builder->CreateStore(builder->CreateIntToPtr(header, recordPtrTy), recordPtr);
+	builder->CreateCondBr(builder->CreateICmpEQ(currentThread(), spToCurrentThread(header)),
+												stackLocked, tryStackLock);
+
+	/* try to stack lock */
+	builder->SetInsertPoint(tryStackLock);
+	llvm::AllocaInst* record = builder->CreateAlloca(recordTy);
+	builder->CreateStore(record, recordPtr);
+	llvm::Value* gepR[] = { builder->getInt32(0), builder->getInt32(J3LockRecord::gepHeader) };
+	builder->CreateStore(header, builder->CreateGEP(record, gepR));
+	llvm::Value* orig = builder->CreateOr(builder->CreateAnd(header, llvm::ConstantInt::get(uintPtrTy, ~6)), 
+																				llvm::ConstantInt::get(uintPtrTy, 1)); /* ...001 */
+	llvm::Value* res = builder->CreateAtomicCmpXchg(headerPtr, 
+																									orig, 
+																									builder->CreatePtrToInt(record, uintPtrTy),
+																									llvm::SequentiallyConsistent, 
+																									llvm::CrossThread);
+	builder->CreateCondBr(builder->CreateICmpEQ(res, orig), stackLocked, stackFail);
+
+	/* stack locked, increment the counter */
+	builder->SetInsertPoint(stackLocked);
+	llvm::Value* gepC[] = { builder->getInt32(0), builder->getInt32(J3LockRecord::gepLockCount) };
+	llvm::Value* countPtr = builder->CreateGEP(builder->CreateLoad(recordPtr), gepC);
+	builder->CreateStore(builder->CreateAdd(builder->CreateLoad(countPtr), builder->getInt32(1)), countPtr);
+	builder->CreateBr(ok);
+
+	/* unable to stack lock, fall back to monitor */
+	builder->SetInsertPoint(stackFail);
+	builder->CreateCall(funcJ3ObjectMonitorEnter, obj);
+	builder->CreateBr(ok);
+}
+
+void J3CodeGen::monitorExit(llvm::Value* obj) {
+	llvm::Type* uintPtrTy = builder->getIntPtrTy(vm->dataLayout());
+	llvm::Type* recordPtrTy = vm->typeJ3LockRecord->getPointerTo();
+
+	llvm::BasicBlock* ok = forwardBranch("unlock-ok", codeReader->tell(), 0, 0);
+	llvm::BasicBlock* stackUnlock = newBB("stack-unlock");
+	//llvm::BasicBlock* tryStackLock = newBB("try-stack-lock");
+	llvm::BasicBlock* monitorUnlock = newBB("monitor-unlock");
+	llvm::BasicBlock* stackRelease = newBB("stack-release");
+	llvm::BasicBlock* stackRec = newBB("stack-rec");
+
+	/* stack locked by myself? */
+	llvm::Value* gepH[] = { builder->getInt32(0), builder->getInt32(J3Object::gepHeader) };
+	llvm::Value* headerPtr = builder->CreateGEP(obj, gepH);
+	llvm::Value* header = builder->CreateLoad(headerPtr);
+	
+	builder->CreateCondBr(builder->CreateICmpEQ(currentThread(), spToCurrentThread(header)),
+												stackUnlock, monitorUnlock);
+	
+	/* ok, I'm the owner */
+	builder->SetInsertPoint(stackUnlock);
+	llvm::Value* gepC[] = { builder->getInt32(0), builder->getInt32(J3LockRecord::gepLockCount) };
+	llvm::Value* recordPtr = builder->CreateIntToPtr(header, recordPtrTy);
+	llvm::Value* countPtr = builder->CreateGEP(recordPtr, gepC);
+	llvm::Value* count = builder->CreateSub(builder->CreateLoad(countPtr), builder->getInt32(1));
+	builder->CreateCondBr(builder->CreateICmpEQ(count, builder->getInt32(0)), stackRelease, stackRec);
+
+	/* last unlock */
+	builder->SetInsertPoint(stackRelease);
+	llvm::Value* gepR[] = { builder->getInt32(0), builder->getInt32(J3LockRecord::gepHeader) };
+	llvm::Value* orig = builder->CreateLoad(builder->CreateGEP(recordPtr, gepR));
+	llvm::Value* res = builder->CreateAtomicCmpXchg(headerPtr, 
+																									header, 
+																									orig,
+																									llvm::SequentiallyConsistent, 
+																									llvm::CrossThread);
+	builder->CreateCondBr(builder->CreateICmpEQ(res, header), ok, monitorUnlock);
+
+	/* recursive unlock */
+	builder->SetInsertPoint(stackRec);
+	builder->CreateStore(count, countPtr);
+	builder->CreateBr(ok);
+
+	/* monitor unlock */
+	builder->SetInsertPoint(monitorUnlock);
+	builder->CreateCall(funcJ3ObjectMonitorExit, obj);
+	builder->CreateBr(ok);
+}
+
 void J3CodeGen::initialiseJ3Type(J3Type* cl) {
 	if(!cl->isInitialised())
 		builder->CreateCall(funcJ3TypeInitialise, builder->CreateBitCast(cl->llvmDescriptor(module()), vm->typeJ3TypePtr));
@@ -1320,11 +1421,11 @@ void J3CodeGen::translate() {
 				break;
 
 			case J3Cst::BC_monitorenter:                  /* 0xc2 */
-				stack.pop();
+				monitorEnter(stack.pop());
 				break;
 
 			case J3Cst::BC_monitorexit:                   /* 0xc3 */
-				stack.pop();
+				monitorExit(stack.pop());
 				break;
 
 			case J3Cst::BC_wide: nyi();                   /* 0xc4 */
@@ -1386,7 +1487,7 @@ void J3CodeGen::generateJava() {
 		J3::classFormatError(cl, L"Code attribute of %ls %ls is too large (%d)", method->name()->cStr(), method->sign()->cStr(), length);
 
 	nullValue = builder
-		->CreateIntToPtr(llvm::ConstantInt::get(vm->dataLayout()->getIntPtrType(module()->getContext()), (uintptr_t)0),
+		->CreateIntToPtr(llvm::ConstantInt::get(builder->getIntPtrTy(vm->dataLayout()), (uintptr_t)0),
 										 vm->typeJ3ObjectPtr);
 
 	llvm::DIBuilder* dbgBuilder = new llvm::DIBuilder(*module());

Modified: vmkit/branches/mcjit/lib/j3/vm/j3object.cc
URL: http://llvm.org/viewvc/llvm-project/vmkit/branches/mcjit/lib/j3/vm/j3object.cc?rev=198210&r1=198209&r2=198210&view=diff
==============================================================================
--- vmkit/branches/mcjit/lib/j3/vm/j3object.cc (original)
+++ vmkit/branches/mcjit/lib/j3/vm/j3object.cc Mon Dec 30 05:34:18 2013
@@ -274,6 +274,7 @@ uintptr_t* J3Object::header() {
 J3Object* J3Object::allocate(J3VirtualTable* vt, size_t n) {
 	J3Object* res = (J3Object*)vmkit::GC::allocate(n);
 	res->_vt = vt;
+	res->_header = 1;
 	return res;
 }
 
@@ -286,6 +287,14 @@ J3Object* J3Object::doNew(J3Class* cl) {
 	return doNewNoInit(cl);
 }
 
+void J3Object::monitorEnter(J3Object* obj) {
+	J3::internalError(L"implement me: monitorenter");
+}
+
+void J3Object::monitorExit(J3Object* obj) {
+	J3::internalError(L"implement me: monitorexit");
+}
+
 /*
  *    ---   J3ArrayObject ---
  */





More information about the vmkit-commits mailing list