8161708: javac, consider a different way to handle access code for operators
Reviewed-by: mcimadamore
This commit is contained in:
parent
e6f3a52942
commit
2bedc263dc
@ -55,7 +55,9 @@ import com.sun.tools.javac.comp.Attr;
|
||||
import com.sun.tools.javac.comp.AttrContext;
|
||||
import com.sun.tools.javac.comp.Env;
|
||||
import com.sun.tools.javac.jvm.*;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
@ -64,9 +66,15 @@ import static com.sun.tools.javac.code.Flags.*;
|
||||
import static com.sun.tools.javac.code.Kinds.*;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
|
||||
import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP;
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
import static com.sun.tools.javac.code.TypeTag.FORALL;
|
||||
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.iadd;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.ishll;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.lushrl;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.lxor;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.string_add;
|
||||
|
||||
/** Root class for Java symbols. It contains subclasses
|
||||
* for specific sorts of symbols, such as variables, methods and operators,
|
||||
@ -1950,15 +1958,90 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
public static class OperatorSymbol extends MethodSymbol {
|
||||
|
||||
public int opcode;
|
||||
private int accessCode = Integer.MIN_VALUE;
|
||||
|
||||
public OperatorSymbol(Name name, Type type, int opcode, Symbol owner) {
|
||||
super(PUBLIC | STATIC, name, type, owner);
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
|
||||
return v.visitOperatorSymbol(this, p);
|
||||
}
|
||||
|
||||
public int getAccessCode(Tag tag) {
|
||||
if (accessCode != Integer.MIN_VALUE && !tag.isIncOrDecUnaryOp()) {
|
||||
return accessCode;
|
||||
}
|
||||
accessCode = AccessCode.from(tag, opcode);
|
||||
return accessCode;
|
||||
}
|
||||
|
||||
/** Access codes for dereferencing, assignment,
|
||||
* and pre/post increment/decrement.
|
||||
|
||||
* All access codes for accesses to the current class are even.
|
||||
* If a member of the superclass should be accessed instead (because
|
||||
* access was via a qualified super), add one to the corresponding code
|
||||
* for the current class, making the number odd.
|
||||
* This numbering scheme is used by the backend to decide whether
|
||||
* to issue an invokevirtual or invokespecial call.
|
||||
*
|
||||
* @see Gen#visitSelect(JCFieldAccess tree)
|
||||
*/
|
||||
public enum AccessCode {
|
||||
UNKNOWN(-1, Tag.NO_TAG),
|
||||
DEREF(0, Tag.NO_TAG),
|
||||
ASSIGN(2, Tag.ASSIGN),
|
||||
PREINC(4, Tag.PREINC),
|
||||
PREDEC(6, Tag.PREDEC),
|
||||
POSTINC(8, Tag.POSTINC),
|
||||
POSTDEC(10, Tag.POSTDEC),
|
||||
FIRSTASGOP(12, Tag.NO_TAG);
|
||||
|
||||
public final int code;
|
||||
public final Tag tag;
|
||||
public static final int numberOfAccessCodes = (lushrl - ishll + lxor + 2 - iadd) * 2 + FIRSTASGOP.code + 2;
|
||||
|
||||
AccessCode(int code, Tag tag) {
|
||||
this.code = code;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
static public AccessCode getFromCode(int code) {
|
||||
for (AccessCode aCodes : AccessCode.values()) {
|
||||
if (aCodes.code == code) {
|
||||
return aCodes;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
static int from(Tag tag, int opcode) {
|
||||
/** Map bytecode of binary operation to access code of corresponding
|
||||
* assignment operation. This is always an even number.
|
||||
*/
|
||||
switch (tag) {
|
||||
case PREINC:
|
||||
return AccessCode.PREINC.code;
|
||||
case PREDEC:
|
||||
return AccessCode.PREDEC.code;
|
||||
case POSTINC:
|
||||
return AccessCode.POSTINC.code;
|
||||
case POSTDEC:
|
||||
return AccessCode.POSTDEC.code;
|
||||
}
|
||||
if (iadd <= opcode && opcode <= lxor) {
|
||||
return (opcode - iadd) * 2 + FIRSTASGOP.code;
|
||||
} else if (opcode == string_add) {
|
||||
return (lxor + 1 - iadd) * 2 + FIRSTASGOP.code;
|
||||
} else if (ishll <= opcode && opcode <= lushrl) {
|
||||
return (opcode - ishll + lxor + 2 - iadd) * 2 + FIRSTASGOP.code;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Symbol completer interface.
|
||||
|
@ -3159,7 +3159,7 @@ public class Attr extends JCTree.Visitor {
|
||||
Type operand = attribExpr(tree.rhs, env);
|
||||
// Find operator.
|
||||
Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), owntype, operand);
|
||||
if (operator.kind == MTH &&
|
||||
if (operator != operators.noOpSymbol &&
|
||||
!owntype.isErroneous() &&
|
||||
!operand.isErroneous()) {
|
||||
chk.checkDivZero(tree.rhs.pos(), operator, operand);
|
||||
@ -3179,7 +3179,7 @@ public class Attr extends JCTree.Visitor {
|
||||
// Find operator.
|
||||
Symbol operator = tree.operator = operators.resolveUnary(tree, tree.getTag(), argtype);
|
||||
Type owntype = types.createErrorType(tree.type);
|
||||
if (operator.kind == MTH &&
|
||||
if (operator != operators.noOpSymbol &&
|
||||
!argtype.isErroneous()) {
|
||||
owntype = (tree.getTag().isIncOrDecUnaryOp())
|
||||
? tree.arg.type
|
||||
@ -3204,7 +3204,7 @@ public class Attr extends JCTree.Visitor {
|
||||
// Find operator.
|
||||
Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
|
||||
Type owntype = types.createErrorType(tree.type);
|
||||
if (operator.kind == MTH &&
|
||||
if (operator != operators.noOpSymbol &&
|
||||
!left.isErroneous() &&
|
||||
!right.isErroneous()) {
|
||||
owntype = operator.type.getReturnType();
|
||||
|
@ -38,6 +38,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.code.Type.*;
|
||||
|
||||
@ -49,6 +50,7 @@ import static com.sun.tools.javac.code.Flags.BLOCK;
|
||||
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
|
||||
import static com.sun.tools.javac.code.TypeTag.*;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||
import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.*;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||
|
||||
@ -816,33 +818,6 @@ public class Lower extends TreeTranslator {
|
||||
* Access methods
|
||||
*************************************************************************/
|
||||
|
||||
/** Access codes for dereferencing, assignment,
|
||||
* and pre/post increment/decrement.
|
||||
* Access codes for assignment operations are determined by method accessCode
|
||||
* below.
|
||||
*
|
||||
* All access codes for accesses to the current class are even.
|
||||
* If a member of the superclass should be accessed instead (because
|
||||
* access was via a qualified super), add one to the corresponding code
|
||||
* for the current class, making the number odd.
|
||||
* This numbering scheme is used by the backend to decide whether
|
||||
* to issue an invokevirtual or invokespecial call.
|
||||
*
|
||||
* @see Gen#visitSelect(JCFieldAccess tree)
|
||||
*/
|
||||
private static final int
|
||||
DEREFcode = 0,
|
||||
ASSIGNcode = 2,
|
||||
PREINCcode = 4,
|
||||
PREDECcode = 6,
|
||||
POSTINCcode = 8,
|
||||
POSTDECcode = 10,
|
||||
FIRSTASGOPcode = 12;
|
||||
|
||||
/** Number of access codes
|
||||
*/
|
||||
private static final int NCODES = accessCode(ByteCodes.lushrl) + 2;
|
||||
|
||||
/** A mapping from symbols to their access numbers.
|
||||
*/
|
||||
private Map<Symbol,Integer> accessNums;
|
||||
@ -864,20 +839,6 @@ public class Lower extends TreeTranslator {
|
||||
*/
|
||||
private ListBuffer<Symbol> accessed;
|
||||
|
||||
/** Map bytecode of binary operation to access code of corresponding
|
||||
* assignment operation. This is always an even number.
|
||||
*/
|
||||
private static int accessCode(int bytecode) {
|
||||
if (ByteCodes.iadd <= bytecode && bytecode <= ByteCodes.lxor)
|
||||
return (bytecode - iadd) * 2 + FIRSTASGOPcode;
|
||||
else if (bytecode == ByteCodes.string_add)
|
||||
return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode;
|
||||
else if (ByteCodes.ishll <= bytecode && bytecode <= ByteCodes.lushrl)
|
||||
return (bytecode - ishll + ByteCodes.lxor + 2 - iadd) * 2 + FIRSTASGOPcode;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** return access code for identifier,
|
||||
* @param tree The tree representing the identifier use.
|
||||
* @param enclOp The closest enclosing operation node of tree,
|
||||
@ -885,24 +846,24 @@ public class Lower extends TreeTranslator {
|
||||
*/
|
||||
private static int accessCode(JCTree tree, JCTree enclOp) {
|
||||
if (enclOp == null)
|
||||
return DEREFcode;
|
||||
return AccessCode.DEREF.code;
|
||||
else if (enclOp.hasTag(ASSIGN) &&
|
||||
tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
|
||||
return ASSIGNcode;
|
||||
return AccessCode.ASSIGN.code;
|
||||
else if (enclOp.getTag().isIncOrDecUnaryOp() &&
|
||||
tree == TreeInfo.skipParens(((JCUnary) enclOp).arg))
|
||||
return mapTagToUnaryOpCode(enclOp.getTag());
|
||||
return (((JCUnary) enclOp).operator).getAccessCode(enclOp.getTag());
|
||||
else if (enclOp.getTag().isAssignop() &&
|
||||
tree == TreeInfo.skipParens(((JCAssignOp) enclOp).lhs))
|
||||
return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode);
|
||||
return (((JCAssignOp) enclOp).operator).getAccessCode(enclOp.getTag());
|
||||
else
|
||||
return DEREFcode;
|
||||
return AccessCode.DEREF.code;
|
||||
}
|
||||
|
||||
/** Return binary operator that corresponds to given access code.
|
||||
*/
|
||||
private OperatorSymbol binaryAccessOperator(int acode) {
|
||||
return (OperatorSymbol)operators.lookupBinaryOp(sym -> accessCode(((OperatorSymbol)sym).opcode) == acode);
|
||||
private OperatorSymbol binaryAccessOperator(int acode, Tag tag) {
|
||||
return operators.lookupBinaryOp(op -> op.getAccessCode(tag) == acode);
|
||||
}
|
||||
|
||||
/** Return tree tag for assignment operation corresponding
|
||||
@ -984,7 +945,7 @@ public class Lower extends TreeTranslator {
|
||||
if (anum == null) {
|
||||
anum = accessed.length();
|
||||
accessNums.put(vsym, anum);
|
||||
accessSyms.put(vsym, new MethodSymbol[NCODES]);
|
||||
accessSyms.put(vsym, new MethodSymbol[AccessCode.numberOfAccessCodes]);
|
||||
accessed.append(vsym);
|
||||
// System.out.println("accessing " + vsym + " in " + vsym.location());
|
||||
}
|
||||
@ -996,13 +957,13 @@ public class Lower extends TreeTranslator {
|
||||
switch (vsym.kind) {
|
||||
case VAR:
|
||||
acode = accessCode(tree, enclOp);
|
||||
if (acode >= FIRSTASGOPcode) {
|
||||
OperatorSymbol operator = binaryAccessOperator(acode);
|
||||
if (acode >= AccessCode.FIRSTASGOP.code) {
|
||||
OperatorSymbol operator = binaryAccessOperator(acode, enclOp.getTag());
|
||||
if (operator.opcode == string_add)
|
||||
argtypes = List.of(syms.objectType);
|
||||
else
|
||||
argtypes = operator.type.getParameterTypes().tail;
|
||||
} else if (acode == ASSIGNcode)
|
||||
} else if (acode == AccessCode.ASSIGN.code)
|
||||
argtypes = List.of(vsym.erasure(types));
|
||||
else
|
||||
argtypes = List.nil();
|
||||
@ -1010,7 +971,7 @@ public class Lower extends TreeTranslator {
|
||||
thrown = List.nil();
|
||||
break;
|
||||
case MTH:
|
||||
acode = DEREFcode;
|
||||
acode = AccessCode.DEREF.code;
|
||||
argtypes = vsym.erasure(types).getParameterTypes();
|
||||
restype = vsym.erasure(types).getReturnType();
|
||||
thrown = vsym.type.getThrownTypes();
|
||||
@ -1306,7 +1267,7 @@ public class Lower extends TreeTranslator {
|
||||
accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
|
||||
} else {
|
||||
MethodSymbol[] accessors = accessSyms.get(sym);
|
||||
for (int i = 0; i < NCODES; i++) {
|
||||
for (int i = 0; i < AccessCode.numberOfAccessCodes; i++) {
|
||||
if (accessors[i] != null)
|
||||
cdef.defs = cdef.defs.prepend(
|
||||
accessDef(cdef.pos, sym, accessors[i], i));
|
||||
@ -1314,42 +1275,6 @@ public class Lower extends TreeTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
/** Maps unary operator integer codes to JCTree.Tag objects
|
||||
* @param unaryOpCode the unary operator code
|
||||
*/
|
||||
private static Tag mapUnaryOpCodeToTag(int unaryOpCode){
|
||||
switch (unaryOpCode){
|
||||
case PREINCcode:
|
||||
return PREINC;
|
||||
case PREDECcode:
|
||||
return PREDEC;
|
||||
case POSTINCcode:
|
||||
return POSTINC;
|
||||
case POSTDECcode:
|
||||
return POSTDEC;
|
||||
default:
|
||||
return NO_TAG;
|
||||
}
|
||||
}
|
||||
|
||||
/** Maps JCTree.Tag objects to unary operator integer codes
|
||||
* @param tag the JCTree.Tag
|
||||
*/
|
||||
private static int mapTagToUnaryOpCode(Tag tag){
|
||||
switch (tag){
|
||||
case PREINC:
|
||||
return PREINCcode;
|
||||
case PREDEC:
|
||||
return PREDECcode;
|
||||
case POSTINC:
|
||||
return POSTINCcode;
|
||||
case POSTDEC:
|
||||
return POSTDECcode;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Construct definition of an access method.
|
||||
* @param pos The source code position of the definition.
|
||||
* @param vsym The private or protected symbol.
|
||||
@ -1388,20 +1313,21 @@ public class Lower extends TreeTranslator {
|
||||
int acode1 = acode - (acode & 1);
|
||||
|
||||
JCExpression expr; // The access method's return value.
|
||||
switch (acode1) {
|
||||
case DEREFcode:
|
||||
AccessCode aCode = AccessCode.getFromCode(acode1);
|
||||
switch (aCode) {
|
||||
case DEREF:
|
||||
expr = ref;
|
||||
break;
|
||||
case ASSIGNcode:
|
||||
case ASSIGN:
|
||||
expr = make.Assign(ref, args.head);
|
||||
break;
|
||||
case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode:
|
||||
expr = makeUnary(mapUnaryOpCodeToTag(acode1), ref);
|
||||
case PREINC: case POSTINC: case PREDEC: case POSTDEC:
|
||||
expr = makeUnary(aCode.tag, ref);
|
||||
break;
|
||||
default:
|
||||
expr = make.Assignop(
|
||||
treeTag(binaryAccessOperator(acode1)), ref, args.head);
|
||||
((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
|
||||
treeTag(binaryAccessOperator(acode1, JCTree.Tag.NO_TAG)), ref, args.head);
|
||||
((JCAssignOp) expr).operator = binaryAccessOperator(acode1, JCTree.Tag.NO_TAG);
|
||||
}
|
||||
stat = make.Return(expr.setType(sym.type));
|
||||
} else {
|
||||
@ -3275,7 +3201,7 @@ public class Lower extends TreeTranslator {
|
||||
// tree.lhs. However, we can still get the
|
||||
// unerased type of tree.lhs as it is stored
|
||||
// in tree.type in Attr.
|
||||
Symbol newOperator = operators.resolveBinary(tree,
|
||||
OperatorSymbol newOperator = operators.resolveBinary(tree,
|
||||
newTag,
|
||||
tree.type,
|
||||
tree.rhs.type);
|
||||
@ -3304,7 +3230,7 @@ public class Lower extends TreeTranslator {
|
||||
JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
|
||||
// if operation is a += on strings,
|
||||
// make sure to convert argument to string
|
||||
JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
|
||||
JCExpression rhs = tree.operator.opcode == string_add
|
||||
? makeString(tree.rhs)
|
||||
: tree.rhs;
|
||||
app.args = List.of(rhs).prependList(app.args);
|
||||
|
@ -95,6 +95,7 @@ public class Operators {
|
||||
names = Names.instance(context);
|
||||
log = Log.instance(context);
|
||||
types = Types.instance(context);
|
||||
noOpSymbol = new OperatorSymbol(names.empty, Type.noType, -1, syms.noSymbol);
|
||||
initOperatorNames();
|
||||
initUnaryOperators();
|
||||
initBinaryOperators();
|
||||
@ -145,7 +146,7 @@ public class Operators {
|
||||
/**
|
||||
* Entry point for resolving a unary operator given an operator tag and an argument type.
|
||||
*/
|
||||
Symbol resolveUnary(DiagnosticPosition pos, JCTree.Tag tag, Type op) {
|
||||
OperatorSymbol resolveUnary(DiagnosticPosition pos, JCTree.Tag tag, Type op) {
|
||||
return resolve(tag,
|
||||
unaryOperators,
|
||||
unop -> unop.test(op),
|
||||
@ -156,7 +157,7 @@ public class Operators {
|
||||
/**
|
||||
* Entry point for resolving a binary operator given an operator tag and a pair of argument types.
|
||||
*/
|
||||
Symbol resolveBinary(DiagnosticPosition pos, JCTree.Tag tag, Type op1, Type op2) {
|
||||
OperatorSymbol resolveBinary(DiagnosticPosition pos, JCTree.Tag tag, Type op1, Type op2) {
|
||||
return resolve(tag,
|
||||
binaryOperators,
|
||||
binop -> binop.test(op1, op2),
|
||||
@ -169,8 +170,8 @@ public class Operators {
|
||||
* map. If there's a matching operator, its resolve routine is called and the result is returned;
|
||||
* otherwise the result of a fallback function is returned.
|
||||
*/
|
||||
private <O> Symbol resolve(Tag tag, Map<Name, List<O>> opMap, Predicate<O> opTestFunc,
|
||||
Function<O, Symbol> resolveFunc, Supplier<Symbol> noResultFunc) {
|
||||
private <O> OperatorSymbol resolve(Tag tag, Map<Name, List<O>> opMap, Predicate<O> opTestFunc,
|
||||
Function<O, OperatorSymbol> resolveFunc, Supplier<OperatorSymbol> noResultFunc) {
|
||||
return opMap.get(operatorName(tag)).stream()
|
||||
.filter(opTestFunc)
|
||||
.map(resolveFunc)
|
||||
@ -181,7 +182,7 @@ public class Operators {
|
||||
/**
|
||||
* Creates an operator symbol.
|
||||
*/
|
||||
private Symbol makeOperator(Name name, List<OperatorType> formals, OperatorType res, int... opcodes) {
|
||||
private OperatorSymbol makeOperator(Name name, List<OperatorType> formals, OperatorType res, int... opcodes) {
|
||||
MethodType opType = new MethodType(
|
||||
formals.stream()
|
||||
.map(o -> o.asType(syms))
|
||||
@ -201,10 +202,14 @@ public class Operators {
|
||||
((opcodes[0] << ByteCodes.preShift) | opcodes[1]);
|
||||
}
|
||||
|
||||
/** A symbol that stands for a missing operator.
|
||||
*/
|
||||
public final OperatorSymbol noOpSymbol;
|
||||
|
||||
/**
|
||||
* Report an operator lookup error.
|
||||
*/
|
||||
private Symbol reportErrorIfNeeded(DiagnosticPosition pos, Tag tag, Type... args) {
|
||||
private OperatorSymbol reportErrorIfNeeded(DiagnosticPosition pos, Tag tag, Type... args) {
|
||||
if (Stream.of(args).noneMatch(Type::isErroneous)) {
|
||||
Name opName = operatorName(tag);
|
||||
JCDiagnostic.Error opError = (args.length) == 1 ?
|
||||
@ -212,7 +217,7 @@ public class Operators {
|
||||
Errors.OperatorCantBeApplied1(opName, args[0], args[1]);
|
||||
log.error(pos, opError);
|
||||
}
|
||||
return syms.noSymbol;
|
||||
return noOpSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,10 +268,10 @@ public class Operators {
|
||||
final Name name;
|
||||
|
||||
/** The list of symbols associated with this operator (lazily populated). */
|
||||
Optional<Symbol[]> alternatives = Optional.empty();
|
||||
Optional<OperatorSymbol[]> alternatives = Optional.empty();
|
||||
|
||||
/** An array of operator symbol suppliers (used to lazily populate the symbol list). */
|
||||
List<Supplier<Symbol>> operatorSuppliers = List.nil();
|
||||
List<Supplier<OperatorSymbol>> operatorSuppliers = List.nil();
|
||||
|
||||
@SuppressWarnings("varargs")
|
||||
OperatorHelper(Tag tag) {
|
||||
@ -278,21 +283,21 @@ public class Operators {
|
||||
* using an applicability predicate; if the test suceeds that same operator is returned,
|
||||
* otherwise a dummy symbol is returned.
|
||||
*/
|
||||
final Symbol doLookup(Predicate<Symbol> applicabilityTest) {
|
||||
final OperatorSymbol doLookup(Predicate<OperatorSymbol> applicabilityTest) {
|
||||
return Stream.of(alternatives.orElseGet(this::initOperators))
|
||||
.filter(applicabilityTest)
|
||||
.findFirst()
|
||||
.orElse(syms.noSymbol);
|
||||
.orElse(noOpSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine performs lazy instantiation of the operator symbols supported by this helper.
|
||||
* After initialization is done, the suppliers are cleared, to free up memory.
|
||||
*/
|
||||
private Symbol[] initOperators() {
|
||||
Symbol[] operators = operatorSuppliers.stream()
|
||||
private OperatorSymbol[] initOperators() {
|
||||
OperatorSymbol[] operators = operatorSuppliers.stream()
|
||||
.map(op -> op.get())
|
||||
.toArray(Symbol[]::new);
|
||||
.toArray(OperatorSymbol[]::new);
|
||||
alternatives = Optional.of(operators);
|
||||
operatorSuppliers = null; //let GC do its work
|
||||
return operators;
|
||||
@ -311,10 +316,10 @@ public class Operators {
|
||||
/**
|
||||
* This routine implements the unary operator lookup process. It customizes the behavior
|
||||
* of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test
|
||||
* (see {@link UnaryOperatorHelper#isUnaryOperatorApplicable(OperatorSymbol, Type)}
|
||||
* (see {@link UnaryOperatorHelper#isUnaryOperatorApplicable(OperatorOperatorSymbol, Type)}
|
||||
*/
|
||||
final Symbol doLookup(Type t) {
|
||||
return doLookup(op -> isUnaryOperatorApplicable((OperatorSymbol)op, t));
|
||||
final OperatorSymbol doLookup(Type t) {
|
||||
return doLookup(op -> isUnaryOperatorApplicable(op, t));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,7 +341,7 @@ public class Operators {
|
||||
* This method will be overridden by unary operator helpers to provide custom resolution
|
||||
* logic.
|
||||
*/
|
||||
abstract Symbol resolve(Type t);
|
||||
abstract OperatorSymbol resolve(Type t);
|
||||
}
|
||||
|
||||
abstract class BinaryOperatorHelper extends OperatorHelper implements BiPredicate<Type, Type> {
|
||||
@ -350,8 +355,8 @@ public class Operators {
|
||||
* of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test
|
||||
* (see {@link BinaryOperatorHelper#isBinaryOperatorApplicable(OperatorSymbol, Type, Type)}
|
||||
*/
|
||||
final Symbol doLookup(Type t1, Type t2) {
|
||||
return doLookup(op -> isBinaryOperatorApplicable((OperatorSymbol)op, t1, t2));
|
||||
final OperatorSymbol doLookup(Type t1, Type t2) {
|
||||
return doLookup(op -> isBinaryOperatorApplicable(op, t1, t2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -375,7 +380,7 @@ public class Operators {
|
||||
* This method will be overridden by binary operator helpers to provide custom resolution
|
||||
* logic.
|
||||
*/
|
||||
abstract Symbol resolve(Type t1, Type t2);
|
||||
abstract OperatorSymbol resolve(Type t1, Type t2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -393,7 +398,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg) {
|
||||
public OperatorSymbol resolve(Type arg) {
|
||||
return doLookup(syms.objectType);
|
||||
}
|
||||
}
|
||||
@ -421,7 +426,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg) {
|
||||
public OperatorSymbol resolve(Type arg) {
|
||||
return doLookup(unaryPromotion(arg));
|
||||
}
|
||||
}
|
||||
@ -442,7 +447,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg) {
|
||||
public OperatorSymbol resolve(Type arg) {
|
||||
return doLookup(syms.booleanType);
|
||||
}
|
||||
}
|
||||
@ -458,7 +463,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg) {
|
||||
public OperatorSymbol resolve(Type arg) {
|
||||
return doLookup(types.unboxedTypeOrType(arg));
|
||||
}
|
||||
}
|
||||
@ -481,7 +486,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg1, Type arg2) {
|
||||
public OperatorSymbol resolve(Type arg1, Type arg2) {
|
||||
Type t = binaryPromotion(arg1, arg2);
|
||||
return doLookup(t, t);
|
||||
}
|
||||
@ -504,7 +509,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg1, Type arg2) {
|
||||
public OperatorSymbol resolve(Type arg1, Type arg2) {
|
||||
return doLookup(syms.booleanType, syms.booleanType);
|
||||
}
|
||||
|
||||
@ -527,7 +532,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg1, Type arg2) {
|
||||
public OperatorSymbol resolve(Type arg1, Type arg2) {
|
||||
return doLookup(stringPromotion(arg1), stringPromotion(arg2));
|
||||
}
|
||||
|
||||
@ -570,7 +575,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type arg1, Type arg2) {
|
||||
public OperatorSymbol resolve(Type arg1, Type arg2) {
|
||||
return doLookup(unaryPromotion(arg1), unaryPromotion(arg2));
|
||||
}
|
||||
|
||||
@ -613,7 +618,7 @@ public class Operators {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol resolve(Type t1, Type t2) {
|
||||
public OperatorSymbol resolve(Type t1, Type t2) {
|
||||
ComparisonKind kind = getKind(t1, t2);
|
||||
Type t = (kind == ComparisonKind.NUMERIC_OR_BOOLEAN) ?
|
||||
binaryPromotion(t1, t2) :
|
||||
@ -798,12 +803,12 @@ public class Operators {
|
||||
.addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_or));
|
||||
}
|
||||
|
||||
Symbol lookupBinaryOp(Predicate<Symbol> applicabilityTest) {
|
||||
OperatorSymbol lookupBinaryOp(Predicate<OperatorSymbol> applicabilityTest) {
|
||||
return binaryOperators.values().stream()
|
||||
.flatMap(List::stream)
|
||||
.map(helper -> helper.doLookup(applicabilityTest))
|
||||
.distinct()
|
||||
.filter(sym -> sym != syms.noSymbol)
|
||||
.filter(sym -> sym != noOpSymbol)
|
||||
.findFirst().get();
|
||||
}
|
||||
|
||||
|
@ -1795,7 +1795,7 @@ public class Gen extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
public void visitAssignop(JCAssignOp tree) {
|
||||
OperatorSymbol operator = (OperatorSymbol) tree.operator;
|
||||
OperatorSymbol operator = tree.operator;
|
||||
Item l;
|
||||
if (operator.opcode == string_add) {
|
||||
l = concat.makeConcat(tree);
|
||||
@ -1827,7 +1827,7 @@ public class Gen extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
public void visitUnary(JCUnary tree) {
|
||||
OperatorSymbol operator = (OperatorSymbol)tree.operator;
|
||||
OperatorSymbol operator = tree.operator;
|
||||
if (tree.hasTag(NOT)) {
|
||||
CondItem od = genCond(tree.arg, false);
|
||||
result = od.negate();
|
||||
@ -1909,7 +1909,7 @@ public class Gen extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
public void visitBinary(JCBinary tree) {
|
||||
OperatorSymbol operator = (OperatorSymbol)tree.operator;
|
||||
OperatorSymbol operator = tree.operator;
|
||||
if (operator.opcode == string_add) {
|
||||
result = concat.makeConcat(tree);
|
||||
} else if (tree.hasTag(AND)) {
|
||||
|
@ -131,8 +131,7 @@ public abstract class StringConcat {
|
||||
tree = TreeInfo.skipParens(tree);
|
||||
if (tree.hasTag(PLUS) && tree.type.constValue() == null) {
|
||||
JCTree.JCBinary op = (JCTree.JCBinary) tree;
|
||||
if (op.operator.kind == MTH &&
|
||||
((Symbol.OperatorSymbol) op.operator).opcode == string_add) {
|
||||
if (op.operator.kind == MTH && op.operator.opcode == string_add) {
|
||||
return res
|
||||
.appendList(collect(op.lhs, res))
|
||||
.appendList(collect(op.rhs, res));
|
||||
|
@ -1876,8 +1876,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
private Tag opcode;
|
||||
public JCExpression lhs;
|
||||
public JCExpression rhs;
|
||||
public Symbol operator;
|
||||
protected JCAssignOp(Tag opcode, JCTree lhs, JCTree rhs, Symbol operator) {
|
||||
public OperatorSymbol operator;
|
||||
protected JCAssignOp(Tag opcode, JCTree lhs, JCTree rhs, OperatorSymbol operator) {
|
||||
this.opcode = opcode;
|
||||
this.lhs = (JCExpression)lhs;
|
||||
this.rhs = (JCExpression)rhs;
|
||||
@ -1892,7 +1892,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public JCExpression getVariable() { return lhs; }
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCExpression getExpression() { return rhs; }
|
||||
public Symbol getOperator() {
|
||||
public OperatorSymbol getOperator() {
|
||||
return operator;
|
||||
}
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
@ -1911,7 +1911,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public static class JCUnary extends JCExpression implements UnaryTree {
|
||||
private Tag opcode;
|
||||
public JCExpression arg;
|
||||
public Symbol operator;
|
||||
public OperatorSymbol operator;
|
||||
protected JCUnary(Tag opcode, JCExpression arg) {
|
||||
this.opcode = opcode;
|
||||
this.arg = arg;
|
||||
@ -1923,7 +1923,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public Kind getKind() { return TreeInfo.tagToKind(getTag()); }
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCExpression getExpression() { return arg; }
|
||||
public Symbol getOperator() {
|
||||
public OperatorSymbol getOperator() {
|
||||
return operator;
|
||||
}
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
@ -1947,11 +1947,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
private Tag opcode;
|
||||
public JCExpression lhs;
|
||||
public JCExpression rhs;
|
||||
public Symbol operator;
|
||||
public OperatorSymbol operator;
|
||||
protected JCBinary(Tag opcode,
|
||||
JCExpression lhs,
|
||||
JCExpression rhs,
|
||||
Symbol operator) {
|
||||
OperatorSymbol operator) {
|
||||
this.opcode = opcode;
|
||||
this.lhs = lhs;
|
||||
this.rhs = rhs;
|
||||
@ -1966,7 +1966,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public JCExpression getLeftOperand() { return lhs; }
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCExpression getRightOperand() { return rhs; }
|
||||
public Symbol getOperator() {
|
||||
public OperatorSymbol getOperator() {
|
||||
return operator;
|
||||
}
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
|
Loading…
Reference in New Issue
Block a user