blob: 50041065629b153012f459bd28a4b2248488bdb7 [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.asm;
import java.util.HashSet;
import org.eclipse.objectteams.otredyn.bytecode.Binding;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinBindingsAttribute;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTClassFlagsAttribute;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.RoleBaseBindingsAttribute;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinBindingsAttribute.MultiBinding;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinPrecedenceAttribute;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTSpecialAccessAttribute;
import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTSpecialAccessAttribute.DecapsMethod;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import static org.eclipse.objectteams.otredyn.bytecode.asm.AsmBoundClass.ASM_API;
/**
* This class is used to parse the bytecode of a class.
* It sets the informations, that are parsed, in the {@link AsmBoundClass}
* @author Oliver Frank
*/
class AsmClassVisitor extends ClassVisitor {
private static boolean DEBUG_ATTRIBUTES = System.getProperty("otdre.debug.attributes") != null;
static final int CALLIN = 1;
static final int STATIC = 2;
static final int FINAL = 4;
private AsmBoundClass clazz;
public AsmClassVisitor(AsmBoundClass clazz) {
super(ASM_API);
this.clazz = clazz;
}
/**
* Parses common information about the class.
*/
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
clazz.setSuperClassName(superName);
clazz.setSuperInterfaces(interfaces);
clazz.setModifiers(access);
}
/**
* Parses the methods of the class
*/
@Override
public MethodVisitor visitMethod(int access, final String name, final String desc, String signature, String[] exceptions) {
clazz.addMethod(name, desc, (access & Opcodes.ACC_STATIC) != 0, (access & (Opcodes.ACC_PUBLIC|Opcodes.ACC_PROTECTED|Opcodes.ACC_PRIVATE)));
if (clazz.isTeam() || clazz.isRole())
// check for method annotation ImplicitTeamActivation:
return new MethodVisitor(this.api) {
@Override
public AnnotationVisitor visitAnnotation(String annDesc, boolean visible) {
if (annDesc.equals(AddImplicitActivationAdapter.ANNOTATION_IMPLICIT_ACTIVATION))
clazz.registerMethodForImplicitActivation(name+desc);
return super.visitAnnotation(annDesc, visible);
}
};
return super.visitMethod(access, name, desc, signature, exceptions);
}
/**
* Parses the fields of the class
*/
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
clazz.addField(name, desc, (access & Opcodes.ACC_STATIC) != 0, (access & (Opcodes.ACC_PUBLIC|Opcodes.ACC_PROTECTED|Opcodes.ACC_PRIVATE)));
return super.visitField(access, name, desc, signature, value);
}
/**
* Parses the class file attributes of a class.
* This is only needed, if the class is a team.
*/
@Override
public void visitAttribute(Attribute attribute) {
if (DEBUG_ATTRIBUTES) {
System.err.println("OTDRE: reading attribute of class "+this.clazz.getName());
System.err.println(attribute);
}
if (clazz.boundBaseClasses == null)
clazz.boundBaseClasses = new HashSet<>();
if (attribute.type == null) {
System.err.println("OTDRE: bytecode attribute in class "+this.clazz.getName()+" has no type "+attribute.getClass().getName());
return;
}
if (attribute.type.equals(Attributes.ATTRIBUTE_OT_DYN_CALLIN_BINDINGS)) {
CallinBindingsAttribute attr = (CallinBindingsAttribute) attribute;
MultiBinding[] multiBindings = attr.getBindings();
for (int i=multiBindings.length-1; i>=0; i--) { // reverse loop to ensure proper overwriting:
String roleClassName = multiBindings[i].getRoleClassName();
String callinLabel = multiBindings[i].getCallinLabel();
String baseClassName = multiBindings[i].getBaseClassName();
clazz.boundBaseClasses.add(baseClassName.replace('/', '.'));
String[] baseMethodNames = multiBindings[i].getBaseMethodNames();
String[] baseMethodSignatures = multiBindings[i].getBaseMethodSignatures();
String[] declaringBaseClassNames = multiBindings[i].getDeclaringBaseClassName();
int callinModifier = multiBindings[i].getCallinModifier();
int[] callinIds = multiBindings[i].getCallinIds();
int[] baseFlags = multiBindings[i].getBaseFlags();
boolean handleCovariantReturn = multiBindings[i].isHandleCovariantReturn();
boolean requireBaseSuperCall = multiBindings[i].requiresBaseSuperCall();
for (int j = 0; j < baseMethodNames.length; j++) {
String declaringBaseClassName = declaringBaseClassNames[j];
String weavableBaseClass = (baseFlags[j] & (STATIC | FINAL)) != 0 ? declaringBaseClassName : baseClassName;
Binding binding = new Binding(clazz, roleClassName, callinLabel, baseClassName,
baseMethodNames[j], baseMethodSignatures[j], weavableBaseClass,
callinModifier, callinIds[j], baseFlags[j], handleCovariantReturn, requireBaseSuperCall);
clazz.addBinding(binding);
clazz.boundBaseClasses.add(declaringBaseClassName.replace('/', '.'));
}
}
} else if (attribute.type.equals(Attributes.ATTRIBUTE_CALLIN_PRECEDENCE)) {
CallinPrecedenceAttribute attr = (CallinPrecedenceAttribute)attribute;
clazz.precedenceses.add(attr.labels);
} else if (attribute.type.equals(Attributes.ATTRIBUTE_OT_CLASS_FLAGS)) {
clazz.setOTClassFlags(((OTClassFlagsAttribute)attribute).flags);
} else if (attribute.type.equals(Attributes.ATTRIBUTE_OT_SPECIAL_ACCESS)) {
OTSpecialAccessAttribute accessAttribute = (OTSpecialAccessAttribute)attribute;
accessAttribute.registerAt(clazz);
for (DecapsMethod method : accessAttribute.methods) {
for (String weaveInto : method.weaveIntoClasses)
clazz.boundBaseClasses.add(weaveInto);
}
} else if (attribute.type.equals(Attributes.ATTRIBUTE_ROLE_BASE_BINDINGS)) {
for (String base : ((RoleBaseBindingsAttribute) attribute).bases) {
if (base.charAt(0) == '^')
base = base.substring(1);
clazz.boundBaseClasses.add(base.replace('/', '.'));
clazz.addBinding(new Binding(clazz, base));
}
}
}
/**
* check for class annotation ImplicitTeamActivation:
*/
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (desc.equals(AddImplicitActivationAdapter.ANNOTATION_IMPLICIT_ACTIVATION))
clazz.enableImplicitActivation();
return super.visitAnnotation(desc, visible);
}
}