001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.impl.Constant;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class SynchronizedStatement extends SubRoutineStatement {
020:
021: public Expression expression;
022: public Block block;
023: public BlockScope scope;
024: public LocalVariableBinding synchroVariable;
025: static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$
026:
027: // for local variables table attributes
028: int preSynchronizedInitStateIndex = -1;
029: int mergedSynchronizedInitStateIndex = -1;
030:
031: public SynchronizedStatement(Expression expression,
032: Block statement, int s, int e) {
033:
034: this .expression = expression;
035: this .block = statement;
036: sourceEnd = e;
037: sourceStart = s;
038: }
039:
040: public FlowInfo analyseCode(BlockScope currentScope,
041: FlowContext flowContext, FlowInfo flowInfo) {
042:
043: this .preSynchronizedInitStateIndex = currentScope.methodScope()
044: .recordInitializationStates(flowInfo);
045: // TODO (philippe) shouldn't it be protected by a check whether reachable statement ?
046:
047: // mark the synthetic variable as being used
048: synchroVariable.useFlag = LocalVariableBinding.USED;
049:
050: // simple propagation to subnodes
051: flowInfo = block.analyseCode(scope,
052: new InsideSubRoutineFlowContext(flowContext, this ),
053: expression.analyseCode(scope, flowContext, flowInfo));
054:
055: this .mergedSynchronizedInitStateIndex = currentScope
056: .methodScope().recordInitializationStates(flowInfo);
057:
058: // optimizing code gen
059: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) {
060: this .bits |= ASTNode.BlockExit;
061: }
062:
063: return flowInfo;
064: }
065:
066: public boolean isSubRoutineEscaping() {
067: return false;
068: }
069:
070: /**
071: * Synchronized statement code generation
072: *
073: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
074: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
075: */
076: public void generateCode(BlockScope currentScope,
077: CodeStream codeStream) {
078: if ((bits & IsReachable) == 0) {
079: return;
080: }
081: // in case the labels needs to be reinitialized
082: // when the code generation is restarted in wide mode
083: this .anyExceptionLabel = null;
084:
085: int pc = codeStream.position;
086:
087: // generate the synchronization expression
088: expression.generateCode(scope, codeStream, true);
089: if (block.isEmptyBlock()) {
090: if ((synchroVariable.type == TypeBinding.LONG)
091: || (synchroVariable.type == TypeBinding.DOUBLE)) {
092: codeStream.dup2();
093: } else {
094: codeStream.dup();
095: }
096: // only take the lock
097: codeStream.monitorenter();
098: codeStream.monitorexit();
099: if (scope != currentScope) {
100: codeStream.exitUserScope(scope);
101: }
102: } else {
103: // enter the monitor
104: codeStream.store(synchroVariable, true);
105: codeStream.addVariable(synchroVariable);
106: codeStream.monitorenter();
107:
108: // generate the body of the synchronized block
109: this .enterAnyExceptionHandler(codeStream);
110: block.generateCode(scope, codeStream);
111: if (scope != currentScope) {
112: // close all locals defined in the synchronized block except the secret local
113: codeStream.exitUserScope(scope, synchroVariable);
114: }
115:
116: BranchLabel endLabel = new BranchLabel(codeStream);
117: if ((this .bits & ASTNode.BlockExit) == 0) {
118: codeStream.load(synchroVariable);
119: codeStream.monitorexit();
120: this .exitAnyExceptionHandler();
121: codeStream.goto_(endLabel);
122: this .enterAnyExceptionHandler(codeStream);
123: }
124: // generate the body of the exception handler
125: codeStream.pushExceptionOnStack(scope
126: .getJavaLangThrowable());
127: if (this .preSynchronizedInitStateIndex != -1) {
128: codeStream.removeNotDefinitelyAssignedVariables(
129: currentScope,
130: this .preSynchronizedInitStateIndex);
131: }
132: this .placeAllAnyExceptionHandler();
133: codeStream.load(synchroVariable);
134: codeStream.monitorexit();
135: this .exitAnyExceptionHandler();
136: codeStream.athrow();
137: // May loose some local variable initializations : affecting the local variable attributes
138: if (this .mergedSynchronizedInitStateIndex != -1) {
139: codeStream.removeNotDefinitelyAssignedVariables(
140: currentScope,
141: this .mergedSynchronizedInitStateIndex);
142: codeStream.addDefinitelyAssignedVariables(currentScope,
143: this .mergedSynchronizedInitStateIndex);
144: }
145: if (scope != currentScope) {
146: codeStream.removeVariable(this .synchroVariable);
147: }
148: if ((this .bits & ASTNode.BlockExit) == 0) {
149: endLabel.place();
150: }
151: }
152: codeStream.recordPositionsFrom(pc, this .sourceStart);
153: }
154:
155: /**
156: * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding)
157: */
158: public boolean generateSubRoutineInvocation(
159: BlockScope currentScope, CodeStream codeStream,
160: Object targetLocation, int stateIndex,
161: LocalVariableBinding secretLocal) {
162: codeStream.load(this .synchroVariable);
163: codeStream.monitorexit();
164: exitAnyExceptionHandler();
165: return false;
166: }
167:
168: public void resolve(BlockScope upperScope) {
169: // special scope for secret locals optimization.
170: scope = new BlockScope(upperScope);
171: TypeBinding type = expression.resolveType(scope);
172: if (type == null)
173: return;
174: switch (type.id) {
175: case T_boolean:
176: case T_char:
177: case T_float:
178: case T_double:
179: case T_byte:
180: case T_short:
181: case T_int:
182: case T_long:
183: scope.problemReporter().invalidTypeToSynchronize(
184: expression, type);
185: break;
186: case T_void:
187: scope.problemReporter().illegalVoidExpression(expression);
188: break;
189: case T_null:
190: scope.problemReporter()
191: .invalidNullToSynchronize(expression);
192: break;
193: }
194: //continue even on errors in order to have the TC done into the statements
195: synchroVariable = new LocalVariableBinding(
196: SecretLocalDeclarationName, type,
197: ClassFileConstants.AccDefault, false);
198: scope.addLocalVariable(synchroVariable);
199: synchroVariable.setConstant(Constant.NotAConstant); // not inlinable
200: expression.computeConversion(scope, type, type);
201: block.resolveUsing(scope);
202: }
203:
204: public StringBuffer printStatement(int indent, StringBuffer output) {
205: printIndent(indent, output);
206: output.append("synchronized ("); //$NON-NLS-1$
207: expression.printExpression(0, output).append(')');
208: output.append('\n');
209: return block.printStatement(indent + 1, output);
210: }
211:
212: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
213: if (visitor.visit(this, blockScope)) {
214: expression.traverse(visitor, scope);
215: block.traverse(visitor, scope);
216: }
217: visitor.endVisit(this, blockScope);
218: }
219: }
|