added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / SynchronizedStatement.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.codegen.*;
15 import org.eclipse.jdt.internal.compiler.flow.*;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17
18 public class SynchronizedStatement extends SubRoutineStatement {
19
20         public Expression expression;
21         public Block block;
22         public BlockScope scope;
23         boolean blockExit;
24         public LocalVariableBinding synchroVariable;
25         static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$
26
27         public SynchronizedStatement(
28                 Expression expression,
29                 Block statement,
30                 int s,
31                 int e) {
32
33                 this.expression = expression;
34                 this.block = statement;
35                 sourceEnd = e;
36                 sourceStart = s;
37         }
38
39         public FlowInfo analyseCode(
40                 BlockScope currentScope,
41                 FlowContext flowContext,
42                 FlowInfo flowInfo) {
43
44             // TODO (philippe) shouldn't it be protected by a check whether reachable statement ?
45             
46                 // mark the synthetic variable as being used
47                 synchroVariable.useFlag = LocalVariableBinding.USED;
48
49                 // simple propagation to subnodes
50                 flowInfo =
51                         block.analyseCode(
52                                 scope,
53                                 new InsideSubRoutineFlowContext(flowContext, this),
54                                 expression.analyseCode(scope, flowContext, flowInfo));
55
56                 // optimizing code gen
57                 this.blockExit = !flowInfo.isReachable();
58
59                 return flowInfo;
60         }
61
62         public boolean isSubRoutineEscaping() {
63
64                 return false;
65         }
66         
67         /**
68          * Synchronized statement code generation
69          *
70          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
71          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
72          */
73         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
74         
75                 if ((bits & IsReachableMASK) == 0) {
76                         return;
77                 }
78                 // in case the labels needs to be reinitialized
79                 // when the code generation is restarted in wide mode
80                 if (this.anyExceptionLabelsCount > 0) {
81                         this.anyExceptionLabels = NO_EXCEPTION_HANDLER;
82                         this.anyExceptionLabelsCount = 0;
83                 }
84                 int pc = codeStream.position;
85         
86                 // generate the synchronization expression
87                 expression.generateCode(scope, codeStream, true);
88                 if (block.isEmptyBlock()) {
89                         if ((synchroVariable.type == LongBinding)
90                                 || (synchroVariable.type == DoubleBinding)) {
91                                 codeStream.dup2();
92                         } else {
93                                 codeStream.dup();
94                         }
95                         // only take the lock
96                         codeStream.monitorenter();
97                         codeStream.monitorexit();
98                 } else {
99                         // enter the monitor
100                         codeStream.store(synchroVariable, true);
101                         codeStream.monitorenter();
102         
103                         // generate  the body of the synchronized block
104                         this.enterAnyExceptionHandler(codeStream);
105                         block.generateCode(scope, codeStream);
106                         Label endLabel = new Label(codeStream);
107                         if (!blockExit) {
108                                 codeStream.load(synchroVariable);
109                                 codeStream.monitorexit();
110                                 this.exitAnyExceptionHandler();
111                                 codeStream.goto_(endLabel);
112                                 this.enterAnyExceptionHandler(codeStream);
113                         }
114                         // generate the body of the exception handler
115                         this.placeAllAnyExceptionHandlers();
116                         codeStream.incrStackSize(1);
117                         codeStream.load(synchroVariable);
118                         codeStream.monitorexit();
119                         this.exitAnyExceptionHandler();
120                         codeStream.athrow();
121                         if (!blockExit) {
122                                 endLabel.place();
123                         }
124                 }
125                 if (scope != currentScope) {
126                         codeStream.exitUserScope(scope);
127                 }
128                 codeStream.recordPositionsFrom(pc, this.sourceStart);
129         }
130
131         /* (non-Javadoc)
132          * @see org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement#generateSubRoutineInvocation(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.codegen.CodeStream)
133          */
134         public void generateSubRoutineInvocation(
135                         BlockScope currentScope,
136                         CodeStream codeStream) {
137
138                 codeStream.load(this.synchroVariable);
139                 codeStream.monitorexit();
140         }
141
142         public void resolve(BlockScope upperScope) {
143
144                 // special scope for secret locals optimization.
145                 scope = new BlockScope(upperScope);
146                 TypeBinding type = expression.resolveType(scope);
147                 if (type == null)
148                         return;
149                 switch (type.id) {
150                         case (T_boolean) :
151                         case (T_char) :
152                         case (T_float) :
153                         case (T_double) :
154                         case (T_byte) :
155                         case (T_short) :
156                         case (T_int) :
157                         case (T_long) :
158                                 scope.problemReporter().invalidTypeToSynchronize(expression, type);
159                                 break;
160                         case (T_void) :
161                                 scope.problemReporter().illegalVoidExpression(expression);
162                                 break;
163                         case (T_null) :
164                                 scope.problemReporter().invalidNullToSynchronize(expression);
165                                 break; 
166                 }
167                 //continue even on errors in order to have the TC done into the statements
168                 synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, AccDefault, false);
169                 scope.addLocalVariable(synchroVariable);
170                 synchroVariable.setConstant(NotAConstant); // not inlinable
171                 expression.computeConversion(scope, type, type);
172                 block.resolveUsing(scope);
173         }
174
175         public StringBuffer printStatement(int indent, StringBuffer output) {
176
177                 printIndent(indent, output);
178                 output.append("synchronized ("); //$NON-NLS-1$
179                 expression.printExpression(0, output).append(')');
180                 output.append('\n');
181                 return block.printStatement(indent + 1, output); 
182         }
183
184         public void traverse(
185                 ASTVisitor visitor,
186                 BlockScope blockScope) {
187
188                 if (visitor.visit(this, blockScope)) {
189                         expression.traverse(visitor, scope);
190                         block.traverse(visitor, scope);
191                 }
192                 visitor.endVisit(this, blockScope);
193         }
194 }