Cleaned up SEach node.

This commit is contained in:
Jack Conradson 2016-06-06 18:21:08 -07:00
parent 231268c89d
commit b3804c47f7
2 changed files with 30 additions and 74 deletions

View File

@ -30,6 +30,7 @@ import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.BitSet; import java.util.BitSet;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
/** /**
@ -56,6 +57,10 @@ public final class WriterConstants {
public final static Type MAP_TYPE = Type.getType(Map.class); public final static Type MAP_TYPE = Type.getType(Map.class);
public final static Method MAP_GET = getAsmMethod(Object.class, "get", Object.class); public final static Method MAP_GET = getAsmMethod(Object.class, "get", Object.class);
public final static Type ITERATOR_TYPE = Type.getType(Iterator.class);
public final static Method ITERATOR_HASNEXT = getAsmMethod(boolean.class, "hasNext");
public final static Method ITERATOR_NEXT = getAsmMethod(Object.class, "next");
public final static Type UTILITY_TYPE = Type.getType(Utility.class); public final static Type UTILITY_TYPE = Type.getType(Utility.class);
public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.class); public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.class);
public final static Method CHAR_TO_STRING = getAsmMethod(String.class, "charToString", char.class); public final static Method CHAR_TO_STRING = getAsmMethod(String.class, "charToString", char.class);

View File

@ -35,6 +35,9 @@ import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE; import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
import static org.elasticsearch.painless.WriterConstants.ITERATOR_HASNEXT;
import static org.elasticsearch.painless.WriterConstants.ITERATOR_NEXT;
import static org.elasticsearch.painless.WriterConstants.ITERATOR_TYPE;
/** /**
* Represents a for-each loop shortcut for iterables. Defers to other S-nodes for non-iterable types. * Represents a for-each loop shortcut for iterables. Defers to other S-nodes for non-iterable types.
@ -59,8 +62,6 @@ public class SEach extends AStatement {
// Members for the iterable case. // Members for the iterable case.
Variable iterator = null; Variable iterator = null;
Method method = null; Method method = null;
Method hasNext = null;
Method next = null;
public SEach(Location location, int maxLoopCounter, String type, String name, AExpression expression, SBlock block) { public SEach(Location location, int maxLoopCounter, String type, String name, AExpression expression, SBlock block) {
super(location); super(location);
@ -78,16 +79,6 @@ public class SEach extends AStatement {
expression.expected = expression.actual; expression.expected = expression.actual;
expression = expression.cast(variables); expression = expression.cast(variables);
if (expression.actual.sort == Sort.ARRAY) {
analyzeArray(variables);
} else if (expression.actual.sort == Sort.DEF || Iterable.class.isAssignableFrom(expression.actual.clazz)) {
analyzeIterable(variables);
} else {
throw location.createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "]."));
}
}
void analyzeArray(Variables variables) {
final Type type; final Type type;
try { try {
@ -99,10 +90,14 @@ public class SEach extends AStatement {
variables.incrementScope(); variables.incrementScope();
variable = variables.addVariable(location, type, name, true, false); variable = variables.addVariable(location, type, name, true, false);
array = variables.addVariable(location, expression.actual, "#array" + location.getOffset(), true, false);
index = variables.addVariable(location, Definition.INT_TYPE, "#index" + location.getOffset(), true, false); if (expression.actual.sort == Sort.ARRAY) {
indexed = Definition.getType(expression.actual.struct, expression.actual.dimensions - 1); analyzeArray(variables, type);
cast = AnalyzerCaster.getLegalCast(location, indexed, type, true, true); } else if (expression.actual.sort == Sort.DEF || Iterable.class.isAssignableFrom(expression.actual.clazz)) {
analyzeIterable(variables, type);
} else {
throw location.createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "]."));
}
if (block == null) { if (block == null) {
throw location.createError(new IllegalArgumentException("Extraneous for each loop.")); throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
@ -126,24 +121,19 @@ public class SEach extends AStatement {
variables.decrementScope(); variables.decrementScope();
} }
void analyzeIterable(Variables variables) { void analyzeArray(Variables variables, Type type) {
final Type type; // We must store the array and index as variables for securing slots on the stack, and
// also add the location offset to make the names unique in case of nested for each loops.
try { array = variables.addVariable(location, expression.actual, "#array" + location.getOffset(), true, false);
type = Definition.getType(this.type); index = variables.addVariable(location, Definition.INT_TYPE, "#index" + location.getOffset(), true, false);
} catch (IllegalArgumentException exception) { indexed = Definition.getType(expression.actual.struct, expression.actual.dimensions - 1);
throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); cast = AnalyzerCaster.getLegalCast(location, indexed, type, true, true);
} }
variables.incrementScope();
Type itr = Definition.getType("Iterator");
variable = variables.addVariable(location, type, name, true, false);
void analyzeIterable(Variables variables, Type type) {
// We must store the iterator as a variable for securing a slot on the stack, and // We must store the iterator as a variable for securing a slot on the stack, and
// also add the location offset to make the name unique in case of nested for each loops. // also add the location offset to make the name unique in case of nested for each loops.
iterator = variables.addVariable(location, itr, "#itr" + location.getOffset(), true, false); iterator = variables.addVariable(location, Definition.getType("Iterator"), "#itr" + location.getOffset(), true, false);
if (expression.actual.sort == Sort.DEF) { if (expression.actual.sort == Sort.DEF) {
method = null; method = null;
@ -156,48 +146,13 @@ public class SEach extends AStatement {
} }
} }
hasNext = itr.struct.methods.get(new MethodKey("hasNext", 0));
if (hasNext == null) {
throw location.createError(new IllegalArgumentException("Method [hasNext] does not exist for type [Iterator]."));
} else if (hasNext.rtn.sort != Sort.BOOL) {
throw location.createError(new IllegalArgumentException("Method [hasNext] does not return type [boolean]."));
}
next = itr.struct.methods.get(new MethodKey("next", 0));
if (next == null) {
throw location.createError(new IllegalArgumentException("Method [next] does not exist for type [Iterator]."));
} else if (next.rtn.sort != Sort.DEF) {
throw location.createError(new IllegalArgumentException("Method [next] does not return type [def]."));
}
cast = AnalyzerCaster.getLegalCast(location, Definition.DEF_TYPE, type, true, true); cast = AnalyzerCaster.getLegalCast(location, Definition.DEF_TYPE, type, true, true);
if (block == null) {
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
}
block.beginLoop = true;
block.inLoop = true;
block.analyze(variables);
block.statementCount = Math.max(1, block.statementCount);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
}
statementCount = 1;
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
variables.decrementScope();
} }
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(location);
if (array != null) { if (array != null) {
writeArray(writer); writeArray(writer);
} else if (iterator != null) { } else if (iterator != null) {
@ -208,8 +163,6 @@ public class SEach extends AStatement {
} }
void writeArray(MethodWriter writer) { void writeArray(MethodWriter writer) {
writer.writeStatementOffset(location);
expression.write(writer); expression.write(writer);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.slot); writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.slot);
writer.push(-1); writer.push(-1);
@ -239,8 +192,6 @@ public class SEach extends AStatement {
} }
void writeIterable(MethodWriter writer) { void writeIterable(MethodWriter writer) {
writer.writeStatementOffset(location);
expression.write(writer); expression.write(writer);
if (method == null) { if (method == null) {
@ -261,11 +212,11 @@ public class SEach extends AStatement {
writer.mark(begin); writer.mark(begin);
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot); writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
writer.invokeInterface(hasNext.owner.type, hasNext.method); writer.invokeInterface(ITERATOR_TYPE, ITERATOR_HASNEXT);
writer.ifZCmp(MethodWriter.EQ, end); writer.ifZCmp(MethodWriter.EQ, end);
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot); writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
writer.invokeInterface(next.owner.type, next.method); writer.invokeInterface(ITERATOR_TYPE, ITERATOR_NEXT);
writer.writeCast(cast); writer.writeCast(cast);
writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot); writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);