implement sun.misc.Unsafe raw memory access methods

The primitive get/put methods are implemented as intrinsics by the
compiler for performance.
This commit is contained in:
Joel Dice 2012-03-06 13:07:59 -07:00
parent 44277db2de
commit e8e3c9066f
3 changed files with 332 additions and 137 deletions

View File

@ -327,3 +327,177 @@ Avian_avian_Singleton_getLong
(t, reinterpret_cast<object>(arguments[0]), arguments[1]), 8);
return v;
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_allocateMemory
(Thread* t, object, uintptr_t* arguments)
{
void* p = malloc(arguments[1]);
if (p) {
return reinterpret_cast<int64_t>(p);
} else {
throwNew(t, Machine::OutOfMemoryErrorType);
}
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_freeMemory
(Thread*, object, uintptr_t* arguments)
{
void* p = reinterpret_cast<void*>(arguments[1]);
if (p) {
free(p);
}
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_setMemory
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int64_t count; memcpy(&count, arguments + 3, 8);
int8_t v = arguments[5];
memset(reinterpret_cast<int8_t*>(p), v, count);
}
// NB: The following primitive get/put methods are only used by the
// interpreter. The JIT/AOT compiler implements them as intrinsics,
// so these versions will be ignored.
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putByte__JB
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int8_t v = arguments[3];
*reinterpret_cast<int8_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putShort__JS
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int16_t v = arguments[3];
*reinterpret_cast<int16_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putChar__JC
(Thread* t, object method, uintptr_t* arguments)
{
Avian_sun_misc_Unsafe_putShort__JS(t, method, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putInt__JI
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int32_t v = arguments[3];
*reinterpret_cast<int32_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putFloat__JF
(Thread* t, object method, uintptr_t* arguments)
{
Avian_sun_misc_Unsafe_putInt__JI(t, method, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putLong__JJ
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int64_t v; memcpy(&v, arguments + 3, 8);
*reinterpret_cast<int64_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putDouble__JD
(Thread* t, object method, uintptr_t* arguments)
{
Avian_sun_misc_Unsafe_putLong__JJ(t, method, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putAddress__JJ
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int64_t v; memcpy(&v, arguments + 3, 8);
*reinterpret_cast<intptr_t*>(p) = v;
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getByte__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int8_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getShort__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int16_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getChar__J
(Thread* t, object method, uintptr_t* arguments)
{
return Avian_sun_misc_Unsafe_getShort__J(t, method, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getInt__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int32_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getFloat__J
(Thread* t, object method, uintptr_t* arguments)
{
return Avian_sun_misc_Unsafe_getInt__J(t, method, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getLong__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int64_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getDouble__J
(Thread* t, object method, uintptr_t* arguments)
{
return Avian_sun_misc_Unsafe_getLong__J(t, method, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getAddress__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<intptr_t*>(p);
}

View File

@ -2615,115 +2615,6 @@ Avian_sun_misc_Unsafe_compareAndSwapLong
#endif
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_allocateMemory
(Thread* t, object, uintptr_t* arguments)
{
void* p = malloc(arguments[1]);
if (p) {
return reinterpret_cast<int64_t>(p);
} else {
throwNew(t, Machine::OutOfMemoryErrorType);
}
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_freeMemory
(Thread*, object, uintptr_t* arguments)
{
void* p = reinterpret_cast<void*>(arguments[1]);
if (p) {
free(p);
}
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_setMemory
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int64_t count; memcpy(&count, arguments + 3, 8);
int8_t v = arguments[5];
memset(reinterpret_cast<int8_t*>(p), v, count);
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putByte__JB
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int8_t v = arguments[3];
*reinterpret_cast<int8_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putShort__JS
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int16_t v = arguments[3];
*reinterpret_cast<int16_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putLong__JJ
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int64_t v; memcpy(&v, arguments + 3, 8);
*reinterpret_cast<int64_t*>(p) = v;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putInt__JI
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
int32_t v = arguments[3];
*reinterpret_cast<int32_t*>(p) = v;
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getByte__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int8_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getInt__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int32_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getLong__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int64_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getFloat__J
(Thread*, object, uintptr_t* arguments)
{
int64_t p; memcpy(&p, arguments + 1, 8);
return *reinterpret_cast<int32_t*>(p);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_pageSize
(Thread*, object, uintptr_t*)

View File

@ -3809,6 +3809,13 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
return true;
}
Compiler::Operand*
popLongAddress(Frame* frame)
{
return TargetBytesPerWord == 8 ? frame->popLong() : frame->c->load
(8, 8, frame->popLong(), TargetBytesPerWord);
}
bool
intrinsic(MyThread* t, Frame* frame, object target)
{
@ -3837,6 +3844,127 @@ intrinsic(MyThread* t, Frame* frame, object target)
return true;
}
}
} else if (UNLIKELY(MATCH(className, "sun/misc/Unsafe"))) {
Compiler* c = frame->c;
if (MATCH(methodName(t, target), "getByte")
and MATCH(methodSpec(t, target), "(J)B"))
{
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
frame->pushInt
(c->load
(1, 1, c->memory(address, Compiler::IntegerType, 0, 0, 1),
TargetBytesPerWord));
return true;
} else if (MATCH(methodName(t, target), "putByte")
and MATCH(methodSpec(t, target), "(JB)V"))
{
Compiler::Operand* value = frame->popInt();
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
c->store
(TargetBytesPerWord, value, 1, c->memory
(address, Compiler::IntegerType, 0, 0, 1));
return true;
} else if ((MATCH(methodName(t, target), "getShort")
and MATCH(methodSpec(t, target), "(J)S"))
or (MATCH(methodName(t, target), "getChar")
and MATCH(methodSpec(t, target), "(J)C")))
{
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
frame->pushInt
(c->load
(2, 2, c->memory(address, Compiler::IntegerType, 0, 0, 1),
TargetBytesPerWord));
return true;
} else if ((MATCH(methodName(t, target), "putShort")
and MATCH(methodSpec(t, target), "(JS)V"))
or (MATCH(methodName(t, target), "putChar")
and MATCH(methodSpec(t, target), "(JC)V")))
{
Compiler::Operand* value = frame->popInt();
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
c->store
(TargetBytesPerWord, value, 2, c->memory
(address, Compiler::IntegerType, 0, 0, 1));
return true;
} else if ((MATCH(methodName(t, target), "getInt")
and MATCH(methodSpec(t, target), "(J)I"))
or (MATCH(methodName(t, target), "getFloat")
and MATCH(methodSpec(t, target), "(J)F")))
{
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
frame->pushInt
(c->load
(4, 4, c->memory
(address, MATCH(methodName(t, target), "getInt")
? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1),
TargetBytesPerWord));
return true;
} else if ((MATCH(methodName(t, target), "putInt")
and MATCH(methodSpec(t, target), "(JI)V"))
or (MATCH(methodName(t, target), "putFloat")
and MATCH(methodSpec(t, target), "(JF)V")))
{
Compiler::Operand* value = frame->popInt();
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
c->store
(TargetBytesPerWord, value, 4, c->memory
(address, MATCH(methodName(t, target), "putInt")
? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1));
return true;
} else if ((MATCH(methodName(t, target), "getLong")
and MATCH(methodSpec(t, target), "(J)J"))
or (MATCH(methodName(t, target), "getDouble")
and MATCH(methodSpec(t, target), "(J)D")))
{
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
frame->pushLong
(c->load
(8, 8, c->memory
(address, MATCH(methodName(t, target), "getLong")
? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1),
8));
return true;
} else if ((MATCH(methodName(t, target), "putLong")
and MATCH(methodSpec(t, target), "(JJ)V"))
or (MATCH(methodName(t, target), "putDouble")
and MATCH(methodSpec(t, target), "(JD)V")))
{
Compiler::Operand* value = frame->popLong();
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
c->store
(8, value, 8, c->memory
(address, MATCH(methodName(t, target), "putLong")
? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1));
return true;
} else if (MATCH(methodName(t, target), "getAddress")
and MATCH(methodSpec(t, target), "(J)J"))
{
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
frame->pushLong
(c->load
(TargetBytesPerWord, TargetBytesPerWord,
c->memory(address, Compiler::AddressType, 0, 0, 1), 8));
return true;
} else if (MATCH(methodName(t, target), "putAddress")
and MATCH(methodSpec(t, target), "(JJ)V"))
{
Compiler::Operand* value = frame->popLong();
Compiler::Operand* address = popLongAddress(frame);
frame->popObject();
c->store
(8, value, TargetBytesPerWord, c->memory
(address, Compiler::AddressType, 0, 0, 1));
return true;
}
}
return false;
}
@ -5022,43 +5150,45 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
if (LIKELY(target)) {
assert(t, (methodFlags(t, target) & ACC_STATIC) == 0);
if (not intrinsic(t, frame, target)) {
bool tailCall = isTailCall(t, code, ip, context->method, target);
bool tailCall = isTailCall(t, code, ip, context->method, target);
if (LIKELY(methodVirtual(t, target))) {
unsigned parameterFootprint = methodParameterFootprint(t, target);
if (LIKELY(methodVirtual(t, target))) {
unsigned parameterFootprint = methodParameterFootprint(t, target);
unsigned offset = TargetClassVtable
+ (methodOffset(t, target) * TargetBytesPerWord);
unsigned offset = TargetClassVtable
+ (methodOffset(t, target) * TargetBytesPerWord);
Compiler::Operand* instance = c->peek(1, parameterFootprint - 1);
Compiler::Operand* instance = c->peek(1, parameterFootprint - 1);
unsigned rSize = resultSize(t, methodReturnCode(t, target));
unsigned rSize = resultSize(t, methodReturnCode(t, target));
Compiler::Operand* result = c->stackCall
(c->memory
(c->and_
(TargetBytesPerWord, c->constant
(TargetPointerMask, Compiler::IntegerType),
c->memory(instance, Compiler::ObjectType, 0, 0, 1)),
Compiler::ObjectType, offset, 0, 1),
tailCall ? Compiler::TailJump : 0,
frame->trace(0, 0),
rSize,
operandTypeForFieldCode(t, methodReturnCode(t, target)),
parameterFootprint);
Compiler::Operand* result = c->stackCall
(c->memory
(c->and_
(TargetBytesPerWord, c->constant
(TargetPointerMask, Compiler::IntegerType),
c->memory(instance, Compiler::ObjectType, 0, 0, 1)),
Compiler::ObjectType, offset, 0, 1),
tailCall ? Compiler::TailJump : 0,
frame->trace(0, 0),
rSize,
operandTypeForFieldCode(t, methodReturnCode(t, target)),
parameterFootprint);
frame->pop(parameterFootprint);
frame->pop(parameterFootprint);
if (rSize) {
pushReturnValue(t, frame, methodReturnCode(t, target), result);
}
} else {
// OpenJDK generates invokevirtual calls to private methods
// (e.g. readObject and writeObject for serialization), so
// we must handle such cases here.
if (rSize) {
pushReturnValue(t, frame, methodReturnCode(t, target), result);
compileDirectInvoke(t, frame, target, tailCall);
}
} else {
// OpenJDK generates invokevirtual calls to private methods
// (e.g. readObject and writeObject for serialization), so
// we must handle such cases here.
compileDirectInvoke(t, frame, target, tailCall);
}
} else {
PROTECT(t, reference);