4fc31bf3f20e374e75e18b908d122f74a62ff333
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / SynchronizedStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.codegen.ExceptionLabel;
16 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
17 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
18 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
19 import net.sourceforge.phpdt.internal.compiler.flow.InsideSubRoutineFlowContext;
20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
23
24 public class SynchronizedStatement extends Statement {
25
26         public Expression expression;
27         public Block block;
28         public BlockScope scope;
29
30         boolean blockExit;
31         public LocalVariableBinding synchroVariable;
32         static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$
33
34         public SynchronizedStatement(
35                 Expression expression,
36                 Block statement,
37                 int s,
38                 int e) {
39
40                 this.expression = expression;
41                 this.block = statement;
42                 sourceEnd = e;
43                 sourceStart = s;
44         }
45
46         public FlowInfo analyseCode(
47                 BlockScope currentScope,
48                 FlowContext flowContext,
49                 FlowInfo flowInfo) {
50
51                 // mark the synthetic variable as being used
52                 synchroVariable.used = true;
53
54                 // simple propagation to subnodes
55                 flowInfo =
56                         block.analyseCode(
57                                 scope,
58                                 new InsideSubRoutineFlowContext(flowContext, this),
59                                 expression.analyseCode(scope, flowContext, flowInfo));
60
61                 // optimizing code gen
62                 if ((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()) {
63                         blockExit = true;
64                 }
65                 return flowInfo;
66         }
67
68         /**
69          * Synchronized statement code generation
70          *
71          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
72          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
73          */
74         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
75
76                 if ((bits & IsReachableMASK) == 0) {
77                         return;
78                 }
79                 int pc = codeStream.position;
80
81                 // generate the synchronization expression
82                 expression.generateCode(scope, codeStream, true);
83                 if (block.isEmptyBlock()) {
84                         if ((synchroVariable.type == LongBinding)
85                                 || (synchroVariable.type == DoubleBinding)) {
86                                 codeStream.dup2();
87                         } else {
88                                 codeStream.dup();
89                         }
90                         // only take the lock
91                         codeStream.monitorenter();
92                         codeStream.monitorexit();
93                 } else {
94                         // enter the monitor
95                         codeStream.store(synchroVariable, true);
96                         codeStream.monitorenter();
97
98                         // generate  the body of the synchronized block
99                         ExceptionLabel anyExceptionHandler = new ExceptionLabel(codeStream, null);
100                         //'null' denotes any kind of exception
101                         block.generateCode(scope, codeStream);
102                         Label endLabel = new Label(codeStream);
103                         if (!blockExit) {
104                                 codeStream.load(synchroVariable);
105                                 codeStream.monitorexit();
106                                 codeStream.goto_(endLabel);
107                         }
108                         // generate the body of the exception handler
109                         anyExceptionHandler.placeEnd();
110                         anyExceptionHandler.place();
111                         codeStream.incrStackSize(1);
112                         codeStream.load(synchroVariable);
113                         codeStream.monitorexit();
114                         codeStream.athrow();
115                         if (!blockExit) {
116                                 endLabel.place();
117                         }
118                 }
119                 if (scope != currentScope) {
120                         codeStream.exitUserScope(scope);
121                 }
122                 codeStream.recordPositionsFrom(pc, this.sourceStart);
123         }
124
125         public void resolve(BlockScope upperScope) {
126
127                 // special scope for secret locals optimization.
128                 scope = new BlockScope(upperScope);
129                 TypeBinding type = expression.resolveType(scope);
130                 if (type == null)
131                         return;
132                 switch (type.id) {
133                         case (T_boolean) :
134                         case (T_char) :
135                         case (T_float) :
136                         case (T_double) :
137                         case (T_byte) :
138                         case (T_short) :
139                         case (T_int) :
140                         case (T_long) :
141                                 scope.problemReporter().invalidTypeToSynchronize(expression, type);
142                                 break;
143                         case (T_void) :
144                                 scope.problemReporter().illegalVoidExpression(expression);
145                                 break;
146                         case (T_null) :
147                                 scope.problemReporter().invalidNullToSynchronize(expression);
148                                 break; 
149                 }
150                 //continue even on errors in order to have the TC done into the statements
151                 synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, AccDefault, false);
152                 scope.addLocalVariable(synchroVariable);
153                 synchroVariable.constant = NotAConstant; // not inlinable
154                 expression.implicitWidening(type, type);
155                 block.resolveUsing(scope);
156         }
157
158         public String toString(int tab) {
159
160                 String s = tabString(tab);
161                 s = s + "synchronized (" + expression.toStringExpression() + ")";  //$NON-NLS-1$ //$NON-NLS-2$
162                 s = s + "\n" + block.toString(tab + 1); //$NON-NLS-1$
163                 return s;
164         }
165
166         public void traverse(
167                 IAbstractSyntaxTreeVisitor visitor,
168                 BlockScope blockScope) {
169
170                 if (visitor.visit(this, blockScope)) {
171                         expression.traverse(visitor, scope);
172                         block.traverse(visitor, scope);
173                 }
174                 visitor.endVisit(this, blockScope);
175         }
176 }