KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > Clinit


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.ClassFile;
15 import org.eclipse.jdt.internal.compiler.CompilationResult;
16 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
17 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
18 import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
19 import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
20 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
21 import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
22 import org.eclipse.jdt.internal.compiler.lookup.Binding;
23 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
24 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
25 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
26 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
27 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
28 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
29 import org.eclipse.jdt.internal.compiler.parser.Parser;
30 import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
31
32 public class Clinit extends AbstractMethodDeclaration {
33     
34     private FieldBinding assertionSyntheticFieldBinding = null;
35     private FieldBinding classLiteralSyntheticField = null;
36
37     public Clinit(CompilationResult compilationResult) {
38         super(compilationResult);
39         modifiers = 0;
40         selector = TypeConstants.CLINIT;
41     }
42
43     public void analyseCode(
44         ClassScope classScope,
45         InitializationFlowContext staticInitializerFlowContext,
46         FlowInfo flowInfo) {
47
48         if (ignoreFurtherInvestigation)
49             return;
50         try {
51             ExceptionHandlingFlowContext clinitContext =
52                 new ExceptionHandlingFlowContext(
53                     staticInitializerFlowContext.parent,
54                     this,
55                     Binding.NO_EXCEPTIONS,
56                     scope,
57                     FlowInfo.DEAD_END);
58
59             // check for missing returning path
60
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
61                 this.bits |= ASTNode.NeedFreeReturn;
62             }
63
64             // check missing blank final field initializations
65
flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
66             FieldBinding[] fields = scope.enclosingSourceType().fields();
67             for (int i = 0, count = fields.length; i < count; i++) {
68                 FieldBinding field;
69                 if ((field = fields[i]).isStatic()
70                     && field.isFinal()
71                     && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
72                     scope.problemReporter().uninitializedBlankFinalField(
73                         field,
74                         scope.referenceType().declarationOf(field.original()));
75                     // can complain against the field decl, since only one <clinit>
76
}
77             }
78             // check static initializers thrown exceptions
79
staticInitializerFlowContext.checkInitializerExceptions(
80                 scope,
81                 clinitContext,
82                 flowInfo);
83         } catch (AbortMethod e) {
84             this.ignoreFurtherInvestigation = true;
85         }
86     }
87
88     /**
89      * Bytecode generation for a <clinit> method
90      *
91      * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
92      * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
93      */

94     public void generateCode(ClassScope classScope, ClassFile classFile) {
95
96         int clinitOffset = 0;
97         if (ignoreFurtherInvestigation) {
98             // should never have to add any <clinit> problem method
99
return;
100         }
101         try {
102             clinitOffset = classFile.contentsOffset;
103             this.generateCode(classScope, classFile, clinitOffset);
104         } catch (AbortMethod e) {
105             // should never occur
106
// the clinit referenceContext is the type declaration
107
// All clinit problems will be reported against the type: AbortType instead of AbortMethod
108
// reset the contentsOffset to the value before generating the clinit code
109
// decrement the number of method info as well.
110
// This is done in the addProblemMethod and addProblemConstructor for other
111
// cases.
112
if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
113                 // a branch target required a goto_w, restart code gen in wide mode.
114
try {
115                     classFile.contentsOffset = clinitOffset;
116                     classFile.methodCount--;
117                     classFile.codeStream.wideMode = true; // request wide mode
118
this.generateCode(classScope, classFile, clinitOffset);
119                     // restart method generation
120
} catch (AbortMethod e2) {
121                     classFile.contentsOffset = clinitOffset;
122                     classFile.methodCount--;
123                 }
124             } else {
125                 // produce a problem method accounting for this fatal error
126
classFile.contentsOffset = clinitOffset;
127                 classFile.methodCount--;
128             }
129         }
130     }
131
132     /**
133      * Bytecode generation for a <clinit> method
134      *
135      * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
136      * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
137      */

138     private void generateCode(
139         ClassScope classScope,
140         ClassFile classFile,
141         int clinitOffset) {
142
143         ConstantPool constantPool = classFile.constantPool;
144         int constantPoolOffset = constantPool.currentOffset;
145         int constantPoolIndex = constantPool.currentIndex;
146         classFile.generateMethodInfoHeaderForClinit();
147         int codeAttributeOffset = classFile.contentsOffset;
148         classFile.generateCodeAttributeHeader();
149         CodeStream codeStream = classFile.codeStream;
150         this.resolve(classScope);
151
152         codeStream.reset(this, classFile);
153         TypeDeclaration declaringType = classScope.referenceContext;
154
155         // initialize local positions - including initializer scope.
156
MethodScope staticInitializerScope = declaringType.staticInitializerScope;
157         staticInitializerScope.computeLocalVariablePositions(0, codeStream);
158
159         // 1.4 feature
160
// This has to be done before any other initialization
161
if (this.assertionSyntheticFieldBinding != null) {
162             // generate code related to the activation of assertion for this class
163
codeStream.generateClassLiteralAccessForType(
164                     classScope.outerMostClassScope().enclosingSourceType(),
165                     this.classLiteralSyntheticField);
166             codeStream.invokeJavaLangClassDesiredAssertionStatus();
167             BranchLabel falseLabel = new BranchLabel(codeStream);
168             codeStream.ifne(falseLabel);
169             codeStream.iconst_1();
170             BranchLabel jumpLabel = new BranchLabel(codeStream);
171             codeStream.decrStackSize(1);
172             codeStream.goto_(jumpLabel);
173             falseLabel.place();
174             codeStream.iconst_0();
175             jumpLabel.place();
176             codeStream.putstatic(this.assertionSyntheticFieldBinding);
177         }
178         // generate static fields/initializers/enum constants
179
final FieldDeclaration[] fieldDeclarations = declaringType.fields;
180         BlockScope lastInitializerScope = null;
181         if (TypeDeclaration.kind(declaringType.modifiers) == TypeDeclaration.ENUM_DECL) {
182             int enumCount = 0;
183             int remainingFieldCount = 0;
184             if (fieldDeclarations != null) {
185                 for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
186                     FieldDeclaration fieldDecl = fieldDeclarations[i];
187                     if (fieldDecl.isStatic()) {
188                         if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
189                             fieldDecl.generateCode(staticInitializerScope, codeStream);
190                             enumCount++;
191                         } else {
192                             remainingFieldCount++;
193                         }
194                     }
195                 }
196             }
197             // enum need to initialize $VALUES synthetic cache of enum constants
198
// $VALUES := new <EnumType>[<enumCount>]
199
codeStream.generateInlinedValue(enumCount);
200             codeStream.anewarray(declaringType.binding);
201             if (enumCount > 0) {
202                 if (fieldDeclarations != null) {
203                     for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
204                         FieldDeclaration fieldDecl = fieldDeclarations[i];
205                         // $VALUES[i] = <enum-constant-i>
206
if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
207                             codeStream.dup();
208                             codeStream.generateInlinedValue(fieldDecl.binding.id);
209                             codeStream.getstatic(fieldDecl.binding);
210                             codeStream.aastore();
211                         }
212                     }
213                 }
214             }
215             codeStream.putstatic(declaringType.enumValuesSyntheticfield);
216             if (remainingFieldCount != 0) {
217                 // if fields that are not enum constants need to be generated (static initializer/static field)
218
for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
219                     FieldDeclaration fieldDecl = fieldDeclarations[i];
220                     switch (fieldDecl.getKind()) {
221                         case AbstractVariableDeclaration.ENUM_CONSTANT :
222                             break;
223                         case AbstractVariableDeclaration.INITIALIZER :
224                             if (!fieldDecl.isStatic())
225                                 break;
226                             lastInitializerScope = ((Initializer) fieldDecl).block.scope;
227                             fieldDecl.generateCode(staticInitializerScope, codeStream);
228                             break;
229                         case AbstractVariableDeclaration.FIELD :
230                             if (!fieldDecl.binding.isStatic())
231                                 break;
232                             lastInitializerScope = null;
233                             fieldDecl.generateCode(staticInitializerScope, codeStream);
234                             break;
235                     }
236                 }
237             }
238         } else {
239             if (fieldDeclarations != null) {
240                 for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
241                     FieldDeclaration fieldDecl = fieldDeclarations[i];
242                     switch (fieldDecl.getKind()) {
243                         case AbstractVariableDeclaration.INITIALIZER :
244                             if (!fieldDecl.isStatic())
245                                 break;
246                             lastInitializerScope = ((Initializer) fieldDecl).block.scope;
247                             fieldDecl.generateCode(staticInitializerScope, codeStream);
248                             break;
249                         case AbstractVariableDeclaration.FIELD :
250                             if (!fieldDecl.binding.isStatic())
251                                 break;
252                             lastInitializerScope = null;
253                             fieldDecl.generateCode(staticInitializerScope, codeStream);
254                             break;
255                     }
256                 }
257             }
258         }
259         
260         if (codeStream.position == 0) {
261             // do not need to output a Clinit if no bytecodes
262
// so we reset the offset inside the byte array contents.
263
classFile.contentsOffset = clinitOffset;
264             // like we don't addd a method we need to undo the increment on the method count
265
classFile.methodCount--;
266             // reset the constant pool to its state before the clinit
267
constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
268         } else {
269             if ((this.bits & ASTNode.NeedFreeReturn) != 0) {
270                 int before = codeStream.position;
271                 codeStream.return_();
272                 if (lastInitializerScope != null) {
273                     // expand the last initializer variables to include the trailing return
274
codeStream.updateLastRecordedEndPC(lastInitializerScope, before);
275                 }
276             }
277             // Record the end of the clinit: point to the declaration of the class
278
codeStream.recordPositionsFrom(0, declaringType.sourceStart);
279             classFile.completeCodeAttributeForClinit(codeAttributeOffset);
280         }
281     }
282
283     public boolean isClinit() {
284
285         return true;
286     }
287
288     public boolean isInitializationMethod() {
289
290         return true;
291     }
292
293     public boolean isStatic() {
294
295         return true;
296     }
297
298     public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
299         //the clinit is filled by hand ....
300
}
301
302     public StringBuffer JavaDoc print(int tab, StringBuffer JavaDoc output) {
303
304         printIndent(tab, output).append("<clinit>()"); //$NON-NLS-1$
305
printBody(tab + 1, output);
306         return output;
307     }
308
309     public void resolve(ClassScope classScope) {
310
311         this.scope = new MethodScope(classScope, classScope.referenceContext, true);
312     }
313
314     public void traverse(
315         ASTVisitor visitor,
316         ClassScope classScope) {
317
318         visitor.visit(this, classScope);
319         visitor.endVisit(this, classScope);
320     }
321
322     public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding, boolean needClassLiteralField) {
323
324         this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding;
325
326         // we need to add the field right now, because the field infos are generated before the methods
327
if (needClassLiteralField) {
328             SourceTypeBinding sourceType =
329                 this.scope.outerMostClassScope().enclosingSourceType();
330             // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=22334
331
if (!sourceType.isInterface() && !sourceType.isBaseType()) {
332                 this.classLiteralSyntheticField = sourceType.addSyntheticFieldForClassLiteral(sourceType, scope);
333             }
334         }
335     }
336
337 }
338
Popular Tags