Merge pull request #18849 from rmuir/give_indy_ops_types

Remove casts and boxing for dynamic math
This commit is contained in:
Robert Muir 2016-06-14 13:01:04 -04:00 committed by GitHub
commit e4dc469e58
6 changed files with 2028 additions and 192 deletions

View File

@ -262,6 +262,51 @@ public final class MethodWriter extends GeneratorAdapter {
}
}
/** Writes a dynamic binary instruction: returnType, lhs, and rhs can be different */
public void writeDynamicBinaryInstruction(Location location, Type returnType, Type lhs, Type rhs, Operation operation) {
org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(returnType.type, lhs.type, rhs.type);
String descriptor = methodType.getDescriptor();
switch (operation) {
case MUL:
invokeDynamic("mul", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case DIV:
invokeDynamic("div", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case REM:
invokeDynamic("rem", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case ADD:
invokeDynamic("add", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case SUB:
invokeDynamic("sub", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case LSH:
invokeDynamic("lsh", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
break;
case USH:
invokeDynamic("ush", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
break;
case RSH:
invokeDynamic("rsh", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
break;
case BWAND:
invokeDynamic("and", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case XOR:
invokeDynamic("xor", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case BWOR:
invokeDynamic("or", descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
default:
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
}
/** Writes a static binary instruction */
public void writeBinaryInstruction(Location location, Type type, Operation operation) {
final Sort sort = type.sort;
@ -272,64 +317,20 @@ public final class MethodWriter extends GeneratorAdapter {
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
if (sort == Sort.DEF) {
// XXX: move this out, so we can populate descriptor with what we really have (instead of casts/boxing!)
org.objectweb.asm.Type objectType = org.objectweb.asm.Type.getType(Object.class);
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(objectType, objectType, objectType);
switch (operation) {
case MUL:
invokeDynamic("mul", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case DIV:
invokeDynamic("div", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case REM:
invokeDynamic("rem", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case ADD:
invokeDynamic("add", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case SUB:
invokeDynamic("sub", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case LSH:
invokeDynamic("lsh", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
break;
case USH:
invokeDynamic("ush", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
break;
case RSH:
invokeDynamic("rsh", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
break;
case BWAND:
invokeDynamic("and", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case XOR:
invokeDynamic("xor", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
case BWOR:
invokeDynamic("or", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
break;
default:
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
} else {
switch (operation) {
case MUL: math(GeneratorAdapter.MUL, type.type); break;
case DIV: math(GeneratorAdapter.DIV, type.type); break;
case REM: math(GeneratorAdapter.REM, type.type); break;
case ADD: math(GeneratorAdapter.ADD, type.type); break;
case SUB: math(GeneratorAdapter.SUB, type.type); break;
case LSH: math(GeneratorAdapter.SHL, type.type); break;
case USH: math(GeneratorAdapter.USHR, type.type); break;
case RSH: math(GeneratorAdapter.SHR, type.type); break;
case BWAND: math(GeneratorAdapter.AND, type.type); break;
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
default:
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
switch (operation) {
case MUL: math(GeneratorAdapter.MUL, type.type); break;
case DIV: math(GeneratorAdapter.DIV, type.type); break;
case REM: math(GeneratorAdapter.REM, type.type); break;
case ADD: math(GeneratorAdapter.ADD, type.type); break;
case SUB: math(GeneratorAdapter.SUB, type.type); break;
case LSH: math(GeneratorAdapter.SHL, type.type); break;
case USH: math(GeneratorAdapter.USHR, type.type); break;
case RSH: math(GeneratorAdapter.SHR, type.type); break;
case BWAND: math(GeneratorAdapter.AND, type.type); break;
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
default:
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
}

View File

@ -36,6 +36,8 @@ public final class EBinary extends AExpression {
final Operation operation;
AExpression left;
AExpression right;
Type promote; // promoted type
Type shiftDistance; // for shifts, the RHS is promoted independently
boolean cat = false;
@ -80,15 +82,25 @@ public final class EBinary extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply multiply [*] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -108,23 +120,30 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = promote;
}
private void analyzeDiv(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply divide [/] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -148,23 +167,31 @@ public final class EBinary extends AExpression {
throw createError(e);
}
}
actual = promote;
}
private void analyzeRem(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply remainder [%] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -188,15 +215,13 @@ public final class EBinary extends AExpression {
throw createError(e);
}
}
actual = promote;
}
private void analyzeAdd(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply add [+] to types " +
@ -205,6 +230,8 @@ public final class EBinary extends AExpression {
Sort sort = promote.sort;
actual = promote;
if (sort == Sort.STRING) {
left.expected = left.actual;
@ -217,6 +244,12 @@ public final class EBinary extends AExpression {
if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual.sort == Sort.STRING) {
((EBinary)right).cat = true;
}
} else if (sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
@ -241,22 +274,31 @@ public final class EBinary extends AExpression {
}
}
actual = promote;
}
private void analyzeSub(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply subtract [-] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -276,8 +318,6 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = promote;
}
private void analyzeLSH(Locals variables) {
@ -292,12 +332,23 @@ public final class EBinary extends AExpression {
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = lhspromote;
if (rhspromote.sort == Sort.LONG) {
right.expected = Definition.INT_TYPE;
right.explicit = true;
actual = promote = lhspromote;
shiftDistance = rhspromote;
if (lhspromote.sort == Sort.DEF || rhspromote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
right.expected = rhspromote;
left.expected = lhspromote;
if (rhspromote.sort == Sort.LONG) {
right.expected = Definition.INT_TYPE;
right.explicit = true;
} else {
right.expected = rhspromote;
}
}
left = left.cast(variables);
@ -314,8 +365,6 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = lhspromote;
}
private void analyzeRSH(Locals variables) {
@ -330,12 +379,23 @@ public final class EBinary extends AExpression {
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = lhspromote;
if (rhspromote.sort == Sort.LONG) {
right.expected = Definition.INT_TYPE;
right.explicit = true;
actual = promote = lhspromote;
shiftDistance = rhspromote;
if (lhspromote.sort == Sort.DEF || rhspromote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
right.expected = rhspromote;
left.expected = lhspromote;
if (rhspromote.sort == Sort.LONG) {
right.expected = Definition.INT_TYPE;
right.explicit = true;
} else {
right.expected = rhspromote;
}
}
left = left.cast(variables);
@ -352,8 +412,6 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = lhspromote;
}
private void analyzeUSH(Locals variables) {
@ -363,17 +421,28 @@ public final class EBinary extends AExpression {
Type lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Type rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
actual = promote = lhspromote;
shiftDistance = rhspromote;
if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = lhspromote;
if (rhspromote.sort == Sort.LONG) {
right.expected = Definition.INT_TYPE;
right.explicit = true;
if (lhspromote.sort == Sort.DEF || rhspromote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
right.expected = rhspromote;
left.expected = lhspromote;
if (rhspromote.sort == Sort.LONG) {
right.expected = Definition.INT_TYPE;
right.explicit = true;
} else {
right.expected = rhspromote;
}
}
left = left.cast(variables);
@ -390,23 +459,31 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = lhspromote;
}
private void analyzeBWAnd(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply and [&] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -422,23 +499,31 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = promote;
}
private void analyzeXor(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply xor [^] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -456,23 +541,31 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = promote;
}
private void analyzeBWOr(Locals variables) {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
if (promote == null) {
throw createError(new ClassCastException("Cannot apply or [|] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
actual = promote;
if (promote.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
if (expected != null) {
actual = expected;
}
} else {
left.expected = promote;
right.expected = promote;
}
left = left.cast(variables);
right = right.cast(variables);
@ -488,15 +581,13 @@ public final class EBinary extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = promote;
}
@Override
void write(MethodWriter writer) {
writer.writeDebugInfo(location);
if (actual.sort == Sort.STRING && operation == Operation.ADD) {
if (promote.sort == Sort.STRING && operation == Operation.ADD) {
if (!cat) {
writer.writeNewStrings();
}
@ -520,7 +611,11 @@ public final class EBinary extends AExpression {
left.write(writer);
right.write(writer);
writer.writeBinaryInstruction(location, actual, operation);
if (promote.sort == Sort.DEF || (shiftDistance != null && shiftDistance.sort == Sort.DEF)) {
writer.writeDynamicBinaryInstruction(location, expected, left.actual, right.actual, operation);
} else {
writer.writeBinaryInstruction(location, actual, operation);
}
}
writer.writeBranch(tru, fals);

View File

@ -334,7 +334,15 @@ public final class EChain extends AExpression {
writer.writeCast(there); // if necessary cast the current link's value
// to the promotion type between the lhs and rhs types
expression.write(writer); // write the bytecode for the rhs expression
writer.writeBinaryInstruction(location, promote, operation); // write the operation instruction for compound assignment
// XXX: fix these types, but first we need def compound assignment tests.
// (and also corner cases such as shifts). its tricky here as there are possibly explicit casts, too.
// write the operation instruction for compound assignment
if (promote.sort == Sort.DEF) {
writer.writeDynamicBinaryInstruction(location, promote,
Definition.DEF_TYPE, Definition.DEF_TYPE, operation);
} else {
writer.writeBinaryInstruction(location, promote, operation);
}
writer.writeCast(back); // if necessary cast the promotion type value back to the link's type

View File

@ -42,6 +42,7 @@ public final class EComp extends AExpression {
final Operation operation;
AExpression left;
AExpression right;
Type promotedType;
public EComp(Location location, Operation operation, AExpression left, AExpression right) {
super(location);
@ -78,15 +79,20 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply equals [==] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
@ -96,7 +102,7 @@ public final class EComp extends AExpression {
}
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.BOOL) {
constant = (boolean)left.constant == (boolean)right.constant;
@ -124,15 +130,20 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply reference equals [===] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
@ -142,7 +153,7 @@ public final class EComp extends AExpression {
}
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.BOOL) {
constant = (boolean)left.constant == (boolean)right.constant;
@ -166,15 +177,20 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply not equals [!=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
@ -184,7 +200,7 @@ public final class EComp extends AExpression {
}
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.BOOL) {
constant = (boolean)left.constant != (boolean)right.constant;
@ -212,15 +228,20 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
@ -230,7 +251,7 @@ public final class EComp extends AExpression {
}
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.BOOL) {
constant = (boolean)left.constant != (boolean)right.constant;
@ -254,21 +275,26 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.INT) {
constant = (int)left.constant >= (int)right.constant;
@ -290,21 +316,26 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply greater than [>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.INT) {
constant = (int)left.constant > (int)right.constant;
@ -326,21 +357,26 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.INT) {
constant = (int)left.constant <= (int)right.constant;
@ -362,21 +398,26 @@ public final class EComp extends AExpression {
left.analyze(variables);
right.analyze(variables);
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply less than [>=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
}
left.expected = promote;
right.expected = promote;
if (promotedType.sort == Sort.DEF) {
left.expected = left.actual;
right.expected = right.actual;
} else {
left.expected = promotedType;
right.expected = promotedType;
}
left = left.cast(variables);
right = right.cast(variables);
if (left.constant != null && right.constant != null) {
Sort sort = promote.sort;
Sort sort = promotedType.sort;
if (sort == Sort.INT) {
constant = (int)left.constant < (int)right.constant;
@ -399,8 +440,6 @@ public final class EComp extends AExpression {
writer.writeDebugInfo(location);
boolean branch = tru != null || fals != null;
org.objectweb.asm.Type rtype = right.actual.type;
Sort rsort = right.actual.sort;
left.write(writer);
@ -422,7 +461,7 @@ public final class EComp extends AExpression {
boolean writejump = true;
switch (rsort) {
switch (promotedType.sort) {
case VOID:
case BYTE:
case SHORT:
@ -440,12 +479,12 @@ public final class EComp extends AExpression {
case LONG:
case FLOAT:
case DOUBLE:
if (eq) writer.ifCmp(rtype, MethodWriter.EQ, jump);
else if (ne) writer.ifCmp(rtype, MethodWriter.NE, jump);
else if (lt) writer.ifCmp(rtype, MethodWriter.LT, jump);
else if (lte) writer.ifCmp(rtype, MethodWriter.LE, jump);
else if (gt) writer.ifCmp(rtype, MethodWriter.GT, jump);
else if (gte) writer.ifCmp(rtype, MethodWriter.GE, jump);
if (eq) writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
else if (ne) writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
else if (lt) writer.ifCmp(promotedType.type, MethodWriter.LT, jump);
else if (lte) writer.ifCmp(promotedType.type, MethodWriter.LE, jump);
else if (gt) writer.ifCmp(promotedType.type, MethodWriter.GT, jump);
else if (gte) writer.ifCmp(promotedType.type, MethodWriter.GE, jump);
else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
@ -454,8 +493,7 @@ public final class EComp extends AExpression {
case DEF:
// XXX: move this out, so we can populate descriptor with what we really have (instead of casts/boxing!)
org.objectweb.asm.Type booleanType = org.objectweb.asm.Type.getType(boolean.class);
org.objectweb.asm.Type objectType = org.objectweb.asm.Type.getType(Object.class);
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(booleanType, objectType, objectType);
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(booleanType, left.actual.type, right.actual.type);
if (eq) {
if (right.isNull) {
writer.ifNull(jump);
@ -463,7 +501,7 @@ public final class EComp extends AExpression {
writer.invokeDynamic("eq", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
writejump = false;
} else {
writer.ifCmp(rtype, MethodWriter.EQ, jump);
writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
}
} else if (ne) {
if (right.isNull) {
@ -472,7 +510,7 @@ public final class EComp extends AExpression {
writer.invokeDynamic("eq", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
writer.ifZCmp(MethodWriter.EQ, jump);
} else {
writer.ifCmp(rtype, MethodWriter.NE, jump);
writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
}
} else if (lt) {
writer.invokeDynamic("lt", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
@ -508,7 +546,7 @@ public final class EComp extends AExpression {
writejump = false;
} else {
writer.ifCmp(rtype, MethodWriter.EQ, jump);
writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
}
} else if (ne) {
if (right.isNull) {
@ -517,7 +555,7 @@ public final class EComp extends AExpression {
writer.invokeStatic(OBJECTS_TYPE, EQUALS);
writer.ifZCmp(MethodWriter.EQ, jump);
} else {
writer.ifCmp(rtype, MethodWriter.NE, jump);
writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
}
} else {
throw createError(new IllegalStateException("Illegal tree structure."));

View File

@ -178,4 +178,229 @@ public class DefOptimizationTests extends ScriptTestCase {
});
assertTrue(exception.getMessage().contains("Cannot cast java.lang.Double to java.lang.Integer"));
}
public void testMulOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x * y",
"INVOKEDYNAMIC mul(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testMulOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x * y",
"INVOKEDYNAMIC mul(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testMulOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x * y",
"INVOKEDYNAMIC mul(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testDivOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x / y",
"INVOKEDYNAMIC div(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testDivOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x / y",
"INVOKEDYNAMIC div(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testDivOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x / y",
"INVOKEDYNAMIC div(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testRemOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x % y",
"INVOKEDYNAMIC rem(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testRemOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x % y",
"INVOKEDYNAMIC rem(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testRemOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x % y",
"INVOKEDYNAMIC rem(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testAddOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x + y",
"INVOKEDYNAMIC add(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testAddOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x + y",
"INVOKEDYNAMIC add(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testAddOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x + y",
"INVOKEDYNAMIC add(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testSubOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x - y",
"INVOKEDYNAMIC sub(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testSubOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x - y",
"INVOKEDYNAMIC sub(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testSubOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x - y",
"INVOKEDYNAMIC sub(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testLshOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x << y",
"INVOKEDYNAMIC lsh(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testLshOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x << y",
"INVOKEDYNAMIC lsh(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testLshOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x << y",
"INVOKEDYNAMIC lsh(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testRshOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x >> y",
"INVOKEDYNAMIC rsh(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testRshOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x >> y",
"INVOKEDYNAMIC rsh(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testRshOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x >> y",
"INVOKEDYNAMIC rsh(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testUshOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x >>> y",
"INVOKEDYNAMIC ush(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testUshOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x >>> y",
"INVOKEDYNAMIC ush(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testUshOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x >>> y",
"INVOKEDYNAMIC ush(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testAndOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x & y",
"INVOKEDYNAMIC and(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testAndOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x & y",
"INVOKEDYNAMIC and(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testAndOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x & y",
"INVOKEDYNAMIC and(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testOrOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x | y",
"INVOKEDYNAMIC or(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testOrOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x | y",
"INVOKEDYNAMIC or(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testOrOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x | y",
"INVOKEDYNAMIC or(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testXorOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x ^ y",
"INVOKEDYNAMIC xor(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testXorOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x ^ y",
"INVOKEDYNAMIC xor(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testXorOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x ^ y",
"INVOKEDYNAMIC xor(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testLtOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x < y",
"INVOKEDYNAMIC lt(ILjava/lang/Object;)Z");
}
public void testLtOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x < y",
"INVOKEDYNAMIC lt(Ljava/lang/Object;I)Z");
}
public void testLteOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x <= y",
"INVOKEDYNAMIC lte(ILjava/lang/Object;)Z");
}
public void testLteOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x <= y",
"INVOKEDYNAMIC lte(Ljava/lang/Object;I)Z");
}
public void testEqOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x == y",
"INVOKEDYNAMIC eq(ILjava/lang/Object;)Z");
}
public void testEqOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x == y",
"INVOKEDYNAMIC eq(Ljava/lang/Object;I)Z");
}
public void testNeqOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x != y",
"INVOKEDYNAMIC eq(ILjava/lang/Object;)Z");
}
public void testNeqOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x != y",
"INVOKEDYNAMIC eq(Ljava/lang/Object;I)Z");
}
public void testGteOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x >= y",
"INVOKEDYNAMIC gte(ILjava/lang/Object;)Z");
}
public void testGteOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x >= y",
"INVOKEDYNAMIC gte(Ljava/lang/Object;I)Z");
}
public void testGtOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x > y",
"INVOKEDYNAMIC gt(ILjava/lang/Object;)Z");
}
public void testGtOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x > y",
"INVOKEDYNAMIC gt(Ljava/lang/Object;I)Z");
}
}