Search in sources :

Example 16 with MethodInfo

use of com.jopdesign.common.MethodInfo in project jop by jop-devel.

the class InlineHelper method makePublic.

private void makePublic(ClassMemberInfo member) {
    boolean wasPrivate = member.isPrivate();
    // If we need to make it public, check if we need to make the class and all enclosing classes public too
    ClassInfo cls = member.getClassInfo();
    while (cls != null) {
        if (!cls.isPublic()) {
            cls.setAccessType(AccessType.ACC_PUBLIC);
        }
        cls = cls.getEnclosingClassInfo();
    }
    if (wasPrivate && member instanceof MethodInfo) {
        // we are done here. if the method was private, there are no conflicting
        // methods or we needed to rename it anyway.
        member.setAccessType(AccessType.ACC_PUBLIC);
        return;
    }
    // if we make a non-private method or any field public, need to go down to find all overriding
    // members and make them public too
    final MemberID memberID = member.getMemberID();
    ClassVisitor visitor = new EmptyClassVisitor() {

        @Override
        public boolean visitClass(ClassInfo classInfo) {
            ClassMemberInfo m = classInfo.getMemberInfo(memberID);
            if (m == null) {
                return true;
            }
            if (m.isPublic()) {
                // we do not need to go further down if we find a public member
                return false;
            }
            m.setAccessType(AccessType.ACC_PUBLIC);
            return true;
        }
    };
    new ClassHierarchyTraverser(visitor).traverseDown(member.getClassInfo());
}
Also used : MemberID(com.jopdesign.common.type.MemberID) ClassMemberInfo(com.jopdesign.common.ClassMemberInfo) MethodInfo(com.jopdesign.common.MethodInfo) ClassHierarchyTraverser(com.jopdesign.common.graphutils.ClassHierarchyTraverser) EmptyClassVisitor(com.jopdesign.common.graphutils.EmptyClassVisitor) ClassVisitor(com.jopdesign.common.graphutils.ClassVisitor) EmptyClassVisitor(com.jopdesign.common.graphutils.EmptyClassVisitor) ClassInfo(com.jopdesign.common.ClassInfo)

Example 17 with MethodInfo

use of com.jopdesign.common.MethodInfo in project jop by jop-devel.

the class InlineHelper method checkCode.

/**
     * check the code of the invoked method if it contains instructions which prevent inlining.
     *
     * @param invoker the method into which the invokee will be inlined.
     * @param invokee the invoked method.
     * @return true if the code can be inlined and {@link #prepareInlining(MethodInfo, MethodInfo)} will succeed.
     */
private boolean checkCode(MethodInfo invoker, MethodInfo invokee) {
    MethodCode code = invokee.getCode();
    // Go through code, check for access to fields and invocations
    for (InstructionHandle ih : code.getInstructionList(true, false).getInstructionHandles()) {
        Instruction instr = ih.getInstruction();
        if (instr instanceof InvokeInstruction) {
            InvokeSite invokeSite = code.getInvokeSite(ih);
            MethodRef ref = invokeSite.getInvokeeRef();
            MethodInfo method = ref.getMethodInfo();
            if (method == null) {
                // TODO perform basic check on classnames if invoked method must already be public?
                return false;
            }
            // invokespecial is somewhat, well, special..
            if (invokeSite.isInvokeSpecial()) {
                if (checkInvokeSpecial(invoker, invokee, invokeSite, ref.getClassInfo(), method) == CheckResult.SKIP) {
                    return false;
                }
            } else {
                // check if fields need to be set to public
                if (checkNeedsPublic(invoker, invokee, ref.getClassInfo(), method) == CheckResult.SKIP) {
                    return false;
                }
            }
        } else if (instr instanceof FieldInstruction) {
            FieldRef ref = code.getFieldRef(ih);
            FieldInfo field = ref.getFieldInfo();
            if (field == null) {
                // TODO perform basic check on classnames if field is already public?
                return false;
            }
            // check if fields need to be set to public
            if (checkNeedsPublic(invoker, invokee, ref.getClassInfo(), field) == CheckResult.SKIP) {
                return false;
            }
        }
    }
    return true;
}
Also used : InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) MethodRef(com.jopdesign.common.type.MethodRef) FieldRef(com.jopdesign.common.type.FieldRef) MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite) FieldInstruction(org.apache.bcel.generic.FieldInstruction) MethodCode(com.jopdesign.common.MethodCode) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) ConstantPushInstruction(org.apache.bcel.generic.ConstantPushInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) LocalVariableInstruction(org.apache.bcel.generic.LocalVariableInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) FieldInfo(com.jopdesign.common.FieldInfo)

Example 18 with MethodInfo

use of com.jopdesign.common.MethodInfo in project jop by jop-devel.

the class InlineHelper method prepareInlining.

/**
     * Prepare the invokee for inlining into the invokesite, by widening access restrictions or renaming
     * methods to prevent incorrect method resolving.
     * <p>
     * This may change the code of the invokee, so this needs to be done before inlining the code.
     * The CFG of the invokee will be removed.
     * </p><p>
     * This code assumes that {@link #canInline(CallString, InvokeSite, MethodInfo)} returned true for this invoke.
     * </p>
     *
     * @param invoker the method where the code will be inlined to.
     * @param invokee the method to inline.
     */
public void prepareInlining(MethodInfo invoker, MethodInfo invokee) {
    MethodCode code = invokee.getCode();
    InstructionList il = code.getInstructionList();
    for (InstructionHandle ih : il.getInstructionHandles()) {
        Instruction instr = ih.getInstruction();
        if (instr instanceof InvokeInstruction) {
            InvokeSite invokeSite = code.getInvokeSite(ih);
            MethodRef ref = invokeSite.getInvokeeRef();
            MethodInfo method = ref.getMethodInfo();
            // we already checked that everything can be resolved
            // nothing special to do for invokespecial here (checkInvokeSpecial only skips, no special return codes)
            // check what we need to do
            CheckResult rs = checkNeedsPublic(invoker, invokee, ref.getClassInfo(), method);
            if (rs == CheckResult.NEEDS_PUBLIC) {
                makePublic(method);
            }
            if (rs == CheckResult.NEEDS_PUBLIC_RENAME) {
                if (method.isPrivate()) {
                // TODO check the class for invokers, change to invokevirtual
                } else {
                // if the method is package visible, we need to rename all overriding methods
                // too (but not methods from subclasses in different packages which do not override this)
                // TODO update overriding methods
                // TODO need to update all possible call sites
                }
                makePublic(method);
                throw new AppInfoError("Implement me!");
            }
        } else if (instr instanceof FieldInstruction) {
            FieldRef ref = code.getFieldRef(ih);
            FieldInfo field = ref.getFieldInfo();
            // we already checked that everything can be resolved
            // check if fields need to be set to public
            CheckResult rs = checkNeedsPublic(invoker, invokee, ref.getClassInfo(), field);
            if (rs == CheckResult.NEEDS_PUBLIC) {
                makePublic(field);
            }
            if (rs == CheckResult.NEEDS_PUBLIC_RENAME) {
                throw new AppInfoError("Invalid returncode: renaming of fields not required");
            }
        }
    }
}
Also used : FieldRef(com.jopdesign.common.type.FieldRef) InstructionList(org.apache.bcel.generic.InstructionList) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) ConstantPushInstruction(org.apache.bcel.generic.ConstantPushInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) LocalVariableInstruction(org.apache.bcel.generic.LocalVariableInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) AppInfoError(com.jopdesign.common.misc.AppInfoError) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) MethodRef(com.jopdesign.common.type.MethodRef) MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite) FieldInstruction(org.apache.bcel.generic.FieldInstruction) MethodCode(com.jopdesign.common.MethodCode) FieldInfo(com.jopdesign.common.FieldInfo)

Example 19 with MethodInfo

use of com.jopdesign.common.MethodInfo in project jop by jop-devel.

the class InlineHelper method checkNeedsPublic.

/**
     * Check if access of a field or method must/can be set to public.
     *
     * @param invoker the method containing the invocation to be checked.
     * @param invoked the invoked method to inline.
     * @param classInfo the class accessed in the invoked method.
     * @param memberInfo the modifier info of the accessed object.
     * @return a CheckResult status defining what should be done about the member access.
     */
private CheckResult checkNeedsPublic(MethodInfo invoker, MethodInfo invoked, ClassInfo classInfo, ClassMemberInfo memberInfo) {
    // don't inline if the original code contains access errors
    if (!invoked.canAccess(memberInfo)) {
        return CheckResult.SKIP;
    }
    // if the invoker can access the member, everything is fine
    if (invoker.canAccess(memberInfo)) {
        return CheckResult.OK;
    }
    // need to be changed to public, check if this can be done
    if (!inlineConfig.allowChangeAccess()) {
        return CheckResult.SKIP;
    }
    // fields are not virtually resolved 
    if (memberInfo instanceof MethodInfo) {
        MethodInfo method = (MethodInfo) memberInfo;
        // check if full class hierarchy is known, else the method may be overwritten if set to public by an unkonwn class.
        if (jcopter.getJConfig().doAssumeIncompleteAppInfo() && !memberInfo.getClassInfo().isFinal()) {
            return CheckResult.SKIP;
        }
        // search all subclasses for same method
        List<ClassInfo> queue = new LinkedList<ClassInfo>(method.getClassInfo().getDirectSubclasses());
        while (!queue.isEmpty()) {
            ClassInfo cls = queue.remove(0);
            MethodInfo subMethod = cls.getMethodInfo(method.getMethodSignature());
            if (subMethod != null) {
                // We can simply make private methods public, but we must not change call sites to invokevirtual
                if (method.getAccessType() == AccessType.ACC_PACKAGE && !subMethod.overrides(method, false)) {
                    // Need to rename method and all its overriding methods, but not the not-overriding subMethod (or vice-versa)
                    return inlineConfig.allowRename() ? CheckResult.NEEDS_PUBLIC_RENAME : CheckResult.SKIP;
                }
            }
        }
    }
    return CheckResult.NEEDS_PUBLIC;
}
Also used : MethodInfo(com.jopdesign.common.MethodInfo) LinkedList(java.util.LinkedList) ClassInfo(com.jopdesign.common.ClassInfo)

Example 20 with MethodInfo

use of com.jopdesign.common.MethodInfo in project jop by jop-devel.

the class MethodCacheAnalysis method findRemovedMethods.

private Map<ExecutionContext, Set<MethodInfo>> findRemovedMethods(Set<ExecutionContext> roots, Collection<MethodInfo> removed) {
    Map<ExecutionContext, Set<MethodInfo>> removeMethods = new LinkedHashMap<ExecutionContext, Set<MethodInfo>>();
    LinkedHashSet<ExecutionContext> queue = new LinkedHashSet<ExecutionContext>(roots);
    while (!queue.isEmpty()) {
        ExecutionContext node = queue.iterator().next();
        queue.remove(node);
        boolean changed = false;
        boolean isRoot = roots.contains(node);
        boolean isNew = false;
        // we initialize (lazily) by assuming that all removed methods are no longer reachable in any node,
        // and then removing entries from the set if they are found to be still reachable.
        // This ensures that the size of the sets only decreases and we eventually reach a fixpoint
        Set<MethodInfo> set = removeMethods.get(node);
        if (set == null) {
            set = new LinkedHashSet<MethodInfo>(removed.size());
            removeMethods.put(node, set);
            for (MethodInfo m : removed) {
                // initially add method to remove set if it is reachable from this node
                if (reachableMethods.get(node).contains(m)) {
                    set.add(m);
                }
            }
            changed = true;
            isNew = true;
        }
        // be removed from this node
        for (MethodInfo r : removed) {
            // already removed
            if (!set.contains(r))
                continue;
            for (ExecutionContext child : callGraph.getChildren(node)) {
                // we ignore native methods in the cache analysis
                if (child.getMethodInfo().isNative())
                    continue;
                // skip childs which will be removed
                if (isRoot && removed.contains(child.getMethodInfo()))
                    continue;
                // TODO this is incorrect for cyclic call graphs.. need to fix this!
                if (reachableMethods.get(child).contains(r)) {
                    set.remove(r);
                    changed = true;
                }
            }
        }
        if (isNew && set.isEmpty()) {
            // we did not remove anything here and we did not visit the parents yet, so nothing changes
            changed = false;
        }
        if (changed) {
            // we have found more methods, need to update parents
            queue.addAll(callGraph.getParents(node));
        }
    }
    return removeMethods;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ExecutionContext(com.jopdesign.common.code.ExecutionContext) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) MethodInfo(com.jopdesign.common.MethodInfo) LinkedHashMap(java.util.LinkedHashMap)

Aggregations

MethodInfo (com.jopdesign.common.MethodInfo)108 LinkedHashSet (java.util.LinkedHashSet)21 InstructionHandle (org.apache.bcel.generic.InstructionHandle)20 ClassInfo (com.jopdesign.common.ClassInfo)19 ExecutionContext (com.jopdesign.common.code.ExecutionContext)16 CFGNode (com.jopdesign.common.code.ControlFlowGraph.CFGNode)13 ArrayList (java.util.ArrayList)13 CallString (com.jopdesign.common.code.CallString)12 ControlFlowGraph (com.jopdesign.common.code.ControlFlowGraph)12 HashMap (java.util.HashMap)10 Set (java.util.Set)10 LinkedHashMap (java.util.LinkedHashMap)9 Instruction (org.apache.bcel.generic.Instruction)9 FieldInfo (com.jopdesign.common.FieldInfo)8 MethodCode (com.jopdesign.common.MethodCode)8 AppInfo (com.jopdesign.common.AppInfo)7 ContextEdge (com.jopdesign.common.code.CallGraph.ContextEdge)7 InvokeSite (com.jopdesign.common.code.InvokeSite)7 MemberID (com.jopdesign.common.type.MemberID)7 Context (com.jopdesign.dfa.framework.Context)7