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(); - } - } -}