diff options
author | jfrijters <jfrijters> | 2014-11-14 18:28:34 +0300 |
---|---|---|
committer | jfrijters <jfrijters> | 2014-11-14 18:28:34 +0300 |
commit | dba88a3d8e1231a0abfd3cf4761d2f1aab174d1f (patch) | |
tree | 6fa9a67ee1fe4515b78b3608c37ee4c656678d6c | |
parent | 38d12d653450c3e8b80d3972a3f9d154b7ff47dd (diff) |
Added intrinsic for array version of Unsafe.getAndSetObject().
-rw-r--r-- | runtime/intrinsics.cs | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/runtime/intrinsics.cs b/runtime/intrinsics.cs index 402969d7..319c0d4b 100644 --- a/runtime/intrinsics.cs +++ b/runtime/intrinsics.cs @@ -209,6 +209,7 @@ namespace IKVM.Internal intrinsics.Add(new IntrinsicKey("sun.misc.Unsafe", "getObjectVolatile", "(Ljava.lang.Object;J)Ljava.lang.Object;"), Unsafe_getObjectVolatile); intrinsics.Add(new IntrinsicKey("sun.misc.Unsafe", "getObject", "(Ljava.lang.Object;J)Ljava.lang.Object;"), Unsafe_getObjectVolatile); intrinsics.Add(new IntrinsicKey("sun.misc.Unsafe", "compareAndSwapObject", "(Ljava.lang.Object;JLjava.lang.Object;Ljava.lang.Object;)Z"), Unsafe_compareAndSwapObject); + intrinsics.Add(new IntrinsicKey("sun.misc.Unsafe", "getAndSetObject", "(Ljava.lang.Object;JLjava.lang.Object;)Ljava.lang.Object;"), Unsafe_getAndSetObject); return intrinsics; } @@ -536,7 +537,16 @@ namespace IKVM.Internal mw.EmitCallvirt(eic.Emitter); return true; } - else if (!DynamicTypeWrapper.RequiresDynamicReflectionCallerClass(eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature)) + else if (DynamicTypeWrapper.RequiresDynamicReflectionCallerClass(eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature)) + { + // since the non-intrinsic version of Reflection.getCallerClass() always throws an exception, we have to redirect to the dynamic version + MethodWrapper getCallerClass = ClassLoaderWrapper.LoadClassCritical("sun.reflect.Reflection").GetMethodWrapper("getCallerClass", "(I)Ljava.lang.Class;", false); + getCallerClass.Link(); + eic.Emitter.EmitLdc_I4(2); + getCallerClass.EmitCall(eic.Emitter); + return true; + } + else { StaticCompiler.IssueMessage(Message.ReflectionCallerClassRequiresCallerID, eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature); } @@ -857,6 +867,49 @@ namespace IKVM.Internal return false; } + private static bool Unsafe_getAndSetObject(EmitIntrinsicContext eic) + { + TypeWrapper tw = eic.GetStackTypeWrapper(0, 2); + if (IsSupportedArrayTypeForUnsafeOperation(tw) + && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(tw.ElementTypeWrapper)) + { + Type type = tw.TypeAsLocalOrStackType.GetElementType(); + CodeEmitterLocal newValue = eic.Emitter.AllocTempLocal(type); + CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); + CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); + eic.Emitter.Emit(OpCodes.Stloc, newValue); + eic.Emitter.Emit(OpCodes.Conv_Ovf_I4); + eic.Emitter.Emit(OpCodes.Stloc, index); + eic.Emitter.Emit(OpCodes.Stloc, obj); + EmitConsumeUnsafe(eic); + eic.Emitter.Emit(OpCodes.Ldloc, obj); + eic.Emitter.Emit(OpCodes.Ldloc, index); + eic.Emitter.Emit(OpCodes.Ldelema, type); + eic.Emitter.Emit(OpCodes.Ldloc, newValue); + eic.Emitter.Emit(OpCodes.Call, MakeExchange(type)); + eic.Emitter.ReleaseTempLocal(obj); + eic.Emitter.ReleaseTempLocal(index); + eic.Emitter.ReleaseTempLocal(newValue); + eic.NonLeaf = false; + return true; + } + return false; + } + + internal static MethodInfo MakeExchange(Type type) + { + MethodInfo interlockedExchange = null; + foreach (MethodInfo m in JVM.Import(typeof(System.Threading.Interlocked)).GetMethods()) + { + if (m.Name == "Exchange" && m.IsGenericMethodDefinition) + { + interlockedExchange = m; + break; + } + } + return interlockedExchange.MakeGenericMethod(type); + } + private static void EmitConsumeUnsafe(EmitIntrinsicContext eic) { #if STATIC_COMPILER |