org.robovm.compiler.AttributesEncoder Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 RoboVM AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.robovm.compiler;
import static org.robovm.compiler.Types.*;
import static org.robovm.compiler.llvm.Type.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.robovm.compiler.llvm.ArrayConstant;
import org.robovm.compiler.llvm.ArrayType;
import org.robovm.compiler.llvm.Constant;
import org.robovm.compiler.llvm.FloatingPointConstant;
import org.robovm.compiler.llvm.Global;
import org.robovm.compiler.llvm.IntegerConstant;
import org.robovm.compiler.llvm.Linkage;
import org.robovm.compiler.llvm.StructureConstant;
import org.robovm.compiler.llvm.StructureType;
import org.robovm.compiler.llvm.StructureConstant;
import org.robovm.compiler.llvm.Type;
import org.robovm.compiler.llvm.Value;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.tagkit.AnnotationAnnotationElem;
import soot.tagkit.AnnotationArrayElem;
import soot.tagkit.AnnotationClassElem;
import soot.tagkit.AnnotationConstants;
import soot.tagkit.AnnotationDefaultTag;
import soot.tagkit.AnnotationDoubleElem;
import soot.tagkit.AnnotationElem;
import soot.tagkit.AnnotationEnumElem;
import soot.tagkit.AnnotationFloatElem;
import soot.tagkit.AnnotationIntElem;
import soot.tagkit.AnnotationLongElem;
import soot.tagkit.AnnotationStringElem;
import soot.tagkit.AnnotationTag;
import soot.tagkit.EnclosingMethodTag;
import soot.tagkit.Host;
import soot.tagkit.InnerClassTag;
import soot.tagkit.SignatureTag;
import soot.tagkit.SourceFileTag;
import soot.tagkit.Tag;
import soot.tagkit.VisibilityAnnotationTag;
import soot.tagkit.VisibilityParameterAnnotationTag;
/**
*
*
* @author niklas
*
*/
public class AttributesEncoder {
private static final byte SOURCE_FILE = 1;
private static final byte SIGNATURE = 2;
private static final byte INNER_CLASS = 3;
private static final byte ENCLOSING_METHOD = 4;
private static final byte EXCEPTIONS = 5;
private static final byte RUNTIME_VISIBLE_ANNOTATIONS = 6;
private static final byte RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = 7;
private static final byte ANNOTATION_DEFAULT = 8;
/*
* TODO: Generic signatures may contain class names which should be added to dependencies.
*/
private ModuleBuilder mb;
private Set dependencies;
private Global classAttributes;
private Map fieldAttributes;
private Map methodAttributes;
public void encode(ModuleBuilder mb, SootClass sootClass) {
this.mb = mb;
dependencies = new HashSet<>();
classAttributes = null;
fieldAttributes = new HashMap<>();
methodAttributes = new HashMap<>();
encodeAttributes(sootClass);
Constant classAttributes = encodeAttributes(sootClass);
if (classAttributes != null) {
Global g = new Global(Symbols.classAttributesSymbol(sootClass), Linkage._private, classAttributes, true);
mb.addGlobal(g);
this.classAttributes = g;
}
for (SootField field : sootClass.getFields()) {
Constant fieldAttributes = encodeAttributes(field);
if (fieldAttributes != null) {
Global g = new Global(Symbols.fieldAttributesSymbol(field), Linkage._private, fieldAttributes, true);
mb.addGlobal(g);
this.fieldAttributes.put(field, g);
}
}
for (SootMethod method : sootClass.getMethods()) {
Constant methodAttributes = encodeAttributes(method);
if (methodAttributes != null) {
Global g = new Global(Symbols.methodAttributesSymbol(method), Linkage._private, methodAttributes, true);
mb.addGlobal(g);
this.methodAttributes.put(method, g);
}
}
}
public Set getDependencies() {
return dependencies;
}
public boolean classHasAttributes() {
return classAttributes != null;
}
public Global getClassAttributes() {
return classAttributes;
}
public boolean fieldHasAttributes(SootField f) {
return fieldAttributes.containsKey(f);
}
public Global getFieldAttributes(SootField f) {
return fieldAttributes.get(f);
}
public boolean methodHasAttributes(SootMethod m) {
return methodAttributes.containsKey(m);
}
public Global getMethodAttributes(SootMethod m) {
return methodAttributes.get(m);
}
private StructureType getAnnotationElementType(AnnotationElem ae) {
if (ae instanceof AnnotationIntElem) {
return new StructureType(I8, I32);
} else if (ae instanceof AnnotationLongElem) {
return new StructureType(I8, I64);
} else if (ae instanceof AnnotationFloatElem) {
return new StructureType(I8, FLOAT);
} else if (ae instanceof AnnotationDoubleElem) {
return new StructureType(I8, DOUBLE);
} else if (ae instanceof AnnotationStringElem) {
return new StructureType(I8, I8_PTR);
} else if (ae instanceof AnnotationClassElem) {
return new StructureType(I8, I8_PTR);
} else if (ae instanceof AnnotationEnumElem) {
return new StructureType(I8, I8_PTR, I8_PTR);
} else if (ae instanceof AnnotationArrayElem) {
AnnotationArrayElem aae = (AnnotationArrayElem) ae;
Type[] types = new Type[aae.getNumValues() + 2];
types[0] = I8;
types[1] = I16;
for (int i = 0; i < aae.getNumValues(); i++) {
types[i + 2] = getAnnotationElementType(aae.getValueAt(i));
}
return new StructureType(types);
} else if (ae instanceof AnnotationAnnotationElem) {
AnnotationAnnotationElem aae = (AnnotationAnnotationElem) ae;
return new StructureType(I8, getAnnotationTagType(aae.getValue()));
}
throw new IllegalArgumentException("Unknown AnnotationElem type: " + ae.getClass());
}
private StructureConstant encodeAnnotationElementValue(AnnotationElem ae) {
StructureType type = getAnnotationElementType(ae);
Value kind = new IntegerConstant((byte) ae.getKind());
if (ae instanceof AnnotationIntElem) {
AnnotationIntElem aie = (AnnotationIntElem) ae;
return new StructureConstant(type, kind,
new IntegerConstant(aie.getValue()));
} else if (ae instanceof AnnotationLongElem) {
AnnotationLongElem ale = (AnnotationLongElem) ae;
return new StructureConstant(type, kind,
new IntegerConstant(ale.getValue()));
} else if (ae instanceof AnnotationFloatElem) {
AnnotationFloatElem afe = (AnnotationFloatElem) ae;
return new StructureConstant(type, kind,
new FloatingPointConstant(afe.getValue()));
} else if (ae instanceof AnnotationDoubleElem) {
AnnotationDoubleElem ade = (AnnotationDoubleElem) ae;
return new StructureConstant(type, kind,
new FloatingPointConstant(ade.getValue()));
} else if (ae instanceof AnnotationStringElem) {
AnnotationStringElem ase = (AnnotationStringElem) ae;
return new StructureConstant(type, kind,
getStringOrNull(ase.getValue()));
} else if (ae instanceof AnnotationClassElem) {
AnnotationClassElem ace = (AnnotationClassElem) ae;
addDependencyIfNeeded(ace.getDesc());
return new StructureConstant(type, kind,
getStringOrNull(ace.getDesc()));
} else if (ae instanceof AnnotationEnumElem) {
AnnotationEnumElem aee = (AnnotationEnumElem) ae;
addDependencyIfNeeded(aee.getTypeName());
return new StructureConstant(type, kind,
getStringOrNull(aee.getTypeName()),
getStringOrNull(aee.getConstantName()));
} else if (ae instanceof AnnotationArrayElem) {
AnnotationArrayElem aae = (AnnotationArrayElem) ae;
Value[] values = new Value[aae.getNumValues() + 2];
values[0] = kind;
values[1] = new IntegerConstant((char) aae.getNumValues());
for (int i = 0; i < aae.getNumValues(); i++) {
values[i + 2] = encodeAnnotationElementValue(aae.getValueAt(i));
}
return new StructureConstant(type, values);
} else if (ae instanceof AnnotationAnnotationElem) {
AnnotationAnnotationElem aae = (AnnotationAnnotationElem) ae;
return new StructureConstant(type, kind, encodeAnnotationTagValue(aae.getValue()));
}
throw new IllegalArgumentException("Unknown AnnotationElem type: " + ae.getClass());
}
private StructureType getAnnotationTagType(AnnotationTag tag) {
Type[] types = new Type[tag.getNumElems() * 2 + 2];
types[0] = I8_PTR;
types[1] = I32;
for (int i = 0; i < tag.getNumElems(); i++) {
types[i * 2 + 2] = I8_PTR;
types[i * 2 + 2 + 1] = getAnnotationElementType(tag.getElemAt(i));
}
return new StructureType(types);
}
private StructureConstant encodeAnnotationTagValue(AnnotationTag tag) {
Value[] values = new Value[tag.getNumElems() * 2 + 2];
values[0] = getString(tag.getType());
addDependencyIfNeeded(tag.getType());
values[1] = new IntegerConstant(tag.getNumElems());
for (int i = 0; i < tag.getNumElems(); i++) {
values[i * 2 + 2] = getString(tag.getElemAt(i).getName());
values[i * 2 + 2 + 1] = encodeAnnotationElementValue(tag.getElemAt(i));
}
return new StructureConstant(getAnnotationTagType(tag), values);
}
private Constant encodeAttributes(Host host) {
List attributes = new ArrayList<>();
for (Tag tag : host.getTags()) {
if (tag instanceof SourceFileTag) {
// Skip. We don't need this at this time.
Value sourceFile = getString(((SourceFileTag) tag).getSourceFile());
attributes.add(new StructureConstant(new StructureType(I8, I8_PTR),
new IntegerConstant(SOURCE_FILE), sourceFile));
} else if (tag instanceof EnclosingMethodTag) {
EnclosingMethodTag emt = (EnclosingMethodTag) tag;
Value eClass = getString(emt.getEnclosingClass());
Value eMethod = getStringOrNull(emt.getEnclosingMethod());
Value eDesc = getStringOrNull(emt.getEnclosingMethodSig());
attributes.add(new StructureConstant(new StructureType(I8, I8_PTR, I8_PTR, I8_PTR),
new IntegerConstant(ENCLOSING_METHOD), eClass, eMethod, eDesc));
} else if (tag instanceof SignatureTag) {
Value signature = getString(((SignatureTag) tag).getSignature());
attributes.add(new StructureConstant(new StructureType(I8, I8_PTR),
new IntegerConstant(SIGNATURE), signature));
} else if (tag instanceof InnerClassTag) {
InnerClassTag ict = (InnerClassTag) tag;
Value innerClass = getStringOrNull(ict.getInnerClass());
Value outerClass = getStringOrNull(ict.getOuterClass());
Value innerName = getStringOrNull(ict.getShortName());
Value innerClassAccess = new IntegerConstant(ict.getAccessFlags());
attributes.add(new StructureConstant(new StructureType(I8, I8_PTR, I8_PTR, I8_PTR, I32),
new IntegerConstant(INNER_CLASS), innerClass, outerClass, innerName, innerClassAccess));
} else if (tag instanceof AnnotationDefaultTag) {
StructureConstant value = encodeAnnotationElementValue(((AnnotationDefaultTag) tag).getDefaultVal());
attributes.add(new StructureConstant(new StructureType(I8, value.getType()),
new IntegerConstant(ANNOTATION_DEFAULT), value));
} else if (tag instanceof VisibilityAnnotationTag) {
VisibilityAnnotationTag vat = (VisibilityAnnotationTag) tag;
if (vat.getVisibility() == AnnotationConstants.RUNTIME_VISIBLE) {
Type[] types = new Type[vat.getAnnotations().size()];
Value[] values = new Value[vat.getAnnotations().size()];
int i = 0;
for (AnnotationTag at : vat.getAnnotations()) {
values[i] = encodeAnnotationTagValue(at);
types[i] = values[i].getType();
i++;
}
attributes.add(new StructureConstant(new StructureType(I8, I32, new StructureType(types)),
new IntegerConstant(RUNTIME_VISIBLE_ANNOTATIONS), new IntegerConstant(vat.getAnnotations().size()),
new StructureConstant(new StructureType(types), values)));
}
} else if (tag instanceof VisibilityParameterAnnotationTag) {
VisibilityParameterAnnotationTag vpat = (VisibilityParameterAnnotationTag) tag;
List typesList = new ArrayList<>();
List valuesList = new ArrayList<>();
boolean hasRuntimeVisible = false;
for (VisibilityAnnotationTag vat : vpat.getVisibilityAnnotations()) {
typesList.add(I32);
if (vat.getVisibility() == AnnotationConstants.RUNTIME_VISIBLE
&& vat.getAnnotations() != null && !vat.getAnnotations().isEmpty()) {
hasRuntimeVisible = true;
valuesList.add(new IntegerConstant(vat.getAnnotations().size()));
for (AnnotationTag at : vat.getAnnotations()) {
StructureConstant value = encodeAnnotationTagValue(at);
valuesList.add(value);
typesList.add(value.getType());
}
} else {
valuesList.add(new IntegerConstant(0));
}
}
if (hasRuntimeVisible) {
Type[] types = typesList.toArray(new Type[0]);
Value[] values = valuesList.toArray(new Value[0]);
attributes.add(new StructureConstant(new StructureType(I8, I32, new StructureType(types)),
new IntegerConstant(RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), new IntegerConstant(vpat.getVisibilityAnnotations().size()),
new StructureConstant(new StructureType(types), values)));
}
}
}
if (host instanceof SootMethod) {
List exceptions = ((SootMethod) host).getExceptions();
if (!exceptions.isEmpty()) {
Value[] values = new Value[exceptions.size()];
for (int i = 0; i < exceptions.size(); i++) {
String exName = getInternalName(exceptions.get(i));
values[i] = getString(exName);
addDependency(exName);
}
attributes.add(new StructureConstant(new StructureType(I8, I32, new ArrayType(exceptions.size(), I8_PTR)),
new IntegerConstant(EXCEPTIONS), new IntegerConstant(exceptions.size()),
new ArrayConstant(new ArrayType(exceptions.size(), I8_PTR), values)));
}
}
if (attributes.isEmpty()) {
return null;
}
attributes.add(0, new IntegerConstant(attributes.size()));
Type[] types = new Type[attributes.size()];
for (int i = 0; i < types.length; i++) {
types[i] = attributes.get(i).getType();
}
return new StructureConstant(new StructureType(types), attributes.toArray(new Value[0])).flatten();
}
private Constant getString(String string) {
return mb.getString(string);
}
private Constant getStringOrNull(String string) {
return mb.getStringOrNull(string);
}
private void addDependency(String internalName) {
dependencies.add(internalName);
}
private void addDependencyIfNeeded(String desc) {
if (desc == null || isPrimitive(desc) || isArray(desc) && isPrimitiveBaseType(desc)) {
return;
}
if (isArray(desc)) {
dependencies.add(getBaseType(desc));
} else {
dependencies.add(getInternalNameFromDescriptor(desc));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy