X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2FClassFile.java;fp=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2FClassFile.java;h=0000000000000000000000000000000000000000;hb=6f0cd02d46e011bd5599e1b7fefc6159cb811135;hp=e575af546b2073ce923f84bbec4738e9e7c6182e;hpb=622d0e5a4b1b35b6918a516a79a0cc22272a919e;p=org.ibex.tool.git
diff --git a/src/org/eclipse/jdt/internal/compiler/ClassFile.java b/src/org/eclipse/jdt/internal/compiler/ClassFile.java
deleted file mode 100644
index e575af5..0000000
--- a/src/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ /dev/null
@@ -1,2621 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.compiler;
-
-import java.io.*;
-import java.util.StringTokenizer;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.internal.compiler.ast.*;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
-import org.eclipse.jdt.internal.compiler.codegen.*;
-import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
-import org.eclipse.jdt.internal.compiler.impl.Constant;
-import org.eclipse.jdt.internal.compiler.impl.StringConstant;
-import org.eclipse.jdt.internal.compiler.lookup.*;
-import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
-import org.eclipse.jdt.internal.compiler.util.Util;
-
-/**
- * Represents a class file wrapper on bytes, it is aware of its actual
- * type name.
- *
- * Public APIs are listed below:
- *
- * byte[] getBytes();
- * Answer the actual bytes of the class file
- *
- * char[][] getCompoundName();
- * Answer the compound name of the class file.
- * For example, {{java}, {util}, {Hashtable}}.
- *
- * byte[] getReducedBytes();
- * Answer a smaller byte format, which is only contains some structural
- * information. Those bytes are decodable with a regular class file reader,
- * such as DietClassFileReader
- */
-public class ClassFile
- implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
- public SourceTypeBinding referenceBinding;
- public ConstantPool constantPool;
- public ClassFile enclosingClassFile;
- // used to generate private access methods
- public int produceDebugAttributes;
- public ReferenceBinding[] innerClassesBindings;
- public int numberOfInnerClasses;
- public byte[] header;
- // the header contains all the bytes till the end of the constant pool
- public byte[] contents;
- // that collection contains all the remaining bytes of the .class file
- public int headerOffset;
- public int contentsOffset;
- public int constantPoolOffset;
- public int methodCountOffset;
- public int methodCount;
- protected boolean creatingProblemType;
- public static final int INITIAL_CONTENTS_SIZE = 400;
- public static final int INITIAL_HEADER_SIZE = 1500;
- public boolean ownSharedArrays = false; // flag set when header/contents are set to shared arrays
- public static final int INNER_CLASSES_SIZE = 5;
- public CodeStream codeStream;
- protected int problemLine; // used to create line number attributes for problem methods
- public long targetJDK;
-
- /**
- * INTERNAL USE-ONLY
- * This methods creates a new instance of the receiver.
- */
- public ClassFile() {
- // default constructor for subclasses
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods creates a new instance of the receiver.
- *
- * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
- * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
- * @param creatingProblemType boolean
- */
- public ClassFile(
- SourceTypeBinding aType,
- ClassFile enclosingClassFile,
- boolean creatingProblemType) {
-
- referenceBinding = aType;
- initByteArrays();
-
- // generate the magic numbers inside the header
- header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
- header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
- header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
- header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
-
- this.targetJDK = referenceBinding.scope.environment().options.targetJDK;
- header[headerOffset++] = (byte) (this.targetJDK >> 8); // minor high
- header[headerOffset++] = (byte) (this.targetJDK >> 0); // minor low
- header[headerOffset++] = (byte) (this.targetJDK >> 24); // major high
- header[headerOffset++] = (byte) (this.targetJDK >> 16); // major low
-
- constantPoolOffset = headerOffset;
- headerOffset += 2;
- constantPool = new ConstantPool(this);
-
- // Modifier manipulations for classfile
- int accessFlags = aType.getAccessFlags();
- if (aType.isPrivate()) { // rewrite private to non-public
- accessFlags &= ~AccPublic;
- }
- if (aType.isProtected()) { // rewrite protected into public
- accessFlags |= AccPublic;
- }
- // clear all bits that are illegal for a class or an interface
- accessFlags
- &= ~(
- AccStrictfp
- | AccProtected
- | AccPrivate
- | AccStatic
- | AccSynchronized
- | AccNative);
-
- // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value)
- if (aType.isClass()) {
- accessFlags |= AccSuper;
- }
-
- this.enclosingClassFile = enclosingClassFile;
- // innerclasses get their names computed at code gen time
-
- // now we continue to generate the bytes inside the contents array
- contents[contentsOffset++] = (byte) (accessFlags >> 8);
- contents[contentsOffset++] = (byte) accessFlags;
- int classNameIndex = constantPool.literalIndex(aType);
- contents[contentsOffset++] = (byte) (classNameIndex >> 8);
- contents[contentsOffset++] = (byte) classNameIndex;
- int superclassNameIndex;
- if (aType.isInterface()) {
- superclassNameIndex = constantPool.literalIndexForJavaLangObject();
- } else {
- superclassNameIndex =
- (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
- }
- contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
- contents[contentsOffset++] = (byte) superclassNameIndex;
- ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
- int interfacesCount = superInterfacesBinding.length;
- contents[contentsOffset++] = (byte) (interfacesCount >> 8);
- contents[contentsOffset++] = (byte) interfacesCount;
- for (int i = 0; i < interfacesCount; i++) {
- int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
- contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
- contents[contentsOffset++] = (byte) interfaceIndex;
- }
- produceDebugAttributes = referenceBinding.scope.environment().options.produceDebugAttributes;
- innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
- this.creatingProblemType = creatingProblemType;
- codeStream = new CodeStream(this);
-
- // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
- // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
- ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
- if (this == outermostClassFile) {
- codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
- } else {
- codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a boggus method.
- *
- * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
- */
- public void addAbstractMethod(
- AbstractMethodDeclaration method,
- MethodBinding methodBinding) {
-
- // force the modifiers to be public and abstract
- methodBinding.modifiers = AccPublic | AccAbstract;
-
- this.generateMethodInfoHeader(methodBinding);
- int methodAttributeOffset = this.contentsOffset;
- int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
- this.completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods generate all the attributes for the receiver.
- * For a class they could be:
- * - source file attribute
- * - inner classes attribute
- * - deprecated attribute
- */
- public void addAttributes() {
- // update the method count
- contents[methodCountOffset++] = (byte) (methodCount >> 8);
- contents[methodCountOffset] = (byte) methodCount;
-
- int attributeNumber = 0;
- // leave two bytes for the number of attributes and store the current offset
- int attributeOffset = contentsOffset;
- contentsOffset += 2;
-
- // source attribute
- if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
- String fullFileName =
- new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
- fullFileName = fullFileName.replace('\\', '/');
- int lastIndex = fullFileName.lastIndexOf('/');
- if (lastIndex != -1) {
- fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
- }
- // check that there is enough space to write all the bytes for the field info corresponding
- // to the @fieldBinding
- if (contentsOffset + 8 >= contents.length) {
- resizeContents(8);
- }
- int sourceAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SourceName);
- contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
- // The length of a source file attribute is 2. This is a fixed-length
- // attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 2;
- // write the source file name
- int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
- contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
- contents[contentsOffset++] = (byte) fileNameIndex;
- attributeNumber++;
- }
- // Deprecated attribute
- if (referenceBinding.isDeprecated()) {
- // check that there is enough space to write all the bytes for the field info corresponding
- // to the @fieldBinding
- if (contentsOffset + 6 >= contents.length) {
- resizeContents(6);
- }
- int deprecatedAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
- contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
- // the length of a deprecated attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- attributeNumber++;
- }
- // Inner class attribute
- if (numberOfInnerClasses != 0) {
- // Generate the inner class attribute
- int exSize = 8 * numberOfInnerClasses + 8;
- if (exSize + contentsOffset >= this.contents.length) {
- resizeContents(exSize);
- }
- // Now we now the size of the attribute and the number of entries
- // attribute name
- int attributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
- contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) attributeNameIndex;
- int value = (numberOfInnerClasses << 3) + 2;
- contents[contentsOffset++] = (byte) (value >> 24);
- contents[contentsOffset++] = (byte) (value >> 16);
- contents[contentsOffset++] = (byte) (value >> 8);
- contents[contentsOffset++] = (byte) value;
- contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
- contents[contentsOffset++] = (byte) numberOfInnerClasses;
- for (int i = 0; i < numberOfInnerClasses; i++) {
- ReferenceBinding innerClass = innerClassesBindings[i];
- int accessFlags = innerClass.getAccessFlags();
- int innerClassIndex = constantPool.literalIndex(innerClass);
- // inner class index
- contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
- contents[contentsOffset++] = (byte) innerClassIndex;
- // outer class index: anonymous and local have no outer class index
- if (innerClass.isMemberType()) {
- // member or member of local
- int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
- contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
- contents[contentsOffset++] = (byte) outerClassIndex;
- } else {
- // equals to 0 if the innerClass is not a member type
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- }
- // name index
- if (!innerClass.isAnonymousType()) {
- int nameIndex = constantPool.literalIndex(innerClass.sourceName());
- contents[contentsOffset++] = (byte) (nameIndex >> 8);
- contents[contentsOffset++] = (byte) nameIndex;
- } else {
- // equals to 0 if the innerClass is an anonymous type
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- }
- // access flag
- if (innerClass.isAnonymousType()) {
- accessFlags |= AccPrivate;
- } else
- if (innerClass.isLocalType() && !innerClass.isMemberType()) {
- accessFlags |= AccPrivate;
- }
- contents[contentsOffset++] = (byte) (accessFlags >> 8);
- contents[contentsOffset++] = (byte) accessFlags;
- }
- attributeNumber++;
- }
- // update the number of attributes
- if (attributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- contents[attributeOffset++] = (byte) (attributeNumber >> 8);
- contents[attributeOffset] = (byte) attributeNumber;
-
- // resynchronize all offsets of the classfile
- header = constantPool.poolContent;
- headerOffset = constantPool.currentOffset;
- int constantPoolCount = constantPool.currentIndex;
- header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
- header[constantPoolOffset] = (byte) constantPoolCount;
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods generate all the default abstract method infos that correpond to
- * the abstract methods inherited from superinterfaces.
- */
- public void addDefaultAbstractMethods() { // default abstract methods
- MethodBinding[] defaultAbstractMethods =
- referenceBinding.getDefaultAbstractMethods();
- for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
- generateMethodInfoHeader(defaultAbstractMethods[i]);
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
- completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods generates the bytes for the field binding passed like a parameter
- * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
- */
- public void addFieldInfo(FieldBinding fieldBinding) {
- int attributeNumber = 0;
- // check that there is enough space to write all the bytes for the field info corresponding
- // to the @fieldBinding
- if (contentsOffset + 30 >= contents.length) {
- resizeContents(30);
- }
- // Generate two attribute: constantValueAttribute and SyntheticAttribute
- // Now we can generate all entries into the byte array
- // First the accessFlags
- int accessFlags = fieldBinding.getAccessFlags();
- contents[contentsOffset++] = (byte) (accessFlags >> 8);
- contents[contentsOffset++] = (byte) accessFlags;
- // Then the nameIndex
- int nameIndex = constantPool.literalIndex(fieldBinding.name);
- contents[contentsOffset++] = (byte) (nameIndex >> 8);
- contents[contentsOffset++] = (byte) nameIndex;
- // Then the descriptorIndex
- int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
- contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
- contents[contentsOffset++] = (byte) descriptorIndex;
- // leave some space for the number of attributes
- int fieldAttributeOffset = contentsOffset;
- contentsOffset += 2;
- // 4.7.2 only static constant fields get a ConstantAttribute
- if (fieldBinding.constant != Constant.NotAConstant){
- // Now we generate the constant attribute corresponding to the fieldBinding
- int constantValueNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
- contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
- contents[contentsOffset++] = (byte) constantValueNameIndex;
- // The attribute length = 2 in case of a constantValue attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 2;
- attributeNumber++;
- // Need to add the constant_value_index
- switch (fieldBinding.constant.typeID()) {
- case T_boolean :
- int booleanValueIndex =
- constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
- contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
- contents[contentsOffset++] = (byte) booleanValueIndex;
- break;
- case T_byte :
- case T_char :
- case T_int :
- case T_short :
- int integerValueIndex =
- constantPool.literalIndex(fieldBinding.constant.intValue());
- contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
- contents[contentsOffset++] = (byte) integerValueIndex;
- break;
- case T_float :
- int floatValueIndex =
- constantPool.literalIndex(fieldBinding.constant.floatValue());
- contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
- contents[contentsOffset++] = (byte) floatValueIndex;
- break;
- case T_double :
- int doubleValueIndex =
- constantPool.literalIndex(fieldBinding.constant.doubleValue());
- contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
- contents[contentsOffset++] = (byte) doubleValueIndex;
- break;
- case T_long :
- int longValueIndex =
- constantPool.literalIndex(fieldBinding.constant.longValue());
- contents[contentsOffset++] = (byte) (longValueIndex >> 8);
- contents[contentsOffset++] = (byte) longValueIndex;
- break;
- case T_String :
- int stringValueIndex =
- constantPool.literalIndex(
- ((StringConstant) fieldBinding.constant).stringValue());
- if (stringValueIndex == -1) {
- if (!creatingProblemType) {
- // report an error and abort: will lead to a problem type classfile creation
- TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
- FieldDeclaration[] fieldDecls = typeDeclaration.fields;
- for (int i = 0, max = fieldDecls.length; i < max; i++) {
- if (fieldDecls[i].binding == fieldBinding) {
- // problem should abort
- typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
- fieldDecls[i]);
- }
- }
- } else {
- // already inside a problem type creation : no constant for this field
- contentsOffset = fieldAttributeOffset + 2;
- // +2 is necessary to keep the two byte space for the attribute number
- attributeNumber--;
- }
- } else {
- contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
- contents[contentsOffset++] = (byte) stringValueIndex;
- }
- }
- }
- if (fieldBinding.isSynthetic()) {
- int syntheticAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
- contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
- // the length of a synthetic attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- attributeNumber++;
- }
- if (fieldBinding.isDeprecated()) {
- int deprecatedAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
- contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
- // the length of a deprecated attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- attributeNumber++;
- }
- contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
- contents[fieldAttributeOffset] = (byte) attributeNumber;
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods generate all the fields infos for the receiver.
- * This includes:
- * - a field info for each defined field of that class
- * - a field info for each synthetic field (e.g. this$0)
- */
- public void addFieldInfos() {
- SourceTypeBinding currentBinding = referenceBinding;
- FieldBinding[] syntheticFields = currentBinding.syntheticFields();
- int fieldCount =
- currentBinding.fieldCount()
- + (syntheticFields == null ? 0 : syntheticFields.length);
-
- // write the number of fields
- if (fieldCount > 0xFFFF) {
- referenceBinding.scope.problemReporter().tooManyFields(referenceBinding.scope.referenceType());
- }
- contents[contentsOffset++] = (byte) (fieldCount >> 8);
- contents[contentsOffset++] = (byte) fieldCount;
-
- FieldBinding[] fieldBindings = currentBinding.fields();
- for (int i = 0, max = fieldBindings.length; i < max; i++) {
- addFieldInfo(fieldBindings[i]);
- }
- if (syntheticFields != null) {
- for (int i = 0, max = syntheticFields.length; i < max; i++) {
- addFieldInfo(syntheticFields[i]);
- }
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods stores the bindings for each inner class. They will be used to know which entries
- * have to be generated for the inner classes attributes.
- * @param refBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
- */
- public void addInnerClasses(ReferenceBinding refBinding) {
- // check first if that reference binding is there
- for (int i = 0; i < numberOfInnerClasses; i++) {
- if (innerClassesBindings[i] == refBinding)
- return;
- }
- int length = innerClassesBindings.length;
- if (numberOfInnerClasses == length) {
- System.arraycopy(
- innerClassesBindings,
- 0,
- innerClassesBindings = new ReferenceBinding[length * 2],
- 0,
- length);
- }
- innerClassesBindings[numberOfInnerClasses++] = refBinding;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem clinit method info that correspond to a boggus method.
- *
- * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
- */
- public void addProblemClinit(IProblem[] problems) {
- generateMethodInfoHeaderForClinit();
- // leave two spaces for the number of attributes
- contentsOffset -= 2;
- int attributeOffset = contentsOffset;
- contentsOffset += 2;
- int attributeNumber = 0;
-
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.resetForProblemClinit(this);
- String problemString = "" ; //$NON-NLS-1$
- if (problems != null) {
- int max = problems.length;
- StringBuffer buffer = new StringBuffer(25);
- int count = 0;
- for (int i = 0; i < max; i++) {
- IProblem problem = problems[i];
- if ((problem != null) && (problem.isError())) {
- buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
- count++;
- if (problemLine == 0) {
- problemLine = problem.getSourceLineNumber();
- }
- problems[i] = null;
- }
- } // insert the top line afterwards, once knowing how many problems we have to consider
- if (count > 1) {
- buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
- } else {
- buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
- }
- problemString = buffer.toString();
- }
-
- // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
- codeStream.generateCodeAttributeForProblemMethod(problemString);
- attributeNumber++; // code attribute
- completeCodeAttributeForClinit(
- codeAttributeOffset,
- referenceBinding
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- contents[attributeOffset++] = (byte) (attributeNumber >> 8);
- contents[attributeOffset] = (byte) attributeNumber;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a boggus constructor.
- *
- * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
- * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
- */
- public void addProblemConstructor(
- AbstractMethodDeclaration method,
- MethodBinding methodBinding,
- IProblem[] problems) {
-
- // always clear the strictfp/native/abstract bit for a problem method
- generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(methodBinding);
-
- // Code attribute
- attributeNumber++;
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.reset(method, this);
- String problemString = "" ; //$NON-NLS-1$
- if (problems != null) {
- int max = problems.length;
- StringBuffer buffer = new StringBuffer(25);
- int count = 0;
- for (int i = 0; i < max; i++) {
- IProblem problem = problems[i];
- if ((problem != null) && (problem.isError())) {
- buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
- count++;
- if (problemLine == 0) {
- problemLine = problem.getSourceLineNumber();
- }
- }
- } // insert the top line afterwards, once knowing how many problems we have to consider
- if (count > 1) {
- buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
- } else {
- buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
- }
- problemString = buffer.toString();
- }
-
- // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
- codeStream.generateCodeAttributeForProblemMethod(problemString);
- completeCodeAttributeForProblemMethod(
- method,
- methodBinding,
- codeAttributeOffset,
- ((SourceTypeBinding) methodBinding.declaringClass)
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a boggus constructor.
- * Reset the position inside the contents byte array to the savedOffset.
- *
- * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
- * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
- * @param savedOffset int
- */
- public void addProblemConstructor(
- AbstractMethodDeclaration method,
- MethodBinding methodBinding,
- IProblem[] problems,
- int savedOffset) {
- // we need to move back the contentsOffset to the value at the beginning of the method
- contentsOffset = savedOffset;
- methodCount--; // we need to remove the method that causes the problem
- addProblemConstructor(method, methodBinding, problems);
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a boggus method.
- *
- * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
- * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
- */
- public void addProblemMethod(
- AbstractMethodDeclaration method,
- MethodBinding methodBinding,
- IProblem[] problems) {
- if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
- method.abort(ProblemSeverities.AbortType, null);
- }
- // always clear the strictfp/native/abstract bit for a problem method
- generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(methodBinding);
-
- // Code attribute
- attributeNumber++;
-
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.reset(method, this);
- String problemString = "" ; //$NON-NLS-1$
- if (problems != null) {
- int max = problems.length;
- StringBuffer buffer = new StringBuffer(25);
- int count = 0;
- for (int i = 0; i < max; i++) {
- IProblem problem = problems[i];
- if ((problem != null)
- && (problem.isError())
- && (problem.getSourceStart() >= method.declarationSourceStart)
- && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
- buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
- count++;
- if (problemLine == 0) {
- problemLine = problem.getSourceLineNumber();
- }
- problems[i] = null;
- }
- } // insert the top line afterwards, once knowing how many problems we have to consider
- if (count > 1) {
- buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
- } else {
- buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
- }
- problemString = buffer.toString();
- }
-
- // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
- codeStream.generateCodeAttributeForProblemMethod(problemString);
- completeCodeAttributeForProblemMethod(
- method,
- methodBinding,
- codeAttributeOffset,
- ((SourceTypeBinding) methodBinding.declaringClass)
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a boggus method.
- * Reset the position inside the contents byte array to the savedOffset.
- *
- * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
- * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
- * @param savedOffset int
- */
- public void addProblemMethod(
- AbstractMethodDeclaration method,
- MethodBinding methodBinding,
- IProblem[] problems,
- int savedOffset) {
- // we need to move back the contentsOffset to the value at the beginning of the method
- contentsOffset = savedOffset;
- methodCount--; // we need to remove the method that causes the problem
- addProblemMethod(method, methodBinding, problems);
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for all the special method infos.
- * They are:
- * - synthetic access methods
- * - default abstract methods
- */
- public void addSpecialMethods() {
- // add all methods (default abstract methods and synthetic)
-
- // default abstract methods
- SourceTypeBinding currentBinding = referenceBinding;
- MethodBinding[] defaultAbstractMethods =
- currentBinding.getDefaultAbstractMethods();
- for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
- generateMethodInfoHeader(defaultAbstractMethods[i]);
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
- completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
- // add synthetic methods infos
- SyntheticAccessMethodBinding[] syntheticAccessMethods =
- currentBinding.syntheticAccessMethods();
- if (syntheticAccessMethods != null) {
- for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
- SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
- switch (accessMethodBinding.accessType) {
- case SyntheticAccessMethodBinding.FieldReadAccess :
- // generate a method info to emulate an reading access to
- // a non-accessible field
- addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
- break;
- case SyntheticAccessMethodBinding.FieldWriteAccess :
- // generate a method info to emulate an writing access to
- // a non-accessible field
- addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
- break;
- case SyntheticAccessMethodBinding.MethodAccess :
- case SyntheticAccessMethodBinding.SuperMethodAccess :
- // generate a method info to emulate an access to a non-accessible method / super-method
- addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
- break;
- case SyntheticAccessMethodBinding.ConstructorAccess :
- // generate a method info to emulate an access to a non-accessible constructor
- addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
- }
- }
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for problem method infos that correspond to missing abstract methods.
- * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
- *
- * @param methodDeclarations Array of all missing abstract methods
- */
- public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
- if (methodDeclarations != null) {
- for (int i = 0, max = methodDeclarations.length; i < max; i++) {
- MethodDeclaration methodDeclaration = methodDeclarations[i];
- MethodBinding methodBinding = methodDeclaration.binding;
- String readableName = new String(methodBinding.readableName());
- IProblem[] problems = compilationResult.problems;
- int problemsCount = compilationResult.problemCount;
- for (int j = 0; j < problemsCount; j++) {
- IProblem problem = problems[j];
- if (problem != null
- && problem.getID() == IProblem.AbstractMethodMustBeImplemented
- && problem.getMessage().indexOf(readableName) != -1) {
- // we found a match
- addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
- }
- }
- }
- }
- }
-
- private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
- // always clear the strictfp/native/abstract bit for a problem method
- generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
- int methodAttributeOffset = contentsOffset;
- int attributeNumber = generateMethodInfoAttribute(methodBinding);
-
- // Code attribute
- attributeNumber++;
-
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- StringBuffer buffer = new StringBuffer(25);
- buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
- buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
- String problemString = buffer.toString();
- this.problemLine = problem.getSourceLineNumber();
-
- codeStream.init(this);
- codeStream.preserveUnusedLocals = true;
- codeStream.initializeMaxLocals(methodBinding);
-
- // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
- codeStream.generateCodeAttributeForProblemMethod(problemString);
-
- completeCodeAttributeForMissingAbstractProblemMethod(
- methodBinding,
- codeAttributeOffset,
- compilationResult.lineSeparatorPositions);
-
- completeMethodInfo(methodAttributeOffset, attributeNumber);
- }
-
- /**
- *
- */
- public void completeCodeAttributeForMissingAbstractProblemMethod(
- MethodBinding binding,
- int codeAttributeOffset,
- int[] startLineIndexes) {
- // reinitialize the localContents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
- int max_stack = codeStream.stackMax;
- this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- this.contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- this.contents[codeAttributeOffset + 9] = (byte) max_locals;
- int code_length = codeStream.position;
- this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- this.contents[codeAttributeOffset + 13] = (byte) code_length;
- // write the exception table
- if (localContentsOffset + 50 >= this.contents.length) {
- resizeContents(50);
- }
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0; // leave two bytes for the attribute_length
- localContentsOffset += 2; // first we handle the linenumber attribute
-
- if (codeStream.generateLineNumberAttributes) {
- /* Create and add the line number attribute (used for debugging)
- * Build the pairs of:
- * (bytecodePC lineNumber)
- * according to the table of start line indexes and the pcToSourceMap table
- * contained into the codestream
- */
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 6;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 1;
- if (problemLine == 0) {
- problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
- }
- // first entry at pc = 0
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
- this.contents[localContentsOffset++] = (byte) problemLine;
- // now we change the size of the line number attribute
- attributeNumber++;
- }
-
- // then we do the local variable attribute
- // update the number of attributes// ensure first that there is enough space available inside the localContents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a synthetic method that
- * generate an access to a private constructor.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
- */
- public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
- generateMethodInfoHeader(methodBinding);
- // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 2;
- // Code attribute
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.init(this);
- codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
- methodBinding,
- codeAttributeOffset,
- ((SourceTypeBinding) methodBinding.declaringClass)
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- // add the synthetic attribute
- int syntheticAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
- contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
- // the length of a synthetic attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a synthetic method that
- * generate an read access to a private field.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
- */
- public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
- generateMethodInfoHeader(methodBinding);
- // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 2;
- // Code attribute
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.init(this);
- codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
- methodBinding,
- codeAttributeOffset,
- ((SourceTypeBinding) methodBinding.declaringClass)
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- // add the synthetic attribute
- int syntheticAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
- contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
- // the length of a synthetic attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a synthetic method that
- * generate an write access to a private field.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
- */
- public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
- generateMethodInfoHeader(methodBinding);
- // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 2;
- // Code attribute
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.init(this);
- codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
- methodBinding,
- codeAttributeOffset,
- ((SourceTypeBinding) methodBinding.declaringClass)
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- // add the synthetic attribute
- int syntheticAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
- contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
- // the length of a synthetic attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Generate the byte for a problem method info that correspond to a synthetic method that
- * generate an access to a private method.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
- */
- public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
- generateMethodInfoHeader(methodBinding);
- // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 2;
- // Code attribute
- int codeAttributeOffset = contentsOffset;
- generateCodeAttributeHeader();
- codeStream.init(this);
- codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
- completeCodeAttributeForSyntheticAccessMethod(
- methodBinding,
- codeAttributeOffset,
- ((SourceTypeBinding) methodBinding.declaringClass)
- .scope
- .referenceCompilationUnit()
- .compilationResult
- .lineSeparatorPositions);
- // add the synthetic attribute
- int syntheticAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
- contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
- // the length of a synthetic attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Build all the directories and subdirectories corresponding to the packages names
- * into the directory specified in parameters.
- *
- * outputPath is formed like:
- * c:\temp\ the last character is a file separator
- * relativeFileName is formed like:
- * java\lang\String.class *
- *
- * @param outputPath java.lang.String
- * @param relativeFileName java.lang.String
- * @return java.lang.String
- */
- public static String buildAllDirectoriesInto(
- String outputPath,
- String relativeFileName)
- throws IOException {
- char fileSeparatorChar = File.separatorChar;
- String fileSeparator = File.separator;
- File f;
- // First we ensure that the outputPath exists
- outputPath = outputPath.replace('/', fileSeparatorChar);
- // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
- if (outputPath.endsWith(fileSeparator)) {
- outputPath = outputPath.substring(0, outputPath.length() - 1);
- }
- f = new File(outputPath);
- if (f.exists()) {
- if (!f.isDirectory()) {
- System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
- throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
- }
- } else {
- // we have to create that directory
- if (!f.mkdirs()) {
- System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
- throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
- }
- }
- StringBuffer outDir = new StringBuffer(outputPath);
- outDir.append(fileSeparator);
- StringTokenizer tokenizer =
- new StringTokenizer(relativeFileName, fileSeparator);
- String token = tokenizer.nextToken();
- while (tokenizer.hasMoreTokens()) {
- f = new File(outDir.append(token).append(fileSeparator).toString());
- if (f.exists()) {
- // The outDir already exists, so we proceed the next entry
- // System.out.println("outDir: " + outDir + " already exists.");
- } else {
- // Need to add the outDir
- if (!f.mkdir()) {
- System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
- throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
- }
- }
- token = tokenizer.nextToken();
- }
- // token contains the last one
- return outDir.append(token).toString();
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method completes the creation of the code attribute by setting
- * - the attribute_length
- * - max_stack
- * - max_locals
- * - code_length
- * - exception table
- * - and debug attributes if necessary.
- *
- * @param codeAttributeOffset int
- */
- public void completeCodeAttribute(int codeAttributeOffset) {
- // reinitialize the localContents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside localContents byte array before we started to write
- // any information about the codeAttribute
- // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
- // to get the right position, 6 for the max_stack etc...
- int code_length = codeStream.position;
- if (code_length > 65535) {
- codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
- codeStream.methodDeclaration);
- }
- if (localContentsOffset + 20 >= this.contents.length) {
- resizeContents(20);
- }
- int max_stack = codeStream.stackMax;
- this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- this.contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- this.contents[codeAttributeOffset + 9] = (byte) max_locals;
- this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- this.contents[codeAttributeOffset + 13] = (byte) code_length;
-
- // write the exception table
- int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
- ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
- int exSize = exceptionHandlersNumber * 8 + 2;
- if (exSize + localContentsOffset >= this.contents.length) {
- resizeContents(exSize);
- }
- // there is no exception table, so we need to offset by 2 the current offset and move
- // on the attribute generation
- this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
- this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
- for (int i = 0; i < exceptionHandlersNumber; i++) {
- ExceptionLabel exceptionHandler = exceptionHandlers[i];
- int start = exceptionHandler.start;
- this.contents[localContentsOffset++] = (byte) (start >> 8);
- this.contents[localContentsOffset++] = (byte) start;
- int end = exceptionHandler.end;
- this.contents[localContentsOffset++] = (byte) (end >> 8);
- this.contents[localContentsOffset++] = (byte) end;
- int handlerPC = exceptionHandler.position;
- this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
- this.contents[localContentsOffset++] = (byte) handlerPC;
- if (exceptionHandler.exceptionType == null) {
- // any exception handler
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- } else {
- int nameIndex;
- if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
- /* represents ClassNotFoundException, see class literal access*/
- nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
- } else {
- nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
- }
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- }
- }
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0;
- // leave two bytes for the attribute_length
- localContentsOffset += 2;
-
- // first we handle the linenumber attribute
- if (codeStream.generateLineNumberAttributes) {
- /* Create and add the line number attribute (used for debugging)
- * Build the pairs of:
- * (bytecodePC lineNumber)
- * according to the table of start line indexes and the pcToSourceMap table
- * contained into the codestream
- */
- int[] pcToSourceMapTable;
- if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
- && (codeStream.pcToSourceMapSize != 0)) {
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
- }
- this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- int lineNumberTableOffset = localContentsOffset;
- localContentsOffset += 6;
- // leave space for attribute_length and line_number_table_length
- int numberOfEntries = 0;
- int length = codeStream.pcToSourceMapSize;
- for (int i = 0; i < length;) {
- // write the entry
- if (localContentsOffset + 4 >= this.contents.length) {
- resizeContents(4);
- }
- int pc = pcToSourceMapTable[i++];
- this.contents[localContentsOffset++] = (byte) (pc >> 8);
- this.contents[localContentsOffset++] = (byte) pc;
- int lineNumber = pcToSourceMapTable[i++];
- this.contents[localContentsOffset++] = (byte) (lineNumber >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumber;
- numberOfEntries++;
- }
- // now we change the size of the line number attribute
- int lineNumberAttr_length = numberOfEntries * 4 + 2;
- this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
- this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
- this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
- this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
- this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
- this.contents[lineNumberTableOffset++] = (byte) numberOfEntries;
- attributeNumber++;
- }
- }
- // then we do the local variable attribute
- if (codeStream.generateLocalVariableTableAttributes) {
- int localVariableTableOffset = localContentsOffset;
- int numberOfEntries = 0;
- int localVariableNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
- }
- this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
- localContentsOffset += 6;
- // leave space for attribute_length and local_variable_table_length
- int nameIndex;
- int descriptorIndex;
- if (!codeStream.methodDeclaration.isStatic()) {
- numberOfEntries++;
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (code_length >> 8);
- this.contents[localContentsOffset++] = (byte) code_length;
- nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex =
- constantPool.literalIndex(
- codeStream.methodDeclaration.binding.declaringClass.signature());
- this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- this.contents[localContentsOffset++] = (byte) descriptorIndex;
- this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
- this.contents[localContentsOffset++] = 0;
- }
- for (int i = 0; i < codeStream.allLocalsCounter; i++) {
- LocalVariableBinding localVariable = codeStream.locals[i];
- for (int j = 0; j < localVariable.initializationCount; j++) {
- int startPC = localVariable.initializationPCs[j << 1];
- int endPC = localVariable.initializationPCs[(j << 1) + 1];
- if (startPC != endPC) { // only entries for non zero length
- if (endPC == -1) {
- localVariable.declaringScope.problemReporter().abortDueToInternalError(
- Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
- (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
- }
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- // now we can safely add the local entry
- numberOfEntries++;
- this.contents[localContentsOffset++] = (byte) (startPC >> 8);
- this.contents[localContentsOffset++] = (byte) startPC;
- int length = endPC - startPC;
- this.contents[localContentsOffset++] = (byte) (length >> 8);
- this.contents[localContentsOffset++] = (byte) length;
- nameIndex = constantPool.literalIndex(localVariable.name);
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
- this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- this.contents[localContentsOffset++] = (byte) descriptorIndex;
- int resolvedPosition = localVariable.resolvedPosition;
- this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
- this.contents[localContentsOffset++] = (byte) resolvedPosition;
- }
- }
- }
- int value = numberOfEntries * 10 + 2;
- localVariableTableOffset += 2;
- this.contents[localVariableTableOffset++] = (byte) (value >> 24);
- this.contents[localVariableTableOffset++] = (byte) (value >> 16);
- this.contents[localVariableTableOffset++] = (byte) (value >> 8);
- this.contents[localVariableTableOffset++] = (byte) value;
- this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
- this.contents[localVariableTableOffset] = (byte) numberOfEntries;
- attributeNumber++;
- }
- // update the number of attributes
- // ensure first that there is enough space available inside the localContents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
-
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method completes the creation of the code attribute by setting
- * - the attribute_length
- * - max_stack
- * - max_locals
- * - code_length
- * - exception table
- * - and debug attributes if necessary.
- *
- * @param codeAttributeOffset int
- */
- public void completeCodeAttributeForClinit(int codeAttributeOffset) {
- // reinitialize the contents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside contents byte array before we started to write
- // any information about the codeAttribute
- // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
- // to get the right position, 6 for the max_stack etc...
- int code_length = codeStream.position;
- if (code_length > 65535) {
- codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
- codeStream.methodDeclaration.scope.referenceType());
- }
- if (localContentsOffset + 20 >= this.contents.length) {
- resizeContents(20);
- }
- int max_stack = codeStream.stackMax;
- this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- this.contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- this.contents[codeAttributeOffset + 9] = (byte) max_locals;
- this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- this.contents[codeAttributeOffset + 13] = (byte) code_length;
-
- // write the exception table
- int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
- ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
- int exSize = exceptionHandlersNumber * 8 + 2;
- if (exSize + localContentsOffset >= this.contents.length) {
- resizeContents(exSize);
- }
- // there is no exception table, so we need to offset by 2 the current offset and move
- // on the attribute generation
- this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
- this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
- for (int i = 0; i < exceptionHandlersNumber; i++) {
- ExceptionLabel exceptionHandler = exceptionHandlers[i];
- int start = exceptionHandler.start;
- this.contents[localContentsOffset++] = (byte) (start >> 8);
- this.contents[localContentsOffset++] = (byte) start;
- int end = exceptionHandler.end;
- this.contents[localContentsOffset++] = (byte) (end >> 8);
- this.contents[localContentsOffset++] = (byte) end;
- int handlerPC = exceptionHandler.position;
- this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
- this.contents[localContentsOffset++] = (byte) handlerPC;
- if (exceptionHandler.exceptionType == null) {
- // any exception handler
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- } else {
- int nameIndex;
- if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
- /* represents denote ClassNotFoundException, see class literal access*/
- nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
- } else {
- nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
- }
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- }
- }
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0;
- // leave two bytes for the attribute_length
- localContentsOffset += 2;
-
- // first we handle the linenumber attribute
- if (codeStream.generateLineNumberAttributes) {
- /* Create and add the line number attribute (used for debugging)
- * Build the pairs of:
- * (bytecodePC lineNumber)
- * according to the table of start line indexes and the pcToSourceMap table
- * contained into the codestream
- */
- int[] pcToSourceMapTable;
- if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
- && (codeStream.pcToSourceMapSize != 0)) {
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
- }
- this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- int lineNumberTableOffset = localContentsOffset;
- localContentsOffset += 6;
- // leave space for attribute_length and line_number_table_length
- int numberOfEntries = 0;
- int length = codeStream.pcToSourceMapSize;
- for (int i = 0; i < length;) {
- // write the entry
- if (localContentsOffset + 4 >= this.contents.length) {
- resizeContents(4);
- }
- int pc = pcToSourceMapTable[i++];
- this.contents[localContentsOffset++] = (byte) (pc >> 8);
- this.contents[localContentsOffset++] = (byte) pc;
- int lineNumber = pcToSourceMapTable[i++];
- this.contents[localContentsOffset++] = (byte) (lineNumber >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumber;
- numberOfEntries++;
- }
- // now we change the size of the line number attribute
- int lineNumberAttr_length = numberOfEntries * 4 + 2;
- this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
- this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
- this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
- this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
- this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
- this.contents[lineNumberTableOffset++] = (byte) numberOfEntries;
- attributeNumber++;
- }
- }
- // then we do the local variable attribute
- if (codeStream.generateLocalVariableTableAttributes) {
- int localVariableTableOffset = localContentsOffset;
- int numberOfEntries = 0;
- // codeAttribute.addLocalVariableTableAttribute(this);
- if ((codeStream.pcToSourceMap != null)
- && (codeStream.pcToSourceMapSize != 0)) {
- int localVariableNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
- }
- this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
- localContentsOffset += 6;
- // leave space for attribute_length and local_variable_table_length
- int nameIndex;
- int descriptorIndex;
- for (int i = 0; i < codeStream.allLocalsCounter; i++) {
- LocalVariableBinding localVariable = codeStream.locals[i];
- for (int j = 0; j < localVariable.initializationCount; j++) {
- int startPC = localVariable.initializationPCs[j << 1];
- int endPC = localVariable.initializationPCs[(j << 1) + 1];
- if (startPC != endPC) { // only entries for non zero length
- if (endPC == -1) {
- localVariable.declaringScope.problemReporter().abortDueToInternalError(
- Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
- (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
- }
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- // now we can safely add the local entry
- numberOfEntries++;
- this.contents[localContentsOffset++] = (byte) (startPC >> 8);
- this.contents[localContentsOffset++] = (byte) startPC;
- int length = endPC - startPC;
- this.contents[localContentsOffset++] = (byte) (length >> 8);
- this.contents[localContentsOffset++] = (byte) length;
- nameIndex = constantPool.literalIndex(localVariable.name);
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
- this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- this.contents[localContentsOffset++] = (byte) descriptorIndex;
- int resolvedPosition = localVariable.resolvedPosition;
- this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
- this.contents[localContentsOffset++] = (byte) resolvedPosition;
- }
- }
- }
- int value = numberOfEntries * 10 + 2;
- localVariableTableOffset += 2;
- this.contents[localVariableTableOffset++] = (byte) (value >> 24);
- this.contents[localVariableTableOffset++] = (byte) (value >> 16);
- this.contents[localVariableTableOffset++] = (byte) (value >> 8);
- this.contents[localVariableTableOffset++] = (byte) value;
- this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
- this.contents[localVariableTableOffset] = (byte) numberOfEntries;
- attributeNumber++;
- }
- }
- // update the number of attributes
- // ensure first that there is enough space available inside the contents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method completes the creation of the code attribute by setting
- * - the attribute_length
- * - max_stack
- * - max_locals
- * - code_length
- * - exception table
- * - and debug attributes if necessary.
- *
- * @param codeAttributeOffset int
- * @param startLineIndexes int[]
- */
- public void completeCodeAttributeForClinit(
- int codeAttributeOffset,
- int[] startLineIndexes) {
- // reinitialize the contents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside contents byte array before we started to write
- // any information about the codeAttribute
- // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
- // to get the right position, 6 for the max_stack etc...
- int code_length = codeStream.position;
- if (code_length > 65535) {
- codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
- codeStream.methodDeclaration.scope.referenceType());
- }
- if (localContentsOffset + 20 >= this.contents.length) {
- resizeContents(20);
- }
- int max_stack = codeStream.stackMax;
- this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- this.contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- this.contents[codeAttributeOffset + 9] = (byte) max_locals;
- this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- this.contents[codeAttributeOffset + 13] = (byte) code_length;
-
- // write the exception table
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
-
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0; // leave two bytes for the attribute_length
- localContentsOffset += 2; // first we handle the linenumber attribute
-
- // first we handle the linenumber attribute
- if (codeStream.generateLineNumberAttributes) {
- if (localContentsOffset + 20 >= this.contents.length) {
- resizeContents(20);
- }
- /* Create and add the line number attribute (used for debugging)
- * Build the pairs of:
- * (bytecodePC lineNumber)
- * according to the table of start line indexes and the pcToSourceMap table
- * contained into the codestream
- */
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 6;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 1;
- // first entry at pc = 0
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
- this.contents[localContentsOffset++] = (byte) problemLine;
- // now we change the size of the line number attribute
- attributeNumber++;
- }
- // then we do the local variable attribute
- if (codeStream.generateLocalVariableTableAttributes) {
- int localVariableNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
- }
- this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 2;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- attributeNumber++;
- }
- // update the number of attributes
- // ensure first that there is enough space available inside the contents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method completes the creation of the code attribute by setting
- * - the attribute_length
- * - max_stack
- * - max_locals
- * - code_length
- * - exception table
- * - and debug attributes if necessary.
- *
- * @param codeAttributeOffset int
- */
- public void completeCodeAttributeForProblemMethod(
- AbstractMethodDeclaration method,
- MethodBinding binding,
- int codeAttributeOffset,
- int[] startLineIndexes) {
- // reinitialize the localContents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
- int max_stack = codeStream.stackMax;
- this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- this.contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- this.contents[codeAttributeOffset + 9] = (byte) max_locals;
- int code_length = codeStream.position;
- this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- this.contents[codeAttributeOffset + 13] = (byte) code_length;
- // write the exception table
- if (localContentsOffset + 50 >= this.contents.length) {
- resizeContents(50);
- }
-
- // write the exception table
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0; // leave two bytes for the attribute_length
- localContentsOffset += 2; // first we handle the linenumber attribute
-
- if (codeStream.generateLineNumberAttributes) {
- if (localContentsOffset + 20 >= this.contents.length) {
- resizeContents(20);
- }
- /* Create and add the line number attribute (used for debugging)
- * Build the pairs of:
- * (bytecodePC lineNumber)
- * according to the table of start line indexes and the pcToSourceMap table
- * contained into the codestream
- */
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 6;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 1;
- if (problemLine == 0) {
- problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
- }
- // first entry at pc = 0
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
- this.contents[localContentsOffset++] = (byte) problemLine;
- // now we change the size of the line number attribute
- attributeNumber++;
- }
- // then we do the local variable attribute
- if (codeStream.generateLocalVariableTableAttributes) {
- // compute the resolved position for the arguments of the method
- int argSize;
- int localVariableTableOffset = localContentsOffset;
- int numberOfEntries = 0;
- // codeAttribute.addLocalVariableTableAttribute(this);
- int localVariableNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
- if (localContentsOffset + 8 >= this.contents.length) {
- resizeContents(8);
- }
- this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
- localContentsOffset += 6;
- // leave space for attribute_length and local_variable_table_length
- int descriptorIndex;
- if (!codeStream.methodDeclaration.isStatic()) {
- numberOfEntries++;
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (code_length >> 8);
- this.contents[localContentsOffset++] = (byte) code_length;
- int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex =
- constantPool.literalIndex(
- codeStream.methodDeclaration.binding.declaringClass.signature());
- this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- this.contents[localContentsOffset++] = (byte) descriptorIndex;
- // the resolved position for this is always 0
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- }
- if (binding.isConstructor()) {
- ReferenceBinding declaringClass = binding.declaringClass;
- if (declaringClass.isNestedType()) {
- NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
- argSize = methodDeclaringClass.enclosingInstancesSlotSize;
- SyntheticArgumentBinding[] syntheticArguments;
- if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
- != null) {
- for (int i = 0, max = syntheticArguments.length; i < max; i++) {
- LocalVariableBinding localVariable = syntheticArguments[i];
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- // now we can safely add the local entry
- numberOfEntries++;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (code_length >> 8);
- this.contents[localContentsOffset++] = (byte) code_length;
- int nameIndex = constantPool.literalIndex(localVariable.name);
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
- this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- this.contents[localContentsOffset++] = (byte) descriptorIndex;
- int resolvedPosition = localVariable.resolvedPosition;
- this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
- this.contents[localContentsOffset++] = (byte) resolvedPosition;
- }
- }
- } else {
- argSize = 1;
- }
- } else {
- argSize = binding.isStatic() ? 0 : 1;
- }
- if (method.binding != null) {
- TypeBinding[] parameters = method.binding.parameters;
- Argument[] arguments = method.arguments;
- if ((parameters != null) && (arguments != null)) {
- for (int i = 0, max = parameters.length; i < max; i++) {
- TypeBinding argumentBinding = parameters[i];
- if (localContentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- // now we can safely add the local entry
- numberOfEntries++;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = 0;
- this.contents[localContentsOffset++] = (byte) (code_length >> 8);
- this.contents[localContentsOffset++] = (byte) code_length;
- int nameIndex = constantPool.literalIndex(arguments[i].name);
- this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- this.contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
- this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- this.contents[localContentsOffset++] = (byte) descriptorIndex;
- int resolvedPosition = argSize;
- if ((argumentBinding == BaseTypes.LongBinding)
- || (argumentBinding == BaseTypes.DoubleBinding))
- argSize += 2;
- else
- argSize++;
- this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
- this.contents[localContentsOffset++] = (byte) resolvedPosition;
- }
- }
- }
- int value = numberOfEntries * 10 + 2;
- localVariableTableOffset += 2;
- this.contents[localVariableTableOffset++] = (byte) (value >> 24);
- this.contents[localVariableTableOffset++] = (byte) (value >> 16);
- this.contents[localVariableTableOffset++] = (byte) (value >> 8);
- this.contents[localVariableTableOffset++] = (byte) value;
- this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
- this.contents[localVariableTableOffset] = (byte) numberOfEntries;
- attributeNumber++;
- }
- // update the number of attributes// ensure first that there is enough space available inside the localContents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method completes the creation of the code attribute by setting
- * - the attribute_length
- * - max_stack
- * - max_locals
- * - code_length
- * - exception table
- * - and debug attributes if necessary.
- *
- * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
- * @param codeAttributeOffset int
- */
- public void completeCodeAttributeForSyntheticAccessMethod(
- SyntheticAccessMethodBinding binding,
- int codeAttributeOffset,
- int[] startLineIndexes) {
- // reinitialize the contents with the byte modified by the code stream
- this.contents = codeStream.bCodeStream;
- int localContentsOffset = codeStream.classFileOffset;
- // codeAttributeOffset is the position inside contents byte array before we started to write
- // any information about the codeAttribute
- // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
- // to get the right position, 6 for the max_stack etc...
- int max_stack = codeStream.stackMax;
- contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
- contents[codeAttributeOffset + 7] = (byte) max_stack;
- int max_locals = codeStream.maxLocals;
- contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
- contents[codeAttributeOffset + 9] = (byte) max_locals;
- int code_length = codeStream.position;
- contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
- contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
- contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
- contents[codeAttributeOffset + 13] = (byte) code_length;
- if ((localContentsOffset + 40) >= this.contents.length) {
- resizeContents(40);
- }
- // there is no exception table, so we need to offset by 2 the current offset and move
- // on the attribute generation
- contents[localContentsOffset++] = 0;
- contents[localContentsOffset++] = 0;
- // debug attributes
- int codeAttributeAttributeOffset = localContentsOffset;
- int attributeNumber = 0;
- // leave two bytes for the attribute_length
- localContentsOffset += 2;
-
- // first we handle the linenumber attribute
- if (codeStream.generateLineNumberAttributes) {
- int index = 0;
- int lineNumberNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
- contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
- contents[localContentsOffset++] = (byte) lineNumberNameIndex;
- int lineNumberTableOffset = localContentsOffset;
- localContentsOffset += 6;
- // leave space for attribute_length and line_number_table_length
- // Seems like do would be better, but this preserves the existing behavior.
- index = searchLineNumber(startLineIndexes, binding.sourceStart);
- contents[localContentsOffset++] = 0;
- contents[localContentsOffset++] = 0;
- contents[localContentsOffset++] = (byte) (index >> 8);
- contents[localContentsOffset++] = (byte) index;
- // now we change the size of the line number attribute
- contents[lineNumberTableOffset++] = 0;
- contents[lineNumberTableOffset++] = 0;
- contents[lineNumberTableOffset++] = 0;
- contents[lineNumberTableOffset++] = 6;
- contents[lineNumberTableOffset++] = 0;
- contents[lineNumberTableOffset++] = 1;
- attributeNumber++;
- }
- // then we do the local variable attribute
- if (codeStream.generateLocalVariableTableAttributes) {
- int localVariableTableOffset = localContentsOffset;
- int numberOfEntries = 0;
- int localVariableNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
- if (localContentsOffset + 8 > this.contents.length) {
- resizeContents(8);
- }
- contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
- contents[localContentsOffset++] = (byte) localVariableNameIndex;
- localContentsOffset += 6;
- // leave space for attribute_length and local_variable_table_length
- int nameIndex;
- int descriptorIndex;
- for (int i = 0; i < codeStream.allLocalsCounter; i++) {
- LocalVariableBinding localVariable = codeStream.locals[i];
- for (int j = 0; j < localVariable.initializationCount; j++) {
- int startPC = localVariable.initializationPCs[j << 1];
- int endPC = localVariable.initializationPCs[(j << 1) + 1];
- if (startPC != endPC) { // only entries for non zero length
- if (endPC == -1) {
- localVariable.declaringScope.problemReporter().abortDueToInternalError(
- Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
- (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
- }
- if (localContentsOffset + 10 > this.contents.length) {
- resizeContents(10);
- }
- // now we can safely add the local entry
- numberOfEntries++;
- contents[localContentsOffset++] = (byte) (startPC >> 8);
- contents[localContentsOffset++] = (byte) startPC;
- int length = endPC - startPC;
- contents[localContentsOffset++] = (byte) (length >> 8);
- contents[localContentsOffset++] = (byte) length;
- nameIndex = constantPool.literalIndex(localVariable.name);
- contents[localContentsOffset++] = (byte) (nameIndex >> 8);
- contents[localContentsOffset++] = (byte) nameIndex;
- descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
- contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
- contents[localContentsOffset++] = (byte) descriptorIndex;
- int resolvedPosition = localVariable.resolvedPosition;
- contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
- contents[localContentsOffset++] = (byte) resolvedPosition;
- }
- }
- }
- int value = numberOfEntries * 10 + 2;
- localVariableTableOffset += 2;
- contents[localVariableTableOffset++] = (byte) (value >> 24);
- contents[localVariableTableOffset++] = (byte) (value >> 16);
- contents[localVariableTableOffset++] = (byte) (value >> 8);
- contents[localVariableTableOffset++] = (byte) value;
- contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
- contents[localVariableTableOffset] = (byte) numberOfEntries;
- attributeNumber++;
- }
- // update the number of attributes
- // ensure first that there is enough space available inside the contents array
- if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
- resizeContents(2);
- }
- contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
- contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
-
- // update the attribute length
- int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
- contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
- contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
- contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
- contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
- contentsOffset = localContentsOffset;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Complete the creation of a method info by setting up the number of attributes at the right offset.
- *
- * @param methodAttributeOffset int
- * @param attributeNumber int
- */
- public void completeMethodInfo(
- int methodAttributeOffset,
- int attributeNumber) {
- // update the number of attributes
- contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
- contents[methodAttributeOffset] = (byte) attributeNumber;
- }
-
- /**
- * INTERNAL USE-ONLY
- * Request the creation of a ClassFile compatible representation of a problematic type
- *
- * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
- * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
- */
- public static void createProblemType(
- TypeDeclaration typeDeclaration,
- CompilationResult unitResult) {
- SourceTypeBinding typeBinding = typeDeclaration.binding;
- ClassFile classFile = new ClassFile(typeBinding, null, true);
-
- // TODO (olivier) handle cases where a field cannot be generated (name too long)
- // TODO (olivier) handle too many methods
- // inner attributes
- if (typeBinding.isMemberType())
- classFile.recordEnclosingTypeAttributes(typeBinding);
-
- // add its fields
- FieldBinding[] fields = typeBinding.fields;
- if ((fields != null) && (fields != NoFields)) {
- for (int i = 0, max = fields.length; i < max; i++) {
- if (fields[i].constant == null) {
- FieldReference.getConstantFor(fields[i], null, false, null);
- }
- }
- classFile.addFieldInfos();
- } else {
- // we have to set the number of fields to be equals to 0
- classFile.contents[classFile.contentsOffset++] = 0;
- classFile.contents[classFile.contentsOffset++] = 0;
- }
- // leave some space for the methodCount
- classFile.setForMethodInfos();
- // add its user defined methods
- MethodBinding[] methods = typeBinding.methods;
- AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
- int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
- int problemsLength;
- IProblem[] problems = unitResult.getErrors();
- if (problems == null) {
- problems = new IProblem[0];
- }
- IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
- System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
- if (methods != null) {
- if (typeBinding.isInterface()) {
- // we cannot create problem methods for an interface. So we have to generate a clinit
- // which should contain all the problem
- classFile.addProblemClinit(problemsCopy);
- for (int i = 0, max = methods.length; i < max; i++) {
- MethodBinding methodBinding;
- if ((methodBinding = methods[i]) != null) {
- // find the corresponding method declaration
- for (int j = 0; j < maxMethodDecl; j++) {
- if ((methodDeclarations[j] != null)
- && (methodDeclarations[j].binding == methods[i])) {
- if (!methodBinding.isConstructor()) {
- classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
- }
- break;
- }
- }
- }
- }
- } else {
- for (int i = 0, max = methods.length; i < max; i++) {
- MethodBinding methodBinding;
- if ((methodBinding = methods[i]) != null) {
- // find the corresponding method declaration
- for (int j = 0; j < maxMethodDecl; j++) {
- if ((methodDeclarations[j] != null)
- && (methodDeclarations[j].binding == methods[i])) {
- AbstractMethodDeclaration methodDecl;
- if ((methodDecl = methodDeclarations[j]).isConstructor()) {
- classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
- } else {
- classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
- }
- break;
- }
- }
- }
- }
- }
- // add abstract methods
- classFile.addDefaultAbstractMethods();
- }
- // propagate generation of (problem) member types
- if (typeDeclaration.memberTypes != null) {
- for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
- TypeDeclaration memberType = typeDeclaration.memberTypes[i];
- if (memberType.binding != null) {
- classFile.recordNestedMemberAttribute(memberType.binding);
- ClassFile.createProblemType(memberType, unitResult);
- }
- }
- }
- classFile.addAttributes();
- unitResult.record(typeBinding.constantPoolName(), classFile);
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods returns a char[] representing the file name of the receiver
- *
- * @return char[]
- */
- public char[] fileName() {
- return constantPool.UTF8Cache.returnKeyFor(1);
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method generates the header of a code attribute.
- * - the index inside the constant pool for the attribute name ("Code")
- * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
- */
- public void generateCodeAttributeHeader() {
- if (contentsOffset + 20 >= this.contents.length) {
- resizeContents(20);
- }
- int constantValueNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.CodeName);
- contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
- contents[contentsOffset++] = (byte) constantValueNameIndex;
- // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
- contentsOffset += 12;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method generates the attributes of a code attribute.
- * They could be:
- * - an exception attribute for each try/catch found inside the method
- * - a deprecated attribute
- * - a synthetic attribute for synthetic access methods
- *
- * It returns the number of attributes created for the code attribute.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
- * @return int
- */
- public int generateMethodInfoAttribute(MethodBinding methodBinding) {
- // leave two bytes for the attribute_number
- contentsOffset += 2;
- // now we can handle all the attribute for that method info:
- // it could be:
- // - a CodeAttribute
- // - a ExceptionAttribute
- // - a DeprecatedAttribute
- // - a SyntheticAttribute
-
- // Exception attribute
- ReferenceBinding[] thrownsExceptions;
- int attributeNumber = 0;
- if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
- // The method has a throw clause. So we need to add an exception attribute
- // check that there is enough space to write all the bytes for the exception attribute
- int length = thrownsExceptions.length;
- int exSize = 8 + length * 2;
- if (exSize + contentsOffset >= this.contents.length) {
- resizeContents(exSize);
- }
- int exceptionNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
- contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
- contents[contentsOffset++] = (byte) exceptionNameIndex;
- // The attribute length = length * 2 + 2 in case of a exception attribute
- int attributeLength = length * 2 + 2;
- contents[contentsOffset++] = (byte) (attributeLength >> 24);
- contents[contentsOffset++] = (byte) (attributeLength >> 16);
- contents[contentsOffset++] = (byte) (attributeLength >> 8);
- contents[contentsOffset++] = (byte) attributeLength;
- contents[contentsOffset++] = (byte) (length >> 8);
- contents[contentsOffset++] = (byte) length;
- for (int i = 0; i < length; i++) {
- int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
- contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
- contents[contentsOffset++] = (byte) exceptionIndex;
- }
- attributeNumber++;
- }
- if (methodBinding.isDeprecated()) {
- // Deprecated attribute
- // Check that there is enough space to write the deprecated attribute
- if (contentsOffset + 6 >= this.contents.length) {
- resizeContents(6);
- }
- int deprecatedAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
- contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
- // the length of a deprecated attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
-
- attributeNumber++;
- }
- if (this.targetJDK < ClassFileConstants.JDK1_5 && methodBinding.isSynthetic()) {
- // Synthetic attribute
- // Check that there is enough space to write the deprecated attribute
- if (contentsOffset + 6 >= this.contents.length) {
- resizeContents(6);
- }
- int syntheticAttributeNameIndex =
- constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
- contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
- contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
- // the length of a synthetic attribute is equals to 0
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 0;
-
- attributeNumber++;
- }
- return attributeNumber;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method generates the header of a method info:
- * The header consists in:
- * - the access flags
- * - the name index of the method name inside the constant pool
- * - the descriptor index of the signature of the method inside the constant pool.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
- */
- public void generateMethodInfoHeader(MethodBinding methodBinding) {
- generateMethodInfoHeader(methodBinding, methodBinding.modifiers);
- }
- /**
- * INTERNAL USE-ONLY
- * That method generates the header of a method info:
- * The header consists in:
- * - the access flags
- * - the name index of the method name inside the constant pool
- * - the descriptor index of the signature of the method inside the constant pool.
- *
- * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
- * @param accessFlags the access flags
- */
- public void generateMethodInfoHeader(MethodBinding methodBinding, int accessFlags) {
- // check that there is enough space to write all the bytes for the method info corresponding
- // to the @methodBinding
- methodCount++; // add one more method
- if (contentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- if (targetJDK < ClassFileConstants.JDK1_5) {
- // pre 1.5, synthetic was an attribute, not a modifier
- accessFlags &= ~AccSynthetic;
- }
- if (methodBinding.isRequiredToClearPrivateModifier()) {
- accessFlags &= ~AccPrivate;
- }
- contents[contentsOffset++] = (byte) (accessFlags >> 8);
- contents[contentsOffset++] = (byte) accessFlags;
- int nameIndex = constantPool.literalIndex(methodBinding.selector);
- contents[contentsOffset++] = (byte) (nameIndex >> 8);
- contents[contentsOffset++] = (byte) nameIndex;
- int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
- contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
- contents[contentsOffset++] = (byte) descriptorIndex;
- }
-
- /**
- * INTERNAL USE-ONLY
- * That method generates the method info header of a clinit:
- * The header consists in:
- * - the access flags (always default access + static)
- * - the name index of the method name (always ) inside the constant pool
- * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
- */
- public void generateMethodInfoHeaderForClinit() {
- // check that there is enough space to write all the bytes for the method info corresponding
- // to the @methodBinding
- methodCount++; // add one more method
- if (contentsOffset + 10 >= this.contents.length) {
- resizeContents(10);
- }
- contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
- contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
- int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
- contents[contentsOffset++] = (byte) (nameIndex >> 8);
- contents[contentsOffset++] = (byte) nameIndex;
- int descriptorIndex =
- constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
- contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
- contents[contentsOffset++] = (byte) descriptorIndex;
- // We know that we won't get more than 1 attribute: the code attribute
- contents[contentsOffset++] = 0;
- contents[contentsOffset++] = 1;
- }
-
- /**
- * EXTERNAL API
- * Answer the actual bytes of the class file
- *
- * This method encodes the receiver structure into a byte array which is the content of the classfile.
- * Returns the byte array that represents the encoded structure of the receiver.
- *
- * @return byte[]
- */
- public byte[] getBytes() {
- byte[] fullContents = new byte[headerOffset + contentsOffset];
- System.arraycopy(header, 0, fullContents, 0, headerOffset);
- System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
- return fullContents;
- }
-
- /**
- * EXTERNAL API
- * Answer the compound name of the class file.
- * @return char[][]
- * e.g. {{java}, {util}, {Hashtable}}.
- */
- public char[][] getCompoundName() {
- return CharOperation.splitOn('/', fileName());
- }
-
- protected void initByteArrays() {
- LookupEnvironment env = this.referenceBinding.scope.environment();
- synchronized (env) {
- if (env.sharedArraysUsed) {
- this.ownSharedArrays = false;
- int members = referenceBinding.methods().length + referenceBinding.fields().length;
- this.header = new byte[INITIAL_HEADER_SIZE];
- this.contents = new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE];
- } else {
- this.ownSharedArrays = env.sharedArraysUsed = true;
- this.header = env.sharedClassFileHeader;
- this.contents = env.sharedClassFileContents;
- }
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
- * for all inner types of the receiver.
- * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
- */
- public ClassFile outerMostEnclosingClassFile() {
- ClassFile current = this;
- while (current.enclosingClassFile != null)
- current = current.enclosingClassFile;
- return current;
- }
-
- /**
- * INTERNAL USE-ONLY
- * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
- * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
- *
- * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
- */
- public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
- // add all the enclosing types
- ReferenceBinding enclosingType = referenceBinding.enclosingType();
- int depth = 0;
- while (enclosingType != null) {
- depth++;
- enclosingType = enclosingType.enclosingType();
- }
- enclosingType = referenceBinding;
- ReferenceBinding enclosingTypes[];
- if (depth >= 2) {
- enclosingTypes = new ReferenceBinding[depth];
- for (int i = depth - 1; i >= 0; i--) {
- enclosingTypes[i] = enclosingType;
- enclosingType = enclosingType.enclosingType();
- }
- for (int i = 0; i < depth; i++) {
- addInnerClasses(enclosingTypes[i]);
- }
- } else {
- addInnerClasses(referenceBinding);
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
- * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
- *
- * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
- */
- public void recordNestedLocalAttribute(ReferenceBinding binding) {
- // add all the enclosing types
- ReferenceBinding enclosingType = referenceBinding.enclosingType();
- int depth = 0;
- while (enclosingType != null) {
- depth++;
- enclosingType = enclosingType.enclosingType();
- }
- enclosingType = referenceBinding;
- ReferenceBinding enclosingTypes[];
- if (depth >= 2) {
- enclosingTypes = new ReferenceBinding[depth];
- for (int i = depth - 1; i >= 0; i--) {
- enclosingTypes[i] = enclosingType;
- enclosingType = enclosingType.enclosingType();
- }
- for (int i = 0; i < depth; i++)
- addInnerClasses(enclosingTypes[i]);
- } else {
- addInnerClasses(binding);
- }
- }
-
- /**
- * INTERNAL USE-ONLY
- * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
- * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
- *
- * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
- */
- public void recordNestedMemberAttribute(ReferenceBinding binding) {
- addInnerClasses(binding);
- }
-
- /**
- * Resize the pool contents
- */
- private final void resizeContents(int minimalSize) {
- int length = this.contents.length;
- int toAdd = length;
- if (toAdd < minimalSize)
- toAdd = minimalSize;
- System.arraycopy(this.contents, 0, this.contents = new byte[length + toAdd], 0, length);
- }
-
- /**
- * INTERNAL USE-ONLY
- * Search the line number corresponding to a specific position
- */
- public static final int searchLineNumber(
- int[] startLineIndexes,
- int position) {
- // this code is completely useless, but it is the same implementation than
- // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
- // if (startLineIndexes == null)
- // return 1;
- int length = startLineIndexes.length;
- if (length == 0)
- return 1;
- int g = 0, d = length - 1;
- int m = 0;
- while (g <= d) {
- m = (g + d) / 2;
- if (position < startLineIndexes[m]) {
- d = m - 1;
- } else
- if (position > startLineIndexes[m]) {
- g = m + 1;
- } else {
- return m + 1;
- }
- }
- if (position < startLineIndexes[m]) {
- return m + 1;
- }
- return m + 2;
- }
-
- /**
- * INTERNAL USE-ONLY
- * This methods leaves the space for method counts recording.
- */
- public void setForMethodInfos() {
- // leave some space for the methodCount
- methodCountOffset = contentsOffset;
- contentsOffset += 2;
- }
-
- /**
- * INTERNAL USE-ONLY
- * outputPath is formed like:
- * c:\temp\ the last character is a file separator
- * relativeFileName is formed like:
- * java\lang\String.class
- * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
- * @param outputPath the output directory
- * @param relativeFileName java.lang.String
- * @param contents byte[]
- *
- */
- public static void writeToDisk(
- boolean generatePackagesStructure,
- String outputPath,
- String relativeFileName,
- byte[] contents)
- throws IOException {
-
- BufferedOutputStream output = null;
- if (generatePackagesStructure) {
- output = new BufferedOutputStream(
- new FileOutputStream(
- new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
- } else {
- String fileName = null;
- char fileSeparatorChar = File.separatorChar;
- String fileSeparator = File.separator;
- // First we ensure that the outputPath exists
- outputPath = outputPath.replace('/', fileSeparatorChar);
- // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
- int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
- if (indexOfPackageSeparator == -1) {
- if (outputPath.endsWith(fileSeparator)) {
- fileName = outputPath + relativeFileName;
- } else {
- fileName = outputPath + fileSeparator + relativeFileName;
- }
- } else {
- int length = relativeFileName.length();
- if (outputPath.endsWith(fileSeparator)) {
- fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
- } else {
- fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
- }
- }
- output = new BufferedOutputStream(
- new FileOutputStream(
- new File(fileName)));
- }
- try {
- output.write(contents);
- } finally {
- output.flush();
- output.close();
- }
- }
-}