Пример #1
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);
            }
        }
Пример #2
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);
 }
Пример #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);
         }
     }
     // 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);
 }
Пример #5
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);
        }
Пример #6
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);
        }