removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / SynchronizedStatement.java
diff --git a/src/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/src/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
new file mode 100644 (file)
index 0000000..2a45c54
--- /dev/null
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * 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.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SynchronizedStatement extends SubRoutineStatement {
+
+       public Expression expression;
+       public Block block;
+       public BlockScope scope;
+       boolean blockExit;
+       public LocalVariableBinding synchroVariable;
+       static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$
+
+       public SynchronizedStatement(
+               Expression expression,
+               Block statement,
+               int s,
+               int e) {
+
+               this.expression = expression;
+               this.block = statement;
+               sourceEnd = e;
+               sourceStart = s;
+       }
+
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               // mark the synthetic variable as being used
+               synchroVariable.useFlag = LocalVariableBinding.USED;
+
+               // simple propagation to subnodes
+               flowInfo =
+                       block.analyseCode(
+                               scope,
+                               new InsideSubRoutineFlowContext(flowContext, this),
+                               expression.analyseCode(scope, flowContext, flowInfo));
+
+               // optimizing code gen
+               this.blockExit = !flowInfo.isReachable();
+
+               return flowInfo;
+       }
+
+       public boolean isSubRoutineEscaping() {
+
+               return false;
+       }
+       
+       /**
+        * Synchronized statement code generation
+        *
+        * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+        * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+        */
+       public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+               if ((bits & IsReachableMASK) == 0) {
+                       return;
+               }
+               // in case the labels needs to be reinitialized
+               // when the code generation is restarted in wide mode
+               if (this.anyExceptionLabelsCount > 0) {
+                       this.anyExceptionLabels = NO_EXCEPTION_HANDLER;
+                       this.anyExceptionLabelsCount = 0;
+               }
+               int pc = codeStream.position;
+
+               // generate the synchronization expression
+               expression.generateCode(scope, codeStream, true);
+               if (block.isEmptyBlock()) {
+                       if ((synchroVariable.type == LongBinding)
+                               || (synchroVariable.type == DoubleBinding)) {
+                               codeStream.dup2();
+                       } else {
+                               codeStream.dup();
+                       }
+                       // only take the lock
+                       codeStream.monitorenter();
+                       codeStream.monitorexit();
+               } else {
+                       // enter the monitor
+                       codeStream.store(synchroVariable, true);
+                       codeStream.monitorenter();
+
+                       // generate  the body of the synchronized block
+                       this.enterAnyExceptionHandler(codeStream);
+                       block.generateCode(scope, codeStream);
+                       Label endLabel = new Label(codeStream);
+                       if (!blockExit) {
+                               codeStream.load(synchroVariable);
+                               codeStream.monitorexit();
+                               codeStream.goto_(endLabel);
+                       }
+                       // generate the body of the exception handler
+                       this.exitAnyExceptionHandler();
+                       this.placeAllAnyExceptionHandlers();
+                       codeStream.incrStackSize(1);
+                       codeStream.load(synchroVariable);
+                       codeStream.monitorexit();
+                       codeStream.athrow();
+                       if (!blockExit) {
+                               endLabel.place();
+                       }
+               }
+               if (scope != currentScope) {
+                       codeStream.exitUserScope(scope);
+               }
+               codeStream.recordPositionsFrom(pc, this.sourceStart);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement#generateSubRoutineInvocation(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.codegen.CodeStream)
+        */
+       public void generateSubRoutineInvocation(
+                       BlockScope currentScope,
+                       CodeStream codeStream) {
+
+               codeStream.load(this.synchroVariable);
+               codeStream.monitorexit();
+       }
+
+       public void resolve(BlockScope upperScope) {
+
+               // special scope for secret locals optimization.
+               scope = new BlockScope(upperScope);
+               TypeBinding type = expression.resolveType(scope);
+               if (type == null)
+                       return;
+               switch (type.id) {
+                       case (T_boolean) :
+                       case (T_char) :
+                       case (T_float) :
+                       case (T_double) :
+                       case (T_byte) :
+                       case (T_short) :
+                       case (T_int) :
+                       case (T_long) :
+                               scope.problemReporter().invalidTypeToSynchronize(expression, type);
+                               break;
+                       case (T_void) :
+                               scope.problemReporter().illegalVoidExpression(expression);
+                               break;
+                       case (T_null) :
+                               scope.problemReporter().invalidNullToSynchronize(expression);
+                               break; 
+               }
+               //continue even on errors in order to have the TC done into the statements
+               synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, AccDefault, false);
+               scope.addLocalVariable(synchroVariable);
+               synchroVariable.constant = NotAConstant; // not inlinable
+               expression.implicitWidening(type, type);
+               block.resolveUsing(scope);
+       }
+
+       public StringBuffer printStatement(int indent, StringBuffer output) {
+
+               printIndent(indent, output);
+               output.append("synchronized ("); //$NON-NLS-1$
+               expression.printExpression(0, output).append(')');
+               output.append('\n');
+               return block.printStatement(indent + 1, output); 
+       }
+
+       public void traverse(
+               ASTVisitor visitor,
+               BlockScope blockScope) {
+
+               if (visitor.visit(this, blockScope)) {
+                       expression.traverse(visitor, scope);
+                       block.traverse(visitor, scope);
+               }
+               visitor.endVisit(this, blockScope);
+       }
+}