1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler;
14 import java.util.StringTokenizer;
16 import org.eclipse.jdt.core.compiler.CharOperation;
17 import org.eclipse.jdt.core.compiler.IProblem;
18 import org.eclipse.jdt.internal.compiler.ast.*;
19 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
20 import org.eclipse.jdt.internal.compiler.codegen.*;
21 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22 import org.eclipse.jdt.internal.compiler.impl.Constant;
23 import org.eclipse.jdt.internal.compiler.impl.StringConstant;
24 import org.eclipse.jdt.internal.compiler.lookup.*;
25 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
26 import org.eclipse.jdt.internal.compiler.util.Util;
29 * Represents a class file wrapper on bytes, it is aware of its actual
32 * Public APIs are listed below:
35 * Answer the actual bytes of the class file
37 * char[][] getCompoundName();
38 * Answer the compound name of the class file.
39 * For example, {{java}, {util}, {Hashtable}}.
41 * byte[] getReducedBytes();
42 * Answer a smaller byte format, which is only contains some structural
43 * information. Those bytes are decodable with a regular class file reader,
44 * such as DietClassFileReader
46 public class ClassFile
47 implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
48 public SourceTypeBinding referenceBinding;
49 public ConstantPool constantPool;
50 public ClassFile enclosingClassFile;
51 // used to generate private access methods
52 public int produceDebugAttributes;
53 public ReferenceBinding[] innerClassesBindings;
54 public int numberOfInnerClasses;
56 // the header contains all the bytes till the end of the constant pool
57 public byte[] contents;
58 // that collection contains all the remaining bytes of the .class file
59 public int headerOffset;
60 public int contentsOffset;
61 public int constantPoolOffset;
62 public int methodCountOffset;
63 public int methodCount;
64 protected boolean creatingProblemType;
65 public static final int INITIAL_CONTENTS_SIZE = 400;
66 public static final int INITIAL_HEADER_SIZE = 1500;
67 public boolean ownSharedArrays = false; // flag set when header/contents are set to shared arrays
68 public static final int INNER_CLASSES_SIZE = 5;
69 public CodeStream codeStream;
70 protected int problemLine; // used to create line number attributes for problem methods
71 public long targetJDK;
75 * This methods creates a new instance of the receiver.
78 // default constructor for subclasses
83 * This methods creates a new instance of the receiver.
85 * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
86 * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
87 * @param creatingProblemType <CODE>boolean</CODE>
90 SourceTypeBinding aType,
91 ClassFile enclosingClassFile,
92 boolean creatingProblemType) {
94 referenceBinding = aType;
97 // generate the magic numbers inside the header
98 header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
99 header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
100 header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
101 header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
103 this.targetJDK = referenceBinding.scope.environment().options.targetJDK;
104 header[headerOffset++] = (byte) (this.targetJDK >> 8); // minor high
105 header[headerOffset++] = (byte) (this.targetJDK >> 0); // minor low
106 header[headerOffset++] = (byte) (this.targetJDK >> 24); // major high
107 header[headerOffset++] = (byte) (this.targetJDK >> 16); // major low
109 constantPoolOffset = headerOffset;
111 constantPool = new ConstantPool(this);
113 // Modifier manipulations for classfile
114 int accessFlags = aType.getAccessFlags();
115 if (aType.isPrivate()) { // rewrite private to non-public
116 accessFlags &= ~AccPublic;
118 if (aType.isProtected()) { // rewrite protected into public
119 accessFlags |= AccPublic;
121 // clear all bits that are illegal for a class or an interface
131 // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value)
132 if (aType.isClass()) {
133 accessFlags |= AccSuper;
136 this.enclosingClassFile = enclosingClassFile;
137 // innerclasses get their names computed at code gen time
139 // now we continue to generate the bytes inside the contents array
140 contents[contentsOffset++] = (byte) (accessFlags >> 8);
141 contents[contentsOffset++] = (byte) accessFlags;
142 int classNameIndex = constantPool.literalIndex(aType);
143 contents[contentsOffset++] = (byte) (classNameIndex >> 8);
144 contents[contentsOffset++] = (byte) classNameIndex;
145 int superclassNameIndex;
146 if (aType.isInterface()) {
147 superclassNameIndex = constantPool.literalIndexForJavaLangObject();
149 superclassNameIndex =
150 (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
152 contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
153 contents[contentsOffset++] = (byte) superclassNameIndex;
154 ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
155 int interfacesCount = superInterfacesBinding.length;
156 contents[contentsOffset++] = (byte) (interfacesCount >> 8);
157 contents[contentsOffset++] = (byte) interfacesCount;
158 for (int i = 0; i < interfacesCount; i++) {
159 int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
160 contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
161 contents[contentsOffset++] = (byte) interfaceIndex;
163 produceDebugAttributes = referenceBinding.scope.environment().options.produceDebugAttributes;
164 innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
165 this.creatingProblemType = creatingProblemType;
166 codeStream = new CodeStream(this);
168 // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
169 // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
170 ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
171 if (this == outermostClassFile) {
172 codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
174 codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
180 * Generate the byte for a problem method info that correspond to a boggus method.
182 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
183 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
185 public void addAbstractMethod(
186 AbstractMethodDeclaration method,
187 MethodBinding methodBinding) {
189 // force the modifiers to be public and abstract
190 methodBinding.modifiers = AccPublic | AccAbstract;
192 this.generateMethodInfoHeader(methodBinding);
193 int methodAttributeOffset = this.contentsOffset;
194 int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
195 this.completeMethodInfo(methodAttributeOffset, attributeNumber);
200 * This methods generate all the attributes for the receiver.
201 * For a class they could be:
202 * - source file attribute
203 * - inner classes attribute
204 * - deprecated attribute
206 public void addAttributes() {
207 // update the method count
208 contents[methodCountOffset++] = (byte) (methodCount >> 8);
209 contents[methodCountOffset] = (byte) methodCount;
211 int attributeNumber = 0;
212 // leave two bytes for the number of attributes and store the current offset
213 int attributeOffset = contentsOffset;
217 if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
218 String fullFileName =
219 new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
220 fullFileName = fullFileName.replace('\\', '/');
221 int lastIndex = fullFileName.lastIndexOf('/');
222 if (lastIndex != -1) {
223 fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
225 // check that there is enough space to write all the bytes for the field info corresponding
226 // to the @fieldBinding
227 if (contentsOffset + 8 >= contents.length) {
230 int sourceAttributeNameIndex =
231 constantPool.literalIndex(AttributeNamesConstants.SourceName);
232 contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
233 contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
234 // The length of a source file attribute is 2. This is a fixed-length
236 contents[contentsOffset++] = 0;
237 contents[contentsOffset++] = 0;
238 contents[contentsOffset++] = 0;
239 contents[contentsOffset++] = 2;
240 // write the source file name
241 int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
242 contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
243 contents[contentsOffset++] = (byte) fileNameIndex;
246 // Deprecated attribute
247 if (referenceBinding.isDeprecated()) {
248 // check that there is enough space to write all the bytes for the field info corresponding
249 // to the @fieldBinding
250 if (contentsOffset + 6 >= contents.length) {
253 int deprecatedAttributeNameIndex =
254 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
255 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
256 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
257 // the length of a deprecated attribute is equals to 0
258 contents[contentsOffset++] = 0;
259 contents[contentsOffset++] = 0;
260 contents[contentsOffset++] = 0;
261 contents[contentsOffset++] = 0;
264 // Inner class attribute
265 if (numberOfInnerClasses != 0) {
266 // Generate the inner class attribute
267 int exSize = 8 * numberOfInnerClasses + 8;
268 if (exSize + contentsOffset >= this.contents.length) {
269 resizeContents(exSize);
271 // Now we now the size of the attribute and the number of entries
273 int attributeNameIndex =
274 constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
275 contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
276 contents[contentsOffset++] = (byte) attributeNameIndex;
277 int value = (numberOfInnerClasses << 3) + 2;
278 contents[contentsOffset++] = (byte) (value >> 24);
279 contents[contentsOffset++] = (byte) (value >> 16);
280 contents[contentsOffset++] = (byte) (value >> 8);
281 contents[contentsOffset++] = (byte) value;
282 contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
283 contents[contentsOffset++] = (byte) numberOfInnerClasses;
284 for (int i = 0; i < numberOfInnerClasses; i++) {
285 ReferenceBinding innerClass = innerClassesBindings[i];
286 int accessFlags = innerClass.getAccessFlags();
287 int innerClassIndex = constantPool.literalIndex(innerClass);
289 contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
290 contents[contentsOffset++] = (byte) innerClassIndex;
291 // outer class index: anonymous and local have no outer class index
292 if (innerClass.isMemberType()) {
293 // member or member of local
294 int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
295 contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
296 contents[contentsOffset++] = (byte) outerClassIndex;
298 // equals to 0 if the innerClass is not a member type
299 contents[contentsOffset++] = 0;
300 contents[contentsOffset++] = 0;
303 if (!innerClass.isAnonymousType()) {
304 int nameIndex = constantPool.literalIndex(innerClass.sourceName());
305 contents[contentsOffset++] = (byte) (nameIndex >> 8);
306 contents[contentsOffset++] = (byte) nameIndex;
308 // equals to 0 if the innerClass is an anonymous type
309 contents[contentsOffset++] = 0;
310 contents[contentsOffset++] = 0;
313 if (innerClass.isAnonymousType()) {
314 accessFlags |= AccPrivate;
316 if (innerClass.isLocalType() && !innerClass.isMemberType()) {
317 accessFlags |= AccPrivate;
319 contents[contentsOffset++] = (byte) (accessFlags >> 8);
320 contents[contentsOffset++] = (byte) accessFlags;
324 // update the number of attributes
325 if (attributeOffset + 2 >= this.contents.length) {
328 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
329 contents[attributeOffset] = (byte) attributeNumber;
331 // resynchronize all offsets of the classfile
332 header = constantPool.poolContent;
333 headerOffset = constantPool.currentOffset;
334 int constantPoolCount = constantPool.currentIndex;
335 header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
336 header[constantPoolOffset] = (byte) constantPoolCount;
341 * This methods generate all the default abstract method infos that correpond to
342 * the abstract methods inherited from superinterfaces.
344 public void addDefaultAbstractMethods() { // default abstract methods
345 MethodBinding[] defaultAbstractMethods =
346 referenceBinding.getDefaultAbstractMethods();
347 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
348 generateMethodInfoHeader(defaultAbstractMethods[i]);
349 int methodAttributeOffset = contentsOffset;
350 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
351 completeMethodInfo(methodAttributeOffset, attributeNumber);
357 * This methods generates the bytes for the field binding passed like a parameter
358 * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
360 public void addFieldInfo(FieldBinding fieldBinding) {
361 int attributeNumber = 0;
362 // check that there is enough space to write all the bytes for the field info corresponding
363 // to the @fieldBinding
364 if (contentsOffset + 30 >= contents.length) {
367 // Generate two attribute: constantValueAttribute and SyntheticAttribute
368 // Now we can generate all entries into the byte array
369 // First the accessFlags
370 int accessFlags = fieldBinding.getAccessFlags();
371 contents[contentsOffset++] = (byte) (accessFlags >> 8);
372 contents[contentsOffset++] = (byte) accessFlags;
373 // Then the nameIndex
374 int nameIndex = constantPool.literalIndex(fieldBinding.name);
375 contents[contentsOffset++] = (byte) (nameIndex >> 8);
376 contents[contentsOffset++] = (byte) nameIndex;
377 // Then the descriptorIndex
378 int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
379 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
380 contents[contentsOffset++] = (byte) descriptorIndex;
381 // leave some space for the number of attributes
382 int fieldAttributeOffset = contentsOffset;
384 // 4.7.2 only static constant fields get a ConstantAttribute
385 if (fieldBinding.constant != Constant.NotAConstant){
386 // Now we generate the constant attribute corresponding to the fieldBinding
387 int constantValueNameIndex =
388 constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
389 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
390 contents[contentsOffset++] = (byte) constantValueNameIndex;
391 // The attribute length = 2 in case of a constantValue attribute
392 contents[contentsOffset++] = 0;
393 contents[contentsOffset++] = 0;
394 contents[contentsOffset++] = 0;
395 contents[contentsOffset++] = 2;
397 // Need to add the constant_value_index
398 switch (fieldBinding.constant.typeID()) {
400 int booleanValueIndex =
401 constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
402 contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
403 contents[contentsOffset++] = (byte) booleanValueIndex;
409 int integerValueIndex =
410 constantPool.literalIndex(fieldBinding.constant.intValue());
411 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
412 contents[contentsOffset++] = (byte) integerValueIndex;
415 int floatValueIndex =
416 constantPool.literalIndex(fieldBinding.constant.floatValue());
417 contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
418 contents[contentsOffset++] = (byte) floatValueIndex;
421 int doubleValueIndex =
422 constantPool.literalIndex(fieldBinding.constant.doubleValue());
423 contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
424 contents[contentsOffset++] = (byte) doubleValueIndex;
428 constantPool.literalIndex(fieldBinding.constant.longValue());
429 contents[contentsOffset++] = (byte) (longValueIndex >> 8);
430 contents[contentsOffset++] = (byte) longValueIndex;
433 int stringValueIndex =
434 constantPool.literalIndex(
435 ((StringConstant) fieldBinding.constant).stringValue());
436 if (stringValueIndex == -1) {
437 if (!creatingProblemType) {
438 // report an error and abort: will lead to a problem type classfile creation
439 TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
440 FieldDeclaration[] fieldDecls = typeDeclaration.fields;
441 for (int i = 0, max = fieldDecls.length; i < max; i++) {
442 if (fieldDecls[i].binding == fieldBinding) {
443 // problem should abort
444 typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
449 // already inside a problem type creation : no constant for this field
450 contentsOffset = fieldAttributeOffset + 2;
451 // +2 is necessary to keep the two byte space for the attribute number
455 contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
456 contents[contentsOffset++] = (byte) stringValueIndex;
460 if (fieldBinding.isSynthetic()) {
461 int syntheticAttributeNameIndex =
462 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
463 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
464 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
465 // the length of a synthetic attribute is equals to 0
466 contents[contentsOffset++] = 0;
467 contents[contentsOffset++] = 0;
468 contents[contentsOffset++] = 0;
469 contents[contentsOffset++] = 0;
472 if (fieldBinding.isDeprecated()) {
473 int deprecatedAttributeNameIndex =
474 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
475 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
476 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
477 // the length of a deprecated attribute is equals to 0
478 contents[contentsOffset++] = 0;
479 contents[contentsOffset++] = 0;
480 contents[contentsOffset++] = 0;
481 contents[contentsOffset++] = 0;
484 contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
485 contents[fieldAttributeOffset] = (byte) attributeNumber;
490 * This methods generate all the fields infos for the receiver.
492 * - a field info for each defined field of that class
493 * - a field info for each synthetic field (e.g. this$0)
495 public void addFieldInfos() {
496 SourceTypeBinding currentBinding = referenceBinding;
497 FieldBinding[] syntheticFields = currentBinding.syntheticFields();
499 currentBinding.fieldCount()
500 + (syntheticFields == null ? 0 : syntheticFields.length);
502 // write the number of fields
503 if (fieldCount > 0xFFFF) {
504 referenceBinding.scope.problemReporter().tooManyFields(referenceBinding.scope.referenceType());
506 contents[contentsOffset++] = (byte) (fieldCount >> 8);
507 contents[contentsOffset++] = (byte) fieldCount;
509 FieldBinding[] fieldBindings = currentBinding.fields();
510 for (int i = 0, max = fieldBindings.length; i < max; i++) {
511 addFieldInfo(fieldBindings[i]);
513 if (syntheticFields != null) {
514 for (int i = 0, max = syntheticFields.length; i < max; i++) {
515 addFieldInfo(syntheticFields[i]);
522 * This methods stores the bindings for each inner class. They will be used to know which entries
523 * have to be generated for the inner classes attributes.
524 * @param refBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
526 public void addInnerClasses(ReferenceBinding refBinding) {
527 // check first if that reference binding is there
528 for (int i = 0; i < numberOfInnerClasses; i++) {
529 if (innerClassesBindings[i] == refBinding)
532 int length = innerClassesBindings.length;
533 if (numberOfInnerClasses == length) {
535 innerClassesBindings,
537 innerClassesBindings = new ReferenceBinding[length * 2],
541 innerClassesBindings[numberOfInnerClasses++] = refBinding;
546 * Generate the byte for a problem clinit method info that correspond to a boggus method.
548 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
550 public void addProblemClinit(IProblem[] problems) {
551 generateMethodInfoHeaderForClinit();
552 // leave two spaces for the number of attributes
554 int attributeOffset = contentsOffset;
556 int attributeNumber = 0;
558 int codeAttributeOffset = contentsOffset;
559 generateCodeAttributeHeader();
560 codeStream.resetForProblemClinit(this);
561 String problemString = "" ; //$NON-NLS-1$
562 if (problems != null) {
563 int max = problems.length;
564 StringBuffer buffer = new StringBuffer(25);
566 for (int i = 0; i < max; i++) {
567 IProblem problem = problems[i];
568 if ((problem != null) && (problem.isError())) {
569 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
571 if (problemLine == 0) {
572 problemLine = problem.getSourceLineNumber();
576 } // insert the top line afterwards, once knowing how many problems we have to consider
578 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
580 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
582 problemString = buffer.toString();
585 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
586 codeStream.generateCodeAttributeForProblemMethod(problemString);
587 attributeNumber++; // code attribute
588 completeCodeAttributeForClinit(
592 .referenceCompilationUnit()
594 .lineSeparatorPositions);
595 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
596 contents[attributeOffset] = (byte) attributeNumber;
601 * Generate the byte for a problem method info that correspond to a boggus constructor.
603 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
604 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
605 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
607 public void addProblemConstructor(
608 AbstractMethodDeclaration method,
609 MethodBinding methodBinding,
610 IProblem[] problems) {
612 // always clear the strictfp/native/abstract bit for a problem method
613 generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
614 int methodAttributeOffset = contentsOffset;
615 int attributeNumber = generateMethodInfoAttribute(methodBinding);
619 int codeAttributeOffset = contentsOffset;
620 generateCodeAttributeHeader();
621 codeStream.reset(method, this);
622 String problemString = "" ; //$NON-NLS-1$
623 if (problems != null) {
624 int max = problems.length;
625 StringBuffer buffer = new StringBuffer(25);
627 for (int i = 0; i < max; i++) {
628 IProblem problem = problems[i];
629 if ((problem != null) && (problem.isError())) {
630 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
632 if (problemLine == 0) {
633 problemLine = problem.getSourceLineNumber();
636 } // insert the top line afterwards, once knowing how many problems we have to consider
638 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
640 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
642 problemString = buffer.toString();
645 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
646 codeStream.generateCodeAttributeForProblemMethod(problemString);
647 completeCodeAttributeForProblemMethod(
651 ((SourceTypeBinding) methodBinding.declaringClass)
653 .referenceCompilationUnit()
655 .lineSeparatorPositions);
656 completeMethodInfo(methodAttributeOffset, attributeNumber);
661 * Generate the byte for a problem method info that correspond to a boggus constructor.
662 * Reset the position inside the contents byte array to the savedOffset.
664 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
665 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
666 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
667 * @param savedOffset <CODE>int</CODE>
669 public void addProblemConstructor(
670 AbstractMethodDeclaration method,
671 MethodBinding methodBinding,
674 // we need to move back the contentsOffset to the value at the beginning of the method
675 contentsOffset = savedOffset;
676 methodCount--; // we need to remove the method that causes the problem
677 addProblemConstructor(method, methodBinding, problems);
682 * Generate the byte for a problem method info that correspond to a boggus method.
684 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
685 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
686 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
688 public void addProblemMethod(
689 AbstractMethodDeclaration method,
690 MethodBinding methodBinding,
691 IProblem[] problems) {
692 if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
693 method.abort(ProblemSeverities.AbortType, null);
695 // always clear the strictfp/native/abstract bit for a problem method
696 generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
697 int methodAttributeOffset = contentsOffset;
698 int attributeNumber = generateMethodInfoAttribute(methodBinding);
703 int codeAttributeOffset = contentsOffset;
704 generateCodeAttributeHeader();
705 codeStream.reset(method, this);
706 String problemString = "" ; //$NON-NLS-1$
707 if (problems != null) {
708 int max = problems.length;
709 StringBuffer buffer = new StringBuffer(25);
711 for (int i = 0; i < max; i++) {
712 IProblem problem = problems[i];
713 if ((problem != null)
714 && (problem.isError())
715 && (problem.getSourceStart() >= method.declarationSourceStart)
716 && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
717 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
719 if (problemLine == 0) {
720 problemLine = problem.getSourceLineNumber();
724 } // insert the top line afterwards, once knowing how many problems we have to consider
726 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
728 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
730 problemString = buffer.toString();
733 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
734 codeStream.generateCodeAttributeForProblemMethod(problemString);
735 completeCodeAttributeForProblemMethod(
739 ((SourceTypeBinding) methodBinding.declaringClass)
741 .referenceCompilationUnit()
743 .lineSeparatorPositions);
744 completeMethodInfo(methodAttributeOffset, attributeNumber);
749 * Generate the byte for a problem method info that correspond to a boggus method.
750 * Reset the position inside the contents byte array to the savedOffset.
752 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
753 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
754 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
755 * @param savedOffset <CODE>int</CODE>
757 public void addProblemMethod(
758 AbstractMethodDeclaration method,
759 MethodBinding methodBinding,
762 // we need to move back the contentsOffset to the value at the beginning of the method
763 contentsOffset = savedOffset;
764 methodCount--; // we need to remove the method that causes the problem
765 addProblemMethod(method, methodBinding, problems);
770 * Generate the byte for all the special method infos.
772 * - synthetic access methods
773 * - default abstract methods
775 public void addSpecialMethods() {
776 // add all methods (default abstract methods and synthetic)
778 // default abstract methods
779 SourceTypeBinding currentBinding = referenceBinding;
780 MethodBinding[] defaultAbstractMethods =
781 currentBinding.getDefaultAbstractMethods();
782 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
783 generateMethodInfoHeader(defaultAbstractMethods[i]);
784 int methodAttributeOffset = contentsOffset;
785 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
786 completeMethodInfo(methodAttributeOffset, attributeNumber);
788 // add synthetic methods infos
789 SyntheticAccessMethodBinding[] syntheticAccessMethods =
790 currentBinding.syntheticAccessMethods();
791 if (syntheticAccessMethods != null) {
792 for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
793 SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
794 switch (accessMethodBinding.accessType) {
795 case SyntheticAccessMethodBinding.FieldReadAccess :
796 // generate a method info to emulate an reading access to
797 // a non-accessible field
798 addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
800 case SyntheticAccessMethodBinding.FieldWriteAccess :
801 // generate a method info to emulate an writing access to
802 // a non-accessible field
803 addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
805 case SyntheticAccessMethodBinding.MethodAccess :
806 case SyntheticAccessMethodBinding.SuperMethodAccess :
807 // generate a method info to emulate an access to a non-accessible method / super-method
808 addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
810 case SyntheticAccessMethodBinding.ConstructorAccess :
811 // generate a method info to emulate an access to a non-accessible constructor
812 addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
820 * Generate the byte for problem method infos that correspond to missing abstract methods.
821 * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
823 * @param methodDeclarations Array of all missing abstract methods
825 public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
826 if (methodDeclarations != null) {
827 for (int i = 0, max = methodDeclarations.length; i < max; i++) {
828 MethodDeclaration methodDeclaration = methodDeclarations[i];
829 MethodBinding methodBinding = methodDeclaration.binding;
830 String readableName = new String(methodBinding.readableName());
831 IProblem[] problems = compilationResult.problems;
832 int problemsCount = compilationResult.problemCount;
833 for (int j = 0; j < problemsCount; j++) {
834 IProblem problem = problems[j];
836 && problem.getID() == IProblem.AbstractMethodMustBeImplemented
837 && problem.getMessage().indexOf(readableName) != -1) {
839 addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
846 private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
847 // always clear the strictfp/native/abstract bit for a problem method
848 generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
849 int methodAttributeOffset = contentsOffset;
850 int attributeNumber = generateMethodInfoAttribute(methodBinding);
855 int codeAttributeOffset = contentsOffset;
856 generateCodeAttributeHeader();
857 StringBuffer buffer = new StringBuffer(25);
858 buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
859 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
860 String problemString = buffer.toString();
861 this.problemLine = problem.getSourceLineNumber();
863 codeStream.init(this);
864 codeStream.preserveUnusedLocals = true;
865 codeStream.initializeMaxLocals(methodBinding);
867 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
868 codeStream.generateCodeAttributeForProblemMethod(problemString);
870 completeCodeAttributeForMissingAbstractProblemMethod(
873 compilationResult.lineSeparatorPositions);
875 completeMethodInfo(methodAttributeOffset, attributeNumber);
881 public void completeCodeAttributeForMissingAbstractProblemMethod(
882 MethodBinding binding,
883 int codeAttributeOffset,
884 int[] startLineIndexes) {
885 // reinitialize the localContents with the byte modified by the code stream
886 this.contents = codeStream.bCodeStream;
887 int localContentsOffset = codeStream.classFileOffset;
888 // 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...
889 int max_stack = codeStream.stackMax;
890 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
891 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
892 int max_locals = codeStream.maxLocals;
893 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
894 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
895 int code_length = codeStream.position;
896 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
897 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
898 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
899 this.contents[codeAttributeOffset + 13] = (byte) code_length;
900 // write the exception table
901 if (localContentsOffset + 50 >= this.contents.length) {
904 this.contents[localContentsOffset++] = 0;
905 this.contents[localContentsOffset++] = 0;
907 int codeAttributeAttributeOffset = localContentsOffset;
908 int attributeNumber = 0; // leave two bytes for the attribute_length
909 localContentsOffset += 2; // first we handle the linenumber attribute
911 if (codeStream.generateLineNumberAttributes) {
912 /* Create and add the line number attribute (used for debugging)
913 * Build the pairs of:
914 * (bytecodePC lineNumber)
915 * according to the table of start line indexes and the pcToSourceMap table
916 * contained into the codestream
918 int lineNumberNameIndex =
919 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
920 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
921 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
922 this.contents[localContentsOffset++] = 0;
923 this.contents[localContentsOffset++] = 0;
924 this.contents[localContentsOffset++] = 0;
925 this.contents[localContentsOffset++] = 6;
926 this.contents[localContentsOffset++] = 0;
927 this.contents[localContentsOffset++] = 1;
928 if (problemLine == 0) {
929 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
931 // first entry at pc = 0
932 this.contents[localContentsOffset++] = 0;
933 this.contents[localContentsOffset++] = 0;
934 this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
935 this.contents[localContentsOffset++] = (byte) problemLine;
936 // now we change the size of the line number attribute
940 // then we do the local variable attribute
941 // update the number of attributes// ensure first that there is enough space available inside the localContents array
942 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
945 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
946 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
947 // update the attribute length
948 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
949 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
950 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
951 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
952 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
953 contentsOffset = localContentsOffset;
958 * Generate the byte for a problem method info that correspond to a synthetic method that
959 * generate an access to a private constructor.
961 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
963 public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
964 generateMethodInfoHeader(methodBinding);
965 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
966 contents[contentsOffset++] = 0;
967 contents[contentsOffset++] = 2;
969 int codeAttributeOffset = contentsOffset;
970 generateCodeAttributeHeader();
971 codeStream.init(this);
972 codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
973 completeCodeAttributeForSyntheticAccessMethod(
976 ((SourceTypeBinding) methodBinding.declaringClass)
978 .referenceCompilationUnit()
980 .lineSeparatorPositions);
981 // add the synthetic attribute
982 int syntheticAttributeNameIndex =
983 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
984 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
985 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
986 // the length of a synthetic attribute is equals to 0
987 contents[contentsOffset++] = 0;
988 contents[contentsOffset++] = 0;
989 contents[contentsOffset++] = 0;
990 contents[contentsOffset++] = 0;
995 * Generate the byte for a problem method info that correspond to a synthetic method that
996 * generate an read access to a private field.
998 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1000 public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1001 generateMethodInfoHeader(methodBinding);
1002 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1003 contents[contentsOffset++] = 0;
1004 contents[contentsOffset++] = 2;
1006 int codeAttributeOffset = contentsOffset;
1007 generateCodeAttributeHeader();
1008 codeStream.init(this);
1009 codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
1010 completeCodeAttributeForSyntheticAccessMethod(
1012 codeAttributeOffset,
1013 ((SourceTypeBinding) methodBinding.declaringClass)
1015 .referenceCompilationUnit()
1017 .lineSeparatorPositions);
1018 // add the synthetic attribute
1019 int syntheticAttributeNameIndex =
1020 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1021 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1022 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1023 // the length of a synthetic attribute is equals to 0
1024 contents[contentsOffset++] = 0;
1025 contents[contentsOffset++] = 0;
1026 contents[contentsOffset++] = 0;
1027 contents[contentsOffset++] = 0;
1032 * Generate the byte for a problem method info that correspond to a synthetic method that
1033 * generate an write access to a private field.
1035 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1037 public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1038 generateMethodInfoHeader(methodBinding);
1039 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1040 contents[contentsOffset++] = 0;
1041 contents[contentsOffset++] = 2;
1043 int codeAttributeOffset = contentsOffset;
1044 generateCodeAttributeHeader();
1045 codeStream.init(this);
1046 codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
1047 completeCodeAttributeForSyntheticAccessMethod(
1049 codeAttributeOffset,
1050 ((SourceTypeBinding) methodBinding.declaringClass)
1052 .referenceCompilationUnit()
1054 .lineSeparatorPositions);
1055 // add the synthetic attribute
1056 int syntheticAttributeNameIndex =
1057 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1058 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1059 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1060 // the length of a synthetic attribute is equals to 0
1061 contents[contentsOffset++] = 0;
1062 contents[contentsOffset++] = 0;
1063 contents[contentsOffset++] = 0;
1064 contents[contentsOffset++] = 0;
1069 * Generate the byte for a problem method info that correspond to a synthetic method that
1070 * generate an access to a private method.
1072 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1074 public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1075 generateMethodInfoHeader(methodBinding);
1076 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1077 contents[contentsOffset++] = 0;
1078 contents[contentsOffset++] = 2;
1080 int codeAttributeOffset = contentsOffset;
1081 generateCodeAttributeHeader();
1082 codeStream.init(this);
1083 codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
1084 completeCodeAttributeForSyntheticAccessMethod(
1086 codeAttributeOffset,
1087 ((SourceTypeBinding) methodBinding.declaringClass)
1089 .referenceCompilationUnit()
1091 .lineSeparatorPositions);
1092 // add the synthetic attribute
1093 int syntheticAttributeNameIndex =
1094 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1095 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1096 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1097 // the length of a synthetic attribute is equals to 0
1098 contents[contentsOffset++] = 0;
1099 contents[contentsOffset++] = 0;
1100 contents[contentsOffset++] = 0;
1101 contents[contentsOffset++] = 0;
1106 * Build all the directories and subdirectories corresponding to the packages names
1107 * into the directory specified in parameters.
1109 * outputPath is formed like:
1110 * c:\temp\ the last character is a file separator
1111 * relativeFileName is formed like:
1112 * java\lang\String.class *
1114 * @param outputPath java.lang.String
1115 * @param relativeFileName java.lang.String
1116 * @return java.lang.String
1118 public static String buildAllDirectoriesInto(
1120 String relativeFileName)
1121 throws IOException {
1122 char fileSeparatorChar = File.separatorChar;
1123 String fileSeparator = File.separator;
1125 // First we ensure that the outputPath exists
1126 outputPath = outputPath.replace('/', fileSeparatorChar);
1127 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
1128 if (outputPath.endsWith(fileSeparator)) {
1129 outputPath = outputPath.substring(0, outputPath.length() - 1);
1131 f = new File(outputPath);
1133 if (!f.isDirectory()) {
1134 System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
1135 throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
1138 // we have to create that directory
1140 System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
1141 throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
1144 StringBuffer outDir = new StringBuffer(outputPath);
1145 outDir.append(fileSeparator);
1146 StringTokenizer tokenizer =
1147 new StringTokenizer(relativeFileName, fileSeparator);
1148 String token = tokenizer.nextToken();
1149 while (tokenizer.hasMoreTokens()) {
1150 f = new File(outDir.append(token).append(fileSeparator).toString());
1152 // The outDir already exists, so we proceed the next entry
1153 // System.out.println("outDir: " + outDir + " already exists.");
1155 // Need to add the outDir
1157 System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
1158 throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
1161 token = tokenizer.nextToken();
1163 // token contains the last one
1164 return outDir.append(token).toString();
1169 * That method completes the creation of the code attribute by setting
1170 * - the attribute_length
1175 * - and debug attributes if necessary.
1177 * @param codeAttributeOffset <CODE>int</CODE>
1179 public void completeCodeAttribute(int codeAttributeOffset) {
1180 // reinitialize the localContents with the byte modified by the code stream
1181 this.contents = codeStream.bCodeStream;
1182 int localContentsOffset = codeStream.classFileOffset;
1183 // codeAttributeOffset is the position inside localContents byte array before we started to write
1184 // any information about the codeAttribute
1185 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1186 // to get the right position, 6 for the max_stack etc...
1187 int code_length = codeStream.position;
1188 if (code_length > 65535) {
1189 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1190 codeStream.methodDeclaration);
1192 if (localContentsOffset + 20 >= this.contents.length) {
1195 int max_stack = codeStream.stackMax;
1196 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1197 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
1198 int max_locals = codeStream.maxLocals;
1199 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1200 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
1201 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1202 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1203 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1204 this.contents[codeAttributeOffset + 13] = (byte) code_length;
1206 // write the exception table
1207 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1208 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1209 int exSize = exceptionHandlersNumber * 8 + 2;
1210 if (exSize + localContentsOffset >= this.contents.length) {
1211 resizeContents(exSize);
1213 // there is no exception table, so we need to offset by 2 the current offset and move
1214 // on the attribute generation
1215 this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1216 this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1217 for (int i = 0; i < exceptionHandlersNumber; i++) {
1218 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1219 int start = exceptionHandler.start;
1220 this.contents[localContentsOffset++] = (byte) (start >> 8);
1221 this.contents[localContentsOffset++] = (byte) start;
1222 int end = exceptionHandler.end;
1223 this.contents[localContentsOffset++] = (byte) (end >> 8);
1224 this.contents[localContentsOffset++] = (byte) end;
1225 int handlerPC = exceptionHandler.position;
1226 this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
1227 this.contents[localContentsOffset++] = (byte) handlerPC;
1228 if (exceptionHandler.exceptionType == null) {
1229 // any exception handler
1230 this.contents[localContentsOffset++] = 0;
1231 this.contents[localContentsOffset++] = 0;
1234 if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
1235 /* represents ClassNotFoundException, see class literal access*/
1236 nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1238 nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1240 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1241 this.contents[localContentsOffset++] = (byte) nameIndex;
1245 int codeAttributeAttributeOffset = localContentsOffset;
1246 int attributeNumber = 0;
1247 // leave two bytes for the attribute_length
1248 localContentsOffset += 2;
1250 // first we handle the linenumber attribute
1251 if (codeStream.generateLineNumberAttributes) {
1252 /* Create and add the line number attribute (used for debugging)
1253 * Build the pairs of:
1254 * (bytecodePC lineNumber)
1255 * according to the table of start line indexes and the pcToSourceMap table
1256 * contained into the codestream
1258 int[] pcToSourceMapTable;
1259 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1260 && (codeStream.pcToSourceMapSize != 0)) {
1261 int lineNumberNameIndex =
1262 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1263 if (localContentsOffset + 8 >= this.contents.length) {
1266 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1267 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1268 int lineNumberTableOffset = localContentsOffset;
1269 localContentsOffset += 6;
1270 // leave space for attribute_length and line_number_table_length
1271 int numberOfEntries = 0;
1272 int length = codeStream.pcToSourceMapSize;
1273 for (int i = 0; i < length;) {
1275 if (localContentsOffset + 4 >= this.contents.length) {
1278 int pc = pcToSourceMapTable[i++];
1279 this.contents[localContentsOffset++] = (byte) (pc >> 8);
1280 this.contents[localContentsOffset++] = (byte) pc;
1281 int lineNumber = pcToSourceMapTable[i++];
1282 this.contents[localContentsOffset++] = (byte) (lineNumber >> 8);
1283 this.contents[localContentsOffset++] = (byte) lineNumber;
1286 // now we change the size of the line number attribute
1287 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1288 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1289 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1290 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1291 this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1292 this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1293 this.contents[lineNumberTableOffset++] = (byte) numberOfEntries;
1297 // then we do the local variable attribute
1298 if (codeStream.generateLocalVariableTableAttributes) {
1299 int localVariableTableOffset = localContentsOffset;
1300 int numberOfEntries = 0;
1301 int localVariableNameIndex =
1302 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1303 if (localContentsOffset + 8 >= this.contents.length) {
1306 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1307 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
1308 localContentsOffset += 6;
1309 // leave space for attribute_length and local_variable_table_length
1311 int descriptorIndex;
1312 if (!codeStream.methodDeclaration.isStatic()) {
1314 if (localContentsOffset + 10 >= this.contents.length) {
1317 this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
1318 this.contents[localContentsOffset++] = 0;
1319 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
1320 this.contents[localContentsOffset++] = (byte) code_length;
1321 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
1322 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1323 this.contents[localContentsOffset++] = (byte) nameIndex;
1325 constantPool.literalIndex(
1326 codeStream.methodDeclaration.binding.declaringClass.signature());
1327 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1328 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1329 this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
1330 this.contents[localContentsOffset++] = 0;
1332 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1333 LocalVariableBinding localVariable = codeStream.locals[i];
1334 for (int j = 0; j < localVariable.initializationCount; j++) {
1335 int startPC = localVariable.initializationPCs[j << 1];
1336 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1337 if (startPC != endPC) { // only entries for non zero length
1339 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1340 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1341 (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
1343 if (localContentsOffset + 10 >= this.contents.length) {
1346 // now we can safely add the local entry
1348 this.contents[localContentsOffset++] = (byte) (startPC >> 8);
1349 this.contents[localContentsOffset++] = (byte) startPC;
1350 int length = endPC - startPC;
1351 this.contents[localContentsOffset++] = (byte) (length >> 8);
1352 this.contents[localContentsOffset++] = (byte) length;
1353 nameIndex = constantPool.literalIndex(localVariable.name);
1354 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1355 this.contents[localContentsOffset++] = (byte) nameIndex;
1356 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1357 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1358 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1359 int resolvedPosition = localVariable.resolvedPosition;
1360 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1361 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1365 int value = numberOfEntries * 10 + 2;
1366 localVariableTableOffset += 2;
1367 this.contents[localVariableTableOffset++] = (byte) (value >> 24);
1368 this.contents[localVariableTableOffset++] = (byte) (value >> 16);
1369 this.contents[localVariableTableOffset++] = (byte) (value >> 8);
1370 this.contents[localVariableTableOffset++] = (byte) value;
1371 this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1372 this.contents[localVariableTableOffset] = (byte) numberOfEntries;
1375 // update the number of attributes
1376 // ensure first that there is enough space available inside the localContents array
1377 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
1380 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1381 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1383 // update the attribute length
1384 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1385 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1386 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1387 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1388 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1389 contentsOffset = localContentsOffset;
1394 * That method completes the creation of the code attribute by setting
1395 * - the attribute_length
1400 * - and debug attributes if necessary.
1402 * @param codeAttributeOffset <CODE>int</CODE>
1404 public void completeCodeAttributeForClinit(int codeAttributeOffset) {
1405 // reinitialize the contents with the byte modified by the code stream
1406 this.contents = codeStream.bCodeStream;
1407 int localContentsOffset = codeStream.classFileOffset;
1408 // codeAttributeOffset is the position inside contents byte array before we started to write
1409 // any information about the codeAttribute
1410 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1411 // to get the right position, 6 for the max_stack etc...
1412 int code_length = codeStream.position;
1413 if (code_length > 65535) {
1414 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1415 codeStream.methodDeclaration.scope.referenceType());
1417 if (localContentsOffset + 20 >= this.contents.length) {
1420 int max_stack = codeStream.stackMax;
1421 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1422 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
1423 int max_locals = codeStream.maxLocals;
1424 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1425 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
1426 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1427 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1428 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1429 this.contents[codeAttributeOffset + 13] = (byte) code_length;
1431 // write the exception table
1432 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1433 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1434 int exSize = exceptionHandlersNumber * 8 + 2;
1435 if (exSize + localContentsOffset >= this.contents.length) {
1436 resizeContents(exSize);
1438 // there is no exception table, so we need to offset by 2 the current offset and move
1439 // on the attribute generation
1440 this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1441 this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1442 for (int i = 0; i < exceptionHandlersNumber; i++) {
1443 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1444 int start = exceptionHandler.start;
1445 this.contents[localContentsOffset++] = (byte) (start >> 8);
1446 this.contents[localContentsOffset++] = (byte) start;
1447 int end = exceptionHandler.end;
1448 this.contents[localContentsOffset++] = (byte) (end >> 8);
1449 this.contents[localContentsOffset++] = (byte) end;
1450 int handlerPC = exceptionHandler.position;
1451 this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
1452 this.contents[localContentsOffset++] = (byte) handlerPC;
1453 if (exceptionHandler.exceptionType == null) {
1454 // any exception handler
1455 this.contents[localContentsOffset++] = 0;
1456 this.contents[localContentsOffset++] = 0;
1459 if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
1460 /* represents denote ClassNotFoundException, see class literal access*/
1461 nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1463 nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1465 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1466 this.contents[localContentsOffset++] = (byte) nameIndex;
1470 int codeAttributeAttributeOffset = localContentsOffset;
1471 int attributeNumber = 0;
1472 // leave two bytes for the attribute_length
1473 localContentsOffset += 2;
1475 // first we handle the linenumber attribute
1476 if (codeStream.generateLineNumberAttributes) {
1477 /* Create and add the line number attribute (used for debugging)
1478 * Build the pairs of:
1479 * (bytecodePC lineNumber)
1480 * according to the table of start line indexes and the pcToSourceMap table
1481 * contained into the codestream
1483 int[] pcToSourceMapTable;
1484 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1485 && (codeStream.pcToSourceMapSize != 0)) {
1486 int lineNumberNameIndex =
1487 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1488 if (localContentsOffset + 8 >= this.contents.length) {
1491 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1492 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1493 int lineNumberTableOffset = localContentsOffset;
1494 localContentsOffset += 6;
1495 // leave space for attribute_length and line_number_table_length
1496 int numberOfEntries = 0;
1497 int length = codeStream.pcToSourceMapSize;
1498 for (int i = 0; i < length;) {
1500 if (localContentsOffset + 4 >= this.contents.length) {
1503 int pc = pcToSourceMapTable[i++];
1504 this.contents[localContentsOffset++] = (byte) (pc >> 8);
1505 this.contents[localContentsOffset++] = (byte) pc;
1506 int lineNumber = pcToSourceMapTable[i++];
1507 this.contents[localContentsOffset++] = (byte) (lineNumber >> 8);
1508 this.contents[localContentsOffset++] = (byte) lineNumber;
1511 // now we change the size of the line number attribute
1512 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1513 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1514 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1515 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1516 this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1517 this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1518 this.contents[lineNumberTableOffset++] = (byte) numberOfEntries;
1522 // then we do the local variable attribute
1523 if (codeStream.generateLocalVariableTableAttributes) {
1524 int localVariableTableOffset = localContentsOffset;
1525 int numberOfEntries = 0;
1526 // codeAttribute.addLocalVariableTableAttribute(this);
1527 if ((codeStream.pcToSourceMap != null)
1528 && (codeStream.pcToSourceMapSize != 0)) {
1529 int localVariableNameIndex =
1530 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1531 if (localContentsOffset + 8 >= this.contents.length) {
1534 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1535 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
1536 localContentsOffset += 6;
1537 // leave space for attribute_length and local_variable_table_length
1539 int descriptorIndex;
1540 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1541 LocalVariableBinding localVariable = codeStream.locals[i];
1542 for (int j = 0; j < localVariable.initializationCount; j++) {
1543 int startPC = localVariable.initializationPCs[j << 1];
1544 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1545 if (startPC != endPC) { // only entries for non zero length
1547 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1548 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1549 (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
1551 if (localContentsOffset + 10 >= this.contents.length) {
1554 // now we can safely add the local entry
1556 this.contents[localContentsOffset++] = (byte) (startPC >> 8);
1557 this.contents[localContentsOffset++] = (byte) startPC;
1558 int length = endPC - startPC;
1559 this.contents[localContentsOffset++] = (byte) (length >> 8);
1560 this.contents[localContentsOffset++] = (byte) length;
1561 nameIndex = constantPool.literalIndex(localVariable.name);
1562 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1563 this.contents[localContentsOffset++] = (byte) nameIndex;
1564 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1565 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1566 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1567 int resolvedPosition = localVariable.resolvedPosition;
1568 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1569 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1573 int value = numberOfEntries * 10 + 2;
1574 localVariableTableOffset += 2;
1575 this.contents[localVariableTableOffset++] = (byte) (value >> 24);
1576 this.contents[localVariableTableOffset++] = (byte) (value >> 16);
1577 this.contents[localVariableTableOffset++] = (byte) (value >> 8);
1578 this.contents[localVariableTableOffset++] = (byte) value;
1579 this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1580 this.contents[localVariableTableOffset] = (byte) numberOfEntries;
1584 // update the number of attributes
1585 // ensure first that there is enough space available inside the contents array
1586 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
1589 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1590 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1591 // update the attribute length
1592 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1593 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1594 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1595 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1596 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1597 contentsOffset = localContentsOffset;
1602 * That method completes the creation of the code attribute by setting
1603 * - the attribute_length
1608 * - and debug attributes if necessary.
1610 * @param codeAttributeOffset <CODE>int</CODE>
1611 * @param startLineIndexes int[]
1613 public void completeCodeAttributeForClinit(
1614 int codeAttributeOffset,
1615 int[] startLineIndexes) {
1616 // reinitialize the contents with the byte modified by the code stream
1617 this.contents = codeStream.bCodeStream;
1618 int localContentsOffset = codeStream.classFileOffset;
1619 // codeAttributeOffset is the position inside contents byte array before we started to write
1620 // any information about the codeAttribute
1621 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1622 // to get the right position, 6 for the max_stack etc...
1623 int code_length = codeStream.position;
1624 if (code_length > 65535) {
1625 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1626 codeStream.methodDeclaration.scope.referenceType());
1628 if (localContentsOffset + 20 >= this.contents.length) {
1631 int max_stack = codeStream.stackMax;
1632 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1633 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
1634 int max_locals = codeStream.maxLocals;
1635 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1636 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
1637 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1638 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1639 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1640 this.contents[codeAttributeOffset + 13] = (byte) code_length;
1642 // write the exception table
1643 this.contents[localContentsOffset++] = 0;
1644 this.contents[localContentsOffset++] = 0;
1647 int codeAttributeAttributeOffset = localContentsOffset;
1648 int attributeNumber = 0; // leave two bytes for the attribute_length
1649 localContentsOffset += 2; // first we handle the linenumber attribute
1651 // first we handle the linenumber attribute
1652 if (codeStream.generateLineNumberAttributes) {
1653 if (localContentsOffset + 20 >= this.contents.length) {
1656 /* Create and add the line number attribute (used for debugging)
1657 * Build the pairs of:
1658 * (bytecodePC lineNumber)
1659 * according to the table of start line indexes and the pcToSourceMap table
1660 * contained into the codestream
1662 int lineNumberNameIndex =
1663 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1664 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1665 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1666 this.contents[localContentsOffset++] = 0;
1667 this.contents[localContentsOffset++] = 0;
1668 this.contents[localContentsOffset++] = 0;
1669 this.contents[localContentsOffset++] = 6;
1670 this.contents[localContentsOffset++] = 0;
1671 this.contents[localContentsOffset++] = 1;
1672 // first entry at pc = 0
1673 this.contents[localContentsOffset++] = 0;
1674 this.contents[localContentsOffset++] = 0;
1675 this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
1676 this.contents[localContentsOffset++] = (byte) problemLine;
1677 // now we change the size of the line number attribute
1680 // then we do the local variable attribute
1681 if (codeStream.generateLocalVariableTableAttributes) {
1682 int localVariableNameIndex =
1683 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1684 if (localContentsOffset + 8 >= this.contents.length) {
1687 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1688 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
1689 this.contents[localContentsOffset++] = 0;
1690 this.contents[localContentsOffset++] = 0;
1691 this.contents[localContentsOffset++] = 0;
1692 this.contents[localContentsOffset++] = 2;
1693 this.contents[localContentsOffset++] = 0;
1694 this.contents[localContentsOffset++] = 0;
1697 // update the number of attributes
1698 // ensure first that there is enough space available inside the contents array
1699 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
1702 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1703 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1704 // update the attribute length
1705 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1706 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1707 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1708 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1709 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1710 contentsOffset = localContentsOffset;
1715 * That method completes the creation of the code attribute by setting
1716 * - the attribute_length
1721 * - and debug attributes if necessary.
1723 * @param codeAttributeOffset <CODE>int</CODE>
1725 public void completeCodeAttributeForProblemMethod(
1726 AbstractMethodDeclaration method,
1727 MethodBinding binding,
1728 int codeAttributeOffset,
1729 int[] startLineIndexes) {
1730 // reinitialize the localContents with the byte modified by the code stream
1731 this.contents = codeStream.bCodeStream;
1732 int localContentsOffset = codeStream.classFileOffset;
1733 // 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...
1734 int max_stack = codeStream.stackMax;
1735 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1736 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
1737 int max_locals = codeStream.maxLocals;
1738 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1739 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
1740 int code_length = codeStream.position;
1741 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1742 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1743 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1744 this.contents[codeAttributeOffset + 13] = (byte) code_length;
1745 // write the exception table
1746 if (localContentsOffset + 50 >= this.contents.length) {
1750 // write the exception table
1751 this.contents[localContentsOffset++] = 0;
1752 this.contents[localContentsOffset++] = 0;
1754 int codeAttributeAttributeOffset = localContentsOffset;
1755 int attributeNumber = 0; // leave two bytes for the attribute_length
1756 localContentsOffset += 2; // first we handle the linenumber attribute
1758 if (codeStream.generateLineNumberAttributes) {
1759 if (localContentsOffset + 20 >= this.contents.length) {
1762 /* Create and add the line number attribute (used for debugging)
1763 * Build the pairs of:
1764 * (bytecodePC lineNumber)
1765 * according to the table of start line indexes and the pcToSourceMap table
1766 * contained into the codestream
1768 int lineNumberNameIndex =
1769 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1770 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1771 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1772 this.contents[localContentsOffset++] = 0;
1773 this.contents[localContentsOffset++] = 0;
1774 this.contents[localContentsOffset++] = 0;
1775 this.contents[localContentsOffset++] = 6;
1776 this.contents[localContentsOffset++] = 0;
1777 this.contents[localContentsOffset++] = 1;
1778 if (problemLine == 0) {
1779 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
1781 // first entry at pc = 0
1782 this.contents[localContentsOffset++] = 0;
1783 this.contents[localContentsOffset++] = 0;
1784 this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
1785 this.contents[localContentsOffset++] = (byte) problemLine;
1786 // now we change the size of the line number attribute
1789 // then we do the local variable attribute
1790 if (codeStream.generateLocalVariableTableAttributes) {
1791 // compute the resolved position for the arguments of the method
1793 int localVariableTableOffset = localContentsOffset;
1794 int numberOfEntries = 0;
1795 // codeAttribute.addLocalVariableTableAttribute(this);
1796 int localVariableNameIndex =
1797 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1798 if (localContentsOffset + 8 >= this.contents.length) {
1801 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1802 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
1803 localContentsOffset += 6;
1804 // leave space for attribute_length and local_variable_table_length
1805 int descriptorIndex;
1806 if (!codeStream.methodDeclaration.isStatic()) {
1808 if (localContentsOffset + 10 >= this.contents.length) {
1811 this.contents[localContentsOffset++] = 0;
1812 this.contents[localContentsOffset++] = 0;
1813 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
1814 this.contents[localContentsOffset++] = (byte) code_length;
1815 int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
1816 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1817 this.contents[localContentsOffset++] = (byte) nameIndex;
1819 constantPool.literalIndex(
1820 codeStream.methodDeclaration.binding.declaringClass.signature());
1821 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1822 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1823 // the resolved position for this is always 0
1824 this.contents[localContentsOffset++] = 0;
1825 this.contents[localContentsOffset++] = 0;
1827 if (binding.isConstructor()) {
1828 ReferenceBinding declaringClass = binding.declaringClass;
1829 if (declaringClass.isNestedType()) {
1830 NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
1831 argSize = methodDeclaringClass.enclosingInstancesSlotSize;
1832 SyntheticArgumentBinding[] syntheticArguments;
1833 if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
1835 for (int i = 0, max = syntheticArguments.length; i < max; i++) {
1836 LocalVariableBinding localVariable = syntheticArguments[i];
1837 if (localContentsOffset + 10 >= this.contents.length) {
1840 // now we can safely add the local entry
1842 this.contents[localContentsOffset++] = 0;
1843 this.contents[localContentsOffset++] = 0;
1844 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
1845 this.contents[localContentsOffset++] = (byte) code_length;
1846 int nameIndex = constantPool.literalIndex(localVariable.name);
1847 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1848 this.contents[localContentsOffset++] = (byte) nameIndex;
1849 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1850 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1851 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1852 int resolvedPosition = localVariable.resolvedPosition;
1853 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1854 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1861 argSize = binding.isStatic() ? 0 : 1;
1863 if (method.binding != null) {
1864 TypeBinding[] parameters = method.binding.parameters;
1865 Argument[] arguments = method.arguments;
1866 if ((parameters != null) && (arguments != null)) {
1867 for (int i = 0, max = parameters.length; i < max; i++) {
1868 TypeBinding argumentBinding = parameters[i];
1869 if (localContentsOffset + 10 >= this.contents.length) {
1872 // now we can safely add the local entry
1874 this.contents[localContentsOffset++] = 0;
1875 this.contents[localContentsOffset++] = 0;
1876 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
1877 this.contents[localContentsOffset++] = (byte) code_length;
1878 int nameIndex = constantPool.literalIndex(arguments[i].name);
1879 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1880 this.contents[localContentsOffset++] = (byte) nameIndex;
1881 descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
1882 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1883 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1884 int resolvedPosition = argSize;
1885 if ((argumentBinding == BaseTypes.LongBinding)
1886 || (argumentBinding == BaseTypes.DoubleBinding))
1890 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1891 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1895 int value = numberOfEntries * 10 + 2;
1896 localVariableTableOffset += 2;
1897 this.contents[localVariableTableOffset++] = (byte) (value >> 24);
1898 this.contents[localVariableTableOffset++] = (byte) (value >> 16);
1899 this.contents[localVariableTableOffset++] = (byte) (value >> 8);
1900 this.contents[localVariableTableOffset++] = (byte) value;
1901 this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1902 this.contents[localVariableTableOffset] = (byte) numberOfEntries;
1905 // update the number of attributes// ensure first that there is enough space available inside the localContents array
1906 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
1909 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1910 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1911 // update the attribute length
1912 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1913 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1914 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1915 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1916 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1917 contentsOffset = localContentsOffset;
1922 * That method completes the creation of the code attribute by setting
1923 * - the attribute_length
1928 * - and debug attributes if necessary.
1930 * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
1931 * @param codeAttributeOffset <CODE>int</CODE>
1933 public void completeCodeAttributeForSyntheticAccessMethod(
1934 SyntheticAccessMethodBinding binding,
1935 int codeAttributeOffset,
1936 int[] startLineIndexes) {
1937 // reinitialize the contents with the byte modified by the code stream
1938 this.contents = codeStream.bCodeStream;
1939 int localContentsOffset = codeStream.classFileOffset;
1940 // codeAttributeOffset is the position inside contents byte array before we started to write
1941 // any information about the codeAttribute
1942 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1943 // to get the right position, 6 for the max_stack etc...
1944 int max_stack = codeStream.stackMax;
1945 contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1946 contents[codeAttributeOffset + 7] = (byte) max_stack;
1947 int max_locals = codeStream.maxLocals;
1948 contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1949 contents[codeAttributeOffset + 9] = (byte) max_locals;
1950 int code_length = codeStream.position;
1951 contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1952 contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1953 contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1954 contents[codeAttributeOffset + 13] = (byte) code_length;
1955 if ((localContentsOffset + 40) >= this.contents.length) {
1958 // there is no exception table, so we need to offset by 2 the current offset and move
1959 // on the attribute generation
1960 contents[localContentsOffset++] = 0;
1961 contents[localContentsOffset++] = 0;
1963 int codeAttributeAttributeOffset = localContentsOffset;
1964 int attributeNumber = 0;
1965 // leave two bytes for the attribute_length
1966 localContentsOffset += 2;
1968 // first we handle the linenumber attribute
1969 if (codeStream.generateLineNumberAttributes) {
1971 int lineNumberNameIndex =
1972 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1973 contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1974 contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1975 int lineNumberTableOffset = localContentsOffset;
1976 localContentsOffset += 6;
1977 // leave space for attribute_length and line_number_table_length
1978 // Seems like do would be better, but this preserves the existing behavior.
1979 index = searchLineNumber(startLineIndexes, binding.sourceStart);
1980 contents[localContentsOffset++] = 0;
1981 contents[localContentsOffset++] = 0;
1982 contents[localContentsOffset++] = (byte) (index >> 8);
1983 contents[localContentsOffset++] = (byte) index;
1984 // now we change the size of the line number attribute
1985 contents[lineNumberTableOffset++] = 0;
1986 contents[lineNumberTableOffset++] = 0;
1987 contents[lineNumberTableOffset++] = 0;
1988 contents[lineNumberTableOffset++] = 6;
1989 contents[lineNumberTableOffset++] = 0;
1990 contents[lineNumberTableOffset++] = 1;
1993 // then we do the local variable attribute
1994 if (codeStream.generateLocalVariableTableAttributes) {
1995 int localVariableTableOffset = localContentsOffset;
1996 int numberOfEntries = 0;
1997 int localVariableNameIndex =
1998 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1999 if (localContentsOffset + 8 > this.contents.length) {
2002 contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2003 contents[localContentsOffset++] = (byte) localVariableNameIndex;
2004 localContentsOffset += 6;
2005 // leave space for attribute_length and local_variable_table_length
2007 int descriptorIndex;
2008 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
2009 LocalVariableBinding localVariable = codeStream.locals[i];
2010 for (int j = 0; j < localVariable.initializationCount; j++) {
2011 int startPC = localVariable.initializationPCs[j << 1];
2012 int endPC = localVariable.initializationPCs[(j << 1) + 1];
2013 if (startPC != endPC) { // only entries for non zero length
2015 localVariable.declaringScope.problemReporter().abortDueToInternalError(
2016 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
2017 (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
2019 if (localContentsOffset + 10 > this.contents.length) {
2022 // now we can safely add the local entry
2024 contents[localContentsOffset++] = (byte) (startPC >> 8);
2025 contents[localContentsOffset++] = (byte) startPC;
2026 int length = endPC - startPC;
2027 contents[localContentsOffset++] = (byte) (length >> 8);
2028 contents[localContentsOffset++] = (byte) length;
2029 nameIndex = constantPool.literalIndex(localVariable.name);
2030 contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2031 contents[localContentsOffset++] = (byte) nameIndex;
2032 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2033 contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2034 contents[localContentsOffset++] = (byte) descriptorIndex;
2035 int resolvedPosition = localVariable.resolvedPosition;
2036 contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2037 contents[localContentsOffset++] = (byte) resolvedPosition;
2041 int value = numberOfEntries * 10 + 2;
2042 localVariableTableOffset += 2;
2043 contents[localVariableTableOffset++] = (byte) (value >> 24);
2044 contents[localVariableTableOffset++] = (byte) (value >> 16);
2045 contents[localVariableTableOffset++] = (byte) (value >> 8);
2046 contents[localVariableTableOffset++] = (byte) value;
2047 contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2048 contents[localVariableTableOffset] = (byte) numberOfEntries;
2051 // update the number of attributes
2052 // ensure first that there is enough space available inside the contents array
2053 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
2056 contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2057 contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2059 // update the attribute length
2060 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2061 contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2062 contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2063 contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2064 contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2065 contentsOffset = localContentsOffset;
2070 * Complete the creation of a method info by setting up the number of attributes at the right offset.
2072 * @param methodAttributeOffset <CODE>int</CODE>
2073 * @param attributeNumber <CODE>int</CODE>
2075 public void completeMethodInfo(
2076 int methodAttributeOffset,
2077 int attributeNumber) {
2078 // update the number of attributes
2079 contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
2080 contents[methodAttributeOffset] = (byte) attributeNumber;
2085 * Request the creation of a ClassFile compatible representation of a problematic type
2087 * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
2088 * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
2090 public static void createProblemType(
2091 TypeDeclaration typeDeclaration,
2092 CompilationResult unitResult) {
2093 SourceTypeBinding typeBinding = typeDeclaration.binding;
2094 ClassFile classFile = new ClassFile(typeBinding, null, true);
2096 // TODO (olivier) handle cases where a field cannot be generated (name too long)
2097 // TODO (olivier) handle too many methods
2099 if (typeBinding.isMemberType())
2100 classFile.recordEnclosingTypeAttributes(typeBinding);
2103 FieldBinding[] fields = typeBinding.fields;
2104 if ((fields != null) && (fields != NoFields)) {
2105 for (int i = 0, max = fields.length; i < max; i++) {
2106 if (fields[i].constant == null) {
2107 FieldReference.getConstantFor(fields[i], null, false, null);
2110 classFile.addFieldInfos();
2112 // we have to set the number of fields to be equals to 0
2113 classFile.contents[classFile.contentsOffset++] = 0;
2114 classFile.contents[classFile.contentsOffset++] = 0;
2116 // leave some space for the methodCount
2117 classFile.setForMethodInfos();
2118 // add its user defined methods
2119 MethodBinding[] methods = typeBinding.methods;
2120 AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
2121 int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
2123 IProblem[] problems = unitResult.getErrors();
2124 if (problems == null) {
2125 problems = new IProblem[0];
2127 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
2128 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
2129 if (methods != null) {
2130 if (typeBinding.isInterface()) {
2131 // we cannot create problem methods for an interface. So we have to generate a clinit
2132 // which should contain all the problem
2133 classFile.addProblemClinit(problemsCopy);
2134 for (int i = 0, max = methods.length; i < max; i++) {
2135 MethodBinding methodBinding;
2136 if ((methodBinding = methods[i]) != null) {
2137 // find the corresponding method declaration
2138 for (int j = 0; j < maxMethodDecl; j++) {
2139 if ((methodDeclarations[j] != null)
2140 && (methodDeclarations[j].binding == methods[i])) {
2141 if (!methodBinding.isConstructor()) {
2142 classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
2150 for (int i = 0, max = methods.length; i < max; i++) {
2151 MethodBinding methodBinding;
2152 if ((methodBinding = methods[i]) != null) {
2153 // find the corresponding method declaration
2154 for (int j = 0; j < maxMethodDecl; j++) {
2155 if ((methodDeclarations[j] != null)
2156 && (methodDeclarations[j].binding == methods[i])) {
2157 AbstractMethodDeclaration methodDecl;
2158 if ((methodDecl = methodDeclarations[j]).isConstructor()) {
2159 classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
2161 classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
2169 // add abstract methods
2170 classFile.addDefaultAbstractMethods();
2172 // propagate generation of (problem) member types
2173 if (typeDeclaration.memberTypes != null) {
2174 for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
2175 TypeDeclaration memberType = typeDeclaration.memberTypes[i];
2176 if (memberType.binding != null) {
2177 classFile.recordNestedMemberAttribute(memberType.binding);
2178 ClassFile.createProblemType(memberType, unitResult);
2182 classFile.addAttributes();
2183 unitResult.record(typeBinding.constantPoolName(), classFile);
2188 * This methods returns a char[] representing the file name of the receiver
2192 public char[] fileName() {
2193 return constantPool.UTF8Cache.returnKeyFor(1);
2198 * That method generates the header of a code attribute.
2199 * - the index inside the constant pool for the attribute name ("Code")
2200 * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
2202 public void generateCodeAttributeHeader() {
2203 if (contentsOffset + 20 >= this.contents.length) {
2206 int constantValueNameIndex =
2207 constantPool.literalIndex(AttributeNamesConstants.CodeName);
2208 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
2209 contents[contentsOffset++] = (byte) constantValueNameIndex;
2210 // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
2211 contentsOffset += 12;
2216 * That method generates the attributes of a code attribute.
2218 * - an exception attribute for each try/catch found inside the method
2219 * - a deprecated attribute
2220 * - a synthetic attribute for synthetic access methods
2222 * It returns the number of attributes created for the code attribute.
2224 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2225 * @return <CODE>int</CODE>
2227 public int generateMethodInfoAttribute(MethodBinding methodBinding) {
2228 // leave two bytes for the attribute_number
2229 contentsOffset += 2;
2230 // now we can handle all the attribute for that method info:
2232 // - a CodeAttribute
2233 // - a ExceptionAttribute
2234 // - a DeprecatedAttribute
2235 // - a SyntheticAttribute
2237 // Exception attribute
2238 ReferenceBinding[] thrownsExceptions;
2239 int attributeNumber = 0;
2240 if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
2241 // The method has a throw clause. So we need to add an exception attribute
2242 // check that there is enough space to write all the bytes for the exception attribute
2243 int length = thrownsExceptions.length;
2244 int exSize = 8 + length * 2;
2245 if (exSize + contentsOffset >= this.contents.length) {
2246 resizeContents(exSize);
2248 int exceptionNameIndex =
2249 constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
2250 contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
2251 contents[contentsOffset++] = (byte) exceptionNameIndex;
2252 // The attribute length = length * 2 + 2 in case of a exception attribute
2253 int attributeLength = length * 2 + 2;
2254 contents[contentsOffset++] = (byte) (attributeLength >> 24);
2255 contents[contentsOffset++] = (byte) (attributeLength >> 16);
2256 contents[contentsOffset++] = (byte) (attributeLength >> 8);
2257 contents[contentsOffset++] = (byte) attributeLength;
2258 contents[contentsOffset++] = (byte) (length >> 8);
2259 contents[contentsOffset++] = (byte) length;
2260 for (int i = 0; i < length; i++) {
2261 int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
2262 contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
2263 contents[contentsOffset++] = (byte) exceptionIndex;
2267 if (methodBinding.isDeprecated()) {
2268 // Deprecated attribute
2269 // Check that there is enough space to write the deprecated attribute
2270 if (contentsOffset + 6 >= this.contents.length) {
2273 int deprecatedAttributeNameIndex =
2274 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
2275 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
2276 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
2277 // the length of a deprecated attribute is equals to 0
2278 contents[contentsOffset++] = 0;
2279 contents[contentsOffset++] = 0;
2280 contents[contentsOffset++] = 0;
2281 contents[contentsOffset++] = 0;
2285 if (this.targetJDK < ClassFileConstants.JDK1_5 && methodBinding.isSynthetic()) {
2286 // Synthetic attribute
2287 // Check that there is enough space to write the deprecated attribute
2288 if (contentsOffset + 6 >= this.contents.length) {
2291 int syntheticAttributeNameIndex =
2292 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
2293 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
2294 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
2295 // the length of a synthetic attribute is equals to 0
2296 contents[contentsOffset++] = 0;
2297 contents[contentsOffset++] = 0;
2298 contents[contentsOffset++] = 0;
2299 contents[contentsOffset++] = 0;
2303 return attributeNumber;
2308 * That method generates the header of a method info:
2309 * The header consists in:
2310 * - the access flags
2311 * - the name index of the method name inside the constant pool
2312 * - the descriptor index of the signature of the method inside the constant pool.
2314 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2316 public void generateMethodInfoHeader(MethodBinding methodBinding) {
2317 generateMethodInfoHeader(methodBinding, methodBinding.modifiers);
2321 * That method generates the header of a method info:
2322 * The header consists in:
2323 * - the access flags
2324 * - the name index of the method name inside the constant pool
2325 * - the descriptor index of the signature of the method inside the constant pool.
2327 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2328 * @param accessFlags the access flags
2330 public void generateMethodInfoHeader(MethodBinding methodBinding, int accessFlags) {
2331 // check that there is enough space to write all the bytes for the method info corresponding
2332 // to the @methodBinding
2333 methodCount++; // add one more method
2334 if (contentsOffset + 10 >= this.contents.length) {
2337 if (targetJDK < ClassFileConstants.JDK1_5) {
2338 // pre 1.5, synthetic was an attribute, not a modifier
2339 accessFlags &= ~AccSynthetic;
2341 if (methodBinding.isRequiredToClearPrivateModifier()) {
2342 accessFlags &= ~AccPrivate;
2344 contents[contentsOffset++] = (byte) (accessFlags >> 8);
2345 contents[contentsOffset++] = (byte) accessFlags;
2346 int nameIndex = constantPool.literalIndex(methodBinding.selector);
2347 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2348 contents[contentsOffset++] = (byte) nameIndex;
2349 int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
2350 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2351 contents[contentsOffset++] = (byte) descriptorIndex;
2356 * That method generates the method info header of a clinit:
2357 * The header consists in:
2358 * - the access flags (always default access + static)
2359 * - the name index of the method name (always <clinit>) inside the constant pool
2360 * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
2362 public void generateMethodInfoHeaderForClinit() {
2363 // check that there is enough space to write all the bytes for the method info corresponding
2364 // to the @methodBinding
2365 methodCount++; // add one more method
2366 if (contentsOffset + 10 >= this.contents.length) {
2369 contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
2370 contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
2371 int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
2372 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2373 contents[contentsOffset++] = (byte) nameIndex;
2374 int descriptorIndex =
2375 constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
2376 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2377 contents[contentsOffset++] = (byte) descriptorIndex;
2378 // We know that we won't get more than 1 attribute: the code attribute
2379 contents[contentsOffset++] = 0;
2380 contents[contentsOffset++] = 1;
2385 * Answer the actual bytes of the class file
2387 * This method encodes the receiver structure into a byte array which is the content of the classfile.
2388 * Returns the byte array that represents the encoded structure of the receiver.
2392 public byte[] getBytes() {
2393 byte[] fullContents = new byte[headerOffset + contentsOffset];
2394 System.arraycopy(header, 0, fullContents, 0, headerOffset);
2395 System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
2396 return fullContents;
2401 * Answer the compound name of the class file.
2403 * e.g. {{java}, {util}, {Hashtable}}.
2405 public char[][] getCompoundName() {
2406 return CharOperation.splitOn('/', fileName());
2409 protected void initByteArrays() {
2410 LookupEnvironment env = this.referenceBinding.scope.environment();
2411 synchronized (env) {
2412 if (env.sharedArraysUsed) {
2413 this.ownSharedArrays = false;
2414 int members = referenceBinding.methods().length + referenceBinding.fields().length;
2415 this.header = new byte[INITIAL_HEADER_SIZE];
2416 this.contents = new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE];
2418 this.ownSharedArrays = env.sharedArraysUsed = true;
2419 this.header = env.sharedClassFileHeader;
2420 this.contents = env.sharedClassFileContents;
2427 * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
2428 * for all inner types of the receiver.
2429 * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
2431 public ClassFile outerMostEnclosingClassFile() {
2432 ClassFile current = this;
2433 while (current.enclosingClassFile != null)
2434 current = current.enclosingClassFile;
2440 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2441 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2443 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2445 public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
2446 // add all the enclosing types
2447 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2449 while (enclosingType != null) {
2451 enclosingType = enclosingType.enclosingType();
2453 enclosingType = referenceBinding;
2454 ReferenceBinding enclosingTypes[];
2456 enclosingTypes = new ReferenceBinding[depth];
2457 for (int i = depth - 1; i >= 0; i--) {
2458 enclosingTypes[i] = enclosingType;
2459 enclosingType = enclosingType.enclosingType();
2461 for (int i = 0; i < depth; i++) {
2462 addInnerClasses(enclosingTypes[i]);
2465 addInnerClasses(referenceBinding);
2471 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2472 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2474 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2476 public void recordNestedLocalAttribute(ReferenceBinding binding) {
2477 // add all the enclosing types
2478 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2480 while (enclosingType != null) {
2482 enclosingType = enclosingType.enclosingType();
2484 enclosingType = referenceBinding;
2485 ReferenceBinding enclosingTypes[];
2487 enclosingTypes = new ReferenceBinding[depth];
2488 for (int i = depth - 1; i >= 0; i--) {
2489 enclosingTypes[i] = enclosingType;
2490 enclosingType = enclosingType.enclosingType();
2492 for (int i = 0; i < depth; i++)
2493 addInnerClasses(enclosingTypes[i]);
2495 addInnerClasses(binding);
2501 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2502 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2504 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2506 public void recordNestedMemberAttribute(ReferenceBinding binding) {
2507 addInnerClasses(binding);
2511 * Resize the pool contents
2513 private final void resizeContents(int minimalSize) {
2514 int length = this.contents.length;
2516 if (toAdd < minimalSize)
2517 toAdd = minimalSize;
2518 System.arraycopy(this.contents, 0, this.contents = new byte[length + toAdd], 0, length);
2523 * Search the line number corresponding to a specific position
2525 public static final int searchLineNumber(
2526 int[] startLineIndexes,
2528 // this code is completely useless, but it is the same implementation than
2529 // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
2530 // if (startLineIndexes == null)
2532 int length = startLineIndexes.length;
2535 int g = 0, d = length - 1;
2539 if (position < startLineIndexes[m]) {
2542 if (position > startLineIndexes[m]) {
2548 if (position < startLineIndexes[m]) {
2556 * This methods leaves the space for method counts recording.
2558 public void setForMethodInfos() {
2559 // leave some space for the methodCount
2560 methodCountOffset = contentsOffset;
2561 contentsOffset += 2;
2566 * outputPath is formed like:
2567 * c:\temp\ the last character is a file separator
2568 * relativeFileName is formed like:
2569 * java\lang\String.class
2570 * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
2571 * @param outputPath the output directory
2572 * @param relativeFileName java.lang.String
2573 * @param contents byte[]
2576 public static void writeToDisk(
2577 boolean generatePackagesStructure,
2579 String relativeFileName,
2581 throws IOException {
2583 BufferedOutputStream output = null;
2584 if (generatePackagesStructure) {
2585 output = new BufferedOutputStream(
2586 new FileOutputStream(
2587 new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
2589 String fileName = null;
2590 char fileSeparatorChar = File.separatorChar;
2591 String fileSeparator = File.separator;
2592 // First we ensure that the outputPath exists
2593 outputPath = outputPath.replace('/', fileSeparatorChar);
2594 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
2595 int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
2596 if (indexOfPackageSeparator == -1) {
2597 if (outputPath.endsWith(fileSeparator)) {
2598 fileName = outputPath + relativeFileName;
2600 fileName = outputPath + fileSeparator + relativeFileName;
2603 int length = relativeFileName.length();
2604 if (outputPath.endsWith(fileSeparator)) {
2605 fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2607 fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2610 output = new BufferedOutputStream(
2611 new FileOutputStream(
2612 new File(fileName)));
2615 output.write(contents);