
com.tangosol.dev.compiler.java.IncExpression Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.dev.compiler.java;
import com.tangosol.dev.assembler.CodeAttribute;
import com.tangosol.dev.assembler.Constants;
import com.tangosol.dev.assembler.IntConstant;
import com.tangosol.dev.assembler.LongConstant;
import com.tangosol.dev.assembler.FloatConstant;
import com.tangosol.dev.assembler.DoubleConstant;
import com.tangosol.dev.assembler.FieldConstant;
import com.tangosol.dev.assembler.Op;
import com.tangosol.dev.assembler.OpDeclare;
import com.tangosol.dev.assembler.OpLoad;
import com.tangosol.dev.assembler.OpStore;
import com.tangosol.dev.assembler.Ivar;
import com.tangosol.dev.assembler.Lvar;
import com.tangosol.dev.assembler.Fvar;
import com.tangosol.dev.assembler.Dvar;
import com.tangosol.dev.assembler.Iload;
import com.tangosol.dev.assembler.Lload;
import com.tangosol.dev.assembler.Fload;
import com.tangosol.dev.assembler.Dload;
import com.tangosol.dev.assembler.Istore;
import com.tangosol.dev.assembler.Lstore;
import com.tangosol.dev.assembler.Fstore;
import com.tangosol.dev.assembler.Dstore;
import com.tangosol.dev.assembler.Iconst;
import com.tangosol.dev.assembler.Lconst;
import com.tangosol.dev.assembler.Fconst;
import com.tangosol.dev.assembler.Dconst;
import com.tangosol.dev.assembler.Iadd;
import com.tangosol.dev.assembler.Ladd;
import com.tangosol.dev.assembler.Fadd;
import com.tangosol.dev.assembler.Dadd;
import com.tangosol.dev.assembler.Isub;
import com.tangosol.dev.assembler.Lsub;
import com.tangosol.dev.assembler.Fsub;
import com.tangosol.dev.assembler.Dsub;
import com.tangosol.dev.assembler.Baload;
import com.tangosol.dev.assembler.Caload;
import com.tangosol.dev.assembler.Saload;
import com.tangosol.dev.assembler.Iaload;
import com.tangosol.dev.assembler.Laload;
import com.tangosol.dev.assembler.Faload;
import com.tangosol.dev.assembler.Daload;
import com.tangosol.dev.assembler.Bastore;
import com.tangosol.dev.assembler.Castore;
import com.tangosol.dev.assembler.Sastore;
import com.tangosol.dev.assembler.Iastore;
import com.tangosol.dev.assembler.Lastore;
import com.tangosol.dev.assembler.Fastore;
import com.tangosol.dev.assembler.Dastore;
import com.tangosol.dev.assembler.Iinc;
import com.tangosol.dev.assembler.I2b;
import com.tangosol.dev.assembler.I2c;
import com.tangosol.dev.assembler.I2s;
import com.tangosol.dev.assembler.Dup;
import com.tangosol.dev.assembler.Dup2;
import com.tangosol.dev.assembler.Dup_x1;
import com.tangosol.dev.assembler.Dup2_x1;
import com.tangosol.dev.assembler.Dup_x2;
import com.tangosol.dev.assembler.Dup2_x2;
import com.tangosol.dev.assembler.Getfield;
import com.tangosol.dev.assembler.Putfield;
import com.tangosol.dev.assembler.Getstatic;
import com.tangosol.dev.assembler.Putstatic;
import com.tangosol.dev.compiler.CompilerException;
import com.tangosol.dev.compiler.Context;
import com.tangosol.dev.component.DataType;
import com.tangosol.util.ErrorList;
import java.util.Set;
import java.util.Map;
/**
* The pre- and post-increment and -decrement expressions.
*
* @version 1.00, 01/09/98
* @author Cameron Purdy
*/
abstract public class IncExpression extends UnaryExpression
{
// ----- construction ---------------------------------------------------
/**
* Construct a IncExpression.
*
* @param operator the operator token
* @param expr the sub-expression
*/
protected IncExpression(Token operator, Expression expr)
{
super(operator, expr);
}
// ----- code generation ------------------------------------------------
/**
* Perform semantic checks, parse tree re-organization, name binding,
* and optimizations.
*
* @param ctx the compiler context
* @param setUVars the set of potentially unassigned variables
* @param setFVars the set of potentially assigned final variables
* @param mapThrown the set of potentially thrown checked exceptions
* @param errlist the error list
*
* @return the resulting language element (typically this)
*
* @exception CompilerException thrown if an error occurs that should
* stop the compilation process
*/
protected Element precompile(Context ctx, DualSet setUVars, DualSet setFVars, Map mapThrown, ErrorList errlist)
throws CompilerException
{
// get the sub-expression
Expression expr = getExpression();
// sub-expression must be assignable
if (expr.checkAssignable(errlist))
{
// pre-compile the sub-expression
expr = (Expression) expr.precompile(ctx, setUVars, setFVars, mapThrown, errlist);
// sub-expression must be numeric type
expr.checkNumeric(errlist);
}
// store the sub-expression
setExpression(expr);
// the result type is the type of the sub-expression
setType(expr.getType());
if (expr instanceof VariableExpression)
{
Variable var = ((VariableExpression) expr).getVariable();
// verify variable is definitely assigned
if (setUVars.contains(var))
{
// variable is potentially unassigned
logError(ERROR, VAR_UNASSIGNED, new String[] {var.getName()}, errlist);
}
// JLS 16.1.15 Operators ++ and --
// V is definitely assigned after a preincrement, predecrement,
// postincrement, or postdecrement expression iff either the
// operand expression is V or V is definitely assigned after
// the operand expression.
setUVars.remove(var);
if (var.isFinal())
{
setFVars.add(var);
}
}
return this;
}
/**
* Perform final optimizations and code generation.
*
* @param ctx the compiler context
* @param code the assembler code attribute to compile to
* @param fReached true if this language element is reached (JLS 14.19)
* @param errlist the error list to log errors to
*
* @return true if the element can complete normally (JLS 14.1)
*
* @exception CompilerException thrown if an error occurs that should
* stop the compilation process
*/
protected boolean compile(Context ctx, CodeAttribute code, boolean fReached, ErrorList errlist)
throws CompilerException
{
Expression expr = getExpression();
char chType = expr.getType().getTypeString().charAt(0);
boolean fDiscard = isDiscarded();
boolean fWide = (chType == 'J' || chType == 'D');
boolean fSub = (this instanceof PreDecExpression || this instanceof PostDecExpression);
boolean fPre = (this instanceof PreIncExpression || this instanceof PreDecExpression);
boolean fPost = !fPre;
// compilation of "++var":
// ?load var // i for byte/char/short/int, l for long,
// // f for float, d for double
// ?const_1 // i for byte/char/short/int, l for long,
// // f for float, d for double
// ?add // i for byte/char/short/int, l for long,
// // f for float, d for double
// // ?sub if pre-dec
// i2? // b for byte, c for char, s for short
// // (n/a for int/long/float/double)
// dup? // if not discarded; dup2 for long/double,
// // dup for byte/char/short/int/float
// ?store var // i for byte/char/short/int, l for long,
// // f for float, d for double
//
// optimization of "++var" for int:
// iinc var,1 // -1 if pre-dec
// iload var // if not discarded
//
// compilation of "var++":
// ?load var // i for byte/char/short/int, l for long,
// // f for float, d for double
// dup? // if not discarded; dup2 for long/double,
// // dup for byte/char/short/int/float
// ?const_1 // i for byte/char/short/int, l for long,
// // f for float, d for double
// ?add // i for byte/char/short/int, l for long,
// // f for float, d for double
// // ?sub if pre-dec
// i2? // b for byte, c for char, s for short
// // (n/a for int/long/float/double)
// ?store var // i for byte/char/short/int, l for long,
// // f for float, d for double
//
// optimization of "++var" for int:
// iload var // if not discarded
// iinc var,1 // -1 if pre-dec
//
// Note: The only difference between "++" and "++" is
// the location of the dup when the result is not discarded. This
// holds true for fields and arrays as well as with variables. For
// postfix increment and decrement in which the result is not disc-
// arded, the dup instruction is moved from after the conversion to
// before the constant increment of 1.
//
// compilation of "++field":
// getstatic field
// ?const_1 // i for byte/char/short/int, l for long,
// // f for float, d for double
// ?add // i for byte/char/short/int, l for long,
// // f for float, d for double
// // ?sub if pre-dec
// i2? // b for byte, c for char, s for short
// // (n/a for int/long/float/double)
// dup? // if not discarded; dup2 for long/double,
// // dup for byte/char/short/int/float
// putstatic field
//
// compilation of "++ref.field":
//
// dup
// getfield field
// ?const_1 // i for byte/char/short/int, l for long,
// // f for float, d for double
// ?add // i for byte/char/short/int, l for long,
// // f for float, d for double
// // ?sub if pre-dec
// i2? // b for byte, c for char, s for short
// // (n/a for int/long/float/double)
// dup?_x1 // if not discarded; dup2_x1 for long/double,
// // dup_x1 for byte/char/short/int/float
// putfield field
//
// compilation of "++array[index]":
//
//
// dup2
// ?aload // b for byte, c for char, s for short, i for int,
// // l for long, f for float, d for double
// ?const_1 // i for byte/char/short/int, l for long,
// // f for float, d for double
// ?add // i for byte/char/short/int, l for long,
// // f for float, d for double
// // ?sub if pre-dec
// i2? // b for byte, c for char, s for short
// // (n/a for int/long/float/double)
// dup?_x2 // if not discarded; dup2_x2 for long/double,
// // dup_x2 for byte/char/short/int/float
// ?astore // b for byte, c for char, s for short, i for int,
// // l for long, f for float, d for double
// specific handling for each potential expression class
Op opFinal = null;
Op opDup = null;
if (expr instanceof VariableExpression)
{
OpDeclare opVar = ((VariableExpression) expr).getVariable().getOp();
OpLoad opLoad = null;
OpStore opStore = null;
switch (chType)
{
case 'B':
case 'C':
case 'S':
opLoad = new Iload ((Ivar) opVar);
opStore = new Istore((Ivar) opVar);
break;
case 'I':
{
// optimization for int vars
Ivar var = (Ivar) opVar;
if (!fDiscard && fPost)
{
code.add(new Iload(var));
}
code.add(new Iinc(var, fSub ? (short) -1 : 1));
if (!fDiscard && fPre)
{
code.add(new Iload(var));
}
}
return fReached;
case 'J':
opLoad = new Lload ((Lvar) opVar);
opStore = new Lstore((Lvar) opVar);
break;
case 'F':
opLoad = new Fload ((Fvar) opVar);
opStore = new Fstore((Fvar) opVar);
break;
case 'D':
opLoad = new Dload ((Dvar) opVar);
opStore = new Dstore((Dvar) opVar);
break;
}
// set-up code
code.add(opLoad);
if (!fDiscard)
{
opDup = fWide ? (Op) new Dup2() : new Dup();
}
opFinal = opStore;
}
else if (expr instanceof FieldAccessExpression)
{
FieldAccessExpression exprField = (FieldAccessExpression) expr;
FieldConstant field = exprField.getFieldConstant();
boolean fStatic = exprField.isStatic();
// load field
if (fStatic)
{
code.add(new Getstatic(field));
opDup = fWide ? (Op) new Dup2() : new Dup();
opFinal = new Putstatic(field);
}
else
{
// compile reference expression
exprField.getExpression().compile(ctx, code, fReached, errlist);
// make a copy (it will be used by the Putfield op)
code.add(new Dup());
code.add(new Getfield(field));
opDup = fWide ? (Op) new Dup2_x1() : new Dup_x1();
opFinal = new Putfield(field);
}
}
else if (expr instanceof ArrayAccessExpression)
{
Op opLoad = null;
Op opStore = null;
switch (chType)
{
case 'B':
opLoad = new Baload ();
opStore = new Bastore();
break;
case 'C':
opLoad = new Caload ();
opStore = new Castore();
break;
case 'S':
opLoad = new Saload ();
opStore = new Sastore();
break;
case 'I':
opLoad = new Iaload ();
opStore = new Iastore();
break;
case 'J':
opLoad = new Laload ();
opStore = new Lastore();
break;
case 'F':
opLoad = new Faload ();
opStore = new Fastore();
break;
case 'D':
opLoad = new Daload ();
opStore = new Dastore();
break;
}
// set-up code
ArrayAccessExpression exprElement = (ArrayAccessExpression) expr;
exprElement.getArray().compile(ctx, code, fReached, errlist);
exprElement.getIndex().compile(ctx, code, fReached, errlist);
code.add(new Dup2());
code.add(opLoad);
if (!fDiscard)
{
opDup = fWide ? (Op) new Dup2_x2() : new Dup_x2();
}
opFinal = opStore;
}
else
{
throw new IllegalStateException();
}
Op opConst = null;
Op opAdd = null;
Op opConv = null;
switch (chType)
{
case 'B':
opConst = new Iconst(CONSTANT_ICONST_1);
opAdd = fSub ? (Op) new Isub() : new Iadd();
opConv = new I2b();
break;
case 'C':
opConst = new Iconst(CONSTANT_ICONST_1);
opAdd = fSub ? (Op) new Isub() : new Iadd();
opConv = new I2c();
break;
case 'S':
opConst = new Iconst(CONSTANT_ICONST_1);
opAdd = fSub ? (Op) new Isub() : new Iadd();
opConv = new I2s();
break;
case 'I':
opConst = new Iconst(CONSTANT_ICONST_1);
opAdd = fSub ? (Op) new Isub() : new Iadd();
break;
case 'J':
opConst = new Lconst(CONSTANT_LCONST_1);
opAdd = fSub ? (Op) new Lsub() : new Ladd();
break;
case 'F':
opConst = new Fconst(CONSTANT_FCONST_1);
opAdd = fSub ? (Op) new Fsub() : new Fadd();
break;
case 'D':
opConst = new Dconst(CONSTANT_DCONST_1);
opAdd = fSub ? (Op) new Dsub() : new Dadd();
break;
default:
throw new IllegalStateException();
}
// non-discarded ++ and --
if (fPost && opDup != null)
{
code.add(opDup);
}
// add (or subtract) one
code.add(opConst);
code.add(opAdd);
// convert result if necessary
if (opConv != null)
{
code.add(opConv);
}
// non-discarded ++ and --
if (fPre && opDup != null)
{
code.add(opDup);
}
// store incremented value
if (opFinal != null)
{
code.add(opFinal);
}
// normal completion possible if reachable
return fReached;
}
// ----- data members ---------------------------------------------------
/**
* The class name.
*/
private static final String CLASS = "IncExpression";
private static final IntConstant CONSTANT_ICONST_1 = Constants.CONSTANT_ICONST_1;
private static final LongConstant CONSTANT_LCONST_1 = Constants.CONSTANT_LCONST_1;
private static final FloatConstant CONSTANT_FCONST_1 = Constants.CONSTANT_FCONST_1;
private static final DoubleConstant CONSTANT_DCONST_1 = Constants.CONSTANT_DCONST_1;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy