org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass.java

Source

/**********************************************************************
 * This file is part of "Object Teams Dynamic Runtime Environment"
 * 
 * Copyright 2009, 2015 Oliver Frank and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Please visit http://www.eclipse.org/objectteams for updates and contact.
 * 
 * Contributors:
 *      Oliver Frank - Initial API and implementation
 *      Stephan Herrmann - Initial API and implementation
 **********************************************************************/
package org.eclipse.objectteams.otredyn.bytecode;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.objectteams.otredyn.runtime.ClassIdentifierProviderFactory;
import org.eclipse.objectteams.otredyn.runtime.IBinding;
import org.eclipse.objectteams.otredyn.runtime.IBoundClass;
import org.eclipse.objectteams.otredyn.runtime.IMethod;
import org.eclipse.objectteams.otredyn.runtime.TeamManager;
import org.eclipse.objectteams.otredyn.runtime.ISubclassWiringTask;
import org.eclipse.objectteams.otredyn.transformer.IWeavingContext;
import org.eclipse.objectteams.otredyn.transformer.jplis.ObjectTeamsTransformer;
import org.objectweb.asm.Opcodes;

/**
 * This class represents a java class.
 * It stores the information about a class parsed from the bytecode and
 * it handles callin and decapsulation bindings for the class
 * @author Oliver Frank
 */
public abstract class AbstractBoundClass implements IBoundClass {

    private static enum WeavingTaskType {
        WEAVE_BINDING_OF_SUBCLASS, WEAVE_BINDING, WEAVE_INHERITED_BINDING, WEAVE_METHOD_ACCESS, WEAVE_FIELD_ACCESS, WEAVE_INHERITED_MEMBER_ACCESS, WEAVE_BASE_INFRASTRUCTURE
    }

    /**
     * A structure that is internally used to store which methods are still woven
     * and which has to be woven.
     */
    private static class WeavingTask {

        private WeavingTaskType weavingTaskType;
        private String memberName;
        private String memberSignature;
        private int baseFlags;
        private boolean doAllTransformations;
        private boolean isHandleCovariantReturn;

        public WeavingTask(WeavingTaskType weavingTaskType, String memberName, String memberSignature,
                int baseFlags, boolean handleCovariantReturn) {
            this.weavingTaskType = weavingTaskType;
            this.memberName = memberName;
            this.memberSignature = memberSignature;
            this.isHandleCovariantReturn = handleCovariantReturn;
            this.baseFlags = baseFlags;
        }

        public WeavingTask(WeavingTaskType weavingTaskType, Method method, WeavingTask upstream) {
            this(weavingTaskType, method.getName(), method.getSignature(), upstream.getBaseFlags(),
                    upstream.isHandleCovariantReturn());
        }

        public WeavingTask(WeavingTaskType type) {
            this(type, null, null, 0, false);
        }

        /**
         * Returns the type of the WeavingTask
         * @return
         */
        public WeavingTaskType getType() {
            return weavingTaskType;
        }

        /**
         * Returns the name of the member, that has to be woven
         * @return
         */
        public String getMemberName() {
            return memberName;
        }

        /**
         * Returns the signature of the member, that has to be woven
         * @return
         */
        public String getMemberSignature() {
            return memberSignature;
        }

        public int getBaseFlags() {
            return baseFlags;
        }

        /**
         * This information is only needed for callin bindings.
         * @return If true, all transformation has to be done, if false,
         * only callAllBindings has to be redefined
         */
        public boolean doAllTransformations() {
            return doAllTransformations;
        }

        public void setDoAllTransformations(boolean doAllTransformations) {
            this.doAllTransformations = doAllTransformations;
        }

        public boolean isHandleCovariantReturn() {
            return this.isHandleCovariantReturn;
        }
    }

    // completed WeavingTasks for callin bindings mapped by the method,
    // that was woven
    private Map<Method, WeavingTask> completedBindingTasks;

    // not completed WeavingTasks for callin bindings mapped by the method,
    // that has to be woven
    private Map<Method, WeavingTask> openBindingTasks;

    // completed WeavingTasks for decapsulation bindings mapped by the member,
    // that was woven
    private Map<Member, WeavingTask> completedAccessTasks;

    // open WeavingTasks for decapsulation bindings mapped by the member,
    // that has to be woven
    private Map<Member, WeavingTask> openAccessTasks;

    private List<ISubclassWiringTask> wiringTasks;

    //FQN (e.g. "foo.bar.MyClass")
    private String name;

    //internal FQN (e.g. "foo/bar/MyClass.class")
    private String internalName;

    // A globally unique identifier for the class
    private String id;
    private String superClassName;
    private String internalSuperClassName;
    private String[] internalSuperInterfaces;
    private AbstractBoundClass superclass;
    private AbstractBoundClass enclosingClass;
    private Map<String, Method> methods;
    private Map<String, Field> fields;
    protected Map<AbstractBoundClass, Object> subclasses;

    // Is the java class, that was represented by the AbstractBoundClass
    // already loaded by a class loader or not
    private boolean isLoaded;

    private int modifiers;

    private int otClassFlags;
    private boolean implicitTeamActivationEnabled = false;
    private Set<String> methodsForImplicitActivation;

    protected ClassLoader loader;

    // callback
    protected IWeavingContext weavingContext;

    /**
     * No public constructor, beacause only the ClassRepository should
     * create AbstractBoundClasses
     * @param name dot-separated class name
     * @param id unique identifier, able to differentiate same-named classes from different classloaders
     * @param loader classloader responsible for loading this class
     */
    protected AbstractBoundClass(String name, String id, ClassLoader loader) {
        if (name.indexOf('/') != -1)
            new RuntimeException(name).printStackTrace(System.out);
        this.name = name;
        this.internalName = name.replace('.', '/');
        this.id = id;
        this.loader = loader;
        completedBindingTasks = new IdentityHashMap<Method, WeavingTask>();
        openBindingTasks = new IdentityHashMap<Method, WeavingTask>();
        openAccessTasks = new IdentityHashMap<Member, WeavingTask>();
        completedAccessTasks = new IdentityHashMap<Member, WeavingTask>();
        methods = new HashMap<String, Method>();
        fields = new HashMap<String, Field>();
        subclasses = new IdentityHashMap<AbstractBoundClass, Object>();

        // don't fetch a anonymous subclass for a anonymous subclass
        if (!name.equals(ClassRepository.ANONYMOUS_SUBCLASS_NAME)) {
            AbstractBoundClass anonymousSubclass = ClassRepository.getInstance().getAnonymousSubclass(this);
            subclasses.put(anonymousSubclass, null);
        }
    }

    /**
     * Returns the name of the Class
     * @return
     */
    public String getName() {
        return name;
    }

    public String getId() {
        return id;
    }

    public boolean isAnonymous() {
        return getName().equals(ClassRepository.ANONYMOUS_SUBCLASS_NAME);
    }

    /**
     * Returns the classloader responsible for loading this class.
     * @return
     */
    public ClassLoader getClassLoader() {
        return this.loader;
    }

    /**
     * Set the name of the super class of this class
     * @param superClassName
     */
    public void setSuperClassName(String superClassName) {
        if (superClassName == null) {
            return;
        }
        this.superClassName = superClassName.replace('/', '.');
        this.internalSuperClassName = superClassName.replace('.', '/');
    }

    public void setSuperInterfaces(String[] interfaces) {
        if (interfaces == null)
            return;
        this.internalSuperInterfaces = interfaces;
    }

    public boolean isJavaLangObject() {
        return this.name.equals("java.lang.Object");
    }

    /**
     * Is the class a interface?
     * @return
     */
    public boolean isInterface() {
        parseBytecode();
        return (this.modifiers & Opcodes.ACC_INTERFACE) != 0;
    }

    /**
     * Does this AbstractBoundClass represents a Team.
     * @return if true, the method getTeam of the ClassRepository 
     * could be called to get an instance of AbstractTeam 
     */
    public boolean isTeam() {
        parseBytecode();
        return (this.modifiers & Types.TEAM) != 0;
    }

    /**
     * Number of outer instances required in an instance of this class.
     */
    public int nestingDepth() {
        parseBytecode();
        if ((this.modifiers & Opcodes.ACC_STATIC) != 0)
            return 0;
        if (this.enclosingClass != null)
            return this.enclosingClass.nestingDepth() + 1;
        return 0;
    }

    /**
     * Store class modifiers (incl. visibility, AccStatic, AccInterface, AccStatic
     */
    public void setModifiers(int modifiers) {
        this.modifiers = modifiers;
    }

    public void setOTClassFlags(int flags) {
        this.otClassFlags = flags;
    }

    public boolean isRole() {
        return (this.otClassFlags & Types.ROLE_FLAG) != 0;
    }

    public boolean isProtected() {
        return (this.modifiers & Opcodes.ACC_PROTECTED) != 0;
    }

    public void enableImplicitActivation() {
        this.implicitTeamActivationEnabled = true;
    }

    public void registerMethodForImplicitActivation(String methodNameAndDesc) {
        if (this.methodsForImplicitActivation == null)
            this.methodsForImplicitActivation = new HashSet<String>();
        this.methodsForImplicitActivation.add(methodNameAndDesc);
    }

    public boolean hasMethodImplicitActivation(String methodNameAndDesc) {
        if (this.implicitTeamActivationEnabled) // for all methods
            return true;
        if (this.methodsForImplicitActivation == null)
            return false;
        return this.methodsForImplicitActivation.contains(methodNameAndDesc);
    }

    /**
     * Do all needed transformations needed at load time:
     * Add the interface IBoundBase2
     * Add the empty method callOrig
     * Add the empty method callOrigStatic
     * Add the empty method access
     * Add the empty method accessStatic
     * Add the empty method callAllBindings
     */
    public void transformAtLoadTime(IWeavingContext weavingContext) {
        this.weavingContext = weavingContext;
        handleTaskList();
    }

    /**
     * Mark as loaded
     */
    public void setLoaded() {
        this.isLoaded = true;
    }

    /**
     * Returns an instance of AbstractBoundClass that represents 
     * the super class of this class.
     * It parses the bytecode, if that has not already been done 
     * @return an instance of AbstractBoundClass that represents 
     * the super class of this class
     */
    public synchronized AbstractBoundClass getSuperclass() {
        parseBytecode();
        if (superClassName != null && superclass == null) {
            String superclassId = ClassIdentifierProviderFactory.getClassIdentifierProvider()
                    .getSuperclassIdentifier(id, internalSuperClassName);

            //if superclassId is null the class could be "Object" or an interface
            if (superclassId != null) {
                superclass = ClassRepository.getInstance().getBoundClass(superClassName, superclassId, loader);
                superclass.addSubclass(this);
                // FIXME(SH): can we avoid adding all subclasses to j.l.Object?
            }
        }
        return superclass;
    }

    /**
     * Returns the internal names of all superInterfaces or null.
     */
    public /*@Nullable*/ String[] getSuperInterfaceNames() {
        parseBytecode();
        return this.internalSuperInterfaces;
    }

    /**
     * Returns an instance of AbstractBoundClass that represents 
     * the enclosing class of this class.
     * It parses the bytecode, if that has not already been done 
     * @return an instance of AbstractBoundClass that represents 
     * the enclosing class of this class
     */
    public synchronized AbstractBoundClass getEnclosingClass() {
        parseBytecode();
        int pos = this.internalName.lastIndexOf('$');
        if (pos != -1) {
            String enclosingClassName = this.internalName.substring(0, pos);
            // FIXME(SH): do we need a new getEnclosingClassIdentifier?
            String enclosingClassID = ClassIdentifierProviderFactory.getClassIdentifierProvider()
                    .getSuperclassIdentifier(id, enclosingClassName);

            if (enclosingClassID != null) {
                enclosingClass = ClassRepository.getInstance().getBoundClass(enclosingClassName, enclosingClassID,
                        loader);
                enclosingClass.addSubclass(this);
            }
        }
        return enclosingClass;
    }

    public synchronized String getEnclosingClassName() {
        parseBytecode();
        int pos = this.internalName.lastIndexOf('$');
        if (pos != -1) {
            return this.internalName.substring(0, pos);
        }
        return null;
    }

    /**
     * This method parses the bytecode, if that has not already been done 
     */
    public abstract void parseBytecode();

    /**
     * Returns the internal name of the super class of this class
     * It parses the bytecode, if that has not already been done
     * @return
     */
    public String getInternalSuperClassName() {
        parseBytecode();
        return internalSuperClassName;
    }

    /**
     * Returns the internal name of this class
     * @return
     */
    public String getInternalName() {
        return internalName;
    }

    /**
     * Returns the name of the super class of this class
     * It parses the bytecode, if that has not already been done
     * @return
     */
    public String getSuperClassName() {
        parseBytecode();
        return superClassName;
    }

    /**
     * Adds a method to this class.
     * This method is intended to be called, 
     * while parsing the bytecode
     * @param name the name of the field
     * @param desc the signature of the method
     * @param isStatic is this method static
     * @param isPrivate is this method private
     */
    public void addMethod(String name, String desc, boolean isStatic, int accessFlags) {
        String methodKey = getMethodKey(name, desc);
        Method method = methods.get(methodKey);
        // Does this method already exists?
        // Methods are created by getMethod, if the class is not loaded
        if (method == null) {
            method = new Method(name, desc, isStatic, accessFlags);
            method.setImplemented(true);
            methods.put(methodKey, method);
        } else {
            // Yes, so set additional information.
            method.setImplemented(true);
            method.setStatic(isStatic);
        }
    }

    /** Method signature sauf the return type. */
    private String getMethodKey(String name, String desc) {
        int pos = desc.indexOf(')');
        return name + desc.substring(0, pos + 1);
    }

    /**
     * Adds a field to this class.
     * This method is intended to be called, 
     * while parsing the bytecode
     * @param name the name of the field
     * @param desc the signature of the field
     * @param isStatic is this field static
     * @param accessFlag ACC_PUBLIC, ACC_PROTECTED, ACC_PRIVATE or 0.
     */
    public void addField(String name, String desc, boolean isStatic, int accessFlags) {
        Field field = fields.get(name);
        if (field == null) {
            field = new Field(name, desc, isStatic, accessFlags);
            fields.put(name, field);
        } else {
            field.setStatic(isStatic);
        }
    }

    public synchronized Method getMethod(String name, String desc, int flags, boolean allowCovariantReturn) {
        parseBytecode();
        String methodKey = getMethodKey(name, desc);
        Method method = methods.get(methodKey);
        if (!allowCovariantReturn && method != null && !method.getSignature().equals(desc))
            method = null; // don't use this
        if (method == null) {
            // class was not yet loaded
            method = new Method(name, desc, ((flags & IBinding.STATIC_BASE) != 0), 0/*accessFlags*/);
            methods.put(methodKey, method);
        }
        return method;
    }

    Method getMethod(WeavingTask task) {
        return getMethod(task.getMemberName(), task.getMemberSignature(), task.getBaseFlags(),
                task.isHandleCovariantReturn());
    }

    Method getMethod(Method method, WeavingTask task) {
        return getMethod(method.getName(), method.getSignature(), task.getBaseFlags(),
                task.isHandleCovariantReturn());
    }

    // same as above but specifically request a static/non-static method
    public synchronized Method getMethod(String name, String desc, boolean allowCovariantReturn, boolean isStatic) {
        parseBytecode();
        String methodKey = getMethodKey(name, desc);
        Method method = methods.get(methodKey);
        if (!allowCovariantReturn && method != null && !method.getSignature().equals(desc))
            method = null; // don't use this
        if (method == null) {
            // class was not yet loaded
            method = new Method(name, desc);
            method.setStatic(isStatic);
            methods.put(methodKey, method);
        }
        assert method.isStatic() == isStatic : "Mismatching static/non-static methods " + getName() + '.' + name
                + desc;
        return method;
    }

    public synchronized Field getField(String name, String desc) {
        parseBytecode();
        Field field = fields.get(name);
        if (field == null) {
            // class was not yet loaded
            field = new Field(name, desc);
            fields.put(name, field);
        }
        return field;
    }

    public String getMethodIdentifier(IMethod method) {
        return getId() + method.getName() + method.getSignature();
    }

    /**
     * Adds a subclass to this class
     * @param subclass
     */
    protected void addSubclass(AbstractBoundClass subclass) {
        subclasses.put(subclass, null);
    }

    /**
     * Remove subclass from this class. It's only needed
     * to remove a anonymous subclass, if a real subclass is loaded
     * @param subclass
     */
    protected void removeSubclass(AbstractBoundClass subclass) {
        subclasses.remove(subclass);
    }

    /**
     * Returns all subclasses of this class, 
     * including the anonymous subclass
     * @return
     */
    private Collection<AbstractBoundClass> getSubclasses() {
        return subclasses.keySet();
    }

    /**
     * Handle all open weaving tasks for this class.
     * It redefines the class, if it is not called while loading
     */
    public synchronized void handleTaskList() {
        Set<Map.Entry<Method, WeavingTask>> bindingEntrySet = openBindingTasks.entrySet();

        Set<Map.Entry<Member, WeavingTask>> accessEntrySet = openAccessTasks.entrySet();

        // Are there not handled callin or decapsulation bindings 
        // for this class
        if (bindingEntrySet.size() > 0 || accessEntrySet.size() > 0) {
            // Yes, so start the transformation, parse the bytecode
            // and do load time transforming, if this method is called
            // at load time
            startTransformation();
            parseBytecode();
            prepareAsPossibleBaseClass();
            prepareTeamActivation();
            prepareLiftingParticipant();
        } else if (isFirstTransformation()) {
            // No, so only do load time transforming, if this method is called
            // at load time
            startTransformation();
            prepareAsPossibleBaseClass();
            prepareTeamActivation();
            prepareLiftingParticipant();
            endTransformation();
        }

        for (Map.Entry<Method, WeavingTask> entry : bindingEntrySet) {
            WeavingTask task = entry.getValue();
            Method method = entry.getKey();
            switch (task.getType()) {
            // Weave callin binding to a method of a subclass, that is not implemented
            // in the subclass
            case WEAVE_BINDING_OF_SUBCLASS:
                // Is the method implemented in this class?
                if (method.isImplemented()) {
                    // Yes, so weave this class
                    weaveBindingOfSubclass(task);
                } else {
                    //No, so just delegate the weaving task to the superclass
                    AbstractBoundClass superclass = getSuperclass();
                    // If superclass is null, her is something wrong
                    if (superclass != null) {
                        superclass.addWeavingTask(task);
                        weaveSuperCallInCallOrig(task); // ensure we're actually calling that super version
                    }
                }
                break;
            // Weave callin binding to a method of this class
            case WEAVE_BINDING:
                if (method.isStatic()) {
                    weaveBindingInStaticMethod(task);
                } else {
                    // Is the method implemented in this class?
                    if (method.isImplemented()) {
                        // So redefine the method
                        weaveBindingInImplementedMethod(task);
                    } else {
                        //No, so weave this class and delegate to the super class
                        weaveBindingInNotImplementedMethod(task);
                        AbstractBoundClass superclass = getSuperclass();
                        Method superMethod = superclass.getMethod(method, task);
                        WeavingTask newTask = new WeavingTask(WeavingTaskType.WEAVE_BINDING_OF_SUBCLASS,
                                superMethod, task);
                        superclass.addWeavingTask(newTask);
                    }

                    // Original comment:
                    //   If this method is private, the callin binding is not
                    //   inherited by the subclasses
                    // However, this conflicts with test415_nonexistingBaseMethod3i,
                    // where an empty callAllBindings() was overriding a non-empty one.
                    // see also Method.getId()
                    //               if (!method.isPrivate()) {
                    // Delegate the WeavingTask to the subclasses
                    for (AbstractBoundClass subclass : getSubclasses()) {
                        Method subMethod = subclass.getMethod(method, task);
                        WeavingTask newTask = new WeavingTask(WeavingTaskType.WEAVE_INHERITED_BINDING, subMethod,
                                task);
                        subclass.addWeavingTask(newTask);
                        TeamManager.mergeJoinpoints(this, subclass, method, subMethod,
                                task.isHandleCovariantReturn());
                    }
                    //               }
                }
                break;
            // Weave Binding inherited from the superclass
            case WEAVE_INHERITED_BINDING:
                if (method.isImplemented()) {
                    weaveBindingInImplementedMethod(task);
                } else {
                    weaveBindingInNotImplementedMethod(task);
                }

                // Delegate the WeavingTask to the subclasses
                for (AbstractBoundClass subclass : getSubclasses()) {
                    Method subMethod = subclass.getMethod(method, task);
                    WeavingTask newTask = new WeavingTask(WeavingTaskType.WEAVE_INHERITED_BINDING, subMethod, task);
                    subclass.addWeavingTask(newTask);
                    TeamManager.mergeJoinpoints(this, subclass, method, subMethod, task.isHandleCovariantReturn());
                }

                break;
            }

            // Mark all WeavingTasks for callin bindings 
            // as completed
            completedBindingTasks.put(method, task);
        }

        //handle all WeavinTasks for decapsulation bindings
        for (Map.Entry<Member, WeavingTask> entry : accessEntrySet) {
            WeavingTask task = entry.getValue();
            Member member = entry.getKey();

            switch (task.getType()) {
            // handle decapsulation binding to a field
            case WEAVE_FIELD_ACCESS:
                prepareForFirstMemberAccess();
                Field field = getField(task.getMemberName(), task.getMemberSignature());
                weaveFieldAccess(field, field.getGlobalId(this));
                if (!field.isStatic()) {
                    // If the field is not static it could be accessed through a subclass
                    // so weave the subclass
                    for (AbstractBoundClass subclass : getSubclasses()) {
                        WeavingTask newTask = new WeavingTask(WeavingTaskType.WEAVE_INHERITED_MEMBER_ACCESS);
                        subclass.addWeavingTask(newTask);
                    }
                }
                break;
            // handle decaspulation binding to a method
            case WEAVE_METHOD_ACCESS:
                prepareForFirstMemberAccess();
                Method method = getMethod(task);
                weaveMethodAccess(method, method.getGlobalId(this));
                if (!method.isStatic()) {
                    // If the method is not static it could be accessed through a subclass
                    // so weave the subclass
                    for (AbstractBoundClass subclass : getSubclasses()) {
                        WeavingTask newTask = new WeavingTask(WeavingTaskType.WEAVE_INHERITED_MEMBER_ACCESS);
                        subclass.addWeavingTask(newTask);
                    }
                }
                break;
            case WEAVE_INHERITED_MEMBER_ACCESS:
                prepareForFirstMemberAccess();
                break;
            case WEAVE_BASE_INFRASTRUCTURE:
                prepareForFirstTransformation();
                break;
            }

            // Mark all WeavingTasks for decapsulation bindings 
            // as completed
            completedAccessTasks.put(member, task);
        }
        if (openBindingTasks.size() > 0 || openAccessTasks.size() > 0) {
            // Weave the class, if the method is not called at load time
            endTransformation();
        }
        openBindingTasks.clear();
        openAccessTasks.clear();
    }

    public void handleAddingOfBinding(IBinding binding) {
        WeavingTaskType type = null;
        WeavingTask task = null;
        switch (binding.getType()) {
        case CALLIN_BINDING:
            type = WeavingTaskType.WEAVE_BINDING;
            break;
        case FIELD_ACCESS:
            type = WeavingTaskType.WEAVE_FIELD_ACCESS;
            break;
        case METHOD_ACCESS:
            type = WeavingTaskType.WEAVE_METHOD_ACCESS;
            break;
        case ROLE_BASE_BINDING:
            task = new WeavingTask(WeavingTaskType.WEAVE_BASE_INFRASTRUCTURE);
            break;
        default:
            throw new RuntimeException("Unknown binding type: " + binding.getType().name());
        }
        // TODO: once needed for test4141_dangerousCallinBinding3, but no longer.
        // Instead it causes the need to redefine classes in OT/Equinox, hence disabled.
        //      if (   binding.getType() == IBinding.BindingType.CALLIN_BINDING 
        //         && !binding.getBoundClass().equals(binding.getDeclaringBaseClassName()))
        //         try {
        //            // need to load the declaring base class outside the transform() callback:
        //            this.loader.loadClass(binding.getDeclaringBaseClassName().replace('/', '.'));
        //         } catch (ClassNotFoundException e) {
        //            throw new NoClassDefFoundError(e.getMessage());
        //         }
        if (task == null)
            task = new WeavingTask(type, binding.getMemberName(), binding.getMemberSignature(),
                    binding.getBaseFlags(), binding.isHandleCovariantReturn());
        addWeavingTask(task);
    }

    private void addWeavingTask(WeavingTask task) {
        boolean isNewTask = addWeavingTaskLazy(task);

        if (this.isLoaded && isNewTask) {
            handleTaskList();
        }
    }

    private boolean addWeavingTaskLazy(WeavingTask task) {
        WeavingTaskType type = task.getType();
        boolean isNewTask = false;
        if (type == WeavingTaskType.WEAVE_BINDING || type == WeavingTaskType.WEAVE_BINDING_OF_SUBCLASS
                || type == WeavingTaskType.WEAVE_INHERITED_BINDING) {
            isNewTask = addBindingWeavingTask(task);
        } else {
            isNewTask = addAccessWeavingTask(task);
        }

        return isNewTask;
    }

    /**
     * Handle a new WeavingTask for decapsulation and 
     * figures out if weaving is needed for this task 
     * @param task
     * @return
     */
    private boolean addAccessWeavingTask(WeavingTask task) {
        WeavingTaskType type = task.getType();
        Member member = null;
        switch (type) {
        case WEAVE_FIELD_ACCESS:
            member = getField(task.getMemberName(), task.getMemberSignature());
            break;
        case WEAVE_METHOD_ACCESS:
            member = getMethod(task);
            break;
        case WEAVE_INHERITED_MEMBER_ACCESS:
        case WEAVE_BASE_INFRASTRUCTURE:
            openAccessTasks.put(null, task);
            return true;
        }

        synchronized (member) {
            WeavingTask prevTask = completedAccessTasks.get(member);
            // Is there a already completed task for the member?
            if (prevTask == null) {
                // No, so check the open tasks
                prevTask = openAccessTasks.get(member);
            }

            // Is there a open task for the member?
            if (prevTask == null) {
                // No, so weaving is needed
                openAccessTasks.put(member, task);
                return true;
            } else {
                //Yes, so weaving is not needed
                return false;
            }
        }
    }

    /**
     * Handle a new WeavingTask for a callin binding and 
     * figures out if weaving is needed for this task 
     * @param task
     * @return
     */
    private boolean addBindingWeavingTask(WeavingTask task) {
        Method method = getMethod(task);
        synchronized (method) {
            WeavingTask prevTask = completedBindingTasks.get(method);
            // Is there a already completed task for the method?
            if (prevTask == null) {
                // No, so check the open tasks
                prevTask = openBindingTasks.get(method);
            }

            // Is there a open task for the member?
            if (prevTask == null) {
                //No, so weaving is needed
                task.setDoAllTransformations(true);
                openBindingTasks.put(method, task);
                return true;
            }

            switch (prevTask.getType()) {
            case WEAVE_BINDING:
                return false;
            case WEAVE_BINDING_OF_SUBCLASS:
                // In  this case only the callAllBings was redefined.
                if (task.getType() != WeavingTaskType.WEAVE_BINDING_OF_SUBCLASS) {
                    // Do the other transformations, if the new WeavingTask is not the same
                    // as already existing
                    openBindingTasks.put(method, task);
                    return true;
                }
                return false;
            case WEAVE_INHERITED_BINDING:
                return false;
            default:
                throw new RuntimeException("Unknown WeavingTaskType: " + prevTask.getType().name());
            }
        }
    }

    /**
     * Merge tasks of two AbstractBoundClasses (this class and a other).
     * This method is called if a currently loaded has to be merged 
     * with a anonymous subclass
     * @param clazz
     * @return
     */
    protected boolean mergeTasks(AbstractBoundClass clazz) {
        boolean isNewTask = false;
        for (Map.Entry<Method, WeavingTask> entry : clazz.openBindingTasks.entrySet()) {
            isNewTask |= addWeavingTaskLazy(entry.getValue());
        }

        for (Map.Entry<Member, WeavingTask> entry : clazz.openAccessTasks.entrySet()) {
            isNewTask |= addWeavingTaskLazy(entry.getValue());
        }

        return isNewTask;
    }

    private void weaveBindingInStaticMethod(WeavingTask task) {
        prepareForFirstStaticTransformation();
        Method method = getMethod(task);
        int joinpointId = TeamManager.getJoinpointId(getMethodIdentifier(method));
        int boundMethodId = method.getGlobalId(this);

        moveCodeToCallOrig(method, boundMethodId);
        createDispatchCodeInOrgMethod(method, joinpointId, boundMethodId);
    }

    /**
     * Do all transformations for a method, that is not implemented
     * in this class
     * @param task
     */
    private void weaveBindingInNotImplementedMethod(WeavingTask task) {
        if ((task.getBaseFlags() & IBinding.STATIC_BASE) == 0)
            prepareForFirstTransformation();
        else
            prepareForFirstStaticTransformation();

        Method method = getMethod(task);
        int joinpointId = TeamManager.getJoinpointId(getMethodIdentifier(method));
        int boundMethodId = method.getGlobalId(this);
        if (task.doAllTransformations()) {
            createDispatchCodeInCallAllBindings(joinpointId, boundMethodId);
            // TODO(SH): instead of iterating superclasses fetch it from the Binding
            boolean isWeavable = true; // weavable unless we find it to be declared in an unweavable super
            AbstractBoundClass superClass = getSuperclass();
            while (superClass != null) {
                if (superClass.isJavaLangObject()) {
                    isWeavable = false;
                    break;
                }
                Method superMethod = superClass.getMethod(task);
                if (superMethod.isImplemented()) {
                    isWeavable = ObjectTeamsTransformer.isWeavable(superClass.getInternalName());
                    break;
                }
                superClass = superClass.getSuperclass();
            }
            if (isWeavable)
                createSuperCallInCallOrig(boundMethodId);
            else
                // can't weave into the declaring class, add an override here:
                createCallAllBindingsCallInOrgMethod(method, boundMethodId, true/*needToAddMethod*/);
        } else {
            createDispatchCodeInCallAllBindings(joinpointId, boundMethodId);
        }
    }

    /** 
     * While delegating a task from a sub class to the super class,
      * ensure that the super version is actually called.
     */
    private void weaveSuperCallInCallOrig(WeavingTask task) {
        prepareForFirstTransformation();
        Method method = getMethod(task);
        int boundMethodId = method.getGlobalId(this);
        if (task.doAllTransformations()) {
            createSuperCallInCallOrig(boundMethodId);
        }
    }

    /**
     * Do all transformations for a method, that is implemented
     * in this class
     * @param task
     */
    private void weaveBindingInImplementedMethod(WeavingTask task) {
        prepareForFirstTransformation();
        Method method = getMethod(task);
        int joinpointId = TeamManager.getJoinpointId(getMethodIdentifier(method));
        int boundMethodId = method.getGlobalId(this);
        if (task.doAllTransformations()) {
            moveCodeToCallOrig(method, boundMethodId);
            createDispatchCodeInCallAllBindings(joinpointId, boundMethodId);
            createCallAllBindingsCallInOrgMethod(method, boundMethodId, false);
        } else {
            createDispatchCodeInCallAllBindings(joinpointId, joinpointId);
        }
    }

    /**
     * Do all transformations for a method, that is bound 
     * but not implemented in a subclass
     * @param task
     */
    private void weaveBindingOfSubclass(WeavingTask task) {
        prepareForFirstTransformation();
        Method method = getMethod(task);
        int boundMethodId = method.getGlobalId(this);
        moveCodeToCallOrig(method, boundMethodId);
        createCallAllBindingsCallInOrgMethod(method, boundMethodId, false);

    }

    @Override
    public String toString() {
        return this.name + "[" + this.id + "]";
    }

    // See AsmBoundClass or AsmWritableBoundClass for documentation

    protected abstract void startTransformation();

    protected abstract void endTransformation();

    protected abstract void prepareAsPossibleBaseClass();

    protected abstract void prepareTeamActivation();

    protected abstract void prepareLiftingParticipant();

    protected abstract void createSuperCallInCallOrig(int boundMethodId);

    protected abstract void createCallAllBindingsCallInOrgMethod(Method boundMethod, int joinpointId,
            boolean needToAddMethod);

    protected abstract void createDispatchCodeInCallAllBindings(int joinpointId, int boundMethodId);

    protected abstract void moveCodeToCallOrig(Method boundMethod, int boundMethodId);

    protected abstract void prepareForFirstTransformation();

    protected abstract void prepareForFirstStaticTransformation();

    public abstract boolean isFirstTransformation();

    protected abstract void createDispatchCodeInOrgMethod(Method boundMethod, int joinpointId, int boundMethodId);

    protected abstract void prepareForFirstMemberAccess();

    protected abstract void weaveFieldAccess(Field field, int accessId);

    protected abstract void weaveMethodAccess(Method method, int accessId);

    public abstract boolean isTransformationActive();

    public abstract byte[] getBytecode();

    public void dump(byte[] classfileBuffer, String postfix) {
    }

    public Collection<String> getBoundBaseClasses() {
        return null;
    }

    public abstract int compare(String callinLabel1, String callinLabel2);

    public void addWiringTask(ISubclassWiringTask wiringTask) {
        if (this.wiringTasks == null)
            this.wiringTasks = new ArrayList<ISubclassWiringTask>();
        this.wiringTasks.add(wiringTask);
    }

    public void performWiringTasks(AbstractBoundClass superclass, AbstractBoundClass subclass) {
        if (this.wiringTasks == null)
            return;
        synchronized (this.wiringTasks) {
            for (ISubclassWiringTask task : this.wiringTasks)
                task.wire(superclass, subclass);
            this.wiringTasks.clear();
        }
    }
}