removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / Clinit.java
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
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.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18 import org.eclipse.jdt.internal.compiler.parser.*;
19 import org.eclipse.jdt.internal.compiler.problem.*;
20
21 public class Clinit extends AbstractMethodDeclaration {
22         
23         public final static char[] ConstantPoolName = "<clinit>".toCharArray(); //$NON-NLS-1$
24
25         private FieldBinding assertionSyntheticFieldBinding = null;
26         private FieldBinding classLiteralSyntheticField = null;
27
28         public Clinit(CompilationResult compilationResult) {
29                 super(compilationResult);
30                 modifiers = 0;
31                 selector = ConstantPoolName;
32         }
33
34         public void analyseCode(
35                 ClassScope classScope,
36                 InitializationFlowContext staticInitializerFlowContext,
37                 FlowInfo flowInfo) {
38
39                 if (ignoreFurtherInvestigation)
40                         return;
41                 try {
42                         ExceptionHandlingFlowContext clinitContext =
43                                 new ExceptionHandlingFlowContext(
44                                         staticInitializerFlowContext.parent,
45                                         this,
46                                         NoExceptions,
47                                         scope,
48                                         FlowInfo.DEAD_END);
49
50                         // check for missing returning path
51                         this.needFreeReturn = flowInfo.isReachable();
52
53                         // check missing blank final field initializations
54                         flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
55                         FieldBinding[] fields = scope.enclosingSourceType().fields();
56                         for (int i = 0, count = fields.length; i < count; i++) {
57                                 FieldBinding field;
58                                 if ((field = fields[i]).isStatic()
59                                         && field.isFinal()
60                                         && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
61                                         scope.problemReporter().uninitializedBlankFinalField(
62                                                 field,
63                                                 scope.referenceType().declarationOf(field));
64                                         // can complain against the field decl, since only one <clinit>
65                                 }
66                         }
67                         // check static initializers thrown exceptions
68                         staticInitializerFlowContext.checkInitializerExceptions(
69                                 scope,
70                                 clinitContext,
71                                 flowInfo);
72                 } catch (AbortMethod e) {
73                         this.ignoreFurtherInvestigation = true;
74                 }
75         }
76
77         /**
78          * Bytecode generation for a <clinit> method
79          *
80          * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
81          * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
82          */
83         public void generateCode(ClassScope classScope, ClassFile classFile) {
84
85                 int clinitOffset = 0;
86                 if (ignoreFurtherInvestigation) {
87                         // should never have to add any <clinit> problem method
88                         return;
89                 }
90                 try {
91                         clinitOffset = classFile.contentsOffset;
92                         this.generateCode(classScope, classFile, clinitOffset);
93                 } catch (AbortMethod e) {
94                         // should never occur
95                         // the clinit referenceContext is the type declaration
96                         // All clinit problems will be reported against the type: AbortType instead of AbortMethod
97                         // reset the contentsOffset to the value before generating the clinit code
98                         // decrement the number of method info as well.
99                         // This is done in the addProblemMethod and addProblemConstructor for other
100                         // cases.
101                         if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
102                                 // a branch target required a goto_w, restart code gen in wide mode.
103                                 try {
104                                         classFile.contentsOffset = clinitOffset;
105                                         classFile.methodCount--;
106                                         classFile.codeStream.wideMode = true; // request wide mode 
107                                         this.generateCode(classScope, classFile, clinitOffset);
108                                         // restart method generation
109                                 } catch (AbortMethod e2) {
110                                         classFile.contentsOffset = clinitOffset;
111                                         classFile.methodCount--;
112                                 }
113                         } else {
114                                 // produce a problem method accounting for this fatal error
115                                 classFile.contentsOffset = clinitOffset;
116                                 classFile.methodCount--;
117                         }
118                 }
119         }
120
121         /**
122          * Bytecode generation for a <clinit> method
123          *
124          * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
125          * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
126          */
127         private void generateCode(
128                 ClassScope classScope,
129                 ClassFile classFile,
130                 int clinitOffset) {
131
132                 ConstantPool constantPool = classFile.constantPool;
133                 int constantPoolOffset = constantPool.currentOffset;
134                 int constantPoolIndex = constantPool.currentIndex;
135                 classFile.generateMethodInfoHeaderForClinit();
136                 int codeAttributeOffset = classFile.contentsOffset;
137                 classFile.generateCodeAttributeHeader();
138                 CodeStream codeStream = classFile.codeStream;
139                 this.resolve(classScope);
140
141                 codeStream.reset(this, classFile);
142                 TypeDeclaration declaringType = classScope.referenceContext;
143
144                 // initialize local positions - including initializer scope.
145                 MethodScope staticInitializerScope = declaringType.staticInitializerScope;
146                 staticInitializerScope.computeLocalVariablePositions(0, codeStream);
147
148                 // 1.4 feature
149                 // This has to be done before any other initialization
150                 if (this.assertionSyntheticFieldBinding != null) {
151                         // generate code related to the activation of assertion for this class
152                         codeStream.generateClassLiteralAccessForType(
153                                 classScope.enclosingSourceType(),
154                                 classLiteralSyntheticField);
155                         codeStream.invokeJavaLangClassDesiredAssertionStatus();
156                         Label falseLabel = new Label(codeStream);
157                         codeStream.ifne(falseLabel);
158                         codeStream.iconst_1();
159                         Label jumpLabel = new Label(codeStream);
160                         codeStream.goto_(jumpLabel);
161                         falseLabel.place();
162                         codeStream.iconst_0();
163                         jumpLabel.place();
164                         codeStream.putstatic(this.assertionSyntheticFieldBinding);
165                 }
166                 // generate initializers
167                 if (declaringType.fields != null) {
168                         for (int i = 0, max = declaringType.fields.length; i < max; i++) {
169                                 FieldDeclaration fieldDecl;
170                                 if ((fieldDecl = declaringType.fields[i]).isStatic()) {
171                                         fieldDecl.generateCode(staticInitializerScope, codeStream);
172                                 }
173                         }
174                 }
175                 if (codeStream.position == 0) {
176                         // do not need to output a Clinit if no bytecodes
177                         // so we reset the offset inside the byte array contents.
178                         classFile.contentsOffset = clinitOffset;
179                         // like we don't addd a method we need to undo the increment on the method count
180                         classFile.methodCount--;
181                         // reset the constant pool to its state before the clinit
182                         constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
183                 } else {
184                         if (this.needFreeReturn) {
185                                 int oldPosition = codeStream.position;
186                                 codeStream.return_();
187                                 codeStream.updateLocalVariablesAttribute(oldPosition);
188                         }
189                         // Record the end of the clinit: point to the declaration of the class
190                         codeStream.recordPositionsFrom(0, declaringType.sourceStart);
191                         classFile.completeCodeAttributeForClinit(codeAttributeOffset);
192                 }
193         }
194
195         public boolean isClinit() {
196
197                 return true;
198         }
199
200         public boolean isInitializationMethod() {
201
202                 return true;
203         }
204
205         public boolean isStatic() {
206
207                 return true;
208         }
209
210         public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
211                 //the clinit is filled by hand .... 
212         }
213
214         public StringBuffer print(int tab, StringBuffer output) {
215
216                 printIndent(tab, output).append("<clinit>()"); //$NON-NLS-1$
217                 printBody(tab + 1, output);
218                 return output;
219         }
220
221         public void resolve(ClassScope classScope) {
222
223                 this.scope = new MethodScope(classScope, classScope.referenceContext, true);
224         }
225
226         public void traverse(
227                 ASTVisitor visitor,
228                 ClassScope classScope) {
229
230                 visitor.visit(this, classScope);
231                 visitor.endVisit(this, classScope);
232         }
233
234         // 1.4 feature
235         public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding) {
236
237                 this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding;
238
239                 // we need to add the field right now, because the field infos are generated before the methods
240                 SourceTypeBinding sourceType =
241                         this.scope.outerMostMethodScope().enclosingSourceType();
242                 this.classLiteralSyntheticField =
243                         sourceType.addSyntheticField(sourceType, scope);
244         }
245
246 }