You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
724 lines
27 KiB
724 lines
27 KiB
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with this
|
|
* work for additional information regarding copyright ownership. The ASF
|
|
* licenses this file to You under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
package org.apache.harmony.pack200;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
import org.apache.harmony.pack200.Archive.PackingFile;
|
|
import org.apache.harmony.pack200.Archive.SegmentUnit;
|
|
import org.objectweb.asm.AnnotationVisitor;
|
|
import org.objectweb.asm.Attribute;
|
|
import org.objectweb.asm.ClassReader;
|
|
import org.objectweb.asm.ClassVisitor;
|
|
import org.objectweb.asm.FieldVisitor;
|
|
import org.objectweb.asm.Label;
|
|
import org.objectweb.asm.MethodVisitor;
|
|
import org.objectweb.asm.Opcodes;
|
|
import org.objectweb.asm.Type;
|
|
|
|
/**
|
|
* A Pack200 archive consists of one or more Segments.
|
|
*/
|
|
public class Segment extends ClassVisitor {
|
|
|
|
private SegmentHeader segmentHeader;
|
|
private CpBands cpBands;
|
|
private AttributeDefinitionBands attributeDefinitionBands;
|
|
private IcBands icBands;
|
|
private ClassBands classBands;
|
|
private BcBands bcBands;
|
|
private FileBands fileBands;
|
|
|
|
private final SegmentFieldVisitor fieldVisitor = new SegmentFieldVisitor();
|
|
private final SegmentMethodVisitor methodVisitor = new SegmentMethodVisitor();
|
|
private Pack200ClassReader currentClassReader;
|
|
private PackingOptions options;
|
|
private boolean stripDebug;
|
|
private Attribute[] nonStandardAttributePrototypes;
|
|
|
|
public Segment() {
|
|
super(Opcodes.ASM9);
|
|
}
|
|
|
|
/**
|
|
* The main method on Segment. Reads in all the class files, packs them and
|
|
* then writes the packed segment out to the given OutputStream.
|
|
*
|
|
* @param classes
|
|
* List of Pack200ClassReaders, one for each class file in the
|
|
* segment
|
|
* @param files
|
|
* List of Archive.Files, one for each file in the segment
|
|
* @param out
|
|
* the OutputStream to write the packed Segment to
|
|
* @param options
|
|
* packing options
|
|
* @throws IOException
|
|
* @throws Pack200Exception
|
|
*/
|
|
public void pack(SegmentUnit segmentUnit, OutputStream out, PackingOptions options)
|
|
throws IOException, Pack200Exception {
|
|
this.options = options;
|
|
this.stripDebug = options.isStripDebug();
|
|
int effort = options.getEffort();
|
|
nonStandardAttributePrototypes = options.getUnknownAttributePrototypes();
|
|
|
|
PackingUtils.log("Start to pack a new segment with "
|
|
+ segmentUnit.fileListSize() + " files including "
|
|
+ segmentUnit.classListSize() + " classes");
|
|
|
|
PackingUtils.log("Initialize a header for the segment");
|
|
segmentHeader = new SegmentHeader();
|
|
segmentHeader.setFile_count(segmentUnit.fileListSize());
|
|
segmentHeader.setHave_all_code_flags(!stripDebug);
|
|
if (!options.isKeepDeflateHint()) {
|
|
segmentHeader.setDeflate_hint("true".equals(options
|
|
.getDeflateHint()));
|
|
}
|
|
|
|
PackingUtils.log("Setup constant pool bands for the segment");
|
|
cpBands = new CpBands(this, effort);
|
|
|
|
PackingUtils.log("Setup attribute definition bands for the segment");
|
|
attributeDefinitionBands = new AttributeDefinitionBands(this, effort, nonStandardAttributePrototypes);
|
|
|
|
PackingUtils.log("Setup internal class bands for the segment");
|
|
icBands = new IcBands(segmentHeader, cpBands, effort);
|
|
|
|
PackingUtils.log("Setup class bands for the segment");
|
|
classBands = new ClassBands(this, segmentUnit.classListSize(), effort, stripDebug);
|
|
|
|
PackingUtils.log("Setup byte code bands for the segment");
|
|
bcBands = new BcBands(cpBands, this, effort);
|
|
|
|
PackingUtils.log("Setup file bands for the segment");
|
|
fileBands = new FileBands(cpBands, segmentHeader, options, segmentUnit, effort);
|
|
|
|
processClasses(segmentUnit, nonStandardAttributePrototypes);
|
|
|
|
cpBands.finaliseBands();
|
|
attributeDefinitionBands.finaliseBands();
|
|
icBands.finaliseBands();
|
|
classBands.finaliseBands();
|
|
bcBands.finaliseBands();
|
|
fileBands.finaliseBands();
|
|
|
|
// Using a temporary stream because we have to pack the other bands
|
|
// before segmentHeader because the band_headers band is only created
|
|
// when the other bands are packed, but comes before them in the packed
|
|
// file.
|
|
ByteArrayOutputStream bandsOutputStream = new ByteArrayOutputStream();
|
|
|
|
PackingUtils.log("Packing...");
|
|
int finalNumberOfClasses = classBands.numClassesProcessed();
|
|
segmentHeader.setClass_count(finalNumberOfClasses);
|
|
cpBands.pack(bandsOutputStream);
|
|
if(finalNumberOfClasses > 0) {
|
|
attributeDefinitionBands.pack(bandsOutputStream);
|
|
icBands.pack(bandsOutputStream);
|
|
classBands.pack(bandsOutputStream);
|
|
bcBands.pack(bandsOutputStream);
|
|
}
|
|
fileBands.pack(bandsOutputStream);
|
|
|
|
ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream();
|
|
segmentHeader.pack(headerOutputStream);
|
|
|
|
headerOutputStream.writeTo(out);
|
|
bandsOutputStream.writeTo(out);
|
|
|
|
segmentUnit.addPackedByteAmount(headerOutputStream.size());
|
|
segmentUnit.addPackedByteAmount(bandsOutputStream.size());
|
|
|
|
PackingUtils.log("Wrote total of " + segmentUnit.getPackedByteAmount()
|
|
+ " bytes");
|
|
PackingUtils.log("Transmitted " + segmentUnit.fileListSize() + " files of "
|
|
+ segmentUnit.getByteAmount() + " input bytes in a segment of "
|
|
+ segmentUnit.getPackedByteAmount() + " bytes");
|
|
}
|
|
|
|
private void processClasses(SegmentUnit segmentUnit, Attribute[] attributes) throws Pack200Exception {
|
|
segmentHeader.setClass_count(segmentUnit.classListSize());
|
|
for (Iterator iterator = segmentUnit.getClassList().iterator(); iterator.hasNext();) {
|
|
Pack200ClassReader classReader = (Pack200ClassReader) iterator
|
|
.next();
|
|
currentClassReader = classReader;
|
|
int flags = 0;
|
|
if(stripDebug) {
|
|
flags |= ClassReader.SKIP_DEBUG;
|
|
}
|
|
try {
|
|
classReader.accept(this, attributes, flags);
|
|
} catch (PassException pe) {
|
|
// Pass this class through as-is rather than packing it
|
|
// TODO: probably need to deal with any inner classes
|
|
classBands.removeCurrentClass();
|
|
String name = classReader.getFileName();
|
|
options.addPassFile(name);
|
|
cpBands.addCPUtf8(name);
|
|
boolean found = false;
|
|
for (Iterator iterator2 = segmentUnit.getFileList().iterator(); iterator2
|
|
.hasNext();) {
|
|
PackingFile file = (PackingFile) iterator2.next();
|
|
if(file.getName().equals(name)) {
|
|
found = true;
|
|
file.setContents(classReader.b);
|
|
break;
|
|
}
|
|
}
|
|
if(!found) {
|
|
throw new Pack200Exception("Error passing file " + name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void visit(int version, int access, String name, String signature,
|
|
String superName, String[] interfaces) {
|
|
bcBands.setCurrentClass(name, superName);
|
|
segmentHeader.addMajorVersion(version);
|
|
classBands.addClass(version, access, name, signature, superName,
|
|
interfaces);
|
|
}
|
|
|
|
public void visitSource(String source, String debug) {
|
|
if(!stripDebug) {
|
|
classBands.addSourceFile(source);
|
|
}
|
|
}
|
|
|
|
public void visitOuterClass(String owner, String name, String desc) {
|
|
classBands.addEnclosingMethod(owner, name, desc);
|
|
|
|
}
|
|
|
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
|
return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_CLASS,
|
|
desc, visible);
|
|
}
|
|
|
|
public void visitAttribute(Attribute attribute) {
|
|
if(attribute.isUnknown()) {
|
|
String action = options.getUnknownAttributeAction();
|
|
if(action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
} else {
|
|
if(attribute instanceof NewAttribute) {
|
|
NewAttribute newAttribute = (NewAttribute) attribute;
|
|
if(newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CLASS)) {
|
|
String action = options.getUnknownClassAttributeAction(newAttribute.type);
|
|
if(action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
}
|
|
classBands.addClassAttribute(newAttribute);
|
|
} else {
|
|
throw new RuntimeException("Unexpected attribute encountered: " + attribute.type);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void visitInnerClass(String name, String outerName,
|
|
String innerName, int flags) {
|
|
icBands.addInnerClass(name, outerName, innerName, flags);
|
|
}
|
|
|
|
public FieldVisitor visitField(int flags, String name, String desc,
|
|
String signature, Object value) {
|
|
classBands.addField(flags, name, desc, signature, value);
|
|
return fieldVisitor;
|
|
}
|
|
|
|
public MethodVisitor visitMethod(int flags, String name, String desc,
|
|
String signature, String[] exceptions) {
|
|
classBands.addMethod(flags, name, desc, signature, exceptions);
|
|
return methodVisitor;
|
|
}
|
|
|
|
public void visitEnd() {
|
|
classBands.endOfClass();
|
|
}
|
|
|
|
/**
|
|
* This class implements MethodVisitor to visit the contents and metadata
|
|
* related to methods in a class file.
|
|
*
|
|
* It delegates to BcBands for bytecode related visits and to ClassBands for
|
|
* everything else.
|
|
*/
|
|
public class SegmentMethodVisitor extends MethodVisitor {
|
|
|
|
public SegmentMethodVisitor() {
|
|
super(Opcodes.ASM9);
|
|
}
|
|
|
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
|
return new SegmentAnnotationVisitor(
|
|
MetadataBandGroup.CONTEXT_METHOD, desc, visible);
|
|
}
|
|
|
|
public AnnotationVisitor visitAnnotationDefault() {
|
|
return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD);
|
|
}
|
|
|
|
public void visitAttribute(Attribute attribute) {
|
|
if(attribute.isUnknown()) {
|
|
String action = options.getUnknownAttributeAction();
|
|
if(action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
} else {
|
|
if(attribute instanceof NewAttribute) {
|
|
NewAttribute newAttribute = (NewAttribute) attribute;
|
|
if (attribute.isCodeAttribute()) {
|
|
if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CODE)) {
|
|
String action = options
|
|
.getUnknownCodeAttributeAction(newAttribute.type);
|
|
if (action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
}
|
|
classBands.addCodeAttribute(newAttribute);
|
|
} else {
|
|
if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_METHOD)) {
|
|
String action = options
|
|
.getUnknownMethodAttributeAction(newAttribute.type);
|
|
if (action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
}
|
|
classBands.addMethodAttribute(newAttribute);
|
|
}
|
|
} else {
|
|
throw new RuntimeException("Unexpected attribute encountered: " + attribute.type);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void visitCode() {
|
|
classBands.addCode();
|
|
}
|
|
|
|
public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3,
|
|
Object[] arg4) {
|
|
// TODO: Java 6 - implement support for this
|
|
|
|
}
|
|
|
|
public void visitLabel(Label label) {
|
|
bcBands.visitLabel(label);
|
|
}
|
|
|
|
public void visitLineNumber(int line, Label start) {
|
|
if(!stripDebug) {
|
|
classBands.addLineNumber(line, start);
|
|
}
|
|
}
|
|
|
|
public void visitLocalVariable(String name, String desc,
|
|
String signature, Label start, Label end, int index) {
|
|
if(!stripDebug) {
|
|
classBands.addLocalVariable(name, desc, signature, start, end,
|
|
index);
|
|
}
|
|
}
|
|
|
|
public void visitMaxs(int maxStack, int maxLocals) {
|
|
classBands.addMaxStack(maxStack, maxLocals);
|
|
}
|
|
|
|
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
|
String desc, boolean visible) {
|
|
return new SegmentAnnotationVisitor(
|
|
MetadataBandGroup.CONTEXT_METHOD, parameter, desc, visible);
|
|
}
|
|
|
|
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
|
String type) {
|
|
classBands.addHandler(start, end, handler, type);
|
|
}
|
|
|
|
public void visitEnd() {
|
|
classBands.endOfMethod();
|
|
bcBands.visitEnd();
|
|
}
|
|
|
|
public void visitFieldInsn(int opcode, String owner, String name,
|
|
String desc) {
|
|
bcBands.visitFieldInsn(opcode, owner, name, desc);
|
|
}
|
|
|
|
public void visitIincInsn(int var, int increment) {
|
|
bcBands.visitIincInsn(var, increment);
|
|
}
|
|
|
|
public void visitInsn(int opcode) {
|
|
bcBands.visitInsn(opcode);
|
|
}
|
|
|
|
public void visitIntInsn(int opcode, int operand) {
|
|
bcBands.visitIntInsn(opcode, operand);
|
|
}
|
|
|
|
public void visitJumpInsn(int opcode, Label label) {
|
|
bcBands.visitJumpInsn(opcode, label);
|
|
}
|
|
|
|
public void visitLdcInsn(Object cst) {
|
|
bcBands.visitLdcInsn(cst);
|
|
}
|
|
|
|
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
|
bcBands.visitLookupSwitchInsn(dflt, keys, labels);
|
|
}
|
|
|
|
public void visitMethodInsn(int opcode, String owner, String name,
|
|
String desc, boolean isInterface) {
|
|
bcBands.visitMethodInsn(opcode, owner, name, desc);
|
|
}
|
|
|
|
public void visitMultiANewArrayInsn(String desc, int dimensions) {
|
|
bcBands.visitMultiANewArrayInsn(desc, dimensions);
|
|
}
|
|
|
|
public void visitTableSwitchInsn(int min, int max, Label dflt,
|
|
Label[] labels) {
|
|
bcBands.visitTableSwitchInsn(min, max, dflt, labels);
|
|
}
|
|
|
|
public void visitTypeInsn(int opcode, String type) {
|
|
bcBands.visitTypeInsn(opcode, type);
|
|
}
|
|
|
|
public void visitVarInsn(int opcode, int var) {
|
|
bcBands.visitVarInsn(opcode, var);
|
|
}
|
|
|
|
}
|
|
|
|
public ClassBands getClassBands() {
|
|
return classBands;
|
|
}
|
|
|
|
/**
|
|
* SegmentAnnotationVisitor implements <code>AnnotationVisitor</code> to
|
|
* visit Annotations found in a class file.
|
|
*/
|
|
public class SegmentAnnotationVisitor extends AnnotationVisitor {
|
|
|
|
private int context = -1;
|
|
private int parameter = -1;
|
|
private String desc;
|
|
private boolean visible;
|
|
|
|
private final List nameRU = new ArrayList();
|
|
private final List T = new ArrayList(); // tags
|
|
private final List values = new ArrayList();
|
|
private final List caseArrayN = new ArrayList();
|
|
private final List nestTypeRS = new ArrayList();
|
|
private final List nestNameRU = new ArrayList();
|
|
private final List nestPairN = new ArrayList();
|
|
|
|
public SegmentAnnotationVisitor(int context, String desc,
|
|
boolean visible) {
|
|
super(Opcodes.ASM9);
|
|
this.context = context;
|
|
this.desc = desc;
|
|
this.visible = visible;
|
|
}
|
|
|
|
public SegmentAnnotationVisitor(int context) {
|
|
super(Opcodes.ASM9);
|
|
this.context = context;
|
|
}
|
|
|
|
public SegmentAnnotationVisitor(int context, int parameter,
|
|
String desc, boolean visible) {
|
|
super(Opcodes.ASM9);
|
|
this.context = context;
|
|
this.parameter = parameter;
|
|
this.desc = desc;
|
|
this.visible = visible;
|
|
}
|
|
|
|
public void visit(String name, Object value) {
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
nameRU.add(name);
|
|
addValueAndTag(value, T, values);
|
|
}
|
|
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
|
T.add("@");
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
nameRU.add(name);
|
|
nestTypeRS.add(desc);
|
|
nestPairN.add(new Integer(0));
|
|
return new AnnotationVisitor(Opcodes.ASM9) {
|
|
public void visit(String name, Object value) {
|
|
Integer numPairs = (Integer) nestPairN.remove(nestPairN.size() - 1);
|
|
nestPairN.add(new Integer(numPairs.intValue() + 1));
|
|
nestNameRU.add(name);
|
|
addValueAndTag(value, T, values);
|
|
}
|
|
|
|
public AnnotationVisitor visitAnnotation(String arg0,
|
|
String arg1) {
|
|
throw new RuntimeException("Not yet supported");
|
|
// return null;
|
|
}
|
|
|
|
public AnnotationVisitor visitArray(String arg0) {
|
|
throw new RuntimeException("Not yet supported");
|
|
// return null;
|
|
}
|
|
|
|
public void visitEnd() {
|
|
}
|
|
|
|
public void visitEnum(String name, String desc, String value) {
|
|
Integer numPairs = (Integer) nestPairN.remove(nestPairN.size() - 1);
|
|
nestPairN.add(new Integer(numPairs.intValue() + 1));
|
|
T.add("e");
|
|
nestNameRU.add(name);
|
|
values.add(desc);
|
|
values.add(value);
|
|
}
|
|
};
|
|
}
|
|
|
|
public AnnotationVisitor visitArray(String name) {
|
|
T.add("[");
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
nameRU.add(name);
|
|
caseArrayN.add(new Integer(0));
|
|
return new ArrayVisitor(caseArrayN, T, nameRU, values);
|
|
}
|
|
|
|
public void visitEnd() {
|
|
if (desc == null) {
|
|
Segment.this.classBands.addAnnotationDefault(nameRU, T, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
|
|
} else if(parameter != -1) {
|
|
Segment.this.classBands.addParameterAnnotation(parameter, desc, visible, nameRU, T, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
|
|
} else {
|
|
Segment.this.classBands.addAnnotation(context, desc, visible, nameRU, T, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
|
|
}
|
|
}
|
|
|
|
public void visitEnum(String name, String desc, String value) {
|
|
T.add("e");
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
nameRU.add(name);
|
|
values.add(desc);
|
|
values.add(value);
|
|
}
|
|
}
|
|
|
|
public class ArrayVisitor extends AnnotationVisitor {
|
|
|
|
private int indexInCaseArrayN;
|
|
private List caseArrayN;
|
|
private List values;
|
|
private List nameRU;
|
|
private List T;
|
|
|
|
public ArrayVisitor(List caseArrayN, List T, List nameRU, List values) {
|
|
super(Opcodes.ASM9);
|
|
this.caseArrayN = caseArrayN;
|
|
this.T = T;
|
|
this.nameRU = nameRU;
|
|
this.values = values;
|
|
this.indexInCaseArrayN = caseArrayN.size() - 1;
|
|
}
|
|
|
|
public void visit(String name, Object value) {
|
|
Integer numCases = (Integer) caseArrayN.remove(indexInCaseArrayN);
|
|
caseArrayN.add(indexInCaseArrayN, new Integer(numCases.intValue() + 1));
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
addValueAndTag(value, T, values);
|
|
}
|
|
|
|
public AnnotationVisitor visitAnnotation(String arg0,
|
|
String arg1) {
|
|
throw new RuntimeException("Not yet supported");
|
|
}
|
|
|
|
public AnnotationVisitor visitArray(String name) {
|
|
T.add("[");
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
nameRU.add(name);
|
|
caseArrayN.add(new Integer(0));
|
|
return new ArrayVisitor(caseArrayN, T, nameRU, values);
|
|
}
|
|
|
|
public void visitEnd() {
|
|
}
|
|
|
|
public void visitEnum(String name, String desc, String value) {
|
|
Integer numCases = (Integer) caseArrayN.remove(caseArrayN.size() - 1);
|
|
caseArrayN.add(new Integer(numCases.intValue() + 1));
|
|
T.add("e");
|
|
values.add(desc);
|
|
values.add(value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SegmentFieldVisitor implements <code>FieldVisitor</code> to visit the
|
|
* metadata relating to fields in a class file.
|
|
*/
|
|
public class SegmentFieldVisitor extends FieldVisitor {
|
|
|
|
public SegmentFieldVisitor() {
|
|
super(Opcodes.ASM9);
|
|
}
|
|
|
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
|
return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_FIELD,
|
|
desc, visible);
|
|
}
|
|
|
|
public void visitAttribute(Attribute attribute) {
|
|
if(attribute.isUnknown()) {
|
|
String action = options.getUnknownAttributeAction();
|
|
if(action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
} else {
|
|
if(attribute instanceof NewAttribute) {
|
|
NewAttribute newAttribute = (NewAttribute) attribute;
|
|
if(newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_FIELD)) {
|
|
String action = options.getUnknownFieldAttributeAction(newAttribute.type);
|
|
if(action.equals(PackingOptions.PASS)) {
|
|
passCurrentClass();
|
|
} else if (action.equals(PackingOptions.ERROR)) {
|
|
throw new Error("Unknown attribute encountered");
|
|
} // else skip
|
|
}
|
|
classBands.addFieldAttribute(newAttribute);
|
|
} else {
|
|
throw new RuntimeException("Unexpected attribute encountered: " + attribute.type);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void visitEnd() {
|
|
}
|
|
}
|
|
|
|
// helper method for annotation visitors
|
|
private void addValueAndTag(Object value, List T, List values) {
|
|
if(value instanceof Integer) {
|
|
T.add("I");
|
|
values.add(value);
|
|
} else if (value instanceof Double) {
|
|
T.add("D");
|
|
values.add(value);
|
|
} else if (value instanceof Float) {
|
|
T.add("F");
|
|
values.add(value);
|
|
} else if (value instanceof Long) {
|
|
T.add("J");
|
|
values.add(value);
|
|
} else if (value instanceof Byte) {
|
|
T.add("B");
|
|
values.add(new Integer(((Byte)value).intValue()));
|
|
} else if (value instanceof Character) {
|
|
T.add("C");
|
|
values.add(new Integer(((Character)value).charValue()));
|
|
} else if (value instanceof Short) {
|
|
T.add("S");
|
|
values.add(new Integer(((Short)value).intValue()));
|
|
} else if (value instanceof Boolean) {
|
|
T.add("Z");
|
|
values.add(new Integer(((Boolean)value).booleanValue() ? 1 : 0));
|
|
} else if (value instanceof String) {
|
|
T.add("s");
|
|
values.add(value);
|
|
} else if (value instanceof Type) {
|
|
T.add("c");
|
|
values.add(((Type)value).toString());
|
|
}
|
|
}
|
|
|
|
|
|
public boolean lastConstantHadWideIndex() {
|
|
return currentClassReader.lastConstantHadWideIndex();
|
|
}
|
|
|
|
public CpBands getCpBands() {
|
|
return cpBands;
|
|
}
|
|
|
|
public SegmentHeader getSegmentHeader() {
|
|
return segmentHeader;
|
|
}
|
|
|
|
public AttributeDefinitionBands getAttrBands() {
|
|
return attributeDefinitionBands;
|
|
}
|
|
|
|
public IcBands getIcBands() {
|
|
return icBands;
|
|
}
|
|
|
|
public Pack200ClassReader getCurrentClassReader() {
|
|
return currentClassReader;
|
|
}
|
|
|
|
private void passCurrentClass() {
|
|
throw new PassException();
|
|
}
|
|
|
|
/**
|
|
* Exception indicating that the class currently being visited contains an
|
|
* unknown attribute, which means that by default the class file needs to be
|
|
* passed through as-is in the file_bands rather than being packed with
|
|
* pack200.
|
|
*/
|
|
public static class PassException extends RuntimeException {
|
|
|
|
}
|
|
}
|
|
|