Beispiel #1
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);
 }
Beispiel #2
0
 private static bool Object_getClass(DynamicTypeWrapper.FinishContext context, CodeEmitter ilgen, MethodWrapper method, MethodAnalyzer ma, int opcodeIndex, MethodWrapper caller, ClassFile classFile, Instruction[] code, InstructionFlags[] flags)
 {
     // this is the null-check idiom that javac uses (both in its own source and in the code it generates)
     if (code[opcodeIndex + 1].NormalizedOpCode == NormalizedByteCode.__pop)
     {
         ilgen.Emit(OpCodes.Dup);
         ilgen.EmitNullCheck();
         return(true);
     }
     // this optimizes obj1.getClass() ==/!= obj2.getClass()
     else if (opcodeIndex + 3 < code.Length &&
              (flags[opcodeIndex + 1] & InstructionFlags.BranchTarget) == 0 &&
              (flags[opcodeIndex + 2] & InstructionFlags.BranchTarget) == 0 &&
              (flags[opcodeIndex + 3] & InstructionFlags.BranchTarget) == 0 &&
              code[opcodeIndex + 1].NormalizedOpCode == NormalizedByteCode.__aload &&
              code[opcodeIndex + 2].NormalizedOpCode == NormalizedByteCode.__invokevirtual &&
              (code[opcodeIndex + 3].NormalizedOpCode == NormalizedByteCode.__if_acmpeq || code[opcodeIndex + 3].NormalizedOpCode == NormalizedByteCode.__if_acmpne) &&
              (IsSafeForGetClassOptimization(ma.GetStackTypeWrapper(opcodeIndex, 0)) || IsSafeForGetClassOptimization(ma.GetStackTypeWrapper(opcodeIndex + 2, 0))))
     {
         ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(code[opcodeIndex + 2].Arg1);
         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
             ilgen.Emit(OpCodes.Callvirt, Compiler.getTypeMethod);
             code[opcodeIndex + 2].PatchOpCode(NormalizedByteCode.__intrinsic_gettype);
             return(true);
         }
     }
     return(false);
 }
Beispiel #3
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);
 }
Beispiel #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);
 }
Beispiel #5
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);
 }
Beispiel #6
0
    private static Dictionary <int, string>[] FindLocalVariablesImpl(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, FindLocalVarState[] state)
    {
        ClassFile.Method.Instruction[] instructions = method.Instructions;
        ExceptionTableEntry[]          exceptions   = method.ExceptionTable;
        int maxLocals = method.MaxLocals;

        Dictionary <int, string>[] localStoreReaders = new Dictionary <int, string> [instructions.Length];
        bool done = false;

        while (!done)
        {
            done = true;
            for (int i = 0; i < instructions.Length; i++)
            {
                if (state[i].changed)
                {
                    done             = false;
                    state[i].changed = false;

                    FindLocalVarState curr = state[i].Copy();

                    for (int j = 0; j < exceptions.Length; j++)
                    {
                        if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex)
                        {
                            state[exceptions[j].handlerIndex].Merge(curr);
                        }
                    }

                    if (IsLoadLocal(instructions[i].NormalizedOpCode) &&
                        (instructions[i].NormalizedOpCode != NormalizedByteCode.__aload || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i + 1, 0))))
                    {
                        if (localStoreReaders[i] == null)
                        {
                            localStoreReaders[i] = new Dictionary <int, string>();
                        }
                        for (int j = 0; j < curr.sites[instructions[i].NormalizedArg1].Count; j++)
                        {
                            localStoreReaders[i][curr.sites[instructions[i].NormalizedArg1][j]] = "";
                        }
                    }

                    if (IsStoreLocal(instructions[i].NormalizedOpCode) &&
                        (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0))))
                    {
                        curr.Store(i, instructions[i].NormalizedArg1);
                        // if this is a store at the end of an exception block,
                        // we need to propagate the new state to the exception handler
                        for (int j = 0; j < exceptions.Length; j++)
                        {
                            if (exceptions[j].endIndex == i + 1)
                            {
                                state[exceptions[j].handlerIndex].Merge(curr);
                            }
                        }
                    }

                    if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial)
                    {
                        ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instructions[i].Arg1);
                        if (ReferenceEquals(cpi.Name, StringConstants.INIT))
                        {
                            TypeWrapper type = codeInfo.GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length);
                            // after we've invoked the constructor, the uninitialized references
                            // are now initialized
                            if (type == VerifierTypeWrapper.UninitializedThis ||
                                VerifierTypeWrapper.IsNew(type))
                            {
                                for (int j = 0; j < maxLocals; j++)
                                {
                                    if (codeInfo.GetLocalTypeWrapper(i, j) == type)
                                    {
                                        curr.Store(i, j);
                                    }
                                }
                            }
                        }
                    }
                    else if (instructions[i].NormalizedOpCode == NormalizedByteCode.__goto_finally)
                    {
                        int handler = instructions[i].HandlerIndex;

                        // Normally a store at the end of a try block doesn't affect the handler block,
                        // but in the case of a finally handler it does, so we need to make sure that
                        // we merge here in case the try block ended with a store.
                        state[handler].Merge(curr);

                        // Now we recursively analyse the handler and afterwards merge the endfault locations back to us
                        FindLocalVarState[] handlerState = new FindLocalVarState[instructions.Length];
                        handlerState[handler].Merge(curr);
                        curr = new FindLocalVarState();
                        FindLocalVariablesImpl(codeInfo, classFile, method, handlerState);

                        // Merge back to the target of our __goto_finally
                        for (int j = 0; j < handlerState.Length; j++)
                        {
                            if (instructions[j].NormalizedOpCode == NormalizedByteCode.__athrow &&
                                codeInfo.HasState(j) &&
                                VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0)) &&
                                ((VerifierTypeWrapper)codeInfo.GetRawStackTypeWrapper(j, 0)).Index == handler)
                            {
                                curr.Merge(handlerState[j]);
                            }
                        }
                    }

                    switch (ByteCodeMetaData.GetFlowControl(instructions[i].NormalizedOpCode))
                    {
                    case ByteCodeFlowControl.Switch:
                    {
                        for (int j = 0; j < instructions[i].SwitchEntryCount; j++)
                        {
                            state[instructions[i].GetSwitchTargetIndex(j)].Merge(curr);
                        }
                        state[instructions[i].DefaultTarget].Merge(curr);
                        break;
                    }

                    case ByteCodeFlowControl.Branch:
                        state[instructions[i].TargetIndex].Merge(curr);
                        break;

                    case ByteCodeFlowControl.CondBranch:
                        state[instructions[i].TargetIndex].Merge(curr);
                        state[i + 1].Merge(curr);
                        break;

                    case ByteCodeFlowControl.Return:
                    case ByteCodeFlowControl.Throw:
                        break;

                    case ByteCodeFlowControl.Next:
                        state[i + 1].Merge(curr);
                        break;

                    default:
                        throw new InvalidOperationException();
                    }
                }
            }
        }
        return(localStoreReaders);
    }
 private static bool HasUnloadable(ClassFile.ConstantPoolItemMI cpi)
 {
     return(HasUnloadable(cpi.GetArgTypes()) || cpi.GetRetType().IsUnloadable);
 }
Beispiel #8
0
        // this intrinsifies the following two patterns:
        //   unsafe.objectFieldOffset(XXX.class.getDeclaredField("xxx"));
        // and
        //   Class k = XXX.class;
        //   unsafe.objectFieldOffset(k.getDeclaredField("xxx"));
        // to avoid initializing the full reflection machinery at this point
        private static bool Class_getDeclaredField(EmitIntrinsicContext eic)
        {
            if (eic.Caller.DeclaringType.GetClassLoader() != CoreClasses.java.lang.Object.Wrapper.GetClassLoader())
            {
                // we can only do this optimization when compiling the trusted core classes
                return(false);
            }
            TypeWrapper fieldClass;

            if (eic.MatchRange(-2, 4) &&
                eic.Match(-2, NormalizedByteCode.__ldc) &&
                eic.Match(-1, NormalizedByteCode.__ldc_nothrow) &&
                eic.Match(1, NormalizedByteCode.__invokevirtual))
            {
                // unsafe.objectFieldOffset(XXX.class.getDeclaredField("xxx"));
                fieldClass = eic.GetClassLiteral(-2);
            }
            else if (eic.MatchRange(-5, 7) &&
                     eic.Match(-5, NormalizedByteCode.__ldc) &&
                     eic.Match(-4, NormalizedByteCode.__astore) &&
                     eic.Match(-3, NormalizedByteCode.__getstatic) &&
                     eic.Match(-2, NormalizedByteCode.__aload, eic.Code[eic.OpcodeIndex - 4].NormalizedArg1) &&
                     eic.Match(-1, NormalizedByteCode.__ldc_nothrow) &&
                     eic.Match(1, NormalizedByteCode.__invokevirtual))
            {
                // Class k = XXX.class;
                // unsafe.objectFieldOffset(k.getDeclaredField("xxx"));
                fieldClass = eic.GetClassLiteral(-5);
            }
            else
            {
                return(false);
            }
            FieldWrapper field     = null;
            string       fieldName = eic.GetStringLiteral(-1);

            foreach (FieldWrapper fw in fieldClass.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);
        }