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 Clinit(CompilationResult compilationResult)28 public Clinit(CompilationResult compilationResult) { 29 super(compilationResult); 30 modifiers = 0; 31 selector = ConstantPoolName; 32 } 33 analyseCode( ClassScope classScope, InitializationFlowContext staticInitializerFlowContext, FlowInfo flowInfo)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.original())); 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 */ generateCode(ClassScope classScope, ClassFile classFile)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 */ generateCode( ClassScope classScope, ClassFile classFile, int clinitOffset)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 isClinit()195 public boolean isClinit() { 196 197 return true; 198 } 199 isInitializationMethod()200 public boolean isInitializationMethod() { 201 202 return true; 203 } 204 isStatic()205 public boolean isStatic() { 206 207 return true; 208 } 209 parseStatements(Parser parser, CompilationUnitDeclaration unit)210 public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { 211 //the clinit is filled by hand .... 212 } 213 print(int tab, StringBuffer output)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 resolve(ClassScope classScope)221 public void resolve(ClassScope classScope) { 222 223 this.scope = new MethodScope(classScope, classScope.referenceContext, true); 224 } 225 traverse( ASTVisitor visitor, ClassScope classScope)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 setAssertionSupport(FieldBinding assertionSyntheticFieldBinding, boolean needClassLiteralField)235 public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding, boolean needClassLiteralField) { 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 if (needClassLiteralField) { 243 this.classLiteralSyntheticField = 244 sourceType.addSyntheticField(sourceType, scope); 245 } 246 } 247 248 } 249