示例#1
0
        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);
        }
示例#2
0
 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);
 }
示例#3
0
        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);
        }
示例#4
0
 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);
 }
示例#5
0
        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);
            }
        }
示例#6
0
        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);
        }
示例#7
0
 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);
 }
示例#8
0
 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);
 }
示例#9
0
        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();
            }
        }
示例#10
0
 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);
 }
示例#11
0
 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);
 }
示例#12
0
 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);
 }
示例#13
0
 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);
     }
 }
示例#14
0
 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);
 }
示例#15
0
 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);
 }
示例#16
0
 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);
 }
示例#17
0
 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);
 }
示例#18
0
 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);
 }
示例#19
0
        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
            }
        }
示例#20
0
 // 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);
 }
示例#21
0
 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);
 }
示例#22
0
        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);
        }
示例#23
0
 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));
 }
示例#24
0
 private static bool Double_longBitsToDouble(EmitIntrinsicContext eic)
 {
     EmitConversion(eic.Emitter, typeofDoubleConverter, "ToDouble");
     return(true);
 }
示例#25
0
 private static bool Double_doubleToRawLongBits(EmitIntrinsicContext eic)
 {
     EmitConversion(eic.Emitter, typeofDoubleConverter, "ToLong");
     return(true);
 }
示例#26
0
 private static bool Float_intBitsToFloat(EmitIntrinsicContext eic)
 {
     EmitConversion(eic.Emitter, typeofFloatConverter, "ToFloat");
     return(true);
 }
示例#27
0
        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);
        }
示例#28
0
 private static bool Unsafe_putObjectVolatile(EmitIntrinsicContext eic)
 {
     return(Unsafe_putObjectImpl(eic, true));
 }
示例#29
0
 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));
 }
示例#30
0
        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);
        }