private static bool ThreadLocal_new(EmitIntrinsicContext eic) { // it is only valid to replace a ThreadLocal instantiation by our ThreadStatic based version, if we can prove that the instantiation only happens once // (which is the case when we're in <clinit> and there aren't any branches that lead to the current position) if (eic.Caller.Name != StringConstants.CLINIT) { return(false); } #if CLASSGC if (JVM.classUnloading) { // RunAndCollect assemblies do not support ThreadStaticAttribute return(false); } #endif for (int i = 0; i <= eic.OpcodeIndex; i++) { if ((eic.Flags[i] & InstructionFlags.BranchTarget) != 0) { return(false); } } eic.Emitter.Emit(OpCodes.Newobj, DefineThreadLocalType(eic.Context, eic.OpcodeIndex, eic.Caller)); return(true); }
private static bool Reflection_getCallerClass(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.EmitLdarg(arg); MethodWrapper mw; if (MatchInvokeStatic(eic, 1, "java.lang.ClassLoader", "getClassLoader", "(Ljava.lang.Class;)Ljava.lang.ClassLoader;")) { eic.PatchOpCode(1, NormalizedByteCode.__nop); mw = [email protected]("getCallerClassLoader", "()Ljava.lang.ClassLoader;", false); } else { mw = [email protected]("getCallerClass", "()Ljava.lang.Class;", false); } mw.Link(); mw.EmitCallvirt(eic.Emitter); return(true); } else if (!DynamicTypeWrapper.RequiresDynamicReflectionCallerClass(eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature)) { StaticCompiler.IssueMessage(Message.ReflectionCallerClassRequiresCallerID, eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature); } return(false); }
private static bool Unsafe_getObjectVolatile(EmitIntrinsicContext eic) { // the check here must be kept in sync with the hack in MethodAnalyzer.AnalyzeTypeFlow() TypeWrapper tw = eic.GetStackTypeWrapper(0, 1); if (IsSupportedArrayTypeForUnsafeOperation(tw)) { CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); 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.ReleaseTempLocal(obj); eic.Emitter.ReleaseTempLocal(index); eic.Emitter.Emit(OpCodes.Ldelema, tw.TypeAsLocalOrStackType.GetElementType()); eic.Emitter.Emit(OpCodes.Volatile); eic.Emitter.Emit(OpCodes.Ldind_Ref); // remove the redundant checkcast that usually follows if (eic.Code[eic.OpcodeIndex + 1].NormalizedOpCode == NormalizedByteCode.__checkcast && tw.ElementTypeWrapper.IsAssignableTo(eic.ClassFile.GetConstantPoolClassType(eic.Code[eic.OpcodeIndex + 1].Arg1))) { eic.PatchOpCode(1, NormalizedByteCode.__nop); } eic.NonLeaf = false; return(true); } return(false); }
private static bool Object_getClass(EmitIntrinsicContext eic) { // this is the null-check idiom that javac uses (both in its own source and in the code it generates) if (eic.MatchRange(0, 2) && eic.Match(1, NormalizedByteCode.__pop)) { eic.Emitter.Emit(OpCodes.Dup); eic.Emitter.EmitNullCheck(); return(true); } // this optimizes obj1.getClass() ==/!= obj2.getClass() else if (eic.MatchRange(0, 4) && eic.Match(1, NormalizedByteCode.__aload) && eic.Match(2, NormalizedByteCode.__invokevirtual) && (eic.Match(3, NormalizedByteCode.__if_acmpeq) || eic.Match(3, NormalizedByteCode.__if_acmpne)) && (IsSafeForGetClassOptimization(eic.GetStackTypeWrapper(0, 0)) || IsSafeForGetClassOptimization(eic.GetStackTypeWrapper(2, 0)))) { ClassFile.ConstantPoolItemMI cpi = eic.GetMethodref(2); if (cpi.Class == "java.lang.Object" && cpi.Name == "getClass" && cpi.Signature == "()Ljava.lang.Class;") { // we can't patch the current opcode, so we have to emit the first call to GetTypeHandle here eic.Emitter.Emit(OpCodes.Callvirt, Compiler.getTypeMethod); eic.PatchOpCode(2, NormalizedByteCode.__intrinsic_gettype); return(true); } } return(false); }
private static bool System_arraycopy(EmitIntrinsicContext eic) { // if the array arguments on the stack are of a known array type, we can redirect to an optimized version of arraycopy. // Note that we also have to handle VMSystem.arraycopy, because on GNU Classpath StringBuffer directly calls // this method to avoid prematurely initialising System. TypeWrapper dst_type = eic.GetStackTypeWrapper(0, 2); TypeWrapper src_type = eic.GetStackTypeWrapper(0, 4); if (!dst_type.IsUnloadable && dst_type.IsArray && dst_type == src_type) { switch (dst_type.Name[1]) { case 'J': case 'D': eic.Emitter.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_8); break; case 'I': case 'F': eic.Emitter.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_4); break; case 'S': case 'C': eic.Emitter.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_2); break; case 'B': case 'Z': eic.Emitter.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_primitive_1); break; default: // TODO once the verifier tracks actual types (i.e. it knows that // a particular reference is the result of a "new" opcode) we can // use the fast version if the exact destination type is known // (in that case the "dst_type == src_type" above should // be changed to "src_type.IsAssignableTo(dst_type)". TypeWrapper elemtw = dst_type.ElementTypeWrapper; // note that IsFinal returns true for array types, so we have to be careful! if (!elemtw.IsArray && elemtw.IsFinal) { eic.Emitter.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy_fast); } else { eic.Emitter.Emit(OpCodes.Call, ByteCodeHelperMethods.arraycopy); } break; } return(true); } else { return(false); } }
private static bool Class_getPrimitiveClass(EmitIntrinsicContext eic) { eic.Emitter.Emit(OpCodes.Pop); eic.Emitter.Emit(OpCodes.Ldnull); MethodWrapper mw = CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("<init>", "(Lcli.System.Type;)V", false); mw.Link(); mw.EmitNewobj(eic.Emitter); return(true); }
private static bool MatchInvokeVirtual(EmitIntrinsicContext eic, ref Instruction instr, string clazz, string name, string sig) { if (instr.NormalizedOpCode == NormalizedByteCode.__invokevirtual) { ClassFile.ConstantPoolItemMI method = eic.ClassFile.GetMethodref(instr.Arg1); return(method.Class == clazz && method.Name == name && method.Signature == sig); } return(false); }
private static bool Class_desiredAssertionStatus(EmitIntrinsicContext eic) { if (eic.MatchRange(-1, 2) && eic.Match(-1, NormalizedByteCode.__ldc)) { TypeWrapper classLiteral = eic.GetClassLiteral(-1); if (!classLiteral.IsUnloadable && classLiteral.GetClassLoader().RemoveAsserts) { eic.Emitter.Emit(OpCodes.Pop); eic.Emitter.Emit_Ldc_I4(0); return(true); } } return(false); }
private static void EmitConsumeUnsafe(EmitIntrinsicContext eic) { #if STATIC_COMPILER if (eic.Caller.DeclaringType.GetClassLoader() == CoreClasses.java.lang.Object.Wrapper.GetClassLoader()) { // we're compiling the core library (which is obviously trusted), so we don't need to check // if we really have an Unsafe instance eic.Emitter.Emit(OpCodes.Pop); } else #endif { eic.Emitter.EmitNullCheck(); } }
private static bool Unsafe_ensureClassInitialized(EmitIntrinsicContext eic) { if (eic.MatchRange(-1, 2) && eic.Match(-1, NormalizedByteCode.__ldc)) { TypeWrapper classLiteral = eic.GetClassLiteral(-1); if (!classLiteral.IsUnloadable) { eic.Emitter.Emit(OpCodes.Pop); eic.Emitter.EmitNullCheck(); classLiteral.EmitRunClassConstructor(eic.Emitter); return(true); } } return(false); }
private static bool String_toCharArray(EmitIntrinsicContext eic) { if (eic.MatchRange(-1, 2) && eic.Match(-1, NormalizedByteCode.__ldc)) { string str = eic.ClassFile.GetConstantPoolConstantString(eic.Code[eic.OpcodeIndex - 1].Arg1); // arbitrary length for "big" strings if (str.Length > 128) { eic.Emitter.Emit(OpCodes.Pop); EmitLoadCharArrayLiteral(eic.Emitter, str, eic.Caller.DeclaringType); return(true); } } return(false); }
private static bool String_toCharArray(EmitIntrinsicContext eic) { if (eic.MatchRange(-1, 2) && eic.Match(-1, NormalizedByteCode.__ldc_nothrow)) { string str = eic.GetStringLiteral(-1); // arbitrary length for "big" strings if (str.Length > 128) { eic.Emitter.Emit(OpCodes.Pop); EmitLoadCharArrayLiteral(eic.Emitter, str, eic.Caller.DeclaringType); return(true); } } return(false); }
private static bool CallerID_getCallerID(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.EmitLdarg(arg); return(true); } else { throw new FatalCompilerErrorException(Message.CallerIDRequiresHasCallerIDAnnotation); } }
private static bool ClassLoader_getCallerClassLoader(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.Emit(OpCodes.Ldarg, (short)arg); MethodWrapper mw = [email protected]("getCallerClassLoader", "()Ljava.lang.ClassLoader;", false); mw.Link(); mw.EmitCallvirt(eic.Emitter); return(true); } return(false); }
private static bool CallerID_getCallerID(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.Emit(OpCodes.Ldarg, (short)arg); return(true); } else { JVM.CriticalFailure("CallerID.getCallerID() requires a HasCallerID annotation", null); } return(false); }
private static bool Object_getClass(EmitIntrinsicContext eic) { // this is the null-check idiom that javac uses (both in its own source and in the code it generates) if (eic.MatchRange(0, 2) && eic.Match(1, NormalizedByteCode.__pop)) { eic.Emitter.Emit(OpCodes.Dup); eic.Emitter.EmitNullCheck(); return(true); } // this optimizes obj1.getClass() ==/!= obj2.getClass() else if (eic.MatchRange(0, 4) && eic.Match(1, NormalizedByteCode.__aload) && eic.Match(2, NormalizedByteCode.__invokevirtual) && (eic.Match(3, NormalizedByteCode.__if_acmpeq) || eic.Match(3, NormalizedByteCode.__if_acmpne)) && (IsSafeForGetClassOptimization(eic.GetStackTypeWrapper(0, 0)) || IsSafeForGetClassOptimization(eic.GetStackTypeWrapper(2, 0)))) { ClassFile.ConstantPoolItemMI cpi = eic.GetMethodref(2); if (cpi.Class == "java.lang.Object" && cpi.Name == "getClass" && cpi.Signature == "()Ljava.lang.Class;") { // we can't patch the current opcode, so we have to emit the first call to GetTypeHandle here eic.Emitter.Emit(OpCodes.Callvirt, Compiler.getTypeMethod); eic.PatchOpCode(2, NormalizedByteCode.__intrinsic_gettype); return(true); } } // this optimizes obj.getClass() == Xxx.class else if (eic.MatchRange(0, 3) && eic.Match(1, NormalizedByteCode.__ldc) && eic.GetConstantType(1) == ClassFile.ConstantType.Class && (eic.Match(2, NormalizedByteCode.__if_acmpeq) || eic.Match(2, NormalizedByteCode.__if_acmpne))) { TypeWrapper tw = eic.GetClassLiteral(1); if (tw.IsGhost || tw.IsGhostArray || tw.IsUnloadable || (tw.IsRemapped && tw.IsFinal && tw is DotNetTypeWrapper)) { return(false); } eic.Emitter.Emit(OpCodes.Callvirt, Compiler.getTypeMethod); eic.Emitter.Emit(OpCodes.Ldtoken, (tw.IsRemapped && tw.IsFinal) ? tw.TypeAsTBD : tw.TypeAsBaseType); eic.Emitter.Emit(OpCodes.Call, Compiler.getTypeFromHandleMethod); eic.PatchOpCode(1, NormalizedByteCode.__nop); return(true); } return(false); }
private static bool Reflection_getCallerClass(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID && eic.MatchRange(-1, 2) && eic.Match(-1, NormalizedByteCode.__iconst, 2)) { eic.Emitter.Emit(OpCodes.Pop); int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.Emit(OpCodes.Ldarg, (short)arg); MethodWrapper mw = [email protected]("getCallerClass", "()Ljava.lang.Class;", false); mw.Link(); mw.EmitCallvirt(eic.Emitter); return(true); } return(false); }
private static bool Reflection_getCallerClass(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.EmitLdarg(arg); MethodWrapper mw; if (MatchInvokeStatic(eic, 1, "java.lang.ClassLoader", "getClassLoader", "(Ljava.lang.Class;)Ljava.lang.ClassLoader;")) { eic.PatchOpCode(1, NormalizedByteCode.__nop); mw = [email protected]("getCallerClassLoader", "()Ljava.lang.ClassLoader;", false); } else { mw = [email protected]("getCallerClass", "()Ljava.lang.Class;", false); } mw.Link(); mw.EmitCallvirt(eic.Emitter); return(true); } 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); } return(false); }
private static bool CallerID_getCallerID(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.Emit(OpCodes.Ldarg, (short)arg); return(true); } else { #if STATIC_COMPILER throw new FatalCompilerErrorException(Message.CallerIDRequiresHasCallerIDAnnotation); #else JVM.CriticalFailure("CallerID.getCallerID() requires a HasCallerID annotation", null); return(false); #endif } }
// this intrinsifies the unsafe.objectFieldOffset(XXX.class.getDeclaredField("xxx")) pattern // to avoid initializing the full reflection machinery at this point private static bool Class_getDeclaredField(EmitIntrinsicContext eic) { // validate that we're inside the XXX class and that xxx is an instance field of that class if (eic.MatchRange(-2, 4) && eic.Match(-2, NormalizedByteCode.__ldc) && eic.GetClassLiteral(-2) == eic.Caller.DeclaringType && eic.Match(-1, NormalizedByteCode.__ldc_nothrow) && eic.Match(1, NormalizedByteCode.__invokevirtual)) { FieldWrapper field = null; string fieldName = eic.GetStringLiteral(-1); foreach (FieldWrapper fw in eic.Caller.DeclaringType.GetFields()) { if (fw.Name == fieldName) { if (field != null) { return(false); } field = fw; } } if (field == null || field.IsStatic) { return(false); } ClassFile.ConstantPoolItemMI cpi = eic.GetMethodref(1); if (cpi.Class == "sun.misc.Unsafe" && cpi.Name == "objectFieldOffset" && cpi.Signature == "(Ljava.lang.reflect.Field;)J") { MethodWrapper mw = ClassLoaderWrapper.LoadClassCritical("sun.misc.Unsafe") .GetMethodWrapper("objectFieldOffset", "(Ljava.lang.Class;Ljava.lang.String;)J", false); mw.Link(); mw.EmitCallvirt(eic.Emitter); eic.PatchOpCode(1, NormalizedByteCode.__nop); return(true); } } return(false); }
private static bool Util_getInstanceTypeFromClass(EmitIntrinsicContext eic) { if (eic.MatchRange(-1, 2) && eic.Match(-1, NormalizedByteCode.__ldc)) { TypeWrapper tw = eic.GetClassLiteral(-1); if (!tw.IsUnloadable) { eic.Emitter.Emit(OpCodes.Pop); if (tw.IsRemapped && tw.IsFinal) { eic.Emitter.Emit(OpCodes.Ldtoken, tw.TypeAsTBD); } else { eic.Emitter.Emit(OpCodes.Ldtoken, tw.TypeAsBaseType); } eic.Emitter.Emit(OpCodes.Call, Compiler.getTypeFromHandleMethod); return(true); } } return(false); }
private static bool Unsafe_putObjectImpl(EmitIntrinsicContext eic, bool membarrier) { TypeWrapper tw = eic.GetStackTypeWrapper(0, 2); if (IsSupportedArrayTypeForUnsafeOperation(tw) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(tw.ElementTypeWrapper)) { CodeEmitterLocal value = eic.Emitter.AllocTempLocal(tw.ElementTypeWrapper.TypeAsLocalOrStackType); CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); CodeEmitterLocal array = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, value); eic.Emitter.Emit(OpCodes.Conv_Ovf_I4); eic.Emitter.Emit(OpCodes.Stloc, index); eic.Emitter.Emit(OpCodes.Stloc, array); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, array); eic.Emitter.Emit(OpCodes.Ldloc, index); eic.Emitter.Emit(OpCodes.Ldloc, value); eic.Emitter.ReleaseTempLocal(array); eic.Emitter.ReleaseTempLocal(index); eic.Emitter.ReleaseTempLocal(value); eic.Emitter.Emit(OpCodes.Stelem_Ref); if (membarrier) { eic.Emitter.EmitMemoryBarrier(); } eic.NonLeaf = false; return(true); } if ((eic.Flags[eic.OpcodeIndex] & InstructionFlags.BranchTarget) != 0 || (eic.Flags[eic.OpcodeIndex - 1] & InstructionFlags.BranchTarget) != 0) { return(false); } if ((eic.Match(-1, NormalizedByteCode.__aload) || eic.Match(-1, NormalizedByteCode.__aconst_null)) && eic.Match(-2, NormalizedByteCode.__getstatic)) { FieldWrapper fw = GetUnsafeField(eic, eic.GetFieldref(-2)); if (fw != null && (!fw.IsFinal || (!fw.IsStatic && eic.Caller.Name == "<init>") || (fw.IsStatic && eic.Caller.Name == "<clinit>")) && fw.IsAccessibleFrom(fw.DeclaringType, eic.Caller.DeclaringType, fw.DeclaringType) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(fw.FieldTypeWrapper) && (fw.IsStatic || fw.DeclaringType == eic.GetStackTypeWrapper(0, 2))) { CodeEmitterLocal value = eic.Emitter.AllocTempLocal(fw.FieldTypeWrapper.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, value); eic.Emitter.Emit(OpCodes.Pop); // discard offset field if (fw.IsStatic) { eic.Emitter.Emit(OpCodes.Pop); // discard object EmitConsumeUnsafe(eic); } else { CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(fw.DeclaringType.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, obj); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, obj); eic.Emitter.ReleaseTempLocal(obj); } eic.Emitter.Emit(OpCodes.Ldloc, value); eic.Emitter.ReleaseTempLocal(value); // note that we assume the CLR memory model where all writes are ordered, // so we don't need a volatile store or a memory barrier and putOrderedObject // is typically used with a volatile field, so to avoid the memory barrier, // we don't use FieldWrapper.EmitSet(), but emit the store directly eic.Emitter.Emit(fw.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fw.GetField()); if (membarrier) { eic.Emitter.EmitMemoryBarrier(); } eic.NonLeaf = false; return(true); } } return(false); }
private static bool AtomicReferenceFieldUpdater_newUpdater(EmitIntrinsicContext eic) { return(AtomicReferenceFieldUpdaterEmitter.Emit(eic.Context, eic.Caller.DeclaringType, eic.Emitter, eic.ClassFile, eic.OpcodeIndex, eic.Code, eic.Flags)); }
private static bool Double_longBitsToDouble(EmitIntrinsicContext eic) { EmitConversion(eic.Emitter, typeofDoubleConverter, "ToDouble"); return(true); }
private static bool Double_doubleToRawLongBits(EmitIntrinsicContext eic) { EmitConversion(eic.Emitter, typeofDoubleConverter, "ToLong"); return(true); }
private static bool Float_intBitsToFloat(EmitIntrinsicContext eic) { EmitConversion(eic.Emitter, typeofFloatConverter, "ToFloat"); return(true); }
private static FieldWrapper GetUnsafeField(EmitIntrinsicContext eic, ClassFile.ConstantPoolItemFieldref field) { if (eic.Caller.DeclaringType.GetClassLoader() != CoreClasses.java.lang.Object.Wrapper.GetClassLoader()) { // this code does not solve the general problem and assumes non-hostile, well behaved static initializers // so we only support the core class library return(null); } // the field offset field must be a static field inside the current class // (we don't need to check that the field is static, because the caller already ensured that) if (field.GetField().DeclaringType == eic.Caller.DeclaringType) { // now look inside the static initializer to see if we can found out what field it refers to foreach (ClassFile.Method method in eic.ClassFile.Methods) { if (method.IsClassInitializer) { // TODO should we first verify the method? // TODO should we attempt to make sure the field is definitely assigned (and only once)? // TODO special case/support the pattern used by: // - java.util.concurrent.atomic.AtomicMarkableReference // - java.util.concurrent.atomic.AtomicStampedReference // - java.util.concurrent.locks.AbstractQueuedLongSynchronizer /* * ldc_w test * astore_0 * ... * getstatic <Field test sun/misc/Unsafe UNSAFE> * aload_0 * ldc "next" * invokevirtual <Method java/lang/Class getDeclaredField(Ljava/lang/String;)Ljava/lang/reflect/Field;> * invokevirtual <Method sun/misc/Unsafe objectFieldOffset(Ljava/lang/reflect/Field;)J> * putstatic <Field test long nextOffset> */ for (int i = 0; i < method.Instructions.Length; i++) { if (method.Instructions[i].NormalizedOpCode == NormalizedByteCode.__putstatic && eic.ClassFile.GetFieldref(method.Instructions[i].Arg1) == field) { if (MatchInvokeVirtual(eic, ref method.Instructions[i - 1], "sun.misc.Unsafe", "objectFieldOffset", "(Ljava.lang.reflect.Field;)J") && MatchInvokeVirtual(eic, ref method.Instructions[i - 2], "java.lang.Class", "getDeclaredField", "(Ljava.lang.String;)Ljava.lang.reflect.Field;") && MatchLdc(eic, ref method.Instructions[i - 3], ClassFile.ConstantType.String) && method.Instructions[i - 4].NormalizedOpCode == NormalizedByteCode.__aload && method.Instructions[i - 5].NormalizedOpCode == NormalizedByteCode.__getstatic && eic.ClassFile.GetFieldref(method.Instructions[i - 5].Arg1).Signature == "Lsun.misc.Unsafe;") { // search backward for the astore that corresponds to the aload (of the class object) for (int j = i - 6; j > 0; j--) { if (method.Instructions[j].NormalizedOpCode == NormalizedByteCode.__astore && method.Instructions[j].Arg1 == method.Instructions[i - 4].Arg1 && MatchLdc(eic, ref method.Instructions[j - 1], ClassFile.ConstantType.Class) && eic.ClassFile.GetConstantPoolClassType(method.Instructions[j - 1].Arg1) == eic.Caller.DeclaringType) { string fieldName = eic.ClassFile.GetConstantPoolConstantString(method.Instructions[i - 3].Arg1); FieldWrapper fw = null; foreach (FieldWrapper fw1 in eic.Caller.DeclaringType.GetFields()) { if (fw1.Name == fieldName) { if (fw == null) { fw = fw1; } else { // duplicate name return(null); } } } return(fw); } } break; } } } break; } } } return(null); }
private static bool Unsafe_putObjectVolatile(EmitIntrinsicContext eic) { return(Unsafe_putObjectImpl(eic, true)); }
internal static bool Emit(EmitIntrinsicContext context) { // note that intrinsics can always refuse to emit code and the code generator will fall back to a normal method call return(intrinsics[new IntrinsicKey(context.Method)](context)); }
private static bool Unsafe_compareAndSwapObject(EmitIntrinsicContext eic) { TypeWrapper tw = eic.GetStackTypeWrapper(0, 3); if (IsSupportedArrayTypeForUnsafeOperation(tw) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(tw.ElementTypeWrapper) && eic.GetStackTypeWrapper(0, 1).IsAssignableTo(tw.ElementTypeWrapper)) { Type type = tw.TypeAsLocalOrStackType.GetElementType(); CodeEmitterLocal update = eic.Emitter.AllocTempLocal(type); CodeEmitterLocal expect = eic.Emitter.AllocTempLocal(type); CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, update); eic.Emitter.Emit(OpCodes.Stloc, expect); 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, update); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Call, AtomicReferenceFieldUpdaterEmitter.MakeCompareExchange(type)); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Ceq); eic.Emitter.ReleaseTempLocal(obj); eic.Emitter.ReleaseTempLocal(index); eic.Emitter.ReleaseTempLocal(expect); eic.Emitter.ReleaseTempLocal(update); eic.NonLeaf = false; return(true); } if ((eic.Flags[eic.OpcodeIndex] & InstructionFlags.BranchTarget) != 0 || (eic.Flags[eic.OpcodeIndex - 1] & InstructionFlags.BranchTarget) != 0 || (eic.Flags[eic.OpcodeIndex - 2] & InstructionFlags.BranchTarget) != 0) { return(false); } if ((eic.Match(-1, NormalizedByteCode.__aload) || eic.Match(-1, NormalizedByteCode.__aconst_null)) && (eic.Match(-2, NormalizedByteCode.__aload) || eic.Match(-2, NormalizedByteCode.__aconst_null)) && eic.Match(-3, NormalizedByteCode.__getstatic)) { FieldWrapper fw = GetUnsafeField(eic, eic.GetFieldref(-3)); if (fw != null && fw.IsAccessibleFrom(fw.DeclaringType, eic.Caller.DeclaringType, fw.DeclaringType) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(fw.FieldTypeWrapper) && eic.GetStackTypeWrapper(0, 1).IsAssignableTo(fw.FieldTypeWrapper) && (fw.IsStatic || fw.DeclaringType == eic.GetStackTypeWrapper(0, 3))) { Type type = fw.FieldTypeWrapper.TypeAsLocalOrStackType; CodeEmitterLocal update = eic.Emitter.AllocTempLocal(type); CodeEmitterLocal expect = eic.Emitter.AllocTempLocal(type); eic.Emitter.Emit(OpCodes.Stloc, update); eic.Emitter.Emit(OpCodes.Stloc, expect); eic.Emitter.Emit(OpCodes.Pop); // discard index if (fw.IsStatic) { eic.Emitter.Emit(OpCodes.Pop); // discard obj EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldsflda, fw.GetField()); } else { CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(eic.Caller.DeclaringType.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, obj); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, obj); eic.Emitter.ReleaseTempLocal(obj); eic.Emitter.Emit(OpCodes.Ldflda, fw.GetField()); } eic.Emitter.Emit(OpCodes.Ldloc, update); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Call, AtomicReferenceFieldUpdaterEmitter.MakeCompareExchange(type)); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Ceq); eic.Emitter.ReleaseTempLocal(expect); eic.Emitter.ReleaseTempLocal(update); eic.NonLeaf = false; return(true); } } return(false); }