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