001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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.impl.*;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015: import org.eclipse.jdt.internal.compiler.codegen.*;
016: import org.eclipse.jdt.internal.compiler.flow.*;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class UnaryExpression extends OperatorExpression {
020:
021: public Expression expression;
022: public Constant optimizedBooleanConstant;
023:
024: public UnaryExpression(Expression expression, int operator) {
025: this .expression = expression;
026: this .bits |= operator << OperatorSHIFT; // encode operator
027: }
028:
029: public FlowInfo analyseCode(BlockScope currentScope,
030: FlowContext flowContext, FlowInfo flowInfo) {
031: this .expression.checkNPE(currentScope, flowContext, flowInfo);
032: if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
033: return this .expression.analyseCode(currentScope,
034: flowContext, flowInfo).asNegatedCondition();
035: } else {
036: return this .expression.analyseCode(currentScope,
037: flowContext, flowInfo);
038: }
039: }
040:
041: public Constant optimizedBooleanConstant() {
042:
043: return this .optimizedBooleanConstant == null ? this .constant
044: : this .optimizedBooleanConstant;
045: }
046:
047: /**
048: * Code generation for an unary operation
049: *
050: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
051: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
052: * @param valueRequired boolean
053: */
054: public void generateCode(BlockScope currentScope,
055: CodeStream codeStream, boolean valueRequired) {
056:
057: int pc = codeStream.position;
058: BranchLabel falseLabel, endifLabel;
059: if (this .constant != Constant.NotAConstant) {
060: // inlined value
061: if (valueRequired) {
062: codeStream.generateConstant(this .constant,
063: this .implicitConversion);
064: }
065: codeStream.recordPositionsFrom(pc, this .sourceStart);
066: return;
067: }
068: switch ((bits & OperatorMASK) >> OperatorSHIFT) {
069: case NOT:
070: switch ((this .expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) /* runtime type */{
071: case T_boolean:
072: // ! <boolean>
073: // Generate code for the condition
074: this .expression.generateOptimizedBoolean(currentScope,
075: codeStream, null,
076: (falseLabel = new BranchLabel(codeStream)),
077: valueRequired);
078: if (valueRequired) {
079: codeStream.iconst_0();
080: if (falseLabel.forwardReferenceCount() > 0) {
081: codeStream.goto_(endifLabel = new BranchLabel(
082: codeStream));
083: codeStream.decrStackSize(1);
084: falseLabel.place();
085: codeStream.iconst_1();
086: endifLabel.place();
087: }
088: } else { // 6596: if (!(a && b)){} - must still place falseLabel
089: falseLabel.place();
090: }
091: break;
092: }
093: break;
094: case TWIDDLE:
095: switch ((this .expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4 /* runtime */) {
096: case T_int:
097: // ~int
098: this .expression.generateCode(currentScope, codeStream,
099: valueRequired);
100: if (valueRequired) {
101: codeStream.iconst_m1();
102: codeStream.ixor();
103: }
104: break;
105: case T_long:
106: this .expression.generateCode(currentScope, codeStream,
107: valueRequired);
108: if (valueRequired) {
109: codeStream.ldc2_w(-1L);
110: codeStream.lxor();
111: }
112: }
113: break;
114: case MINUS:
115: // - <num>
116: if (this .constant != Constant.NotAConstant) {
117: if (valueRequired) {
118: switch ((this .expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { /* runtime */
119: case T_int:
120: codeStream.generateInlinedValue(this .constant
121: .intValue()
122: * -1);
123: break;
124: case T_float:
125: codeStream.generateInlinedValue(this .constant
126: .floatValue()
127: * -1.0f);
128: break;
129: case T_long:
130: codeStream.generateInlinedValue(this .constant
131: .longValue()
132: * -1L);
133: break;
134: case T_double:
135: codeStream.generateInlinedValue(this .constant
136: .doubleValue()
137: * -1.0);
138: }
139: }
140: } else {
141: this .expression.generateCode(currentScope, codeStream,
142: valueRequired);
143: if (valueRequired) {
144: switch ((expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { /* runtime type */
145: case T_int:
146: codeStream.ineg();
147: break;
148: case T_float:
149: codeStream.fneg();
150: break;
151: case T_long:
152: codeStream.lneg();
153: break;
154: case T_double:
155: codeStream.dneg();
156: }
157: }
158: }
159: break;
160: case PLUS:
161: this .expression.generateCode(currentScope, codeStream,
162: valueRequired);
163: }
164: if (valueRequired) {
165: codeStream
166: .generateImplicitConversion(this .implicitConversion);
167: }
168: codeStream.recordPositionsFrom(pc, this .sourceStart);
169: }
170:
171: /**
172: * Boolean operator code generation
173: * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
174: */
175: public void generateOptimizedBoolean(BlockScope currentScope,
176: CodeStream codeStream, BranchLabel trueLabel,
177: BranchLabel falseLabel, boolean valueRequired) {
178:
179: if ((this .constant != Constant.NotAConstant)
180: && (this .constant.typeID() == T_boolean)) {
181: super .generateOptimizedBoolean(currentScope, codeStream,
182: trueLabel, falseLabel, valueRequired);
183: return;
184: }
185: if (((this .bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
186: this .expression.generateOptimizedBoolean(currentScope,
187: codeStream, falseLabel, trueLabel, valueRequired);
188: } else {
189: super .generateOptimizedBoolean(currentScope, codeStream,
190: trueLabel, falseLabel, valueRequired);
191: }
192: }
193:
194: public StringBuffer printExpressionNoParenthesis(int indent,
195: StringBuffer output) {
196:
197: output.append(operatorToString()).append(' ');
198: return this .expression.printExpression(0, output);
199: }
200:
201: public TypeBinding resolveType(BlockScope scope) {
202:
203: boolean expressionIsCast;
204: if ((expressionIsCast = this .expression instanceof CastExpression) == true)
205: this .expression.bits |= DisableUnnecessaryCastCheck; // will check later on
206: TypeBinding expressionType = this .expression.resolveType(scope);
207: if (expressionType == null) {
208: this .constant = Constant.NotAConstant;
209: return null;
210: }
211: int expressionTypeID = expressionType.id;
212: // autoboxing support
213: boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
214: if (use15specifics) {
215: if (!expressionType.isBaseType()) {
216: expressionTypeID = scope.environment()
217: .computeBoxingType(expressionType).id;
218: }
219: }
220: if (expressionTypeID > 15) {
221: this .constant = Constant.NotAConstant;
222: scope.problemReporter().invalidOperator(this ,
223: expressionType);
224: return null;
225: }
226:
227: int tableId;
228: switch ((bits & OperatorMASK) >> OperatorSHIFT) {
229: case NOT:
230: tableId = AND_AND;
231: break;
232: case TWIDDLE:
233: tableId = LEFT_SHIFT;
234: break;
235: default:
236: tableId = MINUS;
237: } //+ and - cases
238:
239: // the code is an int
240: // (cast) left Op (cast) rigth --> result
241: // 0000 0000 0000 0000 0000
242: // <<16 <<12 <<8 <<4 <<0
243: int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4)
244: + expressionTypeID];
245: this .expression.computeConversion(scope, TypeBinding
246: .wellKnownType(scope,
247: (operatorSignature >>> 16) & 0x0000F),
248: expressionType);
249: this .bits |= operatorSignature & 0xF;
250: switch (operatorSignature & 0xF) { // only switch on possible result type.....
251: case T_boolean:
252: this .resolvedType = TypeBinding.BOOLEAN;
253: break;
254: case T_byte:
255: this .resolvedType = TypeBinding.BYTE;
256: break;
257: case T_char:
258: this .resolvedType = TypeBinding.CHAR;
259: break;
260: case T_double:
261: this .resolvedType = TypeBinding.DOUBLE;
262: break;
263: case T_float:
264: this .resolvedType = TypeBinding.FLOAT;
265: break;
266: case T_int:
267: this .resolvedType = TypeBinding.INT;
268: break;
269: case T_long:
270: this .resolvedType = TypeBinding.LONG;
271: break;
272: default: //error........
273: this .constant = Constant.NotAConstant;
274: if (expressionTypeID != T_undefined)
275: scope.problemReporter().invalidOperator(this ,
276: expressionType);
277: return null;
278: }
279: // compute the constant when valid
280: if (this .expression.constant != Constant.NotAConstant) {
281: this .constant = Constant.computeConstantOperation(
282: this .expression.constant, expressionTypeID,
283: (bits & OperatorMASK) >> OperatorSHIFT);
284: } else {
285: this .constant = Constant.NotAConstant;
286: if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
287: Constant cst = expression.optimizedBooleanConstant();
288: if (cst != Constant.NotAConstant)
289: this .optimizedBooleanConstant = BooleanConstant
290: .fromValue(!cst.booleanValue());
291: }
292: }
293: if (expressionIsCast) {
294: // check need for operand cast
295: CastExpression.checkNeedForArgumentCast(scope, tableId,
296: operatorSignature, this .expression,
297: expressionTypeID);
298: }
299: return this .resolvedType;
300: }
301:
302: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
303:
304: if (visitor.visit(this, blockScope)) {
305: this.expression.traverse(visitor, blockScope);
306: }
307: visitor.endVisit(this, blockScope);
308: }
309: }
|