Copyright (c) 2000, 2013 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Stephan Herrmann - Contribution for bug 383368 - [compiler][null] syntactic null analysis for field references bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields
/******************************************************************************* * Copyright (c) 2000, 2013 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for * bug 383368 - [compiler][null] syntactic null analysis for field references * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields *******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.impl.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.*; import org.eclipse.jdt.internal.compiler.flow.*; import org.eclipse.jdt.internal.compiler.lookup.*; public class UnaryExpression extends OperatorExpression { public Expression expression; public Constant optimizedBooleanConstant; public UnaryExpression(Expression expression, int operator) { this.expression = expression; this.bits |= operator << OperatorSHIFT; // encode operator } @Override public FlowInfo analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { flowContext.tagBits ^= FlowContext.INSIDE_NEGATION; flowInfo = this.expression. analyseCode(currentScope, flowContext, flowInfo). asNegatedCondition(); flowContext.tagBits ^= FlowContext.INSIDE_NEGATION; } else { flowInfo = this.expression. analyseCode(currentScope, flowContext, flowInfo); } this.expression.checkNPE(currentScope, flowContext, flowInfo); return flowInfo; } @Override public Constant optimizedBooleanConstant() { return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; }
Code generation for an unary operation
Params:
  • currentScope – org.eclipse.jdt.internal.compiler.lookup.BlockScope
  • codeStream – org.eclipse.jdt.internal.compiler.codegen.CodeStream
  • valueRequired – boolean
/** * Code generation for an unary operation * * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream * @param valueRequired boolean */
@Override public void generateCode( BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { int pc = codeStream.position; BranchLabel falseLabel, endifLabel; if (this.constant != Constant.NotAConstant) { // inlined value if (valueRequired) { codeStream.generateConstant(this.constant, this.implicitConversion); } codeStream.recordPositionsFrom(pc, this.sourceStart); return; } switch ((this.bits & OperatorMASK) >> OperatorSHIFT) { case NOT : switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) /* runtime type */ { case T_boolean : // ! <boolean> // Generate code for the condition this.expression.generateOptimizedBoolean( currentScope, codeStream, null, (falseLabel = new BranchLabel(codeStream)), valueRequired); if (valueRequired) { codeStream.iconst_0(); if (falseLabel.forwardReferenceCount() > 0) { codeStream.goto_(endifLabel = new BranchLabel(codeStream)); codeStream.decrStackSize(1); falseLabel.place(); codeStream.iconst_1(); endifLabel.place(); } } else { // 6596: if (!(a && b)){} - must still place falseLabel falseLabel.place(); } break; } break; case TWIDDLE : switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4 /* runtime */) { case T_int : // ~int this.expression.generateCode(currentScope, codeStream, valueRequired); if (valueRequired) { codeStream.iconst_m1(); codeStream.ixor(); } break; case T_long : this.expression.generateCode(currentScope, codeStream, valueRequired); if (valueRequired) { codeStream.ldc2_w(-1L); codeStream.lxor(); } } break; case MINUS : // - <num> if (this.constant != Constant.NotAConstant) { if (valueRequired) { switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime */ case T_int : codeStream.generateInlinedValue(this.constant.intValue() * -1); break; case T_float : codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f); break; case T_long : codeStream.generateInlinedValue(this.constant.longValue() * -1L); break; case T_double : codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0); } } } else { this.expression.generateCode(currentScope, codeStream, valueRequired); if (valueRequired) { switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime type */ case T_int : codeStream.ineg(); break; case T_float : codeStream.fneg(); break; case T_long : codeStream.lneg(); break; case T_double : codeStream.dneg(); } } } break; case PLUS : this.expression.generateCode(currentScope, codeStream, valueRequired); } if (valueRequired) { codeStream.generateImplicitConversion(this.implicitConversion); } codeStream.recordPositionsFrom(pc, this.sourceStart); }
Boolean operator code generation Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
/** * Boolean operator code generation * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^ */
@Override public void generateOptimizedBoolean( BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) { super.generateOptimizedBoolean( currentScope, codeStream, trueLabel, falseLabel, valueRequired); return; } if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { this.expression.generateOptimizedBoolean( currentScope, codeStream, falseLabel, trueLabel, valueRequired); } else { super.generateOptimizedBoolean( currentScope, codeStream, trueLabel, falseLabel, valueRequired); } } @Override public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { output.append(operatorToString()).append(' '); return this.expression.printExpression(0, output); } @Override public TypeBinding resolveType(BlockScope scope) { boolean expressionIsCast; if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on TypeBinding expressionType = this.expression.resolveType(scope); if (expressionType == null) { this.constant = Constant.NotAConstant; return null; } int expressionTypeID = expressionType.id; // autoboxing support boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; if (use15specifics) { if (!expressionType.isBaseType()) { expressionTypeID = scope.environment().computeBoxingType(expressionType).id; } } if (expressionTypeID > 15) { this.constant = Constant.NotAConstant; scope.problemReporter().invalidOperator(this, expressionType); return null; } int tableId; switch ((this.bits & OperatorMASK) >> OperatorSHIFT) { case NOT : tableId = AND_AND; break; case TWIDDLE : tableId = LEFT_SHIFT; break; default : tableId = MINUS; } //+ and - cases // the code is an int // (cast) left Op (cast) rigth --> result // 0000 0000 0000 0000 0000 // <<16 <<12 <<8 <<4 <<0 int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID]; this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), expressionType); this.bits |= operatorSignature & 0xF; switch (operatorSignature & 0xF) { // only switch on possible result type..... case T_boolean : this.resolvedType = TypeBinding.BOOLEAN; break; case T_byte : this.resolvedType = TypeBinding.BYTE; break; case T_char : this.resolvedType = TypeBinding.CHAR; break; case T_double : this.resolvedType = TypeBinding.DOUBLE; break; case T_float : this.resolvedType = TypeBinding.FLOAT; break; case T_int : this.resolvedType = TypeBinding.INT; break; case T_long : this.resolvedType = TypeBinding.LONG; break; default : //error........ this.constant = Constant.NotAConstant; if (expressionTypeID != T_undefined) scope.problemReporter().invalidOperator(this, expressionType); return null; } // compute the constant when valid if (this.expression.constant != Constant.NotAConstant) { this.constant = Constant.computeConstantOperation( this.expression.constant, expressionTypeID, (this.bits & OperatorMASK) >> OperatorSHIFT); } else { this.constant = Constant.NotAConstant; if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { Constant cst = this.expression.optimizedBooleanConstant(); if (cst != Constant.NotAConstant) this.optimizedBooleanConstant = BooleanConstant.fromValue(!cst.booleanValue()); } } if (expressionIsCast) { // check need for operand cast CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeID); } return this.resolvedType; } @Override public void traverse( ASTVisitor visitor, BlockScope blockScope) { if (visitor.visit(this, blockScope)) { this.expression.traverse(visitor, blockScope); } visitor.endVisit(this, blockScope); } }