From 6328899d67cc53a46b868ce9aa869ae280845b20 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 7 Nov 2017 16:29:02 -0800 Subject: [PATCH 1/2] Replace Painless Type with Java Class in Locals, Variable, and Parameter. --- .../org/elasticsearch/painless/Locals.java | 51 +++++++++---------- .../painless/node/ECapturingFunctionRef.java | 19 +++---- .../elasticsearch/painless/node/ELambda.java | 12 ++--- .../painless/node/EVariable.java | 2 +- .../elasticsearch/painless/node/SCatch.java | 13 ++--- .../painless/node/SDeclaration.java | 12 ++--- .../elasticsearch/painless/node/SEach.java | 6 +-- .../painless/node/SExpression.java | 8 ++- .../painless/node/SFunction.java | 2 +- .../elasticsearch/painless/node/SReturn.java | 2 +- .../elasticsearch/painless/node/SSource.java | 6 +-- .../painless/node/SSubEachArray.java | 30 +++++------ .../painless/node/SSubEachIterable.java | 15 +++--- .../painless/node/NodeToStringTests.java | 4 +- 14 files changed, 89 insertions(+), 93 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java index 9f769d484135b..55b924dae89ce 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.MethodKey; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.ScriptClassInfo.MethodArgument; import java.util.Arrays; @@ -58,7 +57,7 @@ public static Locals newLocalScope(Locals currentScope) { *

* This is just like {@link #newFunctionScope}, except the captured parameters are made read-only. */ - public static Locals newLambdaScope(Locals programScope, Type returnType, List parameters, + public static Locals newLambdaScope(Locals programScope, Class returnType, List parameters, int captureCount, int maxLoopCounter) { Locals locals = new Locals(programScope, programScope.definition, returnType, KEYWORDS); for (int i = 0; i < parameters.size(); i++) { @@ -68,43 +67,43 @@ public static Locals newLambdaScope(Locals programScope, Type returnType, List

0) { - locals.defineVariable(null, locals.getDefinition().intType, LOOP, true); + locals.defineVariable(null, int.class, LOOP, true); } return locals; } /** Creates a new function scope inside the current scope */ - public static Locals newFunctionScope(Locals programScope, Type returnType, List parameters, int maxLoopCounter) { + public static Locals newFunctionScope(Locals programScope, Class returnType, List parameters, int maxLoopCounter) { Locals locals = new Locals(programScope, programScope.definition, returnType, KEYWORDS); for (Parameter parameter : parameters) { - locals.addVariable(parameter.location, parameter.type, parameter.name, false); + locals.addVariable(parameter.location, parameter.clazz, parameter.name, false); } // Loop counter to catch infinite loops. Internal use only. if (maxLoopCounter > 0) { - locals.defineVariable(null, locals.getDefinition().intType, LOOP, true); + locals.defineVariable(null, int.class, LOOP, true); } return locals; } /** Creates a new main method scope */ public static Locals newMainMethodScope(ScriptClassInfo scriptClassInfo, Locals programScope, int maxLoopCounter) { - Locals locals = new Locals(programScope, programScope.definition, - scriptClassInfo.getExecuteMethodReturnType(), KEYWORDS); + Locals locals = new Locals( + programScope, programScope.definition, Definition.TypeToClass(scriptClassInfo.getExecuteMethodReturnType()), KEYWORDS); // This reference. Internal use only. - locals.defineVariable(null, programScope.definition.getType("Object"), THIS, true); + locals.defineVariable(null, Object.class, THIS, true); // Method arguments for (MethodArgument arg : scriptClassInfo.getExecuteArguments()) { - locals.defineVariable(null, arg.getType(), arg.getName(), true); + locals.defineVariable(null, Definition.TypeToClass(arg.getType()), arg.getName(), true); } // Loop counter to catch infinite loops. Internal use only. if (maxLoopCounter > 0) { - locals.defineVariable(null, locals.getDefinition().intType, LOOP, true); + locals.defineVariable(null, int.class, LOOP, true); } return locals; } @@ -155,18 +154,18 @@ public Method getMethod(MethodKey key) { } /** Creates a new variable. Throws IAE if the variable has already been defined (even in a parent) or reserved. */ - public Variable addVariable(Location location, Type type, String name, boolean readonly) { + public Variable addVariable(Location location, Class clazz, String name, boolean readonly) { if (hasVariable(name)) { throw location.createError(new IllegalArgumentException("Variable [" + name + "] is already defined.")); } if (keywords.contains(name)) { throw location.createError(new IllegalArgumentException("Variable [" + name + "] is reserved.")); } - return defineVariable(location, type, name, readonly); + return defineVariable(location, clazz, name, readonly); } /** Return type of this scope (e.g. int, if inside a function that returns int) */ - public Type getReturnType() { + public Class getReturnType() { return returnType; } @@ -191,7 +190,7 @@ public Definition getDefinition() { // parent scope private final Locals parent; // return type of this scope - private final Type returnType; + private final Class returnType; // keywords for this scope private final Set keywords; // next slot number to assign @@ -211,7 +210,7 @@ private Locals(Locals parent) { /** * Create a new Locals with specified return type */ - private Locals(Locals parent, Definition definition, Type returnType, Set keywords) { + private Locals(Locals parent, Definition definition, Class returnType, Set keywords) { this.parent = parent; this.definition = definition; this.returnType = returnType; @@ -246,13 +245,13 @@ private Method lookupMethod(MethodKey key) { /** Defines a variable at this scope internally. */ - private Variable defineVariable(Location location, Type type, String name, boolean readonly) { + private Variable defineVariable(Location location, Class type, String name, boolean readonly) { if (variables == null) { variables = new HashMap<>(); } Variable variable = new Variable(location, name, type, getNextSlot(), readonly); variables.put(name, variable); // TODO: check result - nextSlotNumber += type.type.getSize(); + nextSlotNumber += MethodWriter.getType(type).getSize(); return variable; } @@ -272,15 +271,15 @@ private int getNextSlot() { public static final class Variable { public final Location location; public final String name; - public final Type type; + public final Class clazz; public final boolean readonly; private final int slot; private boolean used; - public Variable(Location location, String name, Type type, int slot, boolean readonly) { + public Variable(Location location, String name, Class clazz, int slot, boolean readonly) { this.location = location; this.name = name; - this.type = type; + this.clazz = clazz; this.slot = slot; this.readonly = readonly; } @@ -292,7 +291,7 @@ public int getSlot() { @Override public String toString() { StringBuilder b = new StringBuilder(); - b.append("Variable[type=").append(type); + b.append("Variable[type=").append(Definition.ClassToName(clazz)); b.append(",name=").append(name); b.append(",slot=").append(slot); if (readonly) { @@ -306,12 +305,12 @@ public String toString() { public static final class Parameter { public final Location location; public final String name; - public final Type type; + public final Class clazz; - public Parameter(Location location, String name, Type type) { + public Parameter(Location location, String name, Class clazz) { this.location = location; this.name = name; - this.type = type; + this.clazz = clazz; } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index 67b577523aa7f..724679d3f8538 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Definition; +import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -63,20 +64,20 @@ void extractVariables(Set variables) { void analyze(Locals locals) { captured = locals.getVariable(location, variable); if (expected == null) { - if (captured.type.dynamic) { + if (captured.clazz == def.class) { // dynamic implementation defPointer = "D" + variable + "." + call + ",1"; } else { // typed implementation - defPointer = "S" + captured.type.name + "." + call + ",1"; + defPointer = "S" + Definition.ClassToName(captured.clazz) + "." + call + ",1"; } actual = String.class; } else { defPointer = null; // static case - if (captured.type.dynamic == false) { + if (captured.clazz != def.class) { try { - ref = new FunctionRef(locals.getDefinition(), expected, captured.type.name, call, 1); + ref = new FunctionRef(locals.getDefinition(), expected, Definition.ClassToName(captured.clazz), call, 1); // check casts between the interface method and the delegate method are legal for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) { @@ -103,15 +104,15 @@ void write(MethodWriter writer, Globals globals) { // dynamic interface: push captured parameter on stack // TODO: don't do this: its just to cutover :) writer.push((String)null); - writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot()); + writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); } else if (ref == null) { // typed interface, dynamic implementation - writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot()); - Type methodType = Type.getMethodType(MethodWriter.getType(expected), captured.type.type); + writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); + Type methodType = Type.getMethodType(MethodWriter.getType(expected), MethodWriter.getType(captured.clazz)); writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, Definition.ClassToName(expected)); } else { // typed interface, typed implementation - writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot()); + writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); writer.invokeDynamic( ref.interfaceMethodName, ref.factoryDescriptor, @@ -132,7 +133,7 @@ public String getPointer() { @Override public Type[] getCaptures() { - return new Type[] { captured.type.type }; + return new Type[] { MethodWriter.getType(captured.clazz) }; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index 65b99846395ba..79a914f428457 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -162,7 +162,7 @@ void analyze(Locals locals) { List paramTypes = new ArrayList<>(captures.size() + actualParamTypeStrs.size()); List paramNames = new ArrayList<>(captures.size() + paramNameStrs.size()); for (Variable var : captures) { - paramTypes.add(var.type.name); + paramTypes.add(Definition.ClassToName(var.clazz)); paramNames.add(var.name); } paramTypes.addAll(actualParamTypeStrs); @@ -172,7 +172,7 @@ void analyze(Locals locals) { desugared = new SFunction(reserved, location, Definition.ClassToName(returnType), name, paramTypes, paramNames, statements, true); desugared.generateSignature(locals.getDefinition()); - desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), locals.getDefinition().ClassToType(returnType), + desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), returnType, desugared.parameters, captures.size(), reserved.getMaxLoopCounter())); // setup method reference to synthetic method @@ -191,7 +191,7 @@ void analyze(Locals locals) { // check casts between the interface method and the delegate method are legal for (int i = 0; i < interfaceMethod.arguments.size(); ++i) { Class from = interfaceMethod.arguments.get(i); - Class to = Definition.TypeToClass(desugared.parameters.get(i + captures.size()).type); + Class to = desugared.parameters.get(i + captures.size()).clazz; AnalyzerCaster.getLegalCast(location, from, to, false, true); } @@ -211,7 +211,7 @@ void write(MethodWriter writer, Globals globals) { writer.writeDebugInfo(location); // load captures for (Variable capture : captures) { - writer.visitVarInsn(MethodWriter.getType(capture.type.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + writer.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); } writer.invokeDynamic( @@ -229,7 +229,7 @@ void write(MethodWriter writer, Globals globals) { writer.push((String)null); // load captures for (Variable capture : captures) { - writer.visitVarInsn(MethodWriter.getType(capture.type.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + writer.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); } } @@ -246,7 +246,7 @@ public String getPointer() { public org.objectweb.asm.Type[] getCaptures() { org.objectweb.asm.Type[] types = new org.objectweb.asm.Type[captures.size()]; for (int i = 0; i < types.length; i++) { - types[i] = MethodWriter.getType(captures.get(i).type.clazz); + types[i] = MethodWriter.getType(captures.get(i).clazz); } return types; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java index 932abaeb4fe61..32e8fb3aa7f58 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java @@ -58,7 +58,7 @@ void analyze(Locals locals) { throw createError(new IllegalArgumentException("Variable [" + variable.name + "] is read-only.")); } - actual = Definition.TypeToClass(variable.type); + actual = variable.clazz; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java index 6940e48342a26..9f5f012c6d98f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -65,19 +66,19 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { - final Type type; + Class clazz; try { - type = locals.getDefinition().getType(this.type); + clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } - if (!Exception.class.isAssignableFrom(type.clazz)) { + if (!Exception.class.isAssignableFrom(clazz)) { throw createError(new ClassCastException("Not an exception type [" + this.type + "].")); } - variable = locals.addVariable(location, type, name, true); + variable = locals.addVariable(location, clazz, name, true); if (block != null) { block.lastSource = lastSource; @@ -102,7 +103,7 @@ void write(MethodWriter writer, Globals globals) { Label jump = new Label(); writer.mark(jump); - writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.getSlot()); + writer.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); if (block != null) { block.continu = continu; @@ -110,7 +111,7 @@ void write(MethodWriter writer, Globals globals) { block.write(writer, globals); } - writer.visitTryCatchBlock(begin, end, jump, variable.type.type.getInternalName()); + writer.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(variable.clazz).getInternalName()); if (exception != null && !block.allEscape) { writer.goTo(exception); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java index 87c3b87d476a0..b6b97e8d1e97b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java @@ -61,21 +61,21 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { - final Type type; + Class clazz; try { - type = locals.getDefinition().getType(this.type); + clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } if (expression != null) { - expression.expected = Definition.TypeToClass(type); + expression.expected = clazz; expression.analyze(locals); expression = expression.cast(locals); } - variable = locals.addVariable(location, type, name, false); + variable = locals.addVariable(location, clazz, name, false); } @Override @@ -83,7 +83,7 @@ void write(MethodWriter writer, Globals globals) { writer.writeStatementOffset(location); if (expression == null) { - Class sort = variable.type.clazz; + Class sort = variable.clazz; if (sort == void.class || sort == boolean.class || sort == byte.class || sort == short.class || sort == char.class || sort == int.class) { @@ -101,7 +101,7 @@ void write(MethodWriter writer, Globals globals) { expression.write(writer, globals); } - writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.getSlot()); + writer.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java index a3a5a39d01835..ade4ddef97d0d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java @@ -69,16 +69,16 @@ void analyze(Locals locals) { expression.expected = expression.actual; expression = expression.cast(locals); - final Type type; + Class clazz; try { - type = locals.getDefinition().getType(this.type); + clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type)); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); } locals = Locals.newLocalScope(locals); - Variable variable = locals.addVariable(location, type, name, true); + Variable variable = locals.addVariable(location, clazz, name, true); if (expression.actual.isArray()) { sub = new SSubEachArray(location, variable, expression, block); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java index 4366581838c55..e499ad3273c6c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java @@ -19,8 +19,6 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.Definition; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; @@ -49,8 +47,8 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { - Type rtnType = locals.getReturnType(); - boolean isVoid = rtnType.clazz == void.class; + Class rtnType = locals.getReturnType(); + boolean isVoid = rtnType == void.class; expression.read = lastSource && !isVoid; expression.analyze(locals); @@ -61,7 +59,7 @@ void analyze(Locals locals) { boolean rtn = lastSource && !isVoid && expression.actual != void.class; - expression.expected = rtn ? Definition.TypeToClass(rtnType) : expression.actual; + expression.expected = rtn ? rtnType : expression.actual; expression.internal = rtn; expression = expression.cast(locals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index 494fafb004781..5fa62f27e94dc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -137,7 +137,7 @@ void generateSignature(Definition definition) { paramClasses[param] = Definition.defClassToObjectClass(paramType); paramTypes.add(paramType); - parameters.add(new Parameter(location, paramNameStrs.get(param), definition.ClassToType(paramType))); + parameters.add(new Parameter(location, paramNameStrs.get(param), paramType)); } catch (IllegalArgumentException exception) { throw createError(new IllegalArgumentException( "Illegal parameter type [" + this.paramTypeStrs.get(param) + "] for function [" + name + "].")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java index 1831ca2890cfd..5e7b30cacb966 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java @@ -48,7 +48,7 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { - expression.expected = Definition.TypeToClass(locals.getReturnType()); + expression.expected = locals.getReturnType(); expression.internal = true; expression.analyze(locals); expression = expression.cast(locals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java index c90be8f3060c6..31bca79655ba2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java @@ -186,8 +186,8 @@ public void analyze(Definition definition) { @Override void analyze(Locals program) { for (SFunction function : functions) { - Locals functionLocals = Locals.newFunctionScope(program, program.getDefinition().ClassToType(function.rtnType), - function.parameters, function.reserved.getMaxLoopCounter()); + Locals functionLocals = + Locals.newFunctionScope(program, function.rtnType, function.parameters, function.reserved.getMaxLoopCounter()); function.analyze(functionLocals); } @@ -204,7 +204,7 @@ void analyze(Locals program) { if (reserved.getUsedVariables().contains(name)) { Definition.Type rtn = scriptClassInfo.getGetReturns().get(get); - mainMethod.addVariable(new Location("getter [" + name + "]", 0), rtn, name, true); + mainMethod.addVariable(new Location("getter [" + name + "]", 0), Definition.TypeToClass(rtn), name, true); getMethods.add(method); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java index eba3fb79e56a5..e0c9476ba640a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; @@ -45,7 +44,7 @@ final class SSubEachArray extends AStatement { private Cast cast = null; private Variable array = null; private Variable index = null; - private Type indexed = null; + private Class indexed = null; SSubEachArray(Location location, Variable variable, AExpression expression, SBlock block) { super(location); @@ -64,11 +63,10 @@ void extractVariables(Set variables) { void analyze(Locals locals) { // 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. - Type actualType = locals.getDefinition().ClassToType(expression.actual); - array = locals.addVariable(location, actualType, "#array" + location.getOffset(), true); - index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), true); - indexed = locals.getDefinition().getType(actualType.struct, actualType.dimensions - 1); - cast = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(indexed), Definition.TypeToClass(variable.type), true, true); + array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), true); + index = locals.addVariable(location, int.class, "#index" + location.getOffset(), true); + indexed = expression.actual.getComponentType(); + cast = AnalyzerCaster.getLegalCast(location, indexed, variable.clazz, true, true); } @Override @@ -76,9 +74,9 @@ void write(MethodWriter writer, Globals globals) { writer.writeStatementOffset(location); expression.write(writer, globals); - writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.getSlot()); + writer.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ISTORE), array.getSlot()); writer.push(-1); - writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ISTORE), index.getSlot()); + writer.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ISTORE), index.getSlot()); Label begin = new Label(); Label end = new Label(); @@ -86,16 +84,16 @@ void write(MethodWriter writer, Globals globals) { writer.mark(begin); writer.visitIincInsn(index.getSlot(), 1); - writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ILOAD), index.getSlot()); - writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ILOAD), array.getSlot()); + writer.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); + writer.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); writer.arrayLength(); writer.ifICmp(MethodWriter.GE, end); - writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ILOAD), array.getSlot()); - writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ILOAD), index.getSlot()); - writer.arrayLoad(indexed.type); + writer.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); + writer.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); + writer.arrayLoad(MethodWriter.getType(indexed)); writer.writeCast(cast); - writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.getSlot()); + writer.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); if (loopCounter != null) { writer.writeLoopCounter(loopCounter.getSlot(), statementCount, location); @@ -111,6 +109,6 @@ void write(MethodWriter writer, Globals globals) { @Override public String toString() { - return singleLineToString(variable.type.name, variable.name, expression, block); + return singleLineToString(Definition.ClassToName(variable.clazz), variable.name, expression, block); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index e8ee0b6625f7f..ca30d641e7468 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -73,8 +73,7 @@ void extractVariables(Set variables) { void analyze(Locals locals) { // 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. - iterator = locals.addVariable(location, locals.getDefinition().getType("Iterator"), - "#itr" + location.getOffset(), true); + iterator = locals.addVariable(location, Iterator.class, "#itr" + location.getOffset(), true); if (expression.actual == def.class) { method = null; @@ -88,7 +87,7 @@ void analyze(Locals locals) { } } - cast = AnalyzerCaster.getLegalCast(location, def.class, Definition.TypeToClass(variable.type), true, true); + cast = AnalyzerCaster.getLegalCast(location, def.class, variable.clazz, true, true); } @Override @@ -105,21 +104,21 @@ void write(MethodWriter writer, Globals globals) { method.write(writer); } - writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ISTORE), iterator.getSlot()); + writer.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ISTORE), iterator.getSlot()); Label begin = new Label(); Label end = new Label(); writer.mark(begin); - writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.getSlot()); + writer.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); writer.invokeInterface(ITERATOR_TYPE, ITERATOR_HASNEXT); writer.ifZCmp(MethodWriter.EQ, end); - writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.getSlot()); + writer.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); writer.invokeInterface(ITERATOR_TYPE, ITERATOR_NEXT); writer.writeCast(cast); - writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.getSlot()); + writer.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); if (loopCounter != null) { writer.writeLoopCounter(loopCounter.getSlot(), statementCount, location); @@ -135,6 +134,6 @@ void write(MethodWriter writer, Globals globals) { @Override public String toString() { - return singleLineToString(variable.type.name, variable.name, expression, block); + return singleLineToString(Definition.ClassToName(variable.clazz), variable.name, expression, block); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java index bd6760bfa5d0e..00be123e199f1 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java @@ -763,7 +763,7 @@ public void testSIfElse() { public void testSSubEachArray() { Location l = new Location(getTestName(), 0); - Variable v = new Variable(l, "test", definition.intType, 5, false); + Variable v = new Variable(l, "test", int.class, 5, false); AExpression e = new ENewArray(l, "int", Arrays.asList(new EConstant(l, 1), new EConstant(l, 2), new EConstant(l, 3)), true); SBlock b = new SBlock(l, singletonList(new SReturn(l, new EConstant(l, 5)))); SSubEachArray node = new SSubEachArray(l, v, e, b); @@ -775,7 +775,7 @@ public void testSSubEachArray() { public void testSSubEachIterable() { Location l = new Location(getTestName(), 0); - Variable v = new Variable(l, "test", definition.intType, 5, false); + Variable v = new Variable(l, "test", int.class, 5, false); AExpression e = new EListInit(l, Arrays.asList(new EConstant(l, 1), new EConstant(l, 2), new EConstant(l, 3))); SBlock b = new SBlock(l, singletonList(new SReturn(l, new EConstant(l, 5)))); SSubEachIterable node = new SSubEachIterable(l, v, e, b); From a22146b2a6ff7daba7fa50282ecada1541b7a876 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 7 Nov 2017 16:47:38 -0800 Subject: [PATCH 2/2] Replace Painless Type with Java Class in ScriptClassInfo. --- .../painless/LambdaBootstrap.java | 18 ++++---- .../org/elasticsearch/painless/Locals.java | 4 +- .../painless/ScriptClassInfo.java | 42 +++++++++---------- .../elasticsearch/painless/node/SSource.java | 4 +- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaBootstrap.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaBootstrap.java index 3a0b322d5eaf7..7a2ec9da34e29 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaBootstrap.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaBootstrap.java @@ -93,7 +93,7 @@ * private $$Lambda0(List arg$0) { * this.arg$0 = arg$0; * } - * + * * public static Consumer create$lambda(List arg$0) { * return new $$Lambda0(arg$0); * } @@ -212,7 +212,7 @@ public static CallSite lambdaBootstrap( ClassWriter cw = beginLambdaClass(lambdaClassName, factoryMethodType.returnType()); Capture[] captures = generateCaptureFields(cw, factoryMethodType); generateLambdaConstructor(cw, lambdaClassType, factoryMethodType, captures); - + // Handles the special case where a method reference refers to a ctor (we need a static wrapper method): if (delegateInvokeType == H_NEWINVOKESPECIAL) { assert CTOR_METHOD_NAME.equals(delegateMethodName); @@ -226,7 +226,7 @@ public static CallSite lambdaBootstrap( generateInterfaceMethod(cw, factoryMethodType, lambdaClassType, interfaceMethodName, interfaceMethodType, delegateClassType, delegateInvokeType, delegateMethodName, delegateMethodType, captures); - + endLambdaClass(cw); Class lambdaClass = createLambdaClass(loader, cw, lambdaClassType); @@ -321,7 +321,7 @@ private static void generateLambdaConstructor( constructor.returnValue(); constructor.endMethod(); - + // Add a factory method, if lambda takes captures. // @uschindler says: I talked with RĂ©mi Forax about this. Technically, a plain ctor // and a MethodHandle to the ctor would be enough - BUT: Hotspot is unable to @@ -337,10 +337,10 @@ private static void generateLambdaConstructor( /** * Generates a factory method to delegate to constructors. */ - private static void generateStaticCtorDelegator(ClassWriter cw, int access, String delegatorMethodName, + private static void generateStaticCtorDelegator(ClassWriter cw, int access, String delegatorMethodName, Type delegateClassType, MethodType delegateMethodType) { Method wrapperMethod = new Method(delegatorMethodName, delegateMethodType.toMethodDescriptorString()); - Method constructorMethod = + Method constructorMethod = new Method(CTOR_METHOD_NAME, delegateMethodType.changeReturnType(void.class).toMethodDescriptorString()); int modifiers = access | ACC_STATIC; @@ -379,7 +379,7 @@ private static void generateInterfaceMethod( GeneratorAdapter iface = new GeneratorAdapter(modifiers, lamMeth, cw.visitMethod(modifiers, interfaceMethodName, lamDesc, null, null)); iface.visitCode(); - + // Loads any captured variables onto the stack. for (int captureCount = 0; captureCount < captures.length; ++captureCount) { iface.loadThis(); @@ -473,7 +473,7 @@ private static Class createLambdaClass( private static CallSite createNoCaptureCallSite( MethodType factoryMethodType, Class lambdaClass) { - + try { return new ConstantCallSite(MethodHandles.constant( factoryMethodType.returnType(), lambdaClass.getConstructor().newInstance())); @@ -503,7 +503,7 @@ private static CallSite createCaptureCallSite( * delegate method will use converted types from the interface method. Using * invokedynamic to make the delegate method call allows * {@link MethodHandle#asType} to be used to do the type conversion instead - * of either a lot more code or requiring many {@link Definition.Type}s to be looked + * of either a lot more code or requiring many {@link Class}es to be looked * up at link-time. */ public static CallSite delegateBootstrap(Lookup lookup, diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java index 55b924dae89ce..2498396c891d1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java @@ -92,13 +92,13 @@ public static Locals newFunctionScope(Locals programScope, Class returnType, /** Creates a new main method scope */ public static Locals newMainMethodScope(ScriptClassInfo scriptClassInfo, Locals programScope, int maxLoopCounter) { Locals locals = new Locals( - programScope, programScope.definition, Definition.TypeToClass(scriptClassInfo.getExecuteMethodReturnType()), KEYWORDS); + programScope, programScope.definition, scriptClassInfo.getExecuteMethodReturnType(), KEYWORDS); // This reference. Internal use only. locals.defineVariable(null, Object.class, THIS, true); // Method arguments for (MethodArgument arg : scriptClassInfo.getExecuteArguments()) { - locals.defineVariable(null, Definition.TypeToClass(arg.getType()), arg.getName(), true); + locals.defineVariable(null, arg.getClazz(), arg.getName(), true); } // Loop counter to catch infinite loops. Internal use only. diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java index e52aaf2596965..ee36ac57303fb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java @@ -38,11 +38,11 @@ public class ScriptClassInfo { private final Class baseClass; private final org.objectweb.asm.commons.Method executeMethod; - private final Definition.Type executeMethodReturnType; + private final Class executeMethodReturnType; private final List executeArguments; private final List needsMethods; private final List getMethods; - private final List getReturns; + private final List> getReturns; public ScriptClassInfo(Definition definition, Class baseClass) { this.baseClass = baseClass; @@ -51,7 +51,7 @@ public ScriptClassInfo(Definition definition, Class baseClass) { java.lang.reflect.Method executeMethod = null; List needsMethods = new ArrayList<>(); List getMethods = new ArrayList<>(); - List getReturns = new ArrayList<>(); + List> getReturns = new ArrayList<>(); for (java.lang.reflect.Method m : baseClass.getMethods()) { if (m.isDefault()) { continue; @@ -65,7 +65,7 @@ public ScriptClassInfo(Definition definition, Class baseClass) { + "] has more than one."); } } - if (m.getName().startsWith("needs") && m.getReturnType().equals(boolean.class) && m.getParameterTypes().length == 0) { + if (m.getName().startsWith("needs") && m.getReturnType() == boolean.class && m.getParameterTypes().length == 0) { needsMethods.add(new org.objectweb.asm.commons.Method(m.getName(), NEEDS_PARAMETER_METHOD_TYPE.toMethodDescriptorString())); } if (m.getName().startsWith("get") && m.getName().equals("getClass") == false && Modifier.isStatic(m.getModifiers()) == false) { @@ -118,15 +118,15 @@ public org.objectweb.asm.commons.Method getExecuteMethod() { } /** - * The Painless {@link Definition.Type} or the return type of the {@code execute} method. This is used to generate the appropriate + * The Painless {@link Class} or the return type of the {@code execute} method. This is used to generate the appropriate * return bytecode. */ - public Definition.Type getExecuteMethodReturnType() { + public Class getExecuteMethodReturnType() { return executeMethodReturnType; } /** - * Painless {@link Definition.Type}s and names of the arguments to the {@code execute} method. The names are exposed to the Painless + * Painless {@link Class}s and names of the arguments to the {@code execute} method. The names are exposed to the Painless * script. */ public List getExecuteArguments() { @@ -150,24 +150,24 @@ public List getGetMethods() { /** * The {@code getVarName} methods return types. */ - public List getGetReturns() { + public List> getGetReturns() { return getReturns; } /** - * Painless {@link Definition.Type}s and name of the argument to the {@code execute} method. + * Painless {@link Class}es and name of the argument to the {@code execute} method. */ public static class MethodArgument { - private final Definition.Type type; + private final Class clazz; private final String name; - public MethodArgument(Definition.Type type, String name) { - this.type = type; + public MethodArgument(Class clazz, String name) { + this.clazz = clazz; this.name = name; } - public Definition.Type getType() { - return type; + public Class getClazz() { + return clazz; } public String getName() { @@ -175,13 +175,13 @@ public String getName() { } } - private MethodArgument methodArgument(Definition definition, Class type, String argName) { - Definition.Type defType = definitionTypeForClass(definition, type, componentType -> "[" + argName + "] is of unknown type [" + private MethodArgument methodArgument(Definition definition, Class clazz, String argName) { + Class defClass = definitionTypeForClass(definition, clazz, componentType -> "[" + argName + "] is of unknown type [" + componentType.getName() + ". Painless interfaces can only accept arguments that are of whitelisted types."); - return new MethodArgument(defType, argName); + return new MethodArgument(defClass, argName); } - private static Definition.Type definitionTypeForClass(Definition definition, Class type, + private static Class definitionTypeForClass(Definition definition, Class type, Function, String> unknownErrorMessageSource) { int dimensions = 0; Class componentType = type; @@ -190,8 +190,8 @@ private static Definition.Type definitionTypeForClass(Definition definition, Cla componentType = componentType.getComponentType(); } Definition.Struct struct; - if (componentType.equals(Object.class)) { - struct = definition.DefType.struct; + if (componentType == Object.class) { + struct = definition.getType("def").struct; } else { Definition.RuntimeClass runtimeClass = definition.getRuntimeClass(componentType); if (runtimeClass == null) { @@ -199,7 +199,7 @@ private static Definition.Type definitionTypeForClass(Definition definition, Cla } struct = runtimeClass.getStruct(); } - return definition.getType(struct, dimensions); + return Definition.TypeToClass(definition.getType(struct, dimensions)); } private static String[] readArgumentNamesConstant(Class iface) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java index 31bca79655ba2..69f6b1736a5ee 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java @@ -203,8 +203,8 @@ void analyze(Locals program) { name = Character.toLowerCase(name.charAt(0)) + name.substring(1); if (reserved.getUsedVariables().contains(name)) { - Definition.Type rtn = scriptClassInfo.getGetReturns().get(get); - mainMethod.addVariable(new Location("getter [" + name + "]", 0), Definition.TypeToClass(rtn), name, true); + Class rtn = scriptClassInfo.getGetReturns().get(get); + mainMethod.addVariable(new Location("getter [" + name + "]", 0), rtn, name, true); getMethods.add(method); } }