totally new file layout
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / ast / Clinit.java
diff --git a/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/Clinit.java b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/Clinit.java
new file mode 100644 (file)
index 0000000..2bbac9c
--- /dev/null
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class Clinit extends AbstractMethodDeclaration {
+       
+       public final static char[] ConstantPoolName = "<clinit>".toCharArray(); //$NON-NLS-1$
+
+       private FieldBinding assertionSyntheticFieldBinding = null;
+       private FieldBinding classLiteralSyntheticField = null;
+
+       public Clinit(CompilationResult compilationResult) {
+               super(compilationResult);
+               modifiers = 0;
+               selector = ConstantPoolName;
+       }
+
+       public void analyseCode(
+               ClassScope classScope,
+               InitializationFlowContext staticInitializerFlowContext,
+               FlowInfo flowInfo) {
+
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       ExceptionHandlingFlowContext clinitContext =
+                               new ExceptionHandlingFlowContext(
+                                       staticInitializerFlowContext.parent,
+                                       this,
+                                       NoExceptions,
+                                       scope,
+                                       FlowInfo.DEAD_END);
+
+                       // check for missing returning path
+                       this.needFreeReturn = flowInfo.isReachable();
+
+                       // check missing blank final field initializations
+                       flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
+                       FieldBinding[] fields = scope.enclosingSourceType().fields();
+                       for (int i = 0, count = fields.length; i < count; i++) {
+                               FieldBinding field;
+                               if ((field = fields[i]).isStatic()
+                                       && field.isFinal()
+                                       && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
+                                       scope.problemReporter().uninitializedBlankFinalField(
+                                               field,
+                                               scope.referenceType().declarationOf(field));
+                                       // can complain against the field decl, since only one <clinit>
+                               }
+                       }
+                       // check static initializers thrown exceptions
+                       staticInitializerFlowContext.checkInitializerExceptions(
+                               scope,
+                               clinitContext,
+                               flowInfo);
+               } catch (AbortMethod e) {
+                       this.ignoreFurtherInvestigation = true;
+               }
+       }
+
+       /**
+        * Bytecode generation for a <clinit> method
+        *
+        * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
+        * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+        */
+       public void generateCode(ClassScope classScope, ClassFile classFile) {
+
+               int clinitOffset = 0;
+               if (ignoreFurtherInvestigation) {
+                       // should never have to add any <clinit> problem method
+                       return;
+               }
+               try {
+                       clinitOffset = classFile.contentsOffset;
+                       this.generateCode(classScope, classFile, clinitOffset);
+               } catch (AbortMethod e) {
+                       // should never occur
+                       // the clinit referenceContext is the type declaration
+                       // All clinit problems will be reported against the type: AbortType instead of AbortMethod
+                       // reset the contentsOffset to the value before generating the clinit code
+                       // decrement the number of method info as well.
+                       // This is done in the addProblemMethod and addProblemConstructor for other
+                       // cases.
+                       if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
+                               // a branch target required a goto_w, restart code gen in wide mode.
+                               try {
+                                       classFile.contentsOffset = clinitOffset;
+                                       classFile.methodCount--;
+                                       classFile.codeStream.wideMode = true; // request wide mode 
+                                       this.generateCode(classScope, classFile, clinitOffset);
+                                       // restart method generation
+                               } catch (AbortMethod e2) {
+                                       classFile.contentsOffset = clinitOffset;
+                                       classFile.methodCount--;
+                               }
+                       } else {
+                               // produce a problem method accounting for this fatal error
+                               classFile.contentsOffset = clinitOffset;
+                               classFile.methodCount--;
+                       }
+               }
+       }
+
+       /**
+        * Bytecode generation for a <clinit> method
+        *
+        * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
+        * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+        */
+       private void generateCode(
+               ClassScope classScope,
+               ClassFile classFile,
+               int clinitOffset) {
+
+               ConstantPool constantPool = classFile.constantPool;
+               int constantPoolOffset = constantPool.currentOffset;
+               int constantPoolIndex = constantPool.currentIndex;
+               classFile.generateMethodInfoHeaderForClinit();
+               int codeAttributeOffset = classFile.contentsOffset;
+               classFile.generateCodeAttributeHeader();
+               CodeStream codeStream = classFile.codeStream;
+               this.resolve(classScope);
+
+               codeStream.reset(this, classFile);
+               TypeDeclaration declaringType = classScope.referenceContext;
+
+               // initialize local positions - including initializer scope.
+               MethodScope staticInitializerScope = declaringType.staticInitializerScope;
+               staticInitializerScope.computeLocalVariablePositions(0, codeStream);
+
+               // 1.4 feature
+               // This has to be done before any other initialization
+               if (this.assertionSyntheticFieldBinding != null) {
+                       // generate code related to the activation of assertion for this class
+                       codeStream.generateClassLiteralAccessForType(
+                               classScope.enclosingSourceType(),
+                               classLiteralSyntheticField);
+                       codeStream.invokeJavaLangClassDesiredAssertionStatus();
+                       Label falseLabel = new Label(codeStream);
+                       codeStream.ifne(falseLabel);
+                       codeStream.iconst_1();
+                       Label jumpLabel = new Label(codeStream);
+                       codeStream.goto_(jumpLabel);
+                       falseLabel.place();
+                       codeStream.iconst_0();
+                       jumpLabel.place();
+                       codeStream.putstatic(this.assertionSyntheticFieldBinding);
+               }
+               // generate initializers
+               if (declaringType.fields != null) {
+                       for (int i = 0, max = declaringType.fields.length; i < max; i++) {
+                               FieldDeclaration fieldDecl;
+                               if ((fieldDecl = declaringType.fields[i]).isStatic()) {
+                                       fieldDecl.generateCode(staticInitializerScope, codeStream);
+                               }
+                       }
+               }
+               if (codeStream.position == 0) {
+                       // do not need to output a Clinit if no bytecodes
+                       // so we reset the offset inside the byte array contents.
+                       classFile.contentsOffset = clinitOffset;
+                       // like we don't addd a method we need to undo the increment on the method count
+                       classFile.methodCount--;
+                       // reset the constant pool to its state before the clinit
+                       constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
+               } else {
+                       if (this.needFreeReturn) {
+                               int oldPosition = codeStream.position;
+                               codeStream.return_();
+                               codeStream.updateLocalVariablesAttribute(oldPosition);
+                       }
+                       // Record the end of the clinit: point to the declaration of the class
+                       codeStream.recordPositionsFrom(0, declaringType.sourceStart);
+                       classFile.completeCodeAttributeForClinit(codeAttributeOffset);
+               }
+       }
+
+       public boolean isClinit() {
+
+               return true;
+       }
+
+       public boolean isInitializationMethod() {
+
+               return true;
+       }
+
+       public boolean isStatic() {
+
+               return true;
+       }
+
+       public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
+               //the clinit is filled by hand .... 
+       }
+
+       public StringBuffer print(int tab, StringBuffer output) {
+
+               printIndent(tab, output).append("<clinit>()"); //$NON-NLS-1$
+               printBody(tab + 1, output);
+               return output;
+       }
+
+       public void resolve(ClassScope classScope) {
+
+               this.scope = new MethodScope(classScope, classScope.referenceContext, true);
+       }
+
+       public void traverse(
+               ASTVisitor visitor,
+               ClassScope classScope) {
+
+               visitor.visit(this, classScope);
+               visitor.endVisit(this, classScope);
+       }
+
+       // 1.4 feature
+       public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding) {
+
+               this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding;
+
+               // we need to add the field right now, because the field infos are generated before the methods
+               SourceTypeBinding sourceType =
+                       this.scope.outerMostMethodScope().enclosingSourceType();
+               this.classLiteralSyntheticField =
+                       sourceType.addSyntheticField(sourceType, scope);
+       }
+
+}