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 
SynchronizedStatement( Expression expression, Block statement, int s, int e)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 
analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)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 
isSubRoutineEscaping()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 	 */
generateCode(BlockScope currentScope, CodeStream codeStream)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 	 */
generateSubRoutineInvocation( BlockScope currentScope, CodeStream codeStream)134 	public void generateSubRoutineInvocation(
135 			BlockScope currentScope,
136 			CodeStream codeStream) {
137 
138 		codeStream.load(this.synchroVariable);
139 		codeStream.monitorexit();
140 	}
141 
resolve(BlockScope upperScope)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 
printStatement(int indent, StringBuffer output)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 
traverse( ASTVisitor visitor, BlockScope blockScope)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 }
195