blob: 5d56ae3ff29b4221f41c2c848d06ced6aa86d3f2 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Dynamic Runtime Environment"
*
* Copyright 2009, 2016 Oliver Frank and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0 *
* 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 org.eclipse.objectteams.otredyn.runtime.IBinding;
/**
* This class represents a callin or decapsulation binding
* @author Oliver Frank
*/
public class Binding implements Comparable<Binding>, IBinding {
/** The callin modifier 'before' */
public static final int BEFORE = 1;
/** The callin modifier 'replace' */
public static final int REPLACE = 2;
/** The callin modifier 'after' */
public static final int AFTER = 3;
AbstractBoundClass teamClass;
private String callinLabel;
private String boundClass;
private String memberName;
private String memberSignature;
private String weavableBaseClassName;
private int callinModifier;
/**
* Locally unique id for (an element in) this binding:
* For CALLIN_BINDING this is the callinId,
* for METHOD_ACCESS or FIELD_ACCESS it is the perTeamAccessId
*/
private int perTeamId;
private int baseFlags;
private IBinding.BindingType type;
private boolean isHandleCovariantReturn;
private boolean requireBaseSuperCall;
public IBinding.BindingType getType() {
return type;
}
/**
* Create a callin binding.
*/
public Binding(AbstractBoundClass teamClass,
String roleClassName, String callinLabel, String boundClassName,
String memberName, String memberSignature, String weavableBaseClassName,
int callinModifier, int callinId, int baseFlags, boolean handleCovariantReturn, boolean requireBaseSuperCall)
{
this.teamClass = teamClass;
this.callinLabel = callinLabel;
this.boundClass = boundClassName;
this.memberName = memberName;
this.memberSignature = memberSignature;
this.weavableBaseClassName = weavableBaseClassName;
this.callinModifier = callinModifier;
this.perTeamId = callinId;
this.baseFlags = baseFlags;
this.type = IBinding.BindingType.CALLIN_BINDING;
this.isHandleCovariantReturn = handleCovariantReturn;
this.requireBaseSuperCall = requireBaseSuperCall;
}
/**
* Create a method or field access binding (decapsulation).
*/
public Binding(AbstractBoundClass teamClass,
String boundClassName,
String memberName, String memberSignature, int perTeamAccessId, IBinding.BindingType type)
{
this.teamClass = teamClass;
this.boundClass = boundClassName;
this.memberName = memberName;
this.memberSignature = memberSignature;
this.perTeamId = perTeamAccessId;
this.type = type;
}
/** Create a binding for a role base binding to trigger generating _OT$addRemoveRole. */
public Binding(AbstractBoundClass teamClass, String baseClassName) {
this.teamClass = teamClass;
this.boundClass = baseClassName;
this.type = IBinding.BindingType.ROLE_BASE_BINDING;
}
public String getBoundClass() {
return boundClass;
}
public String getMemberName() {
return memberName;
}
public String getMemberSignature() {
return memberSignature;
}
public int getBaseFlags() {
return baseFlags;
}
public int getPerTeamId() {
return perTeamId;
}
public boolean isHandleCovariantReturn() {
return this.isHandleCovariantReturn;
}
@Override
public boolean requiresBaseSuperCall() {
return this.requireBaseSuperCall;
}
public String getDeclaringBaseClassName() {
return this.weavableBaseClassName;
}
@Override
public boolean equals(Object obj) {
Binding other = (Binding) obj;
return boundClass.equals(other.boundClass)
&& memberName.equals(other.memberName)
&& memberSignature.equals(other.memberSignature)
&& type == other.type && perTeamId == other.perTeamId;
}
public int compareTo(Binding other) {
// ordering strategy for callin bindings:
// - first criterion: callinModifier: before/after have higher priority than replace.
// - second criterion: precedence (only relevant among callins of the same callin modifier).
// the set AbstractTeam.bindings is sorted low-to-high.
// then TeamManager.handleTeamStateChange processes all bindings from low-to-high
// inserting each at the front of the list of active teams, such that last added
// will indeed have highest priority, which is in line with ordering by activation time.
int compare = 0;
if (this.callinLabel == null || other.callinLabel == null) {
// at least one binding is a decaps binding
if (this.callinLabel != null)
return 1;
else if (other.callinLabel != null)
return -1;
} else {
if (this.callinModifier != other.callinModifier) {
// replace has lower priority than before/after:
if (this.callinModifier == REPLACE)
return -1;
else if (other.callinModifier == REPLACE)
return 1;
}
// the following comparison respects precedence:
compare = this.teamClass.compare(this.callinLabel, other.callinLabel);
if (compare != 0)
return compare;
}
if (this.baseFlags != other.baseFlags)
return Integer.valueOf(this.baseFlags).compareTo(other.baseFlags);
return (boundClass + memberName + memberSignature).compareTo(other.boundClass + other.memberName + other.memberSignature);
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
switch (this.type) {
case CALLIN_BINDING: buf.append("callin: ");break;
case METHOD_ACCESS: buf.append("callout: ");break;
case FIELD_ACCESS: buf.append("callout-to-field: ");break;
case ROLE_BASE_BINDING:
buf.append("playedBy: ").append(this.boundClass);
return buf.toString();
}
buf.append('{');
buf.append(this.perTeamId);
buf.append("} ");
buf.append(this.boundClass);
buf.append('.');
buf.append(this.memberName);
buf.append(this.memberSignature);
return buf.toString();
}
}