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