From ceafd7c1009fb50a016a97538dd76c25a289d191 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sun, 15 Dec 2019 09:07:47 -0800 Subject: [PATCH 01/24] copy nodes to split ir and ast --- .../elasticsearch/painless/ir/AStatement.java | 116 +++ .../elasticsearch/painless/ir/AStoreable.java | 123 ++++ .../elasticsearch/painless/ir/ClassNode.java | 349 +++++++++ .../painless/ir/ConstantNode.java | 51 ++ .../painless/ir/EAssignment.java | 358 +++++++++ .../elasticsearch/painless/ir/EBinary.java | 681 ++++++++++++++++++ .../org/elasticsearch/painless/ir/EBool.java | 122 ++++ .../elasticsearch/painless/ir/EBoolean.java | 65 ++ .../elasticsearch/painless/ir/ECallLocal.java | 233 ++++++ .../painless/ir/ECapturingFunctionRef.java | 119 +++ .../org/elasticsearch/painless/ir/ECast.java | 70 ++ .../org/elasticsearch/painless/ir/EComp.java | 185 +++++ .../painless/ir/EConditional.java | 113 +++ .../elasticsearch/painless/ir/EDecimal.java | 86 +++ .../org/elasticsearch/painless/ir/EElvis.java | 114 +++ .../elasticsearch/painless/ir/EExplicit.java | 83 +++ .../painless/ir/EFunctionRef.java | 94 +++ .../painless/ir/EInstanceof.java | 105 +++ .../elasticsearch/painless/ir/ELambda.java | 230 ++++++ .../elasticsearch/painless/ir/EListInit.java | 114 +++ .../elasticsearch/painless/ir/EMapInit.java | 137 ++++ .../elasticsearch/painless/ir/ENewArray.java | 114 +++ .../painless/ir/ENewArrayFunctionRef.java | 108 +++ .../elasticsearch/painless/ir/ENewObj.java | 121 ++++ .../org/elasticsearch/painless/ir/ENull.java | 76 ++ .../elasticsearch/painless/ir/ENumeric.java | 131 ++++ .../org/elasticsearch/painless/ir/ERegex.java | 137 ++++ .../elasticsearch/painless/ir/EStatic.java | 68 ++ .../elasticsearch/painless/ir/EString.java | 66 ++ .../org/elasticsearch/painless/ir/EUnary.java | 257 +++++++ .../elasticsearch/painless/ir/ILambda.java | 40 + .../org/elasticsearch/painless/ir/IRNode.java | 35 + .../org/elasticsearch/painless/ir/PBrace.java | 126 ++++ .../painless/ir/PCallInvoke.java | 107 +++ .../org/elasticsearch/painless/ir/PField.java | 171 +++++ .../painless/ir/PSubArrayLength.java | 105 +++ .../elasticsearch/painless/ir/PSubBrace.java | 104 +++ .../painless/ir/PSubCallInvoke.java | 90 +++ .../painless/ir/PSubDefArray.java | 116 +++ .../painless/ir/PSubDefCall.java | 128 ++++ .../painless/ir/PSubDefField.java | 110 +++ .../elasticsearch/painless/ir/PSubField.java | 127 ++++ .../painless/ir/PSubListShortcut.java | 140 ++++ .../painless/ir/PSubMapShortcut.java | 141 ++++ .../painless/ir/PSubNullSafeCallInvoke.java | 77 ++ .../painless/ir/PSubNullSafeField.java | 105 +++ .../painless/ir/PSubShortcut.java | 134 ++++ .../org/elasticsearch/painless/ir/SBlock.java | 97 +++ .../org/elasticsearch/painless/ir/SBreak.java | 66 ++ .../org/elasticsearch/painless/ir/SCatch.java | 120 +++ .../elasticsearch/painless/ir/SContinue.java | 69 ++ .../elasticsearch/painless/ir/SDeclBlock.java | 75 ++ .../painless/ir/SDeclaration.java | 108 +++ .../org/elasticsearch/painless/ir/SDo.java | 133 ++++ .../org/elasticsearch/painless/ir/SEach.java | 122 ++++ .../painless/ir/SExpression.java | 90 +++ .../org/elasticsearch/painless/ir/SField.java | 91 +++ .../org/elasticsearch/painless/ir/SFor.java | 222 ++++++ .../elasticsearch/painless/ir/SFunction.java | 186 +++++ .../org/elasticsearch/painless/ir/SIf.java | 103 +++ .../elasticsearch/painless/ir/SIfElse.java | 140 ++++ .../elasticsearch/painless/ir/SReturn.java | 89 +++ .../painless/ir/SSubEachArray.java | 116 +++ .../painless/ir/SSubEachIterable.java | 139 ++++ .../org/elasticsearch/painless/ir/SThrow.java | 73 ++ .../org/elasticsearch/painless/ir/STry.java | 136 ++++ .../org/elasticsearch/painless/ir/SWhile.java | 143 ++++ .../painless/ir/VariableNode.java | 62 ++ .../painless/ir/package-info.java | 158 ++++ 69 files changed, 9020 insertions(+) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java new file mode 100644 index 0000000000000..629449c1a58bf --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java @@ -0,0 +1,116 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.objectweb.asm.Label; + +/** + * The superclass for all S* (statement) nodes. + */ +public abstract class AStatement extends ANode { + + /** + * Set to true when the final statement in an {@link SClass} is reached. + * Used to determine whether or not an auto-return is necessary. + */ + boolean lastSource = false; + + /** + * Set to true when a loop begins. Used by {@link SBlock} to help determine + * when the final statement of a loop is reached. + */ + boolean beginLoop = false; + + /** + * Set to true when inside a loop. Used by {@link SBreak} and {@link SContinue} + * to determine if a break/continue statement is legal. + */ + boolean inLoop = false; + + /** + * Set to true when on the last statement of a loop. Used by {@link SContinue} + * to prevent extraneous continue statements. + */ + boolean lastLoop = false; + + /** + * Set to true if a statement would cause the method to exit. Used to + * determine whether or not an auto-return is necessary. + */ + boolean methodEscape = false; + + /** + * Set to true if a statement would cause a loop to exit. Used to + * prevent unreachable statements. + */ + boolean loopEscape = false; + + /** + * Set to true if all current paths escape from the current {@link SBlock}. + * Used during the analysis phase to prevent unreachable statements and + * the writing phase to prevent extraneous bytecode gotos from being written. + */ + boolean allEscape = false; + + /** + * Set to true if any continue statement occurs in a loop. Used to prevent + * unnecessary infinite loops. + */ + boolean anyContinue = false; + + /** + * Set to true if any break statement occurs in a loop. Used to prevent + * extraneous loops. + */ + boolean anyBreak = false; + + /** + * Set to the loop counter variable slot as a shortcut if loop statements + * are being counted. + */ + Variable loopCounter = null; + + /** + * Set to the approximate number of statements in a loop block to prevent + * infinite loops during runtime. + */ + int statementCount = 0; + + /** + * Set to the beginning of a loop so a continue statement knows where to + * jump to. Only used during the writing phase. + */ + Label continu = null; + + /** + * Set to the beginning of a loop so a break statement knows where to + * jump to. Only used during the writing phase. + */ + Label brake = null; + + /** + * Standard constructor with location used for error tracking. + */ + AStatement(Location location) { + super(location); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java new file mode 100644 index 0000000000000..7299a14677d9e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java @@ -0,0 +1,123 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.function.Consumer; + +/** + * The super class for an expression that can store a value in local memory. + */ +abstract class AStoreable extends AExpression { + + /** + * Set to true when this node is an lhs-expression and will be storing + * a value from an rhs-expression. + */ + boolean write = false; + + /** + * Standard constructor with location used for error tracking. + */ + AStoreable(Location location) { + super(location); + + prefix = null; + } + + /** + * This constructor is used by variable/method chains when postfixes are specified. + */ + AStoreable(Location location, AExpression prefix) { + super(location); + + this.prefix = Objects.requireNonNull(prefix); + } + + /** + * Returns a value based on the number of elements previously placed on the + * stack to load/store a certain piece of a variable/method chain. This is + * used during the writing phase to dup stack values from this storeable as + * necessary during certain store operations. + *

+ * Examples: + * {@link EVariable} returns 0 because it requires nothing extra to perform + * a load/store + * {@link PSubField} returns 1 because it requires the name of the field as + * an index on the stack to perform a load/store + * {@link PSubBrace} returns 2 because it requires both the variable slot and + * an index into the array on the stack to perform a + * load/store + */ + abstract int accessElementCount(); + + /** + * Returns true if this node or a sub-node of this node can be optimized with + * rhs actual type to avoid an unnecessary cast. + */ + abstract boolean isDefOptimized(); + + /** + * If this node or a sub-node of this node uses dynamic calls then + * actual will be set to this value. This is used for an optimization + * during assignment to def type targets. + */ + abstract void updateActual(Class actual); + + /** + * Called before a storeable node is loaded or stored. Used to load prefixes and + * push load/store constants onto the stack if necessary. + */ + abstract void setup(ClassWriter classWriter, MethodWriter writer, Globals globals); + + /** + * Called to load a storable used for compound assignments. + */ + abstract void load(ClassWriter classWriter, MethodWriter writer, Globals globals); + + /** + * Called to store a storabable to local memory. + */ + abstract void store(ClassWriter classWriter, MethodWriter writer, Globals globals); + + /** + * Writes the opcodes to flip a negative array index (meaning slots from the end of the array) into a 0-based one (meaning slots from + * the start of the array). + */ + static void writeIndexFlip(MethodWriter writer, Consumer writeGetLength) { + Label noFlip = new Label(); + // Everywhere when it says 'array' below that could also be a list + // The stack after each instruction: array, unnormalized_index + writer.dup(); // array, unnormalized_index, unnormalized_index + writer.ifZCmp(Opcodes.IFGE, noFlip); // array, unnormalized_index + writer.swap(); // negative_index, array + writer.dupX1(); // array, negative_index, array + writeGetLength.accept(writer); // array, negative_index, length + writer.visitInsn(Opcodes.IADD); // array, noralized_index + writer.mark(noFlip); // array, noralized_index + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java new file mode 100644 index 0000000000000..6068d0f8f09fb --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -0,0 +1,349 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.CompilerSettings; +import org.elasticsearch.painless.Constant; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptClassInfo; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.WriterConstants; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.util.Printer; + +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.WriterConstants.BASE_INTERFACE_TYPE; +import static org.elasticsearch.painless.WriterConstants.BITSET_TYPE; +import static org.elasticsearch.painless.WriterConstants.BOOTSTRAP_METHOD_ERROR_TYPE; +import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; +import static org.elasticsearch.painless.WriterConstants.COLLECTIONS_TYPE; +import static org.elasticsearch.painless.WriterConstants.CONVERT_TO_SCRIPT_EXCEPTION_METHOD; +import static org.elasticsearch.painless.WriterConstants.DEFINITION_TYPE; +import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_DELEGATE_METHOD; +import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_DELEGATE_TYPE; +import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_METHOD; +import static org.elasticsearch.painless.WriterConstants.EMPTY_MAP_METHOD; +import static org.elasticsearch.painless.WriterConstants.EXCEPTION_TYPE; +import static org.elasticsearch.painless.WriterConstants.FUNCTION_TABLE_TYPE; +import static org.elasticsearch.painless.WriterConstants.GET_NAME_METHOD; +import static org.elasticsearch.painless.WriterConstants.GET_SOURCE_METHOD; +import static org.elasticsearch.painless.WriterConstants.GET_STATEMENTS_METHOD; +import static org.elasticsearch.painless.WriterConstants.OUT_OF_MEMORY_ERROR_TYPE; +import static org.elasticsearch.painless.WriterConstants.PAINLESS_ERROR_TYPE; +import static org.elasticsearch.painless.WriterConstants.PAINLESS_EXPLAIN_ERROR_GET_HEADERS_METHOD; +import static org.elasticsearch.painless.WriterConstants.PAINLESS_EXPLAIN_ERROR_TYPE; +import static org.elasticsearch.painless.WriterConstants.STACK_OVERFLOW_ERROR_TYPE; +import static org.elasticsearch.painless.WriterConstants.STRING_TYPE; + +/** + * The root of all Painless trees. Contains a series of statements. + */ +public final class ClassNode implements IRNode { + + private final ScriptClassInfo scriptClassInfo; + private final String name; + private final Printer debugStream; + private final List functions = new ArrayList<>(); + private final List fields = new ArrayList<>(); + private final List statements = new ArrayList<>(); + private final Globals globals; + + private CompilerSettings settings; + + private ScriptRoot table; + private Locals mainMethod; + private final Set extractedVariables; + private final List getMethods; + private byte[] bytes; + + public SClass(ScriptClassInfo scriptClassInfo, String name, String sourceText, Printer debugStream, + Location location) { + super(location); + this.scriptClassInfo = Objects.requireNonNull(scriptClassInfo); + this.name = Objects.requireNonNull(name); + this.debugStream = debugStream; + this.functions.addAll(Objects.requireNonNull(functions)); + this.statements = Collections.unmodifiableList(statements); + this.globals = new Globals(new BitSet(sourceText.length())); + + this.extractedVariables = new HashSet<>(); + this.getMethods = new ArrayList<>(); + } + + public Map write() { + // Create the ClassWriter. + + int classFrames = org.objectweb.asm.ClassWriter.COMPUTE_FRAMES | org.objectweb.asm.ClassWriter.COMPUTE_MAXS; + int classAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL; + String interfaceBase = BASE_INTERFACE_TYPE.getInternalName(); + String className = CLASS_TYPE.getInternalName(); + String[] classInterfaces = new String[] { interfaceBase }; + + ClassWriter classWriter = new ClassWriter(settings, globals.getStatements(), debugStream, + scriptClassInfo.getBaseClass(), classFrames, classAccess, className, classInterfaces); + ClassVisitor classVisitor = classWriter.getClassVisitor(); + classVisitor.visitSource(Location.computeSourceName(name), null); + + // Write the a method to bootstrap def calls + MethodWriter bootstrapDef = classWriter.newMethodWriter(Opcodes.ACC_STATIC | Opcodes.ACC_VARARGS, DEF_BOOTSTRAP_METHOD); + bootstrapDef.visitCode(); + bootstrapDef.getStatic(CLASS_TYPE, "$DEFINITION", DEFINITION_TYPE); + bootstrapDef.getStatic(CLASS_TYPE, "$FUNCTIONS", FUNCTION_TABLE_TYPE); + bootstrapDef.loadArgs(); + bootstrapDef.invokeStatic(DEF_BOOTSTRAP_DELEGATE_TYPE, DEF_BOOTSTRAP_DELEGATE_METHOD); + bootstrapDef.returnValue(); + bootstrapDef.endMethod(); + + // Write static variables for name, source and statements used for writing exception messages + classVisitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$NAME", STRING_TYPE.getDescriptor(), null, null).visitEnd(); + classVisitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$SOURCE", STRING_TYPE.getDescriptor(), null, null).visitEnd(); + classVisitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$STATEMENTS", BITSET_TYPE.getDescriptor(), null, null).visitEnd(); + + // Write the static variables used by the method to bootstrap def calls + classVisitor.visitField( + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$DEFINITION", DEFINITION_TYPE.getDescriptor(), null, null).visitEnd(); + classVisitor.visitField( + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$FUNCTIONS", FUNCTION_TABLE_TYPE.getDescriptor(), null, null).visitEnd(); + + org.objectweb.asm.commons.Method init; + + if (scriptClassInfo.getBaseClass().getConstructors().length == 0) { + init = new org.objectweb.asm.commons.Method("", MethodType.methodType(void.class).toMethodDescriptorString()); + } else { + init = new org.objectweb.asm.commons.Method("", MethodType.methodType(void.class, + scriptClassInfo.getBaseClass().getConstructors()[0].getParameterTypes()).toMethodDescriptorString()); + } + + // Write the constructor: + MethodWriter constructor = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, init); + constructor.visitCode(); + constructor.loadThis(); + constructor.loadArgs(); + constructor.invokeConstructor(Type.getType(scriptClassInfo.getBaseClass()), init); + constructor.returnValue(); + constructor.endMethod(); + + // Write a method to get static variable source + MethodWriter nameMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, GET_NAME_METHOD); + nameMethod.visitCode(); + nameMethod.getStatic(CLASS_TYPE, "$NAME", STRING_TYPE); + nameMethod.returnValue(); + nameMethod.endMethod(); + + // Write a method to get static variable source + MethodWriter sourceMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, GET_SOURCE_METHOD); + sourceMethod.visitCode(); + sourceMethod.getStatic(CLASS_TYPE, "$SOURCE", STRING_TYPE); + sourceMethod.returnValue(); + sourceMethod.endMethod(); + + // Write a method to get static variable statements + MethodWriter statementsMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, GET_STATEMENTS_METHOD); + statementsMethod.visitCode(); + statementsMethod.getStatic(CLASS_TYPE, "$STATEMENTS", BITSET_TYPE); + statementsMethod.returnValue(); + statementsMethod.endMethod(); + + // Write the method defined in the interface: + MethodWriter executeMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, scriptClassInfo.getExecuteMethod()); + executeMethod.visitCode(); + write(classWriter, executeMethod, globals); + executeMethod.endMethod(); + + // Write all functions: + for (SFunction function : functions) { + function.write(classWriter, globals); + } + + // Write all fields: + for (SField field : fields) { + field.write(classWriter); + } + + // Write the constants + if (false == globals.getConstantInitializers().isEmpty()) { + Collection inits = globals.getConstantInitializers().values(); + + // Initialize the constants in a static initializer + final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC, + WriterConstants.CLINIT, classVisitor, globals.getStatements(), settings); + clinit.visitCode(); + for (Constant constant : inits) { + constant.initializer.accept(clinit); + clinit.putStatic(CLASS_TYPE, constant.name, constant.type); + } + clinit.returnValue(); + clinit.endMethod(); + } + + // Write any needsVarName methods for used variables + for (org.objectweb.asm.commons.Method needsMethod : scriptClassInfo.getNeedsMethods()) { + String name = needsMethod.getName(); + name = name.substring(5); + name = Character.toLowerCase(name.charAt(0)) + name.substring(1); + MethodWriter ifaceMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, needsMethod); + ifaceMethod.visitCode(); + ifaceMethod.push(extractedVariables.contains(name)); + ifaceMethod.returnValue(); + ifaceMethod.endMethod(); + } + + // End writing the class and store the generated bytes. + + classVisitor.visitEnd(); + bytes = classWriter.getClassBytes(); + + Map statics = new HashMap<>(); + statics.put("$FUNCTIONS", table.getFunctionTable()); + + for (SField field : fields) { + if (field.getInstance() != null) { + statics.put(field.getName(), field.getInstance()); + } + } + + return statics; + } + + @Override + void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // We wrap the whole method in a few try/catches to handle and/or convert other exceptions to ScriptException + Label startTry = new Label(); + Label endTry = new Label(); + Label startExplainCatch = new Label(); + Label startOtherCatch = new Label(); + Label endCatch = new Label(); + methodWriter.mark(startTry); + + if (settings.getMaxLoopCounter() > 0) { + // if there is infinite loop protection, we do this once: + // int #loop = settings.getMaxLoopCounter() + + Variable loop = mainMethod.getVariable(null, Locals.LOOP); + + methodWriter.push(settings.getMaxLoopCounter()); + methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); + } + + for (org.objectweb.asm.commons.Method method : getMethods) { + String name = method.getName().substring(3); + name = Character.toLowerCase(name.charAt(0)) + name.substring(1); + Variable variable = mainMethod.getVariable(null, name); + + methodWriter.loadThis(); + methodWriter.invokeVirtual(Type.getType(scriptClassInfo.getBaseClass()), method); + methodWriter.visitVarInsn(method.getReturnType().getOpcode(Opcodes.ISTORE), variable.getSlot()); + } + + for (AStatement statement : statements) { + statement.write(classWriter, methodWriter, globals); + } + if (!methodEscape) { + switch (scriptClassInfo.getExecuteMethod().getReturnType().getSort()) { + case org.objectweb.asm.Type.VOID: + break; + case org.objectweb.asm.Type.BOOLEAN: + methodWriter.push(false); + break; + case org.objectweb.asm.Type.BYTE: + methodWriter.push(0); + break; + case org.objectweb.asm.Type.SHORT: + methodWriter.push(0); + break; + case org.objectweb.asm.Type.INT: + methodWriter.push(0); + break; + case org.objectweb.asm.Type.LONG: + methodWriter.push(0L); + break; + case org.objectweb.asm.Type.FLOAT: + methodWriter.push(0f); + break; + case org.objectweb.asm.Type.DOUBLE: + methodWriter.push(0d); + break; + default: + methodWriter.visitInsn(Opcodes.ACONST_NULL); + } + methodWriter.returnValue(); + } + + methodWriter.mark(endTry); + methodWriter.goTo(endCatch); + // This looks like: + // } catch (PainlessExplainError e) { + // throw this.convertToScriptException(e, e.getHeaders($DEFINITION)) + // } + methodWriter.visitTryCatchBlock(startTry, endTry, startExplainCatch, PAINLESS_EXPLAIN_ERROR_TYPE.getInternalName()); + methodWriter.mark(startExplainCatch); + methodWriter.loadThis(); + methodWriter.swap(); + methodWriter.dup(); + methodWriter.getStatic(CLASS_TYPE, "$DEFINITION", DEFINITION_TYPE); + methodWriter.invokeVirtual(PAINLESS_EXPLAIN_ERROR_TYPE, PAINLESS_EXPLAIN_ERROR_GET_HEADERS_METHOD); + methodWriter.invokeInterface(BASE_INTERFACE_TYPE, CONVERT_TO_SCRIPT_EXCEPTION_METHOD); + methodWriter.throwException(); + // This looks like: + // } catch (PainlessError | BootstrapMethodError | OutOfMemoryError | StackOverflowError | Exception e) { + // throw this.convertToScriptException(e, e.getHeaders()) + // } + // We *think* it is ok to catch OutOfMemoryError and StackOverflowError because Painless is stateless + methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, PAINLESS_ERROR_TYPE.getInternalName()); + methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, BOOTSTRAP_METHOD_ERROR_TYPE.getInternalName()); + methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, OUT_OF_MEMORY_ERROR_TYPE.getInternalName()); + methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, STACK_OVERFLOW_ERROR_TYPE.getInternalName()); + methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, EXCEPTION_TYPE.getInternalName()); + methodWriter.mark(startOtherCatch); + methodWriter.loadThis(); + methodWriter.swap(); + methodWriter.invokeStatic(COLLECTIONS_TYPE, EMPTY_MAP_METHOD); + methodWriter.invokeInterface(BASE_INTERFACE_TYPE, CONVERT_TO_SCRIPT_EXCEPTION_METHOD); + methodWriter.throwException(); + methodWriter.mark(endCatch); + } + + public BitSet getStatements() { + return globals.getStatements(); + } + + public byte[] getBytes() { + return bytes; + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java new file mode 100644 index 0000000000000..35686ab2a9965 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +import java.util.Objects; + +public class ConstantNode implements IRNode { + + protected final Object constant; + + ConstantNode(Object constant) { + this.constant = Objects.requireNonNull(constant); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (constant instanceof String) methodWriter.push((String)constant); + else if (constant instanceof Double) methodWriter.push((double)constant); + else if (constant instanceof Float) methodWriter.push((float)constant); + else if (constant instanceof Long) methodWriter.push((long)constant); + else if (constant instanceof Integer) methodWriter.push((int)constant); + else if (constant instanceof Character) methodWriter.push((char)constant); + else if (constant instanceof Short) methodWriter.push((short)constant); + else if (constant instanceof Byte) methodWriter.push((byte)constant); + else if (constant instanceof Boolean) methodWriter.push((boolean)constant); + else { + throw new IllegalStateException("unexpected constant [" + constant + "]"); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java new file mode 100644 index 0000000000000..c6fcc9820420e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java @@ -0,0 +1,358 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.def; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Represents an assignment with the lhs and rhs as child nodes. + */ +public final class EAssignment extends AExpression { + + private AExpression lhs; + private AExpression rhs; + private final boolean pre; + private final boolean post; + private Operation operation; + + private boolean cat = false; + private Class promote = null; + private Class shiftDistance; // for shifts, the RHS is promoted independently + private PainlessCast there = null; + private PainlessCast back = null; + + public EAssignment(Location location, AExpression lhs, AExpression rhs, boolean pre, boolean post, Operation operation) { + super(location); + + this.lhs = Objects.requireNonNull(lhs); + this.rhs = rhs; + this.pre = pre; + this.post = post; + this.operation = operation; + } + + @Override + void extractVariables(Set variables) { + lhs.extractVariables(variables); + + if (rhs != null) { + rhs.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + analyzeLHS(scriptRoot, locals); + analyzeIncrDecr(); + + if (operation != null) { + analyzeCompound(scriptRoot, locals); + } else if (rhs != null) { + analyzeSimple(scriptRoot, locals); + } else { + throw new IllegalStateException("Illegal tree structure."); + } + } + + private void analyzeLHS(ScriptRoot scriptRoot, Locals locals) { + if (lhs instanceof AStoreable) { + AStoreable lhs = (AStoreable)this.lhs; + + lhs.read = read; + lhs.write = true; + lhs.analyze(scriptRoot, locals); + } else { + throw new IllegalArgumentException("Left-hand side cannot be assigned a value."); + } + } + + private void analyzeIncrDecr() { + if (pre && post) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } else if (pre || post) { + if (rhs != null) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + if (operation == Operation.INCR) { + if (lhs.actual == double.class) { + rhs = new EConstant(location, 1D); + } else if (lhs.actual == float.class) { + rhs = new EConstant(location, 1F); + } else if (lhs.actual == long.class) { + rhs = new EConstant(location, 1L); + } else { + rhs = new EConstant(location, 1); + } + + operation = Operation.ADD; + } else if (operation == Operation.DECR) { + if (lhs.actual == double.class) { + rhs = new EConstant(location, 1D); + } else if (lhs.actual == float.class) { + rhs = new EConstant(location, 1F); + } else if (lhs.actual == long.class) { + rhs = new EConstant(location, 1L); + } else { + rhs = new EConstant(location, 1); + } + + operation = Operation.SUB; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeCompound(ScriptRoot scriptRoot, Locals locals) { + rhs.analyze(scriptRoot, locals); + boolean shift = false; + + if (operation == Operation.MUL) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); + } else if (operation == Operation.DIV) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); + } else if (operation == Operation.REM) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); + } else if (operation == Operation.ADD) { + promote = AnalyzerCaster.promoteAdd(lhs.actual, rhs.actual); + } else if (operation == Operation.SUB) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); + } else if (operation == Operation.LSH) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, false); + shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false); + shift = true; + } else if (operation == Operation.RSH) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, false); + shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false); + shift = true; + } else if (operation == Operation.USH) { + promote = AnalyzerCaster.promoteNumeric(lhs.actual, false); + shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false); + shift = true; + } else if (operation == Operation.BWAND) { + promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual); + } else if (operation == Operation.XOR) { + promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual); + } else if (operation == Operation.BWOR) { + promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + if (promote == null || (shift && shiftDistance == null)) { + throw createError(new ClassCastException("Cannot apply compound assignment " + + "[" + operation.symbol + "=] to types [" + lhs.actual + "] and [" + rhs.actual + "].")); + } + + cat = operation == Operation.ADD && promote == String.class; + + if (cat) { + if (rhs instanceof EBinary && ((EBinary)rhs).operation == Operation.ADD && rhs.actual == String.class) { + ((EBinary)rhs).cat = true; + } + + rhs.expected = rhs.actual; + } else if (shift) { + if (promote == def.class) { + // shifts are promoted independently, but for the def type, we need object. + rhs.expected = promote; + } else if (shiftDistance == long.class) { + rhs.expected = int.class; + rhs.explicit = true; + } else { + rhs.expected = shiftDistance; + } + } else { + rhs.expected = promote; + } + + rhs = rhs.cast(scriptRoot, locals); + + there = AnalyzerCaster.getLegalCast(location, lhs.actual, promote, false, false); + back = AnalyzerCaster.getLegalCast(location, promote, lhs.actual, true, false); + + this.statement = true; + this.actual = read ? lhs.actual : void.class; + } + + private void analyzeSimple(ScriptRoot scriptRoot, Locals locals) { + AStoreable lhs = (AStoreable)this.lhs; + + // If the lhs node is a def optimized node we update the actual type to remove the need for a cast. + if (lhs.isDefOptimized()) { + rhs.analyze(scriptRoot, locals); + + if (rhs.actual == void.class) { + throw createError(new IllegalArgumentException("Right-hand side cannot be a [void] type for assignment.")); + } + + rhs.expected = rhs.actual; + lhs.updateActual(rhs.actual); + // Otherwise, we must adapt the rhs type to the lhs type with a cast. + } else { + rhs.expected = lhs.actual; + rhs.analyze(scriptRoot, locals); + } + + rhs = rhs.cast(scriptRoot, locals); + + this.statement = true; + this.actual = read ? lhs.actual : void.class; + } + + /** + * Handles writing byte code for variable/method chains for all given possibilities + * including String concatenation, compound assignment, regular assignment, and simple + * reads. Includes proper duplication for chained assignments and assignments that are + * also read from. + */ + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + // For the case where the assignment represents a String concatenation + // we must, depending on the Java version, write a StringBuilder or + // track types going onto the stack. This must be done before the + // lhs is read because we need the StringBuilder to be placed on the + // stack ahead of any potential concatenation arguments. + int catElementStackSize = 0; + + if (cat) { + catElementStackSize = methodWriter.writeNewStrings(); + } + + // Cast the lhs to a storeable to perform the necessary operations to store the rhs. + AStoreable lhs = (AStoreable)this.lhs; + lhs.setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation + + if (cat) { + // Handle the case where we are doing a compound assignment + // representing a String concatenation. + + methodWriter.writeDup(lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it + // before concat helper on stack + lhs.load(classWriter, methodWriter, globals); // read the current lhs's value + methodWriter.writeAppendStrings(lhs.actual); // append the lhs's value using the StringBuilder + + rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs + + if (!(rhs instanceof EBinary) || !((EBinary)rhs).cat) { // check to see if the rhs has already done a concatenation + methodWriter.writeAppendStrings(rhs.actual); // append the rhs's value since it's hasn't already + } + + methodWriter.writeToStrings(); // put the value for string concat onto the stack + methodWriter.writeCast(back); // if necessary, cast the String to the lhs actual type + + if (lhs.read) { + methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // if this lhs is also read + // from dup the value onto the stack + } + + lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array + } else if (operation != null) { + // Handle the case where we are doing a compound assignment that + // does not represent a String concatenation. + + methodWriter.writeDup(lhs.accessElementCount(), 0); // if necessary, dup the previous lhs's value + // to be both loaded from and stored to + lhs.load(classWriter, methodWriter, globals); // load the current lhs's value + + if (lhs.read && post) { + methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the + // lhs is also + // read from and is a post + // increment + } + + methodWriter.writeCast(there); // if necessary cast the current lhs's value + // to the promotion type between the lhs and rhs types + rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs + + // XXX: fix these types, but first we need def compound assignment tests. + // its tricky here as there are possibly explicit casts, too. + // write the operation instruction for compound assignment + if (promote == def.class) { + methodWriter.writeDynamicBinaryInstruction( + location, promote, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); + } else { + methodWriter.writeBinaryInstruction(location, promote, operation); + } + + methodWriter.writeCast(back); // if necessary cast the promotion type value back to the lhs's type + + if (lhs.read && !post) { + methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs + // is also + // read from and is not a post + // increment + } + + lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array + } else { + // Handle the case for a simple write. + + rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs + + if (lhs.read) { + methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs + // is also read from + } + + lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array + } + } + + @Override + public String toString() { + List subs = new ArrayList<>(); + subs.add(lhs); + if (rhs != null) { + // Make sure "=" is in the symbol so this is easy to read at a glance + subs.add(operation == null ? "=" : operation.symbol + "="); + subs.add(rhs); + return singleLineToString(subs); + } + subs.add(operation.symbol); + if (pre) { + subs.add("pre"); + } + if (post) { + subs.add("post"); + } + return singleLineToString(subs); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java new file mode 100644 index 0000000000000..7f67f16fb3b3c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java @@ -0,0 +1,681 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; + +import java.util.Objects; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Represents a binary math expression. + */ +public final class EBinary extends AExpression { + + final Operation operation; + private AExpression left; + private AExpression right; + + private Class promote = null; // promoted type + private Class shiftDistance = null; // for shifts, the rhs is promoted independently + boolean cat = false; + private boolean originallyExplicit = false; // record whether there was originally an explicit cast + + public EBinary(Location location, Operation operation, AExpression left, AExpression right) { + super(location); + + this.operation = Objects.requireNonNull(operation); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + left.extractVariables(variables); + right.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + originallyExplicit = explicit; + + if (operation == Operation.MUL) { + analyzeMul(scriptRoot, locals); + } else if (operation == Operation.DIV) { + analyzeDiv(scriptRoot, locals); + } else if (operation == Operation.REM) { + analyzeRem(scriptRoot, locals); + } else if (operation == Operation.ADD) { + analyzeAdd(scriptRoot, locals); + } else if (operation == Operation.SUB) { + analyzeSub(scriptRoot, locals); + } else if (operation == Operation.FIND) { + analyzeRegexOp(scriptRoot, locals); + } else if (operation == Operation.MATCH) { + analyzeRegexOp(scriptRoot, locals); + } else if (operation == Operation.LSH) { + analyzeLSH(scriptRoot, locals); + } else if (operation == Operation.RSH) { + analyzeRSH(scriptRoot, locals); + } else if (operation == Operation.USH) { + analyzeUSH(scriptRoot, locals); + } else if (operation == Operation.BWAND) { + analyzeBWAnd(scriptRoot, locals); + } else if (operation == Operation.XOR) { + analyzeXor(scriptRoot, locals); + } else if (operation == Operation.BWOR) { + analyzeBWOr(scriptRoot, locals); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + private void analyzeMul(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply multiply [*] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant * (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant * (long)right.constant; + } else if (promote == float.class) { + constant = (float)left.constant * (float)right.constant; + } else if (promote == double.class) { + constant = (double)left.constant * (double)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeDiv(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply divide [/] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + try { + if (promote == int.class) { + constant = (int)left.constant / (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant / (long)right.constant; + } else if (promote == float.class) { + constant = (float)left.constant / (float)right.constant; + } else if (promote == double.class) { + constant = (double)left.constant / (double)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } catch (ArithmeticException exception) { + throw createError(exception); + } + } + } + + private void analyzeRem(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply remainder [%] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + try { + if (promote == int.class) { + constant = (int)left.constant % (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant % (long)right.constant; + } else if (promote == float.class) { + constant = (float)left.constant % (float)right.constant; + } else if (promote == double.class) { + constant = (double)left.constant % (double)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } catch (ArithmeticException exception) { + throw createError(exception); + } + } + } + + private void analyzeAdd(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteAdd(left.actual, right.actual); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply add [+] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == String.class) { + left.expected = left.actual; + + if (left instanceof EBinary && ((EBinary)left).operation == Operation.ADD && left.actual == String.class) { + ((EBinary)left).cat = true; + } + + right.expected = right.actual; + + if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual == String.class) { + ((EBinary)right).cat = true; + } + } else if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant + (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant + (long)right.constant; + } else if (promote == float.class) { + constant = (float)left.constant + (float)right.constant; + } else if (promote == double.class) { + constant = (double)left.constant + (double)right.constant; + } else if (promote == String.class) { + constant = left.constant.toString() + right.constant.toString(); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + } + + private void analyzeSub(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply subtract [-] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant - (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant - (long)right.constant; + } else if (promote == float.class) { + constant = (float)left.constant - (float)right.constant; + } else if (promote == double.class) { + constant = (double)left.constant - (double)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeRegexOp(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + left.expected = String.class; + right.expected = Pattern.class; + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + promote = boolean.class; + actual = boolean.class; + } + + private void analyzeLSH(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + Class lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false); + Class rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false); + + if (lhspromote == null || rhspromote == null) { + throw createError(new ClassCastException("Cannot apply left shift [<<] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote = lhspromote; + shiftDistance = rhspromote; + + if (lhspromote == def.class || rhspromote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = lhspromote; + + if (rhspromote == long.class) { + right.expected = int.class; + right.explicit = true; + } else { + right.expected = rhspromote; + } + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant << (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant << (int)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeRSH(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + Class lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false); + Class rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false); + + if (lhspromote == null || rhspromote == null) { + throw createError(new ClassCastException("Cannot apply right shift [>>] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote = lhspromote; + shiftDistance = rhspromote; + + if (lhspromote == def.class || rhspromote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = lhspromote; + + if (rhspromote == long.class) { + right.expected = int.class; + right.explicit = true; + } else { + right.expected = rhspromote; + } + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant >> (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant >> (int)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeUSH(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + Class lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false); + Class 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 " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + if (lhspromote == def.class || rhspromote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = lhspromote; + + if (rhspromote == long.class) { + right.expected = int.class; + right.explicit = true; + } else { + right.expected = rhspromote; + } + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant >>> (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant >>> (int)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeBWAnd(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply and [&] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant & (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant & (long)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeXor(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteXor(left.actual, right.actual); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply xor [^] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == boolean.class) { + constant = (boolean)left.constant ^ (boolean)right.constant; + } else if (promote == int.class) { + constant = (int)left.constant ^ (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant ^ (long)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + private void analyzeBWOr(ScriptRoot scriptRoot, Locals variables) { + left.analyze(scriptRoot, variables); + right.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply or [|] to types " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); + } + + actual = promote; + + if (promote == def.class) { + left.expected = left.actual; + right.expected = right.actual; + if (expected != null) { + actual = expected; + } + } else { + left.expected = promote; + right.expected = promote; + } + + left = left.cast(scriptRoot, variables); + right = right.cast(scriptRoot, variables); + + if (left.constant != null && right.constant != null) { + if (promote == int.class) { + constant = (int)left.constant | (int)right.constant; + } else if (promote == long.class) { + constant = (long)left.constant | (long)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (promote == String.class && operation == Operation.ADD) { + if (!cat) { + methodWriter.writeNewStrings(); + } + + left.write(classWriter, methodWriter, globals); + + if (!(left instanceof EBinary) || !((EBinary)left).cat) { + methodWriter.writeAppendStrings(left.actual); + } + + right.write(classWriter, methodWriter, globals); + + if (!(right instanceof EBinary) || !((EBinary)right).cat) { + methodWriter.writeAppendStrings(right.actual); + } + + if (!cat) { + methodWriter.writeToStrings(); + } + } else if (operation == Operation.FIND || operation == Operation.MATCH) { + right.write(classWriter, methodWriter, globals); + left.write(classWriter, methodWriter, globals); + methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER); + + if (operation == Operation.FIND) { + methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_FIND); + } else if (operation == Operation.MATCH) { + methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_MATCHES); + } else { + throw new IllegalStateException("Illegal tree structure."); + } + } else { + left.write(classWriter, methodWriter, globals); + right.write(classWriter, methodWriter, globals); + + if (promote == def.class || (shiftDistance != null && shiftDistance == def.class)) { + // def calls adopt the wanted return value. if there was a narrowing cast, + // we need to flag that so that its done at runtime. + int flags = 0; + if (originallyExplicit) { + flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; + } + methodWriter.writeDynamicBinaryInstruction(location, actual, left.actual, right.actual, operation, flags); + } else { + methodWriter.writeBinaryInstruction(location, actual, operation); + } + } + } + + @Override + public String toString() { + return singleLineToString(left, operation.symbol, right); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java new file mode 100644 index 0000000000000..c46242ff28aac --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java @@ -0,0 +1,122 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a boolean expression. + */ +public final class EBool extends AExpression { + + private final Operation operation; + private AExpression left; + private AExpression right; + + public EBool(Location location, Operation operation, AExpression left, AExpression right) { + super(location); + + this.operation = Objects.requireNonNull(operation); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + left.extractVariables(variables); + right.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + left.expected = boolean.class; + left.analyze(scriptRoot, locals); + left = left.cast(scriptRoot, locals); + + right.expected = boolean.class; + right.analyze(scriptRoot, locals); + right = right.cast(scriptRoot, locals); + + if (left.constant != null && right.constant != null) { + if (operation == Operation.AND) { + constant = (boolean)left.constant && (boolean)right.constant; + } else if (operation == Operation.OR) { + constant = (boolean)left.constant || (boolean)right.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + actual = boolean.class; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (operation == Operation.AND) { + Label fals = new Label(); + Label end = new Label(); + + left.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + right.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + methodWriter.push(true); + methodWriter.goTo(end); + methodWriter.mark(fals); + methodWriter.push(false); + methodWriter.mark(end); + } else if (operation == Operation.OR) { + Label tru = new Label(); + Label fals = new Label(); + Label end = new Label(); + + left.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFNE, tru); + right.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + methodWriter.mark(tru); + methodWriter.push(true); + methodWriter.goTo(end); + methodWriter.mark(fals); + methodWriter.push(false); + methodWriter.mark(end); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + @Override + public String toString() { + return singleLineToString(left, operation.symbol, right); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java new file mode 100644 index 0000000000000..e1c4fd05745f9 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java @@ -0,0 +1,65 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Set; + +/** + * Represents a boolean constant. + */ +public final class EBoolean extends AExpression { + + public EBoolean(Location location, boolean constant) { + super(location); + + this.constant = constant; + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from constant [" + constant + "].")); + } + + actual = boolean.class; + } + + @Override + void write(ClassWriter classWriter, MethodWriter adapter, Globals globals) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + public String toString() { + return singleLineToString(constant); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java new file mode 100644 index 0000000000000..e386f94d01b69 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java @@ -0,0 +1,233 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessClassBinding; +import org.elasticsearch.painless.lookup.PainlessInstanceBinding; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.FunctionTable; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; + +/** + * Represents a user-defined call. + */ +public final class ECallLocal extends AExpression { + + private final String name; + private final List arguments; + + private FunctionTable.LocalFunction localFunction = null; + private PainlessMethod importedMethod = null; + private PainlessClassBinding classBinding = null; + private int classBindingOffset = 0; + private PainlessInstanceBinding instanceBinding = null; + private String bindingName = null; + + public ECallLocal(Location location, String name, List arguments) { + super(location); + + this.name = Objects.requireNonNull(name); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + localFunction = scriptRoot.getFunctionTable().getFunction(name, arguments.size()); + + // user cannot call internal functions, reset to null if an internal function is found + if (localFunction != null && localFunction.isInternal()) { + localFunction = null; + } + + if (localFunction == null) { + importedMethod = scriptRoot.getPainlessLookup().lookupImportedPainlessMethod(name, arguments.size()); + + if (importedMethod == null) { + classBinding = scriptRoot.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size()); + + // check to see if this class binding requires an implicit this reference + if (classBinding != null && classBinding.typeParameters.isEmpty() == false && + classBinding.typeParameters.get(0) == scriptRoot.getScriptClassInfo().getBaseClass()) { + classBinding = null; + } + + if (classBinding == null) { + // This extra check looks for a possible match where the class binding requires an implicit this + // reference. This is a temporary solution to allow the class binding access to data from the + // base script class without need for a user to add additional arguments. A long term solution + // will likely involve adding a class instance binding where any instance can have a class binding + // as part of its API. However, the situation at run-time is difficult and will modifications that + // are a substantial change if even possible to do. + classBinding = scriptRoot.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size() + 1); + + if (classBinding != null) { + if (classBinding.typeParameters.isEmpty() == false && + classBinding.typeParameters.get(0) == scriptRoot.getScriptClassInfo().getBaseClass()) { + classBindingOffset = 1; + } else { + classBinding = null; + } + } + + if (classBinding == null) { + instanceBinding = scriptRoot.getPainlessLookup().lookupPainlessInstanceBinding(name, arguments.size()); + + if (instanceBinding == null) { + throw createError(new IllegalArgumentException( + "Unknown call [" + name + "] with [" + arguments.size() + "] arguments.")); + } + } + } + } + } + + List> typeParameters; + + if (localFunction != null) { + typeParameters = new ArrayList<>(localFunction.getTypeParameters()); + actual = localFunction.getReturnType(); + } else if (importedMethod != null) { + typeParameters = new ArrayList<>(importedMethod.typeParameters); + actual = importedMethod.returnType; + } else if (classBinding != null) { + typeParameters = new ArrayList<>(classBinding.typeParameters); + actual = classBinding.returnType; + bindingName = scriptRoot.getNextSyntheticName("class_binding"); + scriptRoot.getClassNode().addField(new SField(location, + Modifier.PRIVATE, bindingName, classBinding.javaConstructor.getDeclaringClass(), null)); + } else if (instanceBinding != null) { + typeParameters = new ArrayList<>(instanceBinding.typeParameters); + actual = instanceBinding.returnType; + bindingName = scriptRoot.getNextSyntheticName("instance_binding"); + scriptRoot.getClassNode().addField(new SField(location, Modifier.STATIC | Modifier.PUBLIC, + bindingName, instanceBinding.targetInstance.getClass(), instanceBinding.targetInstance)); + } else { + throw new IllegalStateException("Illegal tree structure."); + } + + // if the class binding is using an implicit this reference then the arguments counted must + // be incremented by 1 as the this reference will not be part of the arguments passed into + // the class binding call + for (int argument = 0; argument < arguments.size(); ++argument) { + AExpression expression = arguments.get(argument); + + expression.expected = typeParameters.get(argument + classBindingOffset); + expression.internal = true; + expression.analyze(scriptRoot, locals); + arguments.set(argument, expression.cast(scriptRoot, locals)); + } + + statement = true; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (localFunction != null) { + for (AExpression argument : arguments) { + argument.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod()); + } else if (importedMethod != null) { + for (AExpression argument : arguments) { + argument.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeStatic(Type.getType(importedMethod.targetClass), + new Method(importedMethod.javaMethod.getName(), importedMethod.methodType.toMethodDescriptorString())); + } else if (classBinding != null) { + Type type = Type.getType(classBinding.javaConstructor.getDeclaringClass()); + int javaConstructorParameterCount = classBinding.javaConstructor.getParameterCount() - classBindingOffset; + + Label nonNull = new Label(); + + methodWriter.loadThis(); + methodWriter.getField(CLASS_TYPE, bindingName, type); + methodWriter.ifNonNull(nonNull); + methodWriter.loadThis(); + methodWriter.newInstance(type); + methodWriter.dup(); + + if (classBindingOffset == 1) { + methodWriter.loadThis(); + } + + for (int argument = 0; argument < javaConstructorParameterCount; ++argument) { + arguments.get(argument).write(classWriter, methodWriter, globals); + } + + methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor)); + methodWriter.putField(CLASS_TYPE, bindingName, type); + + methodWriter.mark(nonNull); + methodWriter.loadThis(); + methodWriter.getField(CLASS_TYPE, bindingName, type); + + for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) { + arguments.get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); + } + + methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod)); + } else if (instanceBinding != null) { + Type type = Type.getType(instanceBinding.targetInstance.getClass()); + + methodWriter.loadThis(); + methodWriter.getStatic(CLASS_TYPE, bindingName, type); + + for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) { + arguments.get(argument).write(classWriter, methodWriter, globals); + } + + methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod)); + } else { + throw new IllegalStateException("Illegal tree structure."); + } + } + + @Override + public String toString() { + return singleLineToStringWithOptionalArgs(arguments, name); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java new file mode 100644 index 0000000000000..00f2283472e49 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java @@ -0,0 +1,119 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.FunctionRef; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a capturing function reference. + */ +public final class ECapturingFunctionRef extends AExpression implements ILambda { + private final String variable; + private final String call; + + private FunctionRef ref; + private Variable captured; + private String defPointer; + + public ECapturingFunctionRef(Location location, String variable, String call) { + super(location); + + this.variable = Objects.requireNonNull(variable); + this.call = Objects.requireNonNull(call); + } + + @Override + void extractVariables(Set variables) { + variables.add(variable); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + captured = locals.getVariable(location, variable); + if (expected == null) { + if (captured.clazz == def.class) { + // dynamic implementation + defPointer = "D" + variable + "." + call + ",1"; + } else { + // typed implementation + defPointer = "S" + PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz) + "." + call + ",1"; + } + actual = String.class; + } else { + defPointer = null; + // static case + if (captured.clazz != def.class) { + ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), location, + expected, PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz), call, 1); + } + actual = expected; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + if (defPointer != null) { + // dynamic interface: push captured parameter on stack + // TODO: don't do this: its just to cutover :) + methodWriter.push((String)null); + methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); + } else if (ref == null) { + // typed interface, dynamic implementation + methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); + Type methodType = Type.getMethodType(MethodWriter.getType(expected), MethodWriter.getType(captured.clazz)); + methodWriter.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookupUtility.typeToCanonicalTypeName(expected)); + } else { + // typed interface, typed implementation + methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); + methodWriter.invokeLambdaCall(ref); + } + } + + @Override + public String getPointer() { + return defPointer; + } + + @Override + public Type[] getCaptures() { + return new Type[] { MethodWriter.getType(captured.clazz) }; + } + + @Override + public String toString() { + return singleLineToString(variable, call); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java new file mode 100644 index 0000000000000..d33f37fb6049b --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java @@ -0,0 +1,70 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a cast that is inserted into the tree replacing other casts. (Internal only.) + */ +final class ECast extends AExpression { + + private AExpression child; + private final PainlessCast cast; + + ECast(Location location, AExpression child, PainlessCast cast) { + super(location); + + this.child = Objects.requireNonNull(child); + this.cast = Objects.requireNonNull(cast); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + child.write(classWriter, methodWriter, globals); + methodWriter.writeDebugInfo(location); + methodWriter.writeCast(cast); + } + + @Override + public String toString() { + return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(cast.targetType), child); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java new file mode 100644 index 0000000000000..f8aa598c86397 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java @@ -0,0 +1,185 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.ir.IRNode; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; + +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.WriterConstants.EQUALS; +import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE; + +public class ComparisonNode implements IRNode { + + private final Operation operation; + private final Class promotedType; + + private IRNode left; + private IRNode right; + + public ComparisonNode(Operation operation) { + this.operation = Objects.requireNonNull(operation); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + public void setLeft(IRNode left) { + this.left = Objects.requireNonNull(left); + } + + public void setRight(IRNode right) { + this.right = Objects.requireNonNull(right); + } + + public IRNode getLeft() { + return left; + } + + public IRNode getRight() { + return right; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + left.write(classWriter, methodWriter, globals); + + if (!right.isNull) { + right.write(classWriter, methodWriter, globals); + } + + Label jump = new Label(); + Label end = new Label(); + + boolean eq = (operation == Operation.EQ || operation == Operation.EQR); + boolean ne = (operation == Operation.NE || operation == Operation.NER); + boolean lt = operation == Operation.LT; + boolean lte = operation == Operation.LTE; + boolean gt = operation == Operation.GT; + boolean gte = operation == Operation.GTE; + + boolean writejump = true; + + Type type = MethodWriter.getType(promotedType); + + if (promotedType == void.class || promotedType == byte.class || promotedType == short.class || promotedType == char.class) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } else if (promotedType == boolean.class) { + if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); + else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } else if (promotedType == int.class || promotedType == long.class || promotedType == float.class || promotedType == double.class) { + if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); + else if (lt) methodWriter.ifCmp(type, MethodWriter.LT, jump); + else if (lte) methodWriter.ifCmp(type, MethodWriter.LE, jump); + else if (gt) methodWriter.ifCmp(type, MethodWriter.GT, jump); + else if (gte) methodWriter.ifCmp(type, MethodWriter.GE, jump); + else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + } else if (promotedType == def.class) { + Type booleanType = Type.getType(boolean.class); + Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(left.actual), MethodWriter.getType(right.actual)); + + if (eq) { + if (right.isNull) { + methodWriter.ifNull(jump); + } else if (!left.isNull && operation == Operation.EQ) { + methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); + writejump = false; + } else { + methodWriter.ifCmp(type, MethodWriter.EQ, jump); + } + } else if (ne) { + if (right.isNull) { + methodWriter.ifNonNull(jump); + } else if (!left.isNull && operation == Operation.NE) { + methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); + methodWriter.ifZCmp(MethodWriter.EQ, jump); + } else { + methodWriter.ifCmp(type, MethodWriter.NE, jump); + } + } else if (lt) { + methodWriter.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); + writejump = false; + } else if (lte) { + methodWriter.invokeDefCall("lte", descriptor, DefBootstrap.BINARY_OPERATOR, 0); + writejump = false; + } else if (gt) { + methodWriter.invokeDefCall("gt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); + writejump = false; + } else if (gte) { + methodWriter.invokeDefCall("gte", descriptor, DefBootstrap.BINARY_OPERATOR, 0); + writejump = false; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } else { + if (eq) { + if (right.isNull) { + methodWriter.ifNull(jump); + } else if (operation == Operation.EQ) { + methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); + writejump = false; + } else { + methodWriter.ifCmp(type, MethodWriter.EQ, jump); + } + } else if (ne) { + if (right.isNull) { + methodWriter.ifNonNull(jump); + } else if (operation == Operation.NE) { + methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); + methodWriter.ifZCmp(MethodWriter.EQ, jump); + } else { + methodWriter.ifCmp(type, MethodWriter.NE, jump); + } + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + if (writejump) { + methodWriter.push(false); + methodWriter.goTo(end); + methodWriter.mark(jump); + methodWriter.push(true); + methodWriter.mark(end); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java new file mode 100644 index 0000000000000..c8263b587bb44 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java @@ -0,0 +1,113 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a conditional expression. + */ +public final class EConditional extends AExpression { + + private AExpression condition; + private AExpression left; + private AExpression right; + + public EConditional(Location location, AExpression condition, AExpression left, AExpression right) { + super(location); + + this.condition = Objects.requireNonNull(condition); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + left.extractVariables(variables); + right.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + condition.expected = boolean.class; + condition.analyze(scriptRoot, locals); + condition = condition.cast(scriptRoot, locals); + + if (condition.constant != null) { + throw createError(new IllegalArgumentException("Extraneous conditional statement.")); + } + + left.expected = expected; + left.explicit = explicit; + left.internal = internal; + right.expected = expected; + right.explicit = explicit; + right.internal = internal; + actual = expected; + + left.analyze(scriptRoot, locals); + right.analyze(scriptRoot, locals); + + if (expected == null) { + Class promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant); + + left.expected = promote; + right.expected = promote; + actual = promote; + } + + left = left.cast(scriptRoot, locals); + right = right.cast(scriptRoot, locals); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Label fals = new Label(); + Label end = new Label(); + + condition.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + left.write(classWriter, methodWriter, globals); + methodWriter.goTo(end); + methodWriter.mark(fals); + right.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(condition, left, right); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java new file mode 100644 index 0000000000000..faacb3cdc0282 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java @@ -0,0 +1,86 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a decimal constant. + */ +public final class EDecimal extends AExpression { + + private final String value; + + public EDecimal(Location location, String value) { + super(location); + + this.value = Objects.requireNonNull(value); + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from constant [" + value + "].")); + } + + if (value.endsWith("f") || value.endsWith("F")) { + try { + constant = Float.parseFloat(value.substring(0, value.length() - 1)); + actual = float.class; + } catch (NumberFormatException exception) { + throw createError(new IllegalArgumentException("Invalid float constant [" + value + "].")); + } + } else { + String toParse = value; + if (toParse.endsWith("d") || value.endsWith("D")) { + toParse = toParse.substring(0, value.length() - 1); + } + try { + constant = Double.parseDouble(toParse); + actual = double.class; + } catch (NumberFormatException exception) { + throw createError(new IllegalArgumentException("Invalid double constant [" + value + "].")); + } + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + public String toString() { + return singleLineToString(value); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java new file mode 100644 index 0000000000000..d5e494ffa3098 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; + +import java.util.Set; + +import static java.util.Objects.requireNonNull; + +/** + * The Elvis operator ({@code ?:}), a null coalescing operator. Binary operator that evaluates the first expression and return it if it is + * non null. If the first expression is null then it evaluates the second expression and returns it. + */ +public class EElvis extends AExpression { + private AExpression lhs; + private AExpression rhs; + + public EElvis(Location location, AExpression lhs, AExpression rhs) { + super(location); + + this.lhs = requireNonNull(lhs); + this.rhs = requireNonNull(rhs); + } + + @Override + void extractVariables(Set variables) { + lhs.extractVariables(variables); + rhs.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (expected != null && expected.isPrimitive()) { + throw createError(new IllegalArgumentException("Elvis operator cannot return primitives")); + } + lhs.expected = expected; + lhs.explicit = explicit; + lhs.internal = internal; + rhs.expected = expected; + rhs.explicit = explicit; + rhs.internal = internal; + actual = expected; + lhs.analyze(scriptRoot, locals); + rhs.analyze(scriptRoot, locals); + + if (lhs.isNull) { + throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is null.")); + } + if (lhs.constant != null) { + throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a constant.")); + } + if (lhs.actual.isPrimitive()) { + throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a primitive.")); + } + if (rhs.isNull) { + throw createError(new IllegalArgumentException("Extraneous elvis operator. RHS is null.")); + } + + if (expected == null) { + Class promote = AnalyzerCaster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant); + + lhs.expected = promote; + rhs.expected = promote; + actual = promote; + } + + lhs = lhs.cast(scriptRoot, locals); + rhs = rhs.cast(scriptRoot, locals); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Label end = new Label(); + + lhs.write(classWriter, methodWriter, globals); + methodWriter.dup(); + methodWriter.ifNonNull(end); + methodWriter.pop(); + rhs.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(lhs, rhs); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java new file mode 100644 index 0000000000000..b092aef87de42 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java @@ -0,0 +1,83 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents an explicit cast. + */ +public final class EExplicit extends AExpression { + + private final String type; + private AExpression child; + + public EExplicit(Location location, String type, AExpression child) { + super(location); + + this.type = Objects.requireNonNull(type); + this.child = Objects.requireNonNull(child); + } + + @Override + void extractVariables(Set variables) { + child.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(type); + + if (actual == null) { + throw createError(new IllegalArgumentException("Not a type [" + type + "].")); + } + + child.expected = actual; + child.explicit = true; + child.analyze(scriptRoot, locals); + child = child.cast(scriptRoot, locals); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + AExpression cast(ScriptRoot scriptRoot, Locals locals) { + child.expected = expected; + child.explicit = explicit; + child.internal = internal; + + return child.cast(scriptRoot, locals); + } + + @Override + public String toString() { + return singleLineToString(type, child); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java new file mode 100644 index 0000000000000..97b496a5985f9 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java @@ -0,0 +1,94 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.FunctionRef; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Type; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a function reference. + */ +public final class EFunctionRef extends AExpression implements ILambda { + private final String type; + private final String call; + + private FunctionRef ref; + private String defPointer; + + public EFunctionRef(Location location, String type, String call) { + super(location); + + this.type = Objects.requireNonNull(type); + this.call = Objects.requireNonNull(call); + } + + @Override + void extractVariables(Set variables) { + // do nothing + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (expected == null) { + ref = null; + actual = String.class; + defPointer = "S" + type + "." + call + ",0"; + } else { + defPointer = null; + ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), location, expected, type, call, 0); + actual = expected; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (ref != null) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeLambdaCall(ref); + } else { + // TODO: don't do this: its just to cutover :) + methodWriter.push((String)null); + } + } + + @Override + public String getPointer() { + return defPointer; + } + + @Override + public Type[] getCaptures() { + return new Type[0]; // no captures + } + + @Override + public String toString() { + return singleLineToString(type, call); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java new file mode 100644 index 0000000000000..88dc36b497cb4 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java @@ -0,0 +1,105 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents {@code instanceof} operator. + *

+ * Unlike java's, this works for primitive types too. + */ +public final class EInstanceof extends AExpression { + private AExpression expression; + private final String type; + + private Class resolvedType; + private Class expressionType; + private boolean primitiveExpression; + + public EInstanceof(Location location, AExpression expression, String type) { + super(location); + this.expression = Objects.requireNonNull(expression); + this.type = Objects.requireNonNull(type); + } + + @Override + void extractVariables(Set variables) { + expression.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + // ensure the specified type is part of the definition + Class clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); + + if (clazz == null) { + throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); + } + + // map to wrapped type for primitive types + resolvedType = clazz.isPrimitive() ? PainlessLookupUtility.typeToBoxedType(clazz) : + PainlessLookupUtility.typeToJavaType(clazz); + + // analyze and cast the expression + expression.analyze(scriptRoot, locals); + expression.expected = expression.actual; + expression = expression.cast(scriptRoot, locals); + + // record if the expression returns a primitive + primitiveExpression = expression.actual.isPrimitive(); + // map to wrapped type for primitive types + expressionType = expression.actual.isPrimitive() ? + PainlessLookupUtility.typeToBoxedType(expression.actual) : PainlessLookupUtility.typeToJavaType(clazz); + + actual = boolean.class; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // primitive types + if (primitiveExpression) { + // run the expression anyway (who knows what it does) + expression.write(classWriter, methodWriter, globals); + // discard its result + methodWriter.writePop(MethodWriter.getType(expression.actual).getSize()); + // push our result: its a primitive so it cannot be null. + methodWriter.push(resolvedType.isAssignableFrom(expressionType)); + } else { + // ordinary instanceof + expression.write(classWriter, methodWriter, globals); + methodWriter.instanceOf(org.objectweb.asm.Type.getType(resolvedType)); + } + } + + @Override + public String toString() { + return singleLineToString(expression, type); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java new file mode 100644 index 0000000000000..120bbdd744797 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java @@ -0,0 +1,230 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.FunctionRef; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Opcodes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Lambda expression node. + *

+ * This can currently only be the direct argument of a call (method/constructor). + * When the argument is of a known type, it uses + * + * Java's lambda translation. However, if its a def call, then we don't have + * enough information, and have to defer this until link time. In that case a placeholder + * and all captures are pushed onto the stack and folded into the signature of the parent call. + *

+ * For example: + *
+ * {@code def list = new ArrayList(); int capture = 0; list.sort((x,y) -> x - y + capture)} + *
+ * is converted into a call (pseudocode) such as: + *
+ * {@code sort(list, lambda$0, capture)} + *
+ * At link time, when we know the interface type, this is decomposed with MethodHandle + * combinators back into (pseudocode): + *
+ * {@code sort(list, lambda$0(capture))} + */ +public final class ELambda extends AExpression implements ILambda { + + private final List paramTypeStrs; + private final List paramNameStrs; + private final List statements; + + // extracted variables required to determine captures + private final Set extractedVariables; + // desugared synthetic method (lambda body) + private SFunction desugared; + // captured variables + private List captures; + // static parent, static lambda + private FunctionRef ref; + // dynamic parent, deferred until link time + private String defPointer; + + public ELambda(Location location, + List paramTypes, List paramNames, + List statements) { + super(location); + this.paramTypeStrs = Collections.unmodifiableList(paramTypes); + this.paramNameStrs = Collections.unmodifiableList(paramNames); + this.statements = Collections.unmodifiableList(statements); + + this.extractedVariables = new HashSet<>(); + } + + @Override + void extractVariables(Set variables) { + for (AStatement statement : statements) { + statement.extractVariables(extractedVariables); + } + + variables.addAll(extractedVariables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + Class returnType; + List actualParamTypeStrs; + PainlessMethod interfaceMethod; + // inspect the target first, set interface method if we know it. + if (expected == null) { + interfaceMethod = null; + // we don't know anything: treat as def + returnType = def.class; + // don't infer any types, replace any null types with def + actualParamTypeStrs = new ArrayList<>(paramTypeStrs.size()); + for (String type : paramTypeStrs) { + if (type == null) { + actualParamTypeStrs.add("def"); + } else { + actualParamTypeStrs.add(type); + } + } + + } else { + // we know the method statically, infer return type and any unknown/def types + interfaceMethod = scriptRoot.getPainlessLookup().lookupFunctionalInterfacePainlessMethod(expected); + if (interfaceMethod == null) { + throw createError(new IllegalArgumentException("Cannot pass lambda to " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], not a functional interface")); + } + // check arity before we manipulate parameters + if (interfaceMethod.typeParameters.size() != paramTypeStrs.size()) + throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.javaMethod.getName() + + "] in [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "]"); + // for method invocation, its allowed to ignore the return value + if (interfaceMethod.returnType == void.class) { + returnType = def.class; + } else { + returnType = interfaceMethod.returnType; + } + // replace any null types with the actual type + actualParamTypeStrs = new ArrayList<>(paramTypeStrs.size()); + for (int i = 0; i < paramTypeStrs.size(); i++) { + String paramType = paramTypeStrs.get(i); + if (paramType == null) { + actualParamTypeStrs.add(PainlessLookupUtility.typeToCanonicalTypeName(interfaceMethod.typeParameters.get(i))); + } else { + actualParamTypeStrs.add(paramType); + } + } + } + // any of those variables defined in our scope need to be captured + captures = new ArrayList<>(); + for (String variable : extractedVariables) { + if (locals.hasVariable(variable)) { + captures.add(locals.getVariable(location, variable)); + } + } + // prepend capture list to lambda's arguments + List paramTypes = new ArrayList<>(captures.size() + actualParamTypeStrs.size()); + List paramNames = new ArrayList<>(captures.size() + paramNameStrs.size()); + for (Variable var : captures) { + paramTypes.add(PainlessLookupUtility.typeToCanonicalTypeName(var.clazz)); + paramNames.add(var.name); + } + paramTypes.addAll(actualParamTypeStrs); + paramNames.addAll(paramNameStrs); + + // desugar lambda body into a synthetic method + String name = scriptRoot.getNextSyntheticName("lambda"); + desugared = new SFunction( + location, PainlessLookupUtility.typeToCanonicalTypeName(returnType), name, paramTypes, paramNames, + new SBlock(location, statements), true); + desugared.generateSignature(scriptRoot.getPainlessLookup()); + desugared.analyze(scriptRoot, Locals.newLambdaScope(locals.getProgramScope(), desugared.name, returnType, + desugared.parameters, captures.size(), scriptRoot.getCompilerSettings().getMaxLoopCounter())); + scriptRoot.getFunctionTable().addFunction(desugared.name, desugared.returnType, desugared.typeParameters, true); + scriptRoot.getClassNode().addFunction(desugared); + + // setup method reference to synthetic method + if (expected == null) { + ref = null; + actual = String.class; + defPointer = "Sthis." + name + "," + captures.size(); + } else { + defPointer = null; + ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), + location, expected, "this", desugared.name, captures.size()); + actual = expected; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (ref != null) { + methodWriter.writeDebugInfo(location); + // load captures + for (Variable capture : captures) { + methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + } + + methodWriter.invokeLambdaCall(ref); + } else { + // placeholder + methodWriter.push((String)null); + // load captures + for (Variable capture : captures) { + methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + } + } + } + + @Override + public String getPointer() { + return defPointer; + } + + @Override + 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).clazz); + } + return types; + } + + @Override + public String toString() { + return multilineToString(pairwiseToString(paramTypeStrs, paramNameStrs), statements); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java new file mode 100644 index 0000000000000..b0ad7a1a10112 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; + +/** + * Represents a list initialization shortcut. + */ +public final class EListInit extends AExpression { + private final List values; + + private PainlessConstructor constructor = null; + private PainlessMethod method = null; + + public EListInit(Location location, List values) { + super(location); + + this.values = values; + } + + @Override + void extractVariables(Set variables) { + for (AExpression value : values) { + value.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from list initializer.")); + } + + actual = ArrayList.class; + + constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, 0); + + if (constructor == null) { + throw createError(new IllegalArgumentException( + "constructor [" + typeToCanonicalTypeName(actual) + ", /0] not found")); + } + + method = scriptRoot.getPainlessLookup().lookupPainlessMethod(actual, false, "add", 1); + + if (method == null) { + throw createError(new IllegalArgumentException("method [" + typeToCanonicalTypeName(actual) + ", add/1] not found")); + } + + for (int index = 0; index < values.size(); ++index) { + AExpression expression = values.get(index); + + expression.expected = def.class; + expression.internal = true; + expression.analyze(scriptRoot, locals); + values.set(index, expression.cast(scriptRoot, locals)); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.newInstance(MethodWriter.getType(actual)); + methodWriter.dup(); + methodWriter.invokeConstructor( + Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + + for (AExpression value : values) { + methodWriter.dup(); + value.write(classWriter, methodWriter, globals); + methodWriter.invokeMethodCall(method); + methodWriter.pop(); + } + } + + @Override + public String toString() { + return singleLineToString(values); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java new file mode 100644 index 0000000000000..6b2c1861bf39d --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java @@ -0,0 +1,137 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; + +/** + * Represents a map initialization shortcut. + */ +public final class EMapInit extends AExpression { + private final List keys; + private final List values; + + private PainlessConstructor constructor = null; + private PainlessMethod method = null; + + public EMapInit(Location location, List keys, List values) { + super(location); + + this.keys = keys; + this.values = values; + } + + @Override + void extractVariables(Set variables) { + for (AExpression key : keys) { + key.extractVariables(variables); + } + + for (AExpression value : values) { + value.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from map initializer.")); + } + + actual = HashMap.class; + + constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, 0); + + if (constructor == null) { + throw createError(new IllegalArgumentException( + "constructor [" + typeToCanonicalTypeName(actual) + ", /0] not found")); + } + + method = scriptRoot.getPainlessLookup().lookupPainlessMethod(actual, false, "put", 2); + + if (method == null) { + throw createError(new IllegalArgumentException("method [" + typeToCanonicalTypeName(actual) + ", put/2] not found")); + } + + if (keys.size() != values.size()) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + for (int index = 0; index < keys.size(); ++index) { + AExpression expression = keys.get(index); + + expression.expected = def.class; + expression.internal = true; + expression.analyze(scriptRoot, locals); + keys.set(index, expression.cast(scriptRoot, locals)); + } + + for (int index = 0; index < values.size(); ++index) { + AExpression expression = values.get(index); + + expression.expected = def.class; + expression.internal = true; + expression.analyze(scriptRoot, locals); + values.set(index, expression.cast(scriptRoot, locals)); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.newInstance(MethodWriter.getType(actual)); + methodWriter.dup(); + methodWriter.invokeConstructor( + Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + + for (int index = 0; index < keys.size(); ++index) { + AExpression key = keys.get(index); + AExpression value = values.get(index); + + methodWriter.dup(); + key.write(classWriter, methodWriter, globals); + value.write(classWriter, methodWriter, globals); + methodWriter.invokeMethodCall(method); + methodWriter.pop(); + } + } + + @Override + public String toString() { + return singleLineToString(pairwiseToString(keys, values)); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java new file mode 100644 index 0000000000000..03ec8a57fc02d --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Represents an array instantiation. + */ +public final class ENewArray extends AExpression { + + private final String type; + private final List arguments; + private final boolean initialize; + + public ENewArray(Location location, String type, List arguments, boolean initialize) { + super(location); + + this.type = Objects.requireNonNull(type); + this.arguments = Objects.requireNonNull(arguments); + this.initialize = initialize; + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("A newly created array must be read from.")); + } + + Class clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); + + if (clazz == null) { + throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); + } + + for (int argument = 0; argument < arguments.size(); ++argument) { + AExpression expression = arguments.get(argument); + + expression.expected = initialize ? clazz.getComponentType() : int.class; + expression.internal = true; + expression.analyze(scriptRoot, locals); + arguments.set(argument, expression.cast(scriptRoot, locals)); + } + + actual = clazz; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (initialize) { + methodWriter.push(arguments.size()); + methodWriter.newArray(MethodWriter.getType(actual.getComponentType())); + + for (int index = 0; index < arguments.size(); ++index) { + AExpression argument = arguments.get(index); + + methodWriter.dup(); + methodWriter.push(index); + argument.write(classWriter, methodWriter, globals); + methodWriter.arrayStore(MethodWriter.getType(actual.getComponentType())); + } + } else { + for (AExpression argument : arguments) { + argument.write(classWriter, methodWriter, globals); + } + + if (arguments.size() > 1) { + methodWriter.visitMultiANewArrayInsn(MethodWriter.getType(actual).getDescriptor(), arguments.size()); + } else { + methodWriter.newArray(MethodWriter.getType(actual.getComponentType())); + } + } + } + + @Override + public String toString() { + return singleLineToStringWithOptionalArgs(arguments, type, initialize ? "init" : "dims"); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java new file mode 100644 index 0000000000000..f496dec4321a9 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java @@ -0,0 +1,108 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.FunctionRef; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Type; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +/** + * Represents a function reference. + */ +public final class ENewArrayFunctionRef extends AExpression implements ILambda { + private final String type; + + private SFunction function; + private FunctionRef ref; + private String defPointer; + + public ENewArrayFunctionRef(Location location, String type) { + super(location); + + this.type = Objects.requireNonNull(type); + } + + @Override + void extractVariables(Set variables) { + // do nothing + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + SReturn code = new SReturn(location, new ENewArray(location, type, Arrays.asList(new EVariable(location, "size")), false)); + function = new SFunction( + location, type, scriptRoot.getNextSyntheticName("newarray"), + Collections.singletonList("int"), Collections.singletonList("size"), + new SBlock(location, Collections.singletonList(code)), true); + function.generateSignature(scriptRoot.getPainlessLookup()); + function.extractVariables(null); + function.analyze(scriptRoot, Locals.newLambdaScope(locals.getProgramScope(), function.name, function.returnType, + function.parameters, 0, scriptRoot.getCompilerSettings().getMaxLoopCounter())); + scriptRoot.getFunctionTable().addFunction(function.name, function.returnType, function.typeParameters, true); + scriptRoot.getClassNode().addFunction(function); + + if (expected == null) { + ref = null; + actual = String.class; + defPointer = "Sthis." + function.name + ",0"; + } else { + defPointer = null; + ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), + location, expected, "this", function.name, 0); + actual = expected; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (ref != null) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeLambdaCall(ref); + } else { + // push a null instruction as a placeholder for future lambda instructions + methodWriter.push((String)null); + } + } + + @Override + public String getPointer() { + return defPointer; + } + + @Override + public Type[] getCaptures() { + return new Type[0]; // no captures + } + + @Override + public String toString() { + return singleLineToString(type + "[]", "new"); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java new file mode 100644 index 0000000000000..5f17cd9696473 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java @@ -0,0 +1,121 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; + +/** + * Represents and object instantiation. + */ +public final class ENewObj extends AExpression { + + private final String type; + private final List arguments; + + private PainlessConstructor constructor; + + public ENewObj(Location location, String type, List arguments) { + super(location); + + this.type = Objects.requireNonNull(type); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); + + if (actual == null) { + throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); + } + + constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, arguments.size()); + + if (constructor == null) { + throw createError(new IllegalArgumentException( + "constructor [" + typeToCanonicalTypeName(actual) + ", /" + arguments.size() + "] not found")); + } + + Class[] types = new Class[constructor.typeParameters.size()]; + constructor.typeParameters.toArray(types); + + if (constructor.typeParameters.size() != arguments.size()) { + throw createError(new IllegalArgumentException( + "When calling constructor on type [" + PainlessLookupUtility.typeToCanonicalTypeName(actual) + "] " + + "expected [" + constructor.typeParameters.size() + "] arguments, but found [" + arguments.size() + "].")); + } + + for (int argument = 0; argument < arguments.size(); ++argument) { + AExpression expression = arguments.get(argument); + + expression.expected = types[argument]; + expression.internal = true; + expression.analyze(scriptRoot, locals); + arguments.set(argument, expression.cast(scriptRoot, locals)); + } + + statement = true; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.newInstance(MethodWriter.getType(actual)); + + if (read) { + methodWriter.dup(); + } + + for (AExpression argument : arguments) { + argument.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeConstructor( + Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + } + + @Override + public String toString() { + return singleLineToStringWithOptionalArgs(arguments, type); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java new file mode 100644 index 0000000000000..7520700885f9e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Opcodes; + +import java.util.Set; + +/** + * Represents a null constant. + */ +public final class ENull extends AExpression { + + public ENull(Location location) { + super(location); + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from null constant.")); + } + + isNull = true; + + if (expected != null) { + if (expected.isPrimitive()) { + throw createError(new IllegalArgumentException( + "Cannot cast null to a primitive type [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "].")); + } + + actual = expected; + } else { + actual = Object.class; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.visitInsn(Opcodes.ACONST_NULL); + } + + @Override + public String toString() { + return singleLineToString(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java new file mode 100644 index 0000000000000..4778670979c69 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java @@ -0,0 +1,131 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a non-decimal numeric constant. + */ +public final class ENumeric extends AExpression { + + private final String value; + private int radix; + + public ENumeric(Location location, String value, int radix) { + super(location); + + this.value = Objects.requireNonNull(value); + this.radix = radix; + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from constant [" + value + "].")); + } + + if (value.endsWith("d") || value.endsWith("D")) { + if (radix != 10) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + try { + constant = Double.parseDouble(value.substring(0, value.length() - 1)); + actual = double.class; + } catch (NumberFormatException exception) { + throw createError(new IllegalArgumentException("Invalid double constant [" + value + "].")); + } + } else if (value.endsWith("f") || value.endsWith("F")) { + if (radix != 10) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + try { + constant = Float.parseFloat(value.substring(0, value.length() - 1)); + actual = float.class; + } catch (NumberFormatException exception) { + throw createError(new IllegalArgumentException("Invalid float constant [" + value + "].")); + } + } else if (value.endsWith("l") || value.endsWith("L")) { + try { + constant = Long.parseLong(value.substring(0, value.length() - 1), radix); + actual = long.class; + } catch (NumberFormatException exception) { + throw createError(new IllegalArgumentException("Invalid long constant [" + value + "].")); + } + } else { + try { + Class sort = expected == null ? int.class : expected; + int integer = Integer.parseInt(value, radix); + + if (sort == byte.class && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) { + constant = (byte)integer; + actual = byte.class; + } else if (sort == char.class && integer >= Character.MIN_VALUE && integer <= Character.MAX_VALUE) { + constant = (char)integer; + actual = char.class; + } else if (sort == short.class && integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) { + constant = (short)integer; + actual = short.class; + } else { + constant = integer; + actual = int.class; + } + } catch (NumberFormatException exception) { + try { + // Check if we can parse as a long. If so then hint that the user might prefer that. + Long.parseLong(value, radix); + throw createError(new IllegalArgumentException("Invalid int constant [" + value + "]. If you want a long constant " + + "then change it to [" + value + "L].")); + } catch (NumberFormatException longNoGood) { + // Ignored + } + throw createError(new IllegalArgumentException("Invalid int constant [" + value + "].")); + } + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + public String toString() { + if (radix != 10) { + return singleLineToString(value, radix); + } + return singleLineToString(value); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java new file mode 100644 index 0000000000000..210894e86fa4c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java @@ -0,0 +1,137 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Constant; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.WriterConstants; + +import java.lang.reflect.Modifier; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Represents a regex constant. All regexes are constants. + */ +public final class ERegex extends AExpression { + + private final String pattern; + private final int flags; + private Constant constant; + + public ERegex(Location location, String pattern, String flagsString) { + super(location); + + this.pattern = pattern; + + int flags = 0; + + for (int c = 0; c < flagsString.length(); c++) { + flags |= flagForChar(flagsString.charAt(c)); + } + + this.flags = flags; + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (scriptRoot.getCompilerSettings().areRegexesEnabled() == false) { + throw createError(new IllegalStateException("Regexes are disabled. Set [script.painless.regex.enabled] to [true] " + + "in elasticsearch.yaml to allow them. Be careful though, regexes break out of Painless's protection against deep " + + "recursion and long loops.")); + } + + if (!read) { + throw createError(new IllegalArgumentException("Regex constant may only be read [" + pattern + "].")); + } + + try { + Pattern.compile(pattern, flags); + } catch (PatternSyntaxException e) { + throw new Location(location.getSourceName(), location.getOffset() + 1 + e.getIndex()).createError( + new IllegalArgumentException("Error compiling regex: " + e.getDescription())); + } + + String name = scriptRoot.getNextSyntheticName("regex"); + scriptRoot.getClassNode().addField( + new SField(location, Modifier.FINAL | Modifier.STATIC | Modifier.PRIVATE, name, Pattern.class, null)); + constant = new Constant(location, MethodWriter.getType(Pattern.class), name, this::initializeConstant); + actual = Pattern.class; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.getStatic(WriterConstants.CLASS_TYPE, constant.name, org.objectweb.asm.Type.getType(Pattern.class)); + globals.addConstantInitializer(constant); + } + + private void initializeConstant(MethodWriter writer) { + writer.push(pattern); + writer.push(flags); + writer.invokeStatic(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_COMPILE); + } + + private int flagForChar(char c) { + switch (c) { + case 'c': return Pattern.CANON_EQ; + case 'i': return Pattern.CASE_INSENSITIVE; + case 'l': return Pattern.LITERAL; + case 'm': return Pattern.MULTILINE; + case 's': return Pattern.DOTALL; + case 'U': return Pattern.UNICODE_CHARACTER_CLASS; + case 'u': return Pattern.UNICODE_CASE; + case 'x': return Pattern.COMMENTS; + default: + throw new IllegalArgumentException("Unknown flag [" + c + "]"); + } + } + + @Override + public String toString() { + StringBuilder f = new StringBuilder(); + if ((flags & Pattern.CANON_EQ) != 0) f.append('c'); + if ((flags & Pattern.CASE_INSENSITIVE) != 0) f.append('i'); + if ((flags & Pattern.LITERAL) != 0) f.append('l'); + if ((flags & Pattern.MULTILINE) != 0) f.append('m'); + if ((flags & Pattern.DOTALL) != 0) f.append('s'); + if ((flags & Pattern.UNICODE_CHARACTER_CLASS) != 0) f.append('U'); + if ((flags & Pattern.UNICODE_CASE) != 0) f.append('u'); + if ((flags & Pattern.COMMENTS) != 0) f.append('x'); + + String p = "/" + pattern + "/"; + if (f.length() == 0) { + return singleLineToString(p); + } + return singleLineToString(p, f); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java new file mode 100644 index 0000000000000..d1d50a5d590eb --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a static type target. + */ +public final class EStatic extends AExpression { + + private final String type; + + public EStatic(Location location, String type) { + super(location); + + this.type = Objects.requireNonNull(type); + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(type); + + if (actual == null) { + throw createError(new IllegalArgumentException("Not a type [" + type + "].")); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // Do nothing. + } + + @Override + public String toString() { + return singleLineToString(type); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java new file mode 100644 index 0000000000000..79120549de165 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java @@ -0,0 +1,66 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a string constant. + */ +public final class EString extends AExpression { + + public EString(Location location, String string) { + super(location); + + this.constant = Objects.requireNonNull(string); + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!read) { + throw createError(new IllegalArgumentException("Must read from constant [" + constant + "].")); + } + + actual = String.class; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + public String toString() { + return singleLineToString("'" + constant.toString() + "'"); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java new file mode 100644 index 0000000000000..186c11aa70f47 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java @@ -0,0 +1,257 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a unary math expression. + */ +public final class EUnary extends AExpression { + + private final Operation operation; + private AExpression child; + + private Class promote; + private boolean originallyExplicit = false; // record whether there was originally an explicit cast + + public EUnary(Location location, Operation operation, AExpression child) { + super(location); + + this.operation = Objects.requireNonNull(operation); + this.child = Objects.requireNonNull(child); + } + + @Override + void extractVariables(Set variables) { + child.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + originallyExplicit = explicit; + + if (operation == Operation.NOT) { + analyzeNot(scriptRoot, locals); + } else if (operation == Operation.BWNOT) { + analyzeBWNot(scriptRoot, locals); + } else if (operation == Operation.ADD) { + analyzerAdd(scriptRoot, locals); + } else if (operation == Operation.SUB) { + analyzerSub(scriptRoot, locals); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + void analyzeNot(ScriptRoot scriptRoot, Locals variables) { + child.expected = boolean.class; + child.analyze(scriptRoot, variables); + child = child.cast(scriptRoot, variables); + + if (child.constant != null) { + constant = !(boolean)child.constant; + } + + actual = boolean.class; + } + + void analyzeBWNot(ScriptRoot scriptRoot, Locals variables) { + child.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(child.actual, false); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply not [~] to type " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(child.actual) + "].")); + } + + child.expected = promote; + child = child.cast(scriptRoot, variables); + + if (child.constant != null) { + if (promote == int.class) { + constant = ~(int)child.constant; + } else if (promote == long.class) { + constant = ~(long)child.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + if (promote == def.class && expected != null) { + actual = expected; + } else { + actual = promote; + } + } + + void analyzerAdd(ScriptRoot scriptRoot, Locals variables) { + child.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(child.actual, true); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply positive [+] to type " + + "[" + PainlessLookupUtility.typeToJavaType(child.actual) + "].")); + } + + child.expected = promote; + child = child.cast(scriptRoot, variables); + + if (child.constant != null) { + if (promote == int.class) { + constant = +(int)child.constant; + } else if (promote == long.class) { + constant = +(long)child.constant; + } else if (promote == float.class) { + constant = +(float)child.constant; + } else if (promote == double.class) { + constant = +(double)child.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + if (promote == def.class && expected != null) { + actual = expected; + } else { + actual = promote; + } + } + + void analyzerSub(ScriptRoot scriptRoot, Locals variables) { + child.analyze(scriptRoot, variables); + + promote = AnalyzerCaster.promoteNumeric(child.actual, true); + + if (promote == null) { + throw createError(new ClassCastException("Cannot apply negative [-] to type " + + "[" + PainlessLookupUtility.typeToJavaType(child.actual) + "].")); + } + + child.expected = promote; + child = child.cast(scriptRoot, variables); + + if (child.constant != null) { + if (promote == int.class) { + constant = -(int)child.constant; + } else if (promote == long.class) { + constant = -(long)child.constant; + } else if (promote == float.class) { + constant = -(float)child.constant; + } else if (promote == double.class) { + constant = -(double)child.constant; + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + if (promote == def.class && expected != null) { + actual = expected; + } else { + actual = promote; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (operation == Operation.NOT) { + Label fals = new Label(); + Label end = new Label(); + + child.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + methodWriter.push(false); + methodWriter.goTo(end); + methodWriter.mark(fals); + methodWriter.push(true); + methodWriter.mark(end); + } else { + child.write(classWriter, methodWriter, globals); + + // Def calls adopt the wanted return value. If there was a narrowing cast, + // we need to flag that so that it's done at runtime. + int defFlags = 0; + + if (originallyExplicit) { + defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; + } + + Type actualType = MethodWriter.getType(actual); + Type childType = MethodWriter.getType(child.actual); + + if (operation == Operation.BWNOT) { + if (promote == def.class) { + org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); + methodWriter.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); + } else { + if (promote == int.class) { + methodWriter.push(-1); + } else if (promote == long.class) { + methodWriter.push(-1L); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + methodWriter.math(MethodWriter.XOR, actualType); + } + } else if (operation == Operation.SUB) { + if (promote == def.class) { + org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); + methodWriter.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); + } else { + methodWriter.math(MethodWriter.NEG, actualType); + } + } else if (operation == Operation.ADD) { + if (promote == def.class) { + org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); + methodWriter.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); + } + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + @Override + public String toString() { + return singleLineToString(operation.symbol, child); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java new file mode 100644 index 0000000000000..5a279b3a162f3 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +/** + * Interface for lambda/method reference nodes. They need special handling by LDefCall. + *

+ * This is because they know nothing about the target interface, and can only push + * all their captures onto the stack and defer everything until link-time. + */ +interface ILambda { + + /** Returns reference to resolve at link-time */ + String getPointer(); + + /** Returns the types of captured parameters. Can be empty */ + org.objectweb.asm.Type[] getCaptures(); + + /** Returns the number of captured parameters */ + default int getCaptureCount() { + return getCaptures().length; + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java new file mode 100644 index 0000000000000..acad8a9aab0a4 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public interface IRNode { + + /** Writes bytecode for Java class creation. */ + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals); + + default int accessElementCount() {throw new UnsupportedOperationException();} + default void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + default void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + default void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java new file mode 100644 index 0000000000000..f029337a3d7e3 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java @@ -0,0 +1,126 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Represents an array load/store and defers to a child subnode. + */ +public final class PBrace extends AStoreable { + + private AExpression index; + + private AStoreable sub = null; + + public PBrace(Location location, AExpression prefix, AExpression index) { + super(location, prefix); + + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + prefix.extractVariables(variables); + index.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + prefix.analyze(scriptRoot, locals); + prefix.expected = prefix.actual; + prefix = prefix.cast(scriptRoot, locals); + + if (prefix.actual.isArray()) { + sub = new PSubBrace(location, prefix.actual, index); + } else if (prefix.actual == def.class) { + sub = new PSubDefArray(location, index); + } else if (Map.class.isAssignableFrom(prefix.actual)) { + sub = new PSubMapShortcut(location, prefix.actual, index); + } else if (List.class.isAssignableFrom(prefix.actual)) { + sub = new PSubListShortcut(location, prefix.actual, index); + } else { + throw createError(new IllegalArgumentException("Illegal array access on type " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "].")); + } + + sub.write = write; + sub.read = read; + sub.expected = expected; + sub.explicit = explicit; + sub.analyze(scriptRoot, locals); + actual = sub.actual; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefix.write(classWriter, methodWriter, globals); + sub.write(classWriter, methodWriter, globals); + } + + @Override + boolean isDefOptimized() { + return sub.isDefOptimized(); + } + + @Override + void updateActual(Class actual) { + sub.updateActual(actual); + this.actual = actual; + } + + @Override + int accessElementCount() { + return sub.accessElementCount(); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefix.write(classWriter, methodWriter, globals); + sub.setup(classWriter, methodWriter, globals); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + sub.load(classWriter, methodWriter, globals); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + sub.store(classWriter, methodWriter, globals); + } + + @Override + public String toString() { + return singleLineToString(prefix, index); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java new file mode 100644 index 0000000000000..47bd54c288640 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java @@ -0,0 +1,107 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; + +/** + * Represents a method call and defers to a child subnode. + */ +public final class PCallInvoke extends AExpression { + + private final String name; + private final boolean nullSafe; + private final List arguments; + + private AExpression sub = null; + + public PCallInvoke(Location location, AExpression prefix, String name, boolean nullSafe, List arguments) { + super(location, prefix); + + this.name = Objects.requireNonNull(name); + this.nullSafe = nullSafe; + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + prefix.extractVariables(variables); + + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + prefix.analyze(scriptRoot, locals); + prefix.expected = prefix.actual; + prefix = prefix.cast(scriptRoot, locals); + + if (prefix.actual == def.class) { + sub = new PSubDefCall(location, name, arguments); + } else { + PainlessMethod method = + scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, prefix instanceof EStatic, name, arguments.size()); + + if (method == null) { + throw createError(new IllegalArgumentException( + "method [" + typeToCanonicalTypeName(prefix.actual) + ", " + name + "/" + arguments.size() + "] not found")); + } + + sub = new PSubCallInvoke(location, method, prefix.actual, arguments); + } + + if (nullSafe) { + sub = new PSubNullSafeCallInvoke(location, sub); + } + + sub.expected = expected; + sub.explicit = explicit; + sub.analyze(scriptRoot, locals); + actual = sub.actual; + + statement = true; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefix.write(classWriter, methodWriter, globals); + sub.write(classWriter, methodWriter, globals); + } + + @Override + public String toString() { + return singleLineToStringWithOptionalArgs(arguments, prefix, name); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java new file mode 100644 index 0000000000000..a5486524585b6 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java @@ -0,0 +1,171 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; + +/** + * Represents a field load/store and defers to a child subnode. + */ +public final class PField extends AStoreable { + + private final boolean nullSafe; + private final String value; + + private AStoreable sub = null; + + public PField(Location location, AExpression prefix, boolean nullSafe, String value) { + super(location, prefix); + + this.nullSafe = nullSafe; + this.value = Objects.requireNonNull(value); + } + + @Override + void extractVariables(Set variables) { + prefix.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + prefix.analyze(scriptRoot, locals); + prefix.expected = prefix.actual; + prefix = prefix.cast(scriptRoot, locals); + + if (prefix.actual.isArray()) { + sub = new PSubArrayLength(location, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), value); + } else if (prefix.actual == def.class) { + sub = new PSubDefField(location, value); + } else { + PainlessField field = scriptRoot.getPainlessLookup().lookupPainlessField(prefix.actual, prefix instanceof EStatic, value); + + if (field == null) { + PainlessMethod getter; + PainlessMethod setter; + + getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false, + "get" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0); + + if (getter == null) { + getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false, + "is" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0); + } + + setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false, + "set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0); + + if (getter != null || setter != null) { + sub = new PSubShortcut(location, value, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), getter, setter); + } else { + EConstant index = new EConstant(location, value); + index.analyze(scriptRoot, locals); + + if (Map.class.isAssignableFrom(prefix.actual)) { + sub = new PSubMapShortcut(location, prefix.actual, index); + } + + if (List.class.isAssignableFrom(prefix.actual)) { + sub = new PSubListShortcut(location, prefix.actual, index); + } + } + + if (sub == null) { + throw createError(new IllegalArgumentException( + "field [" + typeToCanonicalTypeName(prefix.actual) + ", " + value + "] not found")); + } + } else { + sub = new PSubField(location, field); + } + } + + if (nullSafe) { + sub = new PSubNullSafeField(location, sub); + } + + sub.write = write; + sub.read = read; + sub.expected = expected; + sub.explicit = explicit; + sub.analyze(scriptRoot, locals); + actual = sub.actual; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefix.write(classWriter, methodWriter, globals); + sub.write(classWriter, methodWriter, globals); + } + + @Override + boolean isDefOptimized() { + return sub.isDefOptimized(); + } + + @Override + void updateActual(Class actual) { + sub.updateActual(actual); + this.actual = actual; + } + + @Override + int accessElementCount() { + return sub.accessElementCount(); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefix.write(classWriter, methodWriter, globals); + sub.setup(classWriter, methodWriter, globals); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + sub.load(classWriter, methodWriter, globals); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + sub.store(classWriter, methodWriter, globals); + } + + @Override + public String toString() { + if (nullSafe) { + return singleLineToString("nullSafe", prefix, value); + } + return singleLineToString(prefix, value); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java new file mode 100644 index 0000000000000..07f5e690e2373 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java @@ -0,0 +1,105 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents an array length field load. + */ +final class PSubArrayLength extends AStoreable { + + private final String type; + private final String value; + + PSubArrayLength(Location location, String type, String value) { + super(location); + + this.type = Objects.requireNonNull(type); + this.value = Objects.requireNonNull(value); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if ("length".equals(value)) { + if (write) { + throw createError(new IllegalArgumentException("Cannot write to read-only field [length] for an array.")); + } + + actual = int.class; + } else { + throw createError(new IllegalArgumentException("Field [" + value + "] does not exist for type [" + type + "].")); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.arrayLength(); + } + + @Override + int accessElementCount() { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + boolean isDefOptimized() { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + void updateActual(Class actual) { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw new IllegalStateException("Illegal tree structure."); + } + + @Override + public String toString() { + return singleLineToString(prefix); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java new file mode 100644 index 0000000000000..a793c55f81b6c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java @@ -0,0 +1,104 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents an array load/store. + */ +final class PSubBrace extends AStoreable { + + private final Class clazz; + private AExpression index; + + PSubBrace(Location location, Class clazz, AExpression index) { + super(location); + + this.clazz = Objects.requireNonNull(clazz); + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("illegal tree structure")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + index.expected = int.class; + index.analyze(scriptRoot, locals); + index = index.cast(scriptRoot, locals); + + actual = clazz.getComponentType(); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + setup(classWriter, methodWriter, globals); + load(classWriter, methodWriter, globals); + } + + @Override + int accessElementCount() { + return 2; + } + + @Override + boolean isDefOptimized() { + return false; + } + + @Override + void updateActual(Class actual) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + index.write(classWriter, methodWriter, globals); + writeIndexFlip(methodWriter, MethodWriter::arrayLength); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.arrayLoad(MethodWriter.getType(actual)); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.arrayStore(MethodWriter.getType(actual)); + } + + @Override + public String toString() { + return singleLineToString(prefix, index); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java new file mode 100644 index 0000000000000..34ff18ffec338 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Represents a method call. + */ +final class PSubCallInvoke extends AExpression { + + private final PainlessMethod method; + private final Class box; + private final List arguments; + + PSubCallInvoke(Location location, PainlessMethod method, Class box, List arguments) { + super(location); + + this.method = Objects.requireNonNull(method); + this.box = box; + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + for (int argument = 0; argument < arguments.size(); ++argument) { + AExpression expression = arguments.get(argument); + + expression.expected = method.typeParameters.get(argument); + expression.internal = true; + expression.analyze(scriptRoot, locals); + arguments.set(argument, expression.cast(scriptRoot, locals)); + } + + statement = true; + actual = method.returnType; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (box.isPrimitive()) { + methodWriter.box(MethodWriter.getType(box)); + } + + for (AExpression argument : arguments) { + argument.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeMethodCall(method); + } + + @Override + public String toString() { + return singleLineToStringWithOptionalArgs(arguments, prefix, method.javaMethod.getName()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java new file mode 100644 index 0000000000000..8ac360b200237 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java @@ -0,0 +1,116 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Type; + +import java.time.ZonedDateTime; +import java.util.Objects; +import java.util.Set; + +/** + * Represents an array load/store or shortcut on a def type. (Internal only.) + */ +final class PSubDefArray extends AStoreable { + private AExpression index; + + PSubDefArray(Location location, AExpression index) { + super(location); + + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + index.analyze(scriptRoot, locals); + index.expected = index.actual; + index = index.cast(scriptRoot, locals); + + // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed + actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + setup(classWriter, methodWriter, globals); + load(classWriter, methodWriter, globals); + } + + @Override + int accessElementCount() { + return 2; + } + + @Override + boolean isDefOptimized() { + return true; + } + + @Override + void updateActual(Class actual) { + this.actual = actual; + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.dup(); + index.write(classWriter, methodWriter, globals); + Type methodType = Type.getMethodType( + MethodWriter.getType(index.actual), Type.getType(Object.class), MethodWriter.getType(index.actual)); + methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Type methodType = + Type.getMethodType(MethodWriter.getType(actual), Type.getType(Object.class), MethodWriter.getType(index.actual)); + methodWriter.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Type methodType = + Type.getMethodType( + Type.getType(void.class), Type.getType(Object.class), MethodWriter.getType(index.actual), MethodWriter.getType(actual)); + methodWriter.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE); + } + + @Override + public String toString() { + return singleLineToString(prefix, index); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java new file mode 100644 index 0000000000000..795ce7d566a49 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java @@ -0,0 +1,128 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Type; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Represents a method call made on a def type. (Internal only.) + */ +final class PSubDefCall extends AExpression { + + private final String name; + private final List arguments; + + private StringBuilder recipe = null; + private List pointers = new ArrayList<>(); + + PSubDefCall(Location location, String name, List arguments) { + super(location); + + this.name = Objects.requireNonNull(name); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + recipe = new StringBuilder(); + int totalCaptures = 0; + + for (int argument = 0; argument < arguments.size(); ++argument) { + AExpression expression = arguments.get(argument); + + expression.internal = true; + expression.analyze(scriptRoot, locals); + + if (expression instanceof ILambda) { + ILambda lambda = (ILambda) expression; + pointers.add(lambda.getPointer()); + // encode this parameter as a deferred reference + char ch = (char) (argument + totalCaptures); + recipe.append(ch); + totalCaptures += lambda.getCaptureCount(); + } + + if (expression.actual == void.class) { + throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "].")); + } + + expression.expected = expression.actual; + arguments.set(argument, expression.cast(scriptRoot, locals)); + } + + // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed + actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + List parameterTypes = new ArrayList<>(); + + // first parameter is the receiver, we never know its type: always Object + parameterTypes.add(org.objectweb.asm.Type.getType(Object.class)); + + // append each argument + for (AExpression argument : arguments) { + parameterTypes.add(MethodWriter.getType(argument.actual)); + + if (argument instanceof ILambda) { + ILambda lambda = (ILambda) argument; + Collections.addAll(parameterTypes, lambda.getCaptures()); + } + + argument.write(classWriter, methodWriter, globals); + } + + // create method type from return value and arguments + Type methodType = Type.getMethodType(MethodWriter.getType(actual), parameterTypes.toArray(new Type[0])); + + List args = new ArrayList<>(); + args.add(recipe.toString()); + args.addAll(pointers); + methodWriter.invokeDefCall(name, methodType, DefBootstrap.METHOD_CALL, args.toArray()); + } + + @Override + public String toString() { + return singleLineToStringWithOptionalArgs(arguments, prefix, name); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java new file mode 100644 index 0000000000000..441762a0c58cf --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java @@ -0,0 +1,110 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.def; + +import java.time.ZonedDateTime; +import java.util.Objects; +import java.util.Set; + +/** + * Represents a field load/store or shortcut on a def type. (Internal only.) + */ +final class PSubDefField extends AStoreable { + + private final String value; + + PSubDefField(Location location, String value) { + super(location); + + this.value = Objects.requireNonNull(value); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed + actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + org.objectweb.asm.Type methodType = + org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class)); + methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); + } + + @Override + int accessElementCount() { + return 1; + } + + @Override + boolean isDefOptimized() { + return true; + } + + @Override + void updateActual(Class actual) { + this.actual = actual; + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // Do nothing. + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + org.objectweb.asm.Type methodType = + org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class)); + methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( + org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(actual)); + methodWriter.invokeDefCall(value, methodType, DefBootstrap.STORE); + } + + @Override + public String toString() { + return singleLineToString(prefix, value); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java new file mode 100644 index 0000000000000..b6d683edcee4e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java @@ -0,0 +1,127 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Type; + +import java.lang.reflect.Modifier; +import java.util.Objects; +import java.util.Set; + +/** + * Represents a field load/store. + */ +final class PSubField extends AStoreable { + + private final PainlessField field; + + PSubField(Location location, PainlessField field) { + super(location); + + this.field = Objects.requireNonNull(field); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (write && Modifier.isFinal(field.javaField.getModifiers())) { + throw createError(new IllegalArgumentException("Cannot write to read-only field [" + field.javaField.getName() + "] " + + "for type [" + PainlessLookupUtility.typeToCanonicalTypeName(field.javaField.getDeclaringClass()) + "].")); + } + + actual = field.typeParameter; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { + methodWriter.getStatic(Type.getType( + field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); + } else { + methodWriter.getField(Type.getType( + field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); + } + } + + @Override + int accessElementCount() { + return 1; + } + + @Override + boolean isDefOptimized() { + return false; + } + + @Override + void updateActual(Class actual) { + throw new IllegalArgumentException("Illegal tree structure."); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + // Do nothing. + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + methodWriter.writeDebugInfo(location); + + if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { + methodWriter.getStatic(Type.getType( + field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); + } else { + methodWriter.getField(Type.getType( + field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); + } + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + methodWriter.writeDebugInfo(location); + + if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { + methodWriter.putStatic(Type.getType( + field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); + } else { + methodWriter.putField(Type.getType( + field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); + } + } + + @Override + public String toString() { + return singleLineToString(prefix, field.javaField.getName()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java new file mode 100644 index 0000000000000..9471ea8c56d64 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java @@ -0,0 +1,140 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a list load/store shortcut. (Internal only.) + */ +final class PSubListShortcut extends AStoreable { + + private final Class targetClass; + private AExpression index; + + private PainlessMethod getter; + private PainlessMethod setter; + + PSubListShortcut(Location location, Class targetClass, AExpression index) { + super(location); + + this.targetClass = Objects.requireNonNull(targetClass); + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass); + + getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1); + setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "set", 2); + + if (getter != null && (getter.returnType == void.class || getter.typeParameters.size() != 1 || + getter.typeParameters.get(0) != int.class)) { + throw createError(new IllegalArgumentException("Illegal list get shortcut for type [" + canonicalClassName + "].")); + } + + if (setter != null && (setter.typeParameters.size() != 2 || setter.typeParameters.get(0) != int.class)) { + throw createError(new IllegalArgumentException("Illegal list set shortcut for type [" + canonicalClassName + "].")); + } + + if (getter != null && setter != null && (!getter.typeParameters.get(0).equals(setter.typeParameters.get(0)) + || !getter.returnType.equals(setter.typeParameters.get(1)))) { + throw createError(new IllegalArgumentException("Shortcut argument types must match.")); + } + + if ((read || write) && (!read || getter != null) && (!write || setter != null)) { + index.expected = int.class; + index.analyze(scriptRoot, locals); + index = index.cast(scriptRoot, locals); + + actual = setter != null ? setter.typeParameters.get(1) : getter.returnType; + } else { + throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + canonicalClassName + "].")); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + setup(classWriter, methodWriter, globals); + load(classWriter, methodWriter, globals); + } + + @Override + int accessElementCount() { + return 2; + } + + @Override + boolean isDefOptimized() { + return false; + } + + @Override + void updateActual(Class actual) { + throw new IllegalArgumentException("Illegal tree structure."); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + index.write(classWriter, methodWriter, globals); + writeIndexFlip(methodWriter, w -> { + w.invokeInterface(WriterConstants.COLLECTION_TYPE, WriterConstants.COLLECTION_SIZE); + }); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(getter); + + if (getter.returnType == getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(setter); + methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); + } + + @Override + public String toString() { + return singleLineToString(prefix, index); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java new file mode 100644 index 0000000000000..1558d4ce94bb3 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java @@ -0,0 +1,141 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a map load/store shortcut. (Internal only.) + */ +final class PSubMapShortcut extends AStoreable { + + private final Class targetClass; + private AExpression index; + + private PainlessMethod getter; + private PainlessMethod setter; + + PSubMapShortcut(Location location, Class targetClass, AExpression index) { + super(location); + + this.targetClass = Objects.requireNonNull(targetClass); + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass); + + getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1); + setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "put", 2); + + if (getter != null && (getter.returnType == void.class || getter.typeParameters.size() != 1)) { + throw createError(new IllegalArgumentException("Illegal map get shortcut for type [" + canonicalClassName + "].")); + } + + if (setter != null && setter.typeParameters.size() != 2) { + throw createError(new IllegalArgumentException("Illegal map set shortcut for type [" + canonicalClassName + "].")); + } + + if (getter != null && setter != null && (!getter.typeParameters.get(0).equals(setter.typeParameters.get(0)) || + !getter.returnType.equals(setter.typeParameters.get(1)))) { + throw createError(new IllegalArgumentException("Shortcut argument types must match.")); + } + + if ((read || write) && (!read || getter != null) && (!write || setter != null)) { + index.expected = setter != null ? setter.typeParameters.get(0) : getter.typeParameters.get(0); + index.analyze(scriptRoot, locals); + index = index.cast(scriptRoot, locals); + + actual = setter != null ? setter.typeParameters.get(1) : getter.returnType; + } else { + throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + canonicalClassName + "].")); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + index.write(classWriter, methodWriter, globals); + + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(getter); + + if (getter.returnType != getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + int accessElementCount() { + return 2; + } + + @Override + boolean isDefOptimized() { + return false; + } + + @Override + void updateActual(Class actual) { + throw new IllegalArgumentException("Illegal tree structure."); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + index.write(classWriter, methodWriter, globals); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(getter); + + if (getter.returnType != getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(setter); + methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); + } + + @Override + public String toString() { + return singleLineToString(prefix, index); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java new file mode 100644 index 0000000000000..7ce2a6a8cd889 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java @@ -0,0 +1,77 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; + +import java.util.Set; + +import static java.util.Objects.requireNonNull; + +/** + * Implements a call who's value is null if the prefix is null rather than throwing an NPE. + */ +public class PSubNullSafeCallInvoke extends AExpression { + /** + * The expression gaurded by the null check. Required at construction time and replaced at analysis time. + */ + private AExpression guarded; + + public PSubNullSafeCallInvoke(Location location, AExpression guarded) { + super(location); + this.guarded = requireNonNull(guarded); + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("illegal tree structure")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + guarded.analyze(scriptRoot, locals); + actual = guarded.actual; + if (actual.isPrimitive()) { + throw new IllegalArgumentException("Result of null safe operator must be nullable"); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Label end = new Label(); + methodWriter.dup(); + methodWriter.ifNull(end); + guarded.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(guarded); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java new file mode 100644 index 0000000000000..bc9a7ac3f96b4 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java @@ -0,0 +1,105 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; + +import java.util.Set; + +/** + * Implements a field who's value is null if the prefix is null rather than throwing an NPE. + */ +public class PSubNullSafeField extends AStoreable { + private AStoreable guarded; + + public PSubNullSafeField(Location location, AStoreable guarded) { + super(location); + this.guarded = guarded; + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("illegal tree structure")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (write) { + throw createError(new IllegalArgumentException("Can't write to null safe reference")); + } + guarded.read = read; + guarded.analyze(scriptRoot, locals); + actual = guarded.actual; + if (actual.isPrimitive()) { + throw new IllegalArgumentException("Result of null safe operator must be nullable"); + } + } + + + @Override + int accessElementCount() { + return guarded.accessElementCount(); + } + + @Override + boolean isDefOptimized() { + return guarded.isDefOptimized(); + } + + @Override + void updateActual(Class actual) { + guarded.updateActual(actual); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + Label end = new Label(); + methodWriter.dup(); + methodWriter.ifNull(end); + guarded.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new IllegalArgumentException("Can't write to null safe field")); + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new IllegalArgumentException("Can't write to null safe field")); + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new IllegalArgumentException("Can't write to null safe field")); + } + + @Override + public String toString() { + return singleLineToString(guarded); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java new file mode 100644 index 0000000000000..181a04aa02b1a --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java @@ -0,0 +1,134 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.Set; + +/** + * Represents a field load/store shortcut. (Internal only.) + */ +final class PSubShortcut extends AStoreable { + + private final String value; + private final String type; + private final PainlessMethod getter; + private final PainlessMethod setter; + + PSubShortcut(Location location, String value, String type, PainlessMethod getter, PainlessMethod setter) { + super(location); + + this.value = value; + this.type = type; + this.getter = getter; + this.setter = setter; + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (getter != null && (getter.returnType == void.class || !getter.typeParameters.isEmpty())) { + throw createError(new IllegalArgumentException( + "Illegal get shortcut on field [" + value + "] for type [" + type + "].")); + } + + if (setter != null && (setter.returnType != void.class || setter.typeParameters.size() != 1)) { + throw createError(new IllegalArgumentException( + "Illegal set shortcut on field [" + value + "] for type [" + type + "].")); + } + + if (getter != null && setter != null && setter.typeParameters.get(0) != getter.returnType) { + throw createError(new IllegalArgumentException("Shortcut argument types must match.")); + } + + if ((getter != null || setter != null) && (!read || getter != null) && (!write || setter != null)) { + actual = setter != null ? setter.typeParameters.get(0) : getter.returnType; + } else { + throw createError(new IllegalArgumentException("Illegal shortcut on field [" + value + "] for type [" + type + "].")); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.invokeMethodCall(getter); + + if (!getter.returnType.equals(getter.javaMethod.getReturnType())) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + int accessElementCount() { + return 1; + } + + @Override + boolean isDefOptimized() { + return false; + } + + @Override + void updateActual(Class actual) { + throw new IllegalArgumentException("Illegal tree structure."); + } + + @Override + void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // Do nothing. + } + + @Override + void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.invokeMethodCall(getter); + + if (getter.returnType != getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.invokeMethodCall(setter); + + methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); + } + + @Override + public String toString() { + return singleLineToString(prefix, value); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java new file mode 100644 index 0000000000000..effa818280668 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java @@ -0,0 +1,97 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static java.util.Collections.emptyList; + +/** + * Represents a set of statements as a branch of control-flow. + */ +public final class SBlock extends AStatement { + + final List statements; + + public SBlock(Location location, List statements) { + super(location); + + this.statements = Collections.unmodifiableList(statements); + } + + @Override + void extractVariables(Set variables) { + for (AStatement statement : statements) { + statement.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (statements == null || statements.isEmpty()) { + throw createError(new IllegalArgumentException("A block must contain at least one statement.")); + } + + AStatement last = statements.get(statements.size() - 1); + + for (AStatement statement : statements) { + // Note that we do not need to check after the last statement because + // there is no statement that can be unreachable after the last. + if (allEscape) { + throw createError(new IllegalArgumentException("Unreachable statement.")); + } + + statement.inLoop = inLoop; + statement.lastSource = lastSource && statement == last; + statement.lastLoop = (beginLoop || lastLoop) && statement == last; + statement.analyze(scriptRoot, locals); + + methodEscape = statement.methodEscape; + loopEscape = statement.loopEscape; + allEscape = statement.allEscape; + anyContinue |= statement.anyContinue; + anyBreak |= statement.anyBreak; + statementCount += statement.statementCount; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + for (AStatement statement : statements) { + statement.continu = continu; + statement.brake = brake; + statement.write(classWriter, methodWriter, globals); + } + } + + @Override + public String toString() { + return multilineToString(emptyList(), statements); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java new file mode 100644 index 0000000000000..cc49ac7561bff --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java @@ -0,0 +1,66 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Set; + +/** + * Represents a break statement. + */ +public final class SBreak extends AStatement { + + public SBreak(Location location) { + super(location); + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!inLoop) { + throw createError(new IllegalArgumentException("Break statement outside of a loop.")); + } + + loopEscape = true; + allEscape = true; + anyBreak = true; + statementCount = 1; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.goTo(brake); + } + + @Override + public String toString() { + return singleLineToString(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java new file mode 100644 index 0000000000000..9fc6dc29fe217 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a catch block as part of a try-catch block. + */ +public final class SCatch extends AStatement { + + private final DType baseException; + private final SDeclaration declaration; + private final SBlock block; + + Label begin = null; + Label end = null; + Label exception = null; + + public SCatch(Location location, DType baseException, SDeclaration declaration, SBlock block) { + super(location); + + this.baseException = Objects.requireNonNull(baseException); + this.declaration = Objects.requireNonNull(declaration); + this.block = block; + } + + @Override + void extractVariables(Set variables) { + declaration.extractVariables(variables); + + if (block != null) { + block.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + declaration.analyze(scriptRoot, locals); + + Class baseType = baseException.resolveType(scriptRoot.getPainlessLookup()).getType(); + Class type = declaration.variable.clazz; + + if (baseType.isAssignableFrom(type) == false) { + throw createError(new ClassCastException( + "cannot cast from [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "] " + + "to [" + PainlessLookupUtility.typeToCanonicalTypeName(baseType) + "]")); + } + + if (block != null) { + block.lastSource = lastSource; + block.inLoop = inLoop; + block.lastLoop = lastLoop; + block.analyze(scriptRoot, locals); + + methodEscape = block.methodEscape; + loopEscape = block.loopEscape; + allEscape = block.allEscape; + anyContinue = block.anyContinue; + anyBreak = block.anyBreak; + statementCount = block.statementCount; + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label jump = new Label(); + + methodWriter.mark(jump); + methodWriter.visitVarInsn( + MethodWriter.getType(declaration.variable.clazz).getOpcode(Opcodes.ISTORE), declaration.variable.getSlot()); + + if (block != null) { + block.continu = continu; + block.brake = brake; + block.write(classWriter, methodWriter, globals); + } + + methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declaration.variable.clazz).getInternalName()); + + if (exception != null && (block == null || !block.allEscape)) { + methodWriter.goTo(exception); + } + } + + @Override + public String toString() { + return singleLineToString(baseException, declaration, block); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java new file mode 100644 index 0000000000000..2a9ea5319b6a4 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Set; + +/** + * Represents a continue statement. + */ +public final class SContinue extends AStatement { + + public SContinue(Location location) { + super(location); + } + + @Override + void extractVariables(Set variables) { + // Do nothing. + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (!inLoop) { + throw createError(new IllegalArgumentException("Continue statement outside of a loop.")); + } + + if (lastLoop) { + throw createError(new IllegalArgumentException("Extraneous continue statement.")); + } + + allEscape = true; + anyContinue = true; + statementCount = 1; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.goTo(continu); + } + + @Override + public String toString() { + return singleLineToString(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java new file mode 100644 index 0000000000000..220c9ec3d012c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static java.util.Collections.emptyList; + +/** + * Represents a series of declarations. + */ +public final class SDeclBlock extends AStatement { + + private final List declarations; + + public SDeclBlock(Location location, List declarations) { + super(location); + + this.declarations = Collections.unmodifiableList(declarations); + } + + @Override + void extractVariables(Set variables) { + for (SDeclaration declaration : declarations) { + declaration.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + for (SDeclaration declaration : declarations) { + declaration.analyze(scriptRoot, locals); + } + + statementCount = declarations.size(); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + for (AStatement declaration : declarations) { + declaration.write(classWriter, methodWriter, globals); + } + } + + @Override + public String toString() { + return multilineToString(emptyList(), declarations); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java new file mode 100644 index 0000000000000..bcc2036aaffd4 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java @@ -0,0 +1,108 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a single variable declaration. + */ +public final class SDeclaration extends AStatement { + + private final DType type; + private final String name; + private AExpression expression; + + Variable variable = null; + + public SDeclaration(Location location, DType type, String name, AExpression expression) { + super(location); + + this.type = Objects.requireNonNull(type); + this.name = Objects.requireNonNull(name); + this.expression = expression; + } + + @Override + void extractVariables(Set variables) { + variables.add(name); + + if (expression != null) { + expression.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + DResolvedType resolvedType = type.resolveType(scriptRoot.getPainlessLookup()); + + if (expression != null) { + expression.expected = resolvedType.getType(); + expression.analyze(scriptRoot, locals); + expression = expression.cast(scriptRoot, locals); + } + + variable = locals.addVariable(location, resolvedType.getType(), name, false); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + if (expression == null) { + Class sort = variable.clazz; + + if (sort == void.class || sort == boolean.class || sort == byte.class || + sort == short.class || sort == char.class || sort == int.class) { + methodWriter.push(0); + } else if (sort == long.class) { + methodWriter.push(0L); + } else if (sort == float.class) { + methodWriter.push(0F); + } else if (sort == double.class) { + methodWriter.push(0D); + } else { + methodWriter.visitInsn(Opcodes.ACONST_NULL); + } + } else { + expression.write(classWriter, methodWriter, globals); + } + + methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + } + + @Override + public String toString() { + if (expression == null) { + return singleLineToString(type, name); + } + return singleLineToString(type, name, expression); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java new file mode 100644 index 0000000000000..a6c9c2eb30c24 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java @@ -0,0 +1,133 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a do-while loop. + */ +public final class SDo extends AStatement { + + private final SBlock block; + private AExpression condition; + + private boolean continuous = false; + + public SDo(Location location, SBlock block, AExpression condition) { + super(location); + + this.condition = Objects.requireNonNull(condition); + this.block = block; + } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + + if (block != null) { + block.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + locals = Locals.newLocalScope(locals); + + if (block == null) { + throw createError(new IllegalArgumentException("Extraneous do while loop.")); + } + + block.beginLoop = true; + block.inLoop = true; + block.analyze(scriptRoot, locals); + + if (block.loopEscape && !block.anyContinue) { + throw createError(new IllegalArgumentException("Extraneous do while loop.")); + } + + condition.expected = boolean.class; + condition.analyze(scriptRoot, locals); + condition = condition.cast(scriptRoot, locals); + + if (condition.constant != null) { + continuous = (boolean)condition.constant; + + if (!continuous) { + throw createError(new IllegalArgumentException("Extraneous do while loop.")); + } + + if (!block.anyBreak) { + methodEscape = true; + allEscape = true; + } + } + + statementCount = 1; + + if (locals.hasVariable(Locals.LOOP)) { + loopCounter = locals.getVariable(location, Locals.LOOP); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label start = new Label(); + Label begin = new Label(); + Label end = new Label(); + + methodWriter.mark(start); + + block.continu = begin; + block.brake = end; + block.write(classWriter, methodWriter, globals); + + methodWriter.mark(begin); + + if (!continuous) { + condition.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, end); + } + + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, block.statementCount), location); + } + + methodWriter.goTo(start); + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(condition, block); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java new file mode 100644 index 0000000000000..65377aaa6e59d --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java @@ -0,0 +1,122 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a for-each loop and defers to subnodes depending on type. + */ +public class SEach extends AStatement { + + private final String type; + private final String name; + private AExpression expression; + private final SBlock block; + + private AStatement sub = null; + + public SEach(Location location, String type, String name, AExpression expression, SBlock block) { + super(location); + + this.type = Objects.requireNonNull(type); + this.name = Objects.requireNonNull(name); + this.expression = Objects.requireNonNull(expression); + this.block = block; + } + + @Override + void extractVariables(Set variables) { + variables.add(name); + + expression.extractVariables(variables); + + if (block != null) { + block.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + expression.analyze(scriptRoot, locals); + expression.expected = expression.actual; + expression = expression.cast(scriptRoot, locals); + + Class clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); + + if (clazz == null) { + throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); + } + + locals = Locals.newLocalScope(locals); + Variable variable = locals.addVariable(location, clazz, name, true); + + if (expression.actual.isArray()) { + sub = new SSubEachArray(location, variable, expression, block); + } else if (expression.actual == def.class || Iterable.class.isAssignableFrom(expression.actual)) { + sub = new SSubEachIterable(location, variable, expression, block); + } else { + throw createError(new IllegalArgumentException("Illegal for each type " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(expression.actual) + "].")); + } + + sub.analyze(scriptRoot, locals); + + if (block == null) { + throw createError(new IllegalArgumentException("Extraneous for each loop.")); + } + + block.beginLoop = true; + block.inLoop = true; + block.analyze(scriptRoot, locals); + block.statementCount = Math.max(1, block.statementCount); + + if (block.loopEscape && !block.anyContinue) { + throw createError(new IllegalArgumentException("Extraneous for loop.")); + } + + statementCount = 1; + + if (locals.hasVariable(Locals.LOOP)) { + sub.loopCounter = locals.getVariable(location, Locals.LOOP); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + sub.write(classWriter, methodWriter, globals); + } + + @Override + public String toString() { + return singleLineToString(type, name, expression, block); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java new file mode 100644 index 0000000000000..3057cd689b07f --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents the top-level node for an expression as a statement. + */ +public final class SExpression extends AStatement { + + private AExpression expression; + + public SExpression(Location location, AExpression expression) { + super(location); + + this.expression = Objects.requireNonNull(expression); + } + + @Override + void extractVariables(Set variables) { + expression.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + Class rtnType = locals.getReturnType(); + boolean isVoid = rtnType == void.class; + + expression.read = lastSource && !isVoid; + expression.analyze(scriptRoot, locals); + + if (!lastSource && !expression.statement) { + throw createError(new IllegalArgumentException("Not a statement.")); + } + + boolean rtn = lastSource && !isVoid && expression.actual != void.class; + + expression.expected = rtn ? rtnType : expression.actual; + expression.internal = rtn; + expression = expression.cast(scriptRoot, locals); + + methodEscape = rtn; + loopEscape = rtn; + allEscape = rtn; + statementCount = 1; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + expression.write(classWriter, methodWriter, globals); + + if (methodEscape) { + methodWriter.returnValue(); + } else { + methodWriter.writePop(MethodWriter.getType(expression.expected).getSize()); + } + } + + @Override + public String toString() { + return singleLineToString(expression); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java new file mode 100644 index 0000000000000..569ca608b4502 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java @@ -0,0 +1,91 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Type; + +import java.util.Set; + +/** + * Represents a member field for its parent class (internal only). + */ +public class SField extends ANode { + + private final int modifiers; + private final String name; + private final Class type; + private final Object instance; + + /** + * Standard constructor. + * @param location original location in the source + * @param modifiers java modifiers for the field + * @param name name of the field + * @param type type of the field + * @param instance initial value for the field + */ + public SField(Location location, int modifiers, String name, Class type, Object instance) { + super(location); + + this.modifiers = modifiers; + this.name = name; + this.type = type; + this.instance = instance; + } + + public String getName() { + return name; + } + + public Object getInstance() { + return instance; + } + + @Override + void extractVariables(Set variables) { + throw createError(new UnsupportedOperationException("unexpected node")); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + throw createError(new UnsupportedOperationException("unexpected node")); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + throw createError(new UnsupportedOperationException("unexpected node")); + } + + void write(ClassWriter classWriter) { + classWriter.getClassVisitor().visitField( + ClassWriter.buildAccess(modifiers, true), name, Type.getType(type).getDescriptor(), null, null).visitEnd(); + } + + @Override + public String toString() { + return singleLineToString(name, type); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java new file mode 100644 index 0000000000000..93ba16a41e1ce --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java @@ -0,0 +1,222 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Arrays; +import java.util.Set; + +import static java.util.Collections.emptyList; + +/** + * Represents a for loop. + */ +public final class SFor extends AStatement { + + private ANode initializer; + private AExpression condition; + private AExpression afterthought; + private final SBlock block; + + private boolean continuous = false; + + public SFor(Location location, ANode initializer, AExpression condition, AExpression afterthought, SBlock block) { + super(location); + + this.initializer = initializer; + this.condition = condition; + this.afterthought = afterthought; + this.block = block; + } + + @Override + void extractVariables(Set variables) { + if (initializer != null) { + initializer.extractVariables(variables); + } + + if (condition != null) { + condition.extractVariables(variables); + } + + if (afterthought != null) { + afterthought.extractVariables(variables); + } + + if (block != null) { + block.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + locals = Locals.newLocalScope(locals); + + if (initializer != null) { + if (initializer instanceof SDeclBlock) { + initializer.analyze(scriptRoot, locals); + } else if (initializer instanceof AExpression) { + AExpression initializer = (AExpression)this.initializer; + + initializer.read = false; + initializer.analyze(scriptRoot, locals); + + if (!initializer.statement) { + throw createError(new IllegalArgumentException("Not a statement.")); + } + + initializer.expected = initializer.actual; + this.initializer = initializer.cast(scriptRoot, locals); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + + if (condition != null) { + condition.expected = boolean.class; + condition.analyze(scriptRoot, locals); + condition = condition.cast(scriptRoot, locals); + + if (condition.constant != null) { + continuous = (boolean)condition.constant; + + if (!continuous) { + throw createError(new IllegalArgumentException("Extraneous for loop.")); + } + + if (block == null) { + throw createError(new IllegalArgumentException("For loop has no escape.")); + } + } + } else { + continuous = true; + } + + if (afterthought != null) { + afterthought.read = false; + afterthought.analyze(scriptRoot, locals); + + if (!afterthought.statement) { + throw createError(new IllegalArgumentException("Not a statement.")); + } + + afterthought.expected = afterthought.actual; + afterthought = afterthought.cast(scriptRoot, locals); + } + + if (block != null) { + block.beginLoop = true; + block.inLoop = true; + + block.analyze(scriptRoot, locals); + + if (block.loopEscape && !block.anyContinue) { + throw createError(new IllegalArgumentException("Extraneous for loop.")); + } + + if (continuous && !block.anyBreak) { + methodEscape = true; + allEscape = true; + } + + block.statementCount = Math.max(1, block.statementCount); + } + + statementCount = 1; + + if (locals.hasVariable(Locals.LOOP)) { + loopCounter = locals.getVariable(location, Locals.LOOP); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label start = new Label(); + Label begin = afterthought == null ? start : new Label(); + Label end = new Label(); + + if (initializer instanceof SDeclBlock) { + initializer.write(classWriter, methodWriter, globals); + } else if (initializer instanceof AExpression) { + AExpression initializer = (AExpression)this.initializer; + + initializer.write(classWriter, methodWriter, globals); + methodWriter.writePop(MethodWriter.getType(initializer.expected).getSize()); + } + + methodWriter.mark(start); + + if (condition != null && !continuous) { + condition.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, end); + } + + boolean allEscape = false; + + if (block != null) { + allEscape = block.allEscape; + + int statementCount = Math.max(1, block.statementCount); + + if (afterthought != null) { + ++statementCount; + } + + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + } + + block.continu = begin; + block.brake = end; + block.write(classWriter, methodWriter, globals); + } else { + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); + } + } + + if (afterthought != null) { + methodWriter.mark(begin); + afterthought.write(classWriter, methodWriter, globals); + methodWriter.writePop(MethodWriter.getType(afterthought.expected).getSize()); + } + + if (afterthought != null || !allEscape) { + methodWriter.goTo(start); + } + + methodWriter.mark(end); + } + + @Override + public String toString() { + return multilineToString(emptyList(), Arrays.asList(initializer, condition, afterthought, block)); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java new file mode 100644 index 0000000000000..75122903ef12f --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java @@ -0,0 +1,186 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Parameter; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Opcodes; + +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static java.util.Collections.emptyList; + +/** + * Represents a user-defined function. + */ +public final class SFunction extends AStatement { + + private final String rtnTypeStr; + public final String name; + private final List paramTypeStrs; + private final List paramNameStrs; + private final SBlock block; + public final boolean synthetic; + + private int maxLoopCounter; + + Class returnType; + List> typeParameters; + MethodType methodType; + + org.objectweb.asm.commons.Method method; + List parameters = new ArrayList<>(); + + private Variable loop = null; + + public SFunction(Location location, String rtnType, String name, + List paramTypes, List paramNames, SBlock block, + boolean synthetic) { + super(location); + + this.rtnTypeStr = Objects.requireNonNull(rtnType); + this.name = Objects.requireNonNull(name); + this.paramTypeStrs = Collections.unmodifiableList(paramTypes); + this.paramNameStrs = Collections.unmodifiableList(paramNames); + this.block = Objects.requireNonNull(block); + this.synthetic = synthetic; + } + + @Override + void extractVariables(Set variables) { + // we reset the list for function scope + // note this is not stored for this node + // but still required for lambdas + block.extractVariables(new HashSet<>()); + } + + void generateSignature(PainlessLookup painlessLookup) { + returnType = painlessLookup.canonicalTypeNameToType(rtnTypeStr); + + if (returnType == null) { + throw createError(new IllegalArgumentException("Illegal return type [" + rtnTypeStr + "] for function [" + name + "].")); + } + + if (paramTypeStrs.size() != paramNameStrs.size()) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + Class[] paramClasses = new Class[this.paramTypeStrs.size()]; + List> paramTypes = new ArrayList<>(); + + for (int param = 0; param < this.paramTypeStrs.size(); ++param) { + Class paramType = painlessLookup.canonicalTypeNameToType(this.paramTypeStrs.get(param)); + + if (paramType == null) { + throw createError(new IllegalArgumentException( + "Illegal parameter type [" + this.paramTypeStrs.get(param) + "] for function [" + name + "].")); + } + + paramClasses[param] = PainlessLookupUtility.typeToJavaType(paramType); + paramTypes.add(paramType); + parameters.add(new Parameter(location, paramNameStrs.get(param), paramType)); + } + + typeParameters = paramTypes; + methodType = MethodType.methodType(PainlessLookupUtility.typeToJavaType(returnType), paramClasses); + method = new org.objectweb.asm.commons.Method(name, MethodType.methodType( + PainlessLookupUtility.typeToJavaType(returnType), paramClasses).toMethodDescriptorString()); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + maxLoopCounter = scriptRoot.getCompilerSettings().getMaxLoopCounter(); + + if (block.statements.isEmpty()) { + throw createError(new IllegalArgumentException("Cannot generate an empty function [" + name + "].")); + } + + locals = Locals.newLocalScope(locals); + + block.lastSource = true; + block.analyze(scriptRoot, locals); + methodEscape = block.methodEscape; + + if (!methodEscape && returnType != void.class) { + throw createError(new IllegalArgumentException("Not all paths provide a return value for method [" + name + "].")); + } + + if (maxLoopCounter > 0) { + loop = locals.getVariable(null, Locals.LOOP); + } + } + + /** Writes the function to given ClassVisitor. */ + void write(ClassWriter classWriter, Globals globals) { + int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; + if (synthetic) { + access |= Opcodes.ACC_SYNTHETIC; + } + final MethodWriter methodWriter = classWriter.newMethodWriter(access, method); + methodWriter.visitCode(); + write(classWriter, methodWriter, globals); + methodWriter.endMethod(); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (maxLoopCounter > 0) { + // if there is infinite loop protection, we do this once: + // int #loop = settings.getMaxLoopCounter() + methodWriter.push(maxLoopCounter); + methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); + } + + block.write(classWriter, methodWriter, globals); + + if (!methodEscape) { + if (returnType == void.class) { + methodWriter.returnValue(); + } else { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + } + } + + @Override + public String toString() { + List description = new ArrayList<>(); + description.add(rtnTypeStr); + description.add(name); + if (false == (paramTypeStrs.isEmpty() && paramNameStrs.isEmpty())) { + description.add(joinWithName("Args", pairwiseToString(paramTypeStrs, paramNameStrs), emptyList())); + } + return multilineToString(description, block.statements); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java new file mode 100644 index 0000000000000..1f4350297dc3a --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java @@ -0,0 +1,103 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents an if block. + */ +public final class SIf extends AStatement { + + AExpression condition; + final SBlock ifblock; + + public SIf(Location location, AExpression condition, SBlock ifblock) { + super(location); + + this.condition = Objects.requireNonNull(condition); + this.ifblock = ifblock; + } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + + if (ifblock != null) { + ifblock.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + condition.expected = boolean.class; + condition.analyze(scriptRoot, locals); + condition = condition.cast(scriptRoot, locals); + + if (condition.constant != null) { + throw createError(new IllegalArgumentException("Extraneous if statement.")); + } + + if (ifblock == null) { + throw createError(new IllegalArgumentException("Extraneous if statement.")); + } + + ifblock.lastSource = lastSource; + ifblock.inLoop = inLoop; + ifblock.lastLoop = lastLoop; + + ifblock.analyze(scriptRoot, Locals.newLocalScope(locals)); + + anyContinue = ifblock.anyContinue; + anyBreak = ifblock.anyBreak; + statementCount = ifblock.statementCount; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label fals = new Label(); + + condition.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + ifblock.continu = continu; + ifblock.brake = brake; + ifblock.write(classWriter, methodWriter, globals); + + methodWriter.mark(fals); + } + + @Override + public String toString() { + return singleLineToString(condition, ifblock); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java new file mode 100644 index 0000000000000..85c23977fa5a0 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java @@ -0,0 +1,140 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; + +import static java.util.Collections.singleton; + +/** + * Represents an if/else block. + */ +public final class SIfElse extends AStatement { + + private AExpression condition; + private final SBlock ifblock; + private final SBlock elseblock; + + public SIfElse(Location location, AExpression condition, SBlock ifblock, SBlock elseblock) { + super(location); + + this.condition = Objects.requireNonNull(condition); + this.ifblock = ifblock; + this.elseblock = elseblock; + } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + + if (ifblock != null) { + ifblock.extractVariables(variables); + } + + if (elseblock != null) { + elseblock.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + condition.expected = boolean.class; + condition.analyze(scriptRoot, locals); + condition = condition.cast(scriptRoot, locals); + + if (condition.constant != null) { + throw createError(new IllegalArgumentException("Extraneous if statement.")); + } + + if (ifblock == null) { + throw createError(new IllegalArgumentException("Extraneous if statement.")); + } + + ifblock.lastSource = lastSource; + ifblock.inLoop = inLoop; + ifblock.lastLoop = lastLoop; + + ifblock.analyze(scriptRoot, Locals.newLocalScope(locals)); + + anyContinue = ifblock.anyContinue; + anyBreak = ifblock.anyBreak; + statementCount = ifblock.statementCount; + + if (elseblock == null) { + throw createError(new IllegalArgumentException("Extraneous else statement.")); + } + + elseblock.lastSource = lastSource; + elseblock.inLoop = inLoop; + elseblock.lastLoop = lastLoop; + + elseblock.analyze(scriptRoot, Locals.newLocalScope(locals)); + + methodEscape = ifblock.methodEscape && elseblock.methodEscape; + loopEscape = ifblock.loopEscape && elseblock.loopEscape; + allEscape = ifblock.allEscape && elseblock.allEscape; + anyContinue |= elseblock.anyContinue; + anyBreak |= elseblock.anyBreak; + statementCount = Math.max(ifblock.statementCount, elseblock.statementCount); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label fals = new Label(); + Label end = new Label(); + + condition.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + ifblock.continu = continu; + ifblock.brake = brake; + ifblock.write(classWriter, methodWriter, globals); + + if (!ifblock.allEscape) { + methodWriter.goTo(end); + } + + methodWriter.mark(fals); + + elseblock.continu = continu; + elseblock.brake = brake; + elseblock.write(classWriter, methodWriter, globals); + + methodWriter.mark(end); + } + + @Override + public String toString() { + return multilineToString(singleton(condition), Arrays.asList(ifblock, elseblock)); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java new file mode 100644 index 0000000000000..cfc1dd1e6da9b --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java @@ -0,0 +1,89 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; + +import java.util.Set; + +/** + * Represents a return statement. + */ +public final class SReturn extends AStatement { + + private AExpression expression; + + public SReturn(Location location, AExpression expression) { + super(location); + + this.expression = expression; + } + + @Override + void extractVariables(Set variables) { + if (expression != null) { + expression.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (expression == null) { + if (locals.getReturnType() != void.class) { + throw location.createError(new ClassCastException("Cannot cast from " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(locals.getReturnType()) + "] to " + + "[" + PainlessLookupUtility.typeToCanonicalTypeName(void.class) + "].")); + } + } else { + expression.expected = locals.getReturnType(); + expression.internal = true; + expression.analyze(scriptRoot, locals); + expression = expression.cast(scriptRoot, locals); + } + + methodEscape = true; + loopEscape = true; + allEscape = true; + + statementCount = 1; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + if (expression != null) { + expression.write(classWriter, methodWriter, globals); + } + + methodWriter.returnValue(); + } + + @Override + public String toString() { + return expression == null ? singleLineToString() : singleLineToString(expression); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java new file mode 100644 index 0000000000000..c0ce95ea68adb --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java @@ -0,0 +1,116 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a for-each loop for arrays. + */ +final class SSubEachArray extends AStatement { + private final Variable variable; + private AExpression expression; + private final SBlock block; + + private PainlessCast cast = null; + private Variable array = null; + private Variable index = null; + private Class indexed = null; + + SSubEachArray(Location location, Variable variable, AExpression expression, SBlock block) { + super(location); + + this.variable = Objects.requireNonNull(variable); + this.expression = Objects.requireNonNull(expression); + this.block = block; + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, 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. + 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 + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + expression.write(classWriter, methodWriter, globals); + methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ISTORE), array.getSlot()); + methodWriter.push(-1); + methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ISTORE), index.getSlot()); + + Label begin = new Label(); + Label end = new Label(); + + methodWriter.mark(begin); + + methodWriter.visitIincInsn(index.getSlot(), 1); + methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); + methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); + methodWriter.arrayLength(); + methodWriter.ifICmp(MethodWriter.GE, end); + + methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); + methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); + methodWriter.arrayLoad(MethodWriter.getType(indexed)); + methodWriter.writeCast(cast); + methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + } + + block.continu = begin; + block.brake = end; + block.write(classWriter, methodWriter, globals); + + methodWriter.goTo(begin); + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(variable.clazz), variable.name, expression, block); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java new file mode 100644 index 0000000000000..b6b97503555b1 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java @@ -0,0 +1,139 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Iterator; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.painless.WriterConstants.ITERATOR_HASNEXT; +import static org.elasticsearch.painless.WriterConstants.ITERATOR_NEXT; +import static org.elasticsearch.painless.WriterConstants.ITERATOR_TYPE; +import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; + +/** + * Represents a for-each loop for iterables. + */ +final class SSubEachIterable extends AStatement { + + private AExpression expression; + private final SBlock block; + private final Variable variable; + + private PainlessCast cast = null; + private Variable iterator = null; + private PainlessMethod method = null; + + SSubEachIterable(Location location, Variable variable, AExpression expression, SBlock block) { + super(location); + + this.variable = Objects.requireNonNull(variable); + this.expression = Objects.requireNonNull(expression); + this.block = block; + } + + @Override + void extractVariables(Set variables) { + throw createError(new IllegalStateException("Illegal tree structure.")); + } + + @Override + void analyze(ScriptRoot scriptRoot, 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, Iterator.class, "#itr" + location.getOffset(), true); + + if (expression.actual == def.class) { + method = null; + } else { + method = scriptRoot.getPainlessLookup().lookupPainlessMethod(expression.actual, false, "iterator", 0); + + if (method == null) { + throw createError(new IllegalArgumentException( + "method [" + typeToCanonicalTypeName(expression.actual) + ", iterator/0] not found")); + } + } + + cast = AnalyzerCaster.getLegalCast(location, def.class, variable.clazz, true, true); + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + expression.write(classWriter, methodWriter, globals); + + if (method == null) { + org.objectweb.asm.Type methodType = org.objectweb.asm.Type + .getMethodType(org.objectweb.asm.Type.getType(Iterator.class), org.objectweb.asm.Type.getType(Object.class)); + methodWriter.invokeDefCall("iterator", methodType, DefBootstrap.ITERATOR); + } else { + methodWriter.invokeMethodCall(method); + } + + methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ISTORE), iterator.getSlot()); + + Label begin = new Label(); + Label end = new Label(); + + methodWriter.mark(begin); + + methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); + methodWriter.invokeInterface(ITERATOR_TYPE, ITERATOR_HASNEXT); + methodWriter.ifZCmp(MethodWriter.EQ, end); + + methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); + methodWriter.invokeInterface(ITERATOR_TYPE, ITERATOR_NEXT); + methodWriter.writeCast(cast); + methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + } + + block.continu = begin; + block.brake = end; + block.write(classWriter, methodWriter, globals); + + methodWriter.goTo(begin); + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(variable.clazz), variable.name, expression, block); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java new file mode 100644 index 0000000000000..a8309c7f7f8a7 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a throw statement. + */ +public final class SThrow extends AStatement { + + private AExpression expression; + + public SThrow(Location location, AExpression expression) { + super(location); + + this.expression = Objects.requireNonNull(expression); + } + + @Override + void extractVariables(Set variables) { + expression.extractVariables(variables); + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + expression.expected = Exception.class; + expression.analyze(scriptRoot, locals); + expression = expression.cast(scriptRoot, locals); + + methodEscape = true; + loopEscape = true; + allEscape = true; + statementCount = 1; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + expression.write(classWriter, methodWriter, globals); + methodWriter.throwException(); + } + + @Override + public String toString() { + return singleLineToString(expression); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java new file mode 100644 index 0000000000000..67b038158cbc1 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java @@ -0,0 +1,136 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static java.util.Collections.singleton; + +/** + * Represents the try block as part of a try-catch block. + */ +public final class STry extends AStatement { + + private final SBlock block; + private final List catches; + + public STry(Location location, SBlock block, List catches) { + super(location); + + this.block = block; + this.catches = Collections.unmodifiableList(catches); + } + + @Override + void extractVariables(Set variables) { + if (block != null) { + block.extractVariables(variables); + } + for (SCatch expr : catches) { + expr.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + if (block == null) { + throw createError(new IllegalArgumentException("Extraneous try statement.")); + } + + block.lastSource = lastSource; + block.inLoop = inLoop; + block.lastLoop = lastLoop; + + block.analyze(scriptRoot, Locals.newLocalScope(locals)); + + methodEscape = block.methodEscape; + loopEscape = block.loopEscape; + allEscape = block.allEscape; + anyContinue = block.anyContinue; + anyBreak = block.anyBreak; + + int statementCount = 0; + + for (SCatch catc : catches) { + catc.lastSource = lastSource; + catc.inLoop = inLoop; + catc.lastLoop = lastLoop; + + catc.analyze(scriptRoot, Locals.newLocalScope(locals)); + + methodEscape &= catc.methodEscape; + loopEscape &= catc.loopEscape; + allEscape &= catc.allEscape; + anyContinue |= catc.anyContinue; + anyBreak |= catc.anyBreak; + + statementCount = Math.max(statementCount, catc.statementCount); + } + + this.statementCount = block.statementCount + statementCount; + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label begin = new Label(); + Label end = new Label(); + Label exception = new Label(); + + methodWriter.mark(begin); + + block.continu = continu; + block.brake = brake; + block.write(classWriter, methodWriter, globals); + + if (!block.allEscape) { + methodWriter.goTo(exception); + } + + methodWriter.mark(end); + + for (SCatch catc : catches) { + catc.begin = begin; + catc.end = end; + catc.exception = catches.size() > 1 ? exception : null; + catc.write(classWriter, methodWriter, globals); + } + + if (!block.allEscape || catches.size() > 1) { + methodWriter.mark(exception); + } + } + + @Override + public String toString() { + return multilineToString(singleton(block), catches); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java new file mode 100644 index 0000000000000..ab1f29fad4a5d --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java @@ -0,0 +1,143 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ScriptRoot; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + +/** + * Represents a while loop. + */ +public final class SWhile extends AStatement { + + private AExpression condition; + private final SBlock block; + + private boolean continuous = false; + + public SWhile(Location location, AExpression condition, SBlock block) { + super(location); + + this.condition = Objects.requireNonNull(condition); + this.block = block; + } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + if (block != null) { + block.extractVariables(variables); + } + } + + @Override + void analyze(ScriptRoot scriptRoot, Locals locals) { + locals = Locals.newLocalScope(locals); + + condition.expected = boolean.class; + condition.analyze(scriptRoot, locals); + condition = condition.cast(scriptRoot, locals); + + if (condition.constant != null) { + continuous = (boolean)condition.constant; + + if (!continuous) { + throw createError(new IllegalArgumentException("Extraneous while loop.")); + } + + if (block == null) { + throw createError(new IllegalArgumentException("While loop has no escape.")); + } + } + + if (block != null) { + block.beginLoop = true; + block.inLoop = true; + + block.analyze(scriptRoot, locals); + + if (block.loopEscape && !block.anyContinue) { + throw createError(new IllegalArgumentException("Extraneous while loop.")); + } + + if (continuous && !block.anyBreak) { + methodEscape = true; + allEscape = true; + } + + block.statementCount = Math.max(1, block.statementCount); + } + + statementCount = 1; + + if (locals.hasVariable(Locals.LOOP)) { + loopCounter = locals.getVariable(location, Locals.LOOP); + } + } + + @Override + void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label begin = new Label(); + Label end = new Label(); + + methodWriter.mark(begin); + + if (!continuous) { + condition.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, end); + } + + if (block != null) { + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, block.statementCount), location); + } + + block.continu = begin; + block.brake = end; + block.write(classWriter, methodWriter, globals); + } else { + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); + } + } + + if (block == null || !block.allEscape) { + methodWriter.goTo(begin); + } + + methodWriter.mark(end); + } + + @Override + public String toString() { + return singleLineToString(condition, block); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java new file mode 100644 index 0000000000000..04fde14823d24 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; + +public class VariableNode implements IRNode { + + protected final Variable variable; + + public VariableNode(Variable variable) { + this.variable = Objects.requireNonNull(variable); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); + } + + @Override + public int accessElementCount() { + return 0; + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // do nothing + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java new file mode 100644 index 0000000000000..266968b39cd1d --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java @@ -0,0 +1,158 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A painless tree is composed of the node classes found in this package. + *

+ * The following are the types of nodes: + * A* (abstract) - These are the abstract nodes that are the superclasses for the other types. + * I* (interface) - These are marker interfaces to denote a property of the node. + * S* (statement) - These are nodes that represent a statement in Painless. + * E* (expression) - These are nodes that represent an expression in Painless. + * P* (postfix) - These are nodes that represent a postfix of a variable chain. + * E/P* (storeable) - These are nodes that are allowed to store a value to memory. + * *Sub* (sub) - These are partial nodes with a parent (S/E/P)* node used to split up logic into smaller pieces. + *

+ * The following is a brief description of each node: + * {@link org.elasticsearch.painless.node.AExpression} - The superclass for all E* (expression) and P* (postfix) nodes. + * {@link org.elasticsearch.painless.node.ANode} - The superclass for all nodes. + * {@link org.elasticsearch.painless.node.AStatement} - The superclass for all S* (statement) nodes. + * {@link org.elasticsearch.painless.node.AStoreable} - The super class for an expression that can store a value in local memory. + * {@link org.elasticsearch.painless.node.EAssignment} - Represents an assignment with the lhs and rhs as child nodes. + * {@link org.elasticsearch.painless.node.EBinary} - Represents a binary math expression. + * {@link org.elasticsearch.painless.node.EBool} - Represents a boolean expression. + * {@link org.elasticsearch.painless.node.EBoolean} - Represents a boolean constant. + * {@link org.elasticsearch.painless.node.ECallLocal} - Represents a user-defined call. + * {@link org.elasticsearch.painless.node.ECapturingFunctionRef} - Represents a function reference (capturing). + * {@link org.elasticsearch.painless.node.ECast} - Represents a cast inserted into the tree replacing others. (Internal only.) + * {@link org.elasticsearch.painless.node.EComp} - Represents a comparison expression. + * {@link org.elasticsearch.painless.node.EConditional} - Represents a conditional expression. + * {@link org.elasticsearch.painless.node.EConstant} - Represents a constant inserted into the tree replacing others. (Internal only.) + * {@link org.elasticsearch.painless.node.EDecimal} - Represents a decimal constant. + * {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast. + * {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference (non-capturing). + * {@link org.elasticsearch.painless.node.EInstanceof} - Represents an instanceof check. + * {@link org.elasticsearch.painless.node.ELambda} - Represents a lambda function. + * {@link org.elasticsearch.painless.node.EListInit} - Represents a list initialization shortcut. + * {@link org.elasticsearch.painless.node.EMapInit} - Represents a map initialization shortcut. + * {@link org.elasticsearch.painless.node.ENewArray} - Represents an array instantiation. + * {@link org.elasticsearch.painless.node.ENewObj} - Represents and object instantiation. + * {@link org.elasticsearch.painless.node.ENull} - Represents a null constant. + * {@link org.elasticsearch.painless.node.ENumeric} - Represents a non-decimal numeric constant. + * {@link org.elasticsearch.painless.node.ERegex} - Represents a regular expression constant. + * {@link org.elasticsearch.painless.node.EStatic} - Represents a static type target. + * {@link org.elasticsearch.painless.node.EString} - Represents a string constant. + * {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression. + * {@link org.elasticsearch.painless.node.EVariable} - Represents a variable load/store. + * {@link org.elasticsearch.painless.node.ILambda} - Represents a marker to signify this node is a lambda function. + * {@link org.elasticsearch.painless.node.PBrace} - Represents an array load/store and defers to a child subnode. + * {@link org.elasticsearch.painless.node.PCallInvoke} - Represents a method call and defers to a child subnode. + * {@link org.elasticsearch.painless.node.PField} - Represents a field load/store and defers to a child subnode. + * {@link org.elasticsearch.painless.node.PSubArrayLength} - Represents an array length field load. + * {@link org.elasticsearch.painless.node.PSubBrace} - Represents an array load/store. + * {@link org.elasticsearch.painless.node.PSubCallInvoke} - Represents a method call. + * {@link org.elasticsearch.painless.node.PSubDefArray} - Represents an array load/store or shortcut on a def type. (Internal only.) + * {@link org.elasticsearch.painless.node.PSubDefCall} - Represents a method call made on a def type. (Internal only.) + * {@link org.elasticsearch.painless.node.PSubDefField} - Represents a field load/store or shortcut on a def type. (Internal only.) + * {@link org.elasticsearch.painless.node.PSubField} - Represents a field load/store. + * {@link org.elasticsearch.painless.node.PSubListShortcut} - Represents a list load/store shortcut. (Internal only.) + * {@link org.elasticsearch.painless.node.PSubMapShortcut} - Represents a map load/store shortcut. (Internal only.) + * {@link org.elasticsearch.painless.node.PSubShortcut} - Represents a field load/store shortcut. (Internal only.) + * {@link org.elasticsearch.painless.node.SBlock} - Represents a set of statements as a branch of control-flow. + * {@link org.elasticsearch.painless.node.SBreak} - Represents a break statement. + * {@link org.elasticsearch.painless.node.SCatch} - Represents a catch block as part of a try-catch block. + * {@link org.elasticsearch.painless.node.SContinue} - Represents a continue statement. + * {@link org.elasticsearch.painless.node.SDeclaration} - Represents a single variable declaration. + * {@link org.elasticsearch.painless.node.SDeclBlock} - Represents a series of declarations. + * {@link org.elasticsearch.painless.node.SDo} - Represents a do-while loop. + * {@link org.elasticsearch.painless.node.SEach} - Represents a for-each loop and defers to subnodes depending on type. + * {@link org.elasticsearch.painless.node.SExpression} - Represents the top-level node for an expression as a statement. + * {@link org.elasticsearch.painless.node.SFor} - Represents a for loop. + * {@link org.elasticsearch.painless.node.SFunction} - Represents a user-defined function. + * {@link org.elasticsearch.painless.node.SIf} - Represents an if block. + * {@link org.elasticsearch.painless.node.SIfElse} - Represents an if/else block. + * {@link org.elasticsearch.painless.node.SReturn} - Represents a return statement. + * {@link org.elasticsearch.painless.node.SClass} - The root of all Painless trees. Contains a series of statements. + * {@link org.elasticsearch.painless.node.SSubEachArray} - Represents a for-each loop for arrays. + * {@link org.elasticsearch.painless.node.SSubEachIterable} - Represents a for-each loop for iterables. + * {@link org.elasticsearch.painless.node.SThrow} - Represents a throw statement. + * {@link org.elasticsearch.painless.node.STry} - Represents the try block as part of a try-catch block. + * {@link org.elasticsearch.painless.node.SWhile} - Represents a while loop. + *

+ * Note that internal nodes are generated during the analysis phase by modifying the tree on-the-fly + * for clarity of development and convenience during the writing phase. + *

+ * All Painless trees must start with an SClass node at the root. Each node has a constructor that requires + * all of its values and children be passed in at the time of instantiation. This means that Painless trees + * are build bottom-up; however, this helps enforce tree structure correctness and fits naturally with a + * standard recursive-descent parser. + *

+ * Generally, statement nodes have member data that evaluate legal control-flow during the analysis phase. + * The typical order for statement nodes is for each node to call analyze on it's children during the analysis phase + * and write on it's children during the writing phase. + *

+ * Generally, expression nodes have member data that evaluate static and def types. The typical order for an expression node + * during the analysis phase looks like the following: + *

{@code
+ * For known expected types:
+ *
+ * expression.child.expected = expectedType      // set the known expected type
+ *
+ * expression.child.analyze(...)                 // analyze the child node to set the child's actual type
+ *
+ * expression.child = expression.child.cast(...) // add an implicit cast node if the child node's
+ *                                               // actual type is not the expected type and set the
+ *                                               // expression's child to the implicit cast node
+ *
+ * For unknown expected types that need promotion:
+ *
+ * expression.child.analyze(...)                 // analyze the child node to set the child's actual type
+ *
+ * Type promote = Caster.promote(...)            // get the promotion type for the child based on
+ *                                               // the current operation and child's actual type
+ *
+ * expression.child.expected = promote           // set the expected type to the promotion type
+ *
+ * expression.child = expression.child.cast(...) // add an implicit cast node if the child node's
+ *                                               // actual type is not the expected type and set the
+ *                                               // expression's child to the implicit cast node
+ * }
+ * Expression nodes just call each child during the writing phase. + *

+ * Postfix nodes represent postfixes in a variable/method chain including braces, calls, or fields. + * Postfix nodes will always have a prefix node that is the prior piece of the variable/method chain. + * Analysis of a postfix node will cause a chain of analysis calls to happen where the prefix will + * be analyzed first and continue until the prefix is not a postfix node. Writing out a series of + * loads from a postfix node works in the same fashion. Stores work somewhat differently as + * described by later documentation. + *

+ * Storebable nodes have three methods for writing -- setup, load, and store. These methods + * are used in conjunction with a parent node aware of the storeable node (lhs) that has a node + * representing a value to store (rhs). The setup method is always once called before a store + * to give storeable nodes a chance to write any prefixes they may have and any values such as + * array indices before the store happens. Load is called on a storeable node that must also + * be read from, and store is called to write a value to memory. + *

+ * Sub nodes are partial nodes that require a parent to work correctly. These nodes can really + * represent anything the parent node would like to split up into logical pieces and don't really + * have any distinct set of rules. The currently existing subnodes all have ANode as a super class + * somewhere in their class hierarchy so the parent node can defer some analysis and writing to + * the sub node. + */ +package org.elasticsearch.painless.node; From bf21ab1fbb16317e02304d5103f474e5e211fb6a Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sun, 15 Dec 2019 11:41:08 -0800 Subject: [PATCH 02/24] converted some ast nodes to ir nodes --- .../elasticsearch/painless/ir/AStatement.java | 116 --- .../elasticsearch/painless/ir/AStoreable.java | 123 ---- .../painless/ir/AssignmentNode.java | 158 ++++ .../elasticsearch/painless/ir/BinaryNode.java | 46 ++ .../ir/{EBool.java => BooleanNode.java} | 66 +- .../ir/{EComp.java => ComparisonNode.java} | 107 ++- .../painless/ir/EAssignment.java | 358 --------- .../elasticsearch/painless/ir/EBinary.java | 681 ------------------ .../elasticsearch/painless/ir/EBoolean.java | 65 -- .../elasticsearch/painless/ir/EDecimal.java | 86 --- .../org/elasticsearch/painless/ir/ENull.java | 76 -- .../painless/ir/ExpressionNode.java | 45 ++ .../org/elasticsearch/painless/ir/IRNode.java | 3 +- .../elasticsearch/painless/ir/MathNode.java | 103 +++ .../elasticsearch/painless/ir/NullNode.java | 37 + .../ir/{ClassNode.java => SClass.java} | 0 .../elasticsearch/painless/ir/ShiftNode.java | 45 ++ .../elasticsearch/painless/ir/TypeNode.java | 39 + 18 files changed, 531 insertions(+), 1623 deletions(-) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{EBool.java => BooleanNode.java} (52%) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{EComp.java => ComparisonNode.java} (57%) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{ClassNode.java => SClass.java} (100%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java deleted file mode 100644 index 629449c1a58bf..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStatement.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; -import org.objectweb.asm.Label; - -/** - * The superclass for all S* (statement) nodes. - */ -public abstract class AStatement extends ANode { - - /** - * Set to true when the final statement in an {@link SClass} is reached. - * Used to determine whether or not an auto-return is necessary. - */ - boolean lastSource = false; - - /** - * Set to true when a loop begins. Used by {@link SBlock} to help determine - * when the final statement of a loop is reached. - */ - boolean beginLoop = false; - - /** - * Set to true when inside a loop. Used by {@link SBreak} and {@link SContinue} - * to determine if a break/continue statement is legal. - */ - boolean inLoop = false; - - /** - * Set to true when on the last statement of a loop. Used by {@link SContinue} - * to prevent extraneous continue statements. - */ - boolean lastLoop = false; - - /** - * Set to true if a statement would cause the method to exit. Used to - * determine whether or not an auto-return is necessary. - */ - boolean methodEscape = false; - - /** - * Set to true if a statement would cause a loop to exit. Used to - * prevent unreachable statements. - */ - boolean loopEscape = false; - - /** - * Set to true if all current paths escape from the current {@link SBlock}. - * Used during the analysis phase to prevent unreachable statements and - * the writing phase to prevent extraneous bytecode gotos from being written. - */ - boolean allEscape = false; - - /** - * Set to true if any continue statement occurs in a loop. Used to prevent - * unnecessary infinite loops. - */ - boolean anyContinue = false; - - /** - * Set to true if any break statement occurs in a loop. Used to prevent - * extraneous loops. - */ - boolean anyBreak = false; - - /** - * Set to the loop counter variable slot as a shortcut if loop statements - * are being counted. - */ - Variable loopCounter = null; - - /** - * Set to the approximate number of statements in a loop block to prevent - * infinite loops during runtime. - */ - int statementCount = 0; - - /** - * Set to the beginning of a loop so a continue statement knows where to - * jump to. Only used during the writing phase. - */ - Label continu = null; - - /** - * Set to the beginning of a loop so a break statement knows where to - * jump to. Only used during the writing phase. - */ - Label brake = null; - - /** - * Standard constructor with location used for error tracking. - */ - AStatement(Location location) { - super(location); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java deleted file mode 100644 index 7299a14677d9e..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AStoreable.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Objects; -import java.util.function.Consumer; - -/** - * The super class for an expression that can store a value in local memory. - */ -abstract class AStoreable extends AExpression { - - /** - * Set to true when this node is an lhs-expression and will be storing - * a value from an rhs-expression. - */ - boolean write = false; - - /** - * Standard constructor with location used for error tracking. - */ - AStoreable(Location location) { - super(location); - - prefix = null; - } - - /** - * This constructor is used by variable/method chains when postfixes are specified. - */ - AStoreable(Location location, AExpression prefix) { - super(location); - - this.prefix = Objects.requireNonNull(prefix); - } - - /** - * Returns a value based on the number of elements previously placed on the - * stack to load/store a certain piece of a variable/method chain. This is - * used during the writing phase to dup stack values from this storeable as - * necessary during certain store operations. - *

- * Examples: - * {@link EVariable} returns 0 because it requires nothing extra to perform - * a load/store - * {@link PSubField} returns 1 because it requires the name of the field as - * an index on the stack to perform a load/store - * {@link PSubBrace} returns 2 because it requires both the variable slot and - * an index into the array on the stack to perform a - * load/store - */ - abstract int accessElementCount(); - - /** - * Returns true if this node or a sub-node of this node can be optimized with - * rhs actual type to avoid an unnecessary cast. - */ - abstract boolean isDefOptimized(); - - /** - * If this node or a sub-node of this node uses dynamic calls then - * actual will be set to this value. This is used for an optimization - * during assignment to def type targets. - */ - abstract void updateActual(Class actual); - - /** - * Called before a storeable node is loaded or stored. Used to load prefixes and - * push load/store constants onto the stack if necessary. - */ - abstract void setup(ClassWriter classWriter, MethodWriter writer, Globals globals); - - /** - * Called to load a storable used for compound assignments. - */ - abstract void load(ClassWriter classWriter, MethodWriter writer, Globals globals); - - /** - * Called to store a storabable to local memory. - */ - abstract void store(ClassWriter classWriter, MethodWriter writer, Globals globals); - - /** - * Writes the opcodes to flip a negative array index (meaning slots from the end of the array) into a 0-based one (meaning slots from - * the start of the array). - */ - static void writeIndexFlip(MethodWriter writer, Consumer writeGetLength) { - Label noFlip = new Label(); - // Everywhere when it says 'array' below that could also be a list - // The stack after each instruction: array, unnormalized_index - writer.dup(); // array, unnormalized_index, unnormalized_index - writer.ifZCmp(Opcodes.IFGE, noFlip); // array, unnormalized_index - writer.swap(); // negative_index, array - writer.dupX1(); // array, negative_index, array - writeGetLength.accept(writer); // array, negative_index, length - writer.visitInsn(Opcodes.IADD); // array, noralized_index - writer.mark(noFlip); // array, noralized_index - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java new file mode 100644 index 0000000000000..4ea4c8a4c8db2 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -0,0 +1,158 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.def; + +import java.util.Objects; + +public class AssignmentNode extends BinaryNode { + + protected final Location location; + protected final boolean pre; + protected final boolean post; + protected final Operation operation; + protected final boolean read; + protected final boolean cat; + protected final PainlessCast there; + protected final PainlessCast back; + + public AssignmentNode( + Location location, + boolean pre, + boolean post, + Operation operation, + boolean read, + boolean cat, + PainlessCast there, + PainlessCast back + ) { + this.location = Objects.requireNonNull(location); + this.pre = pre; + this.post = post; + this.operation = Objects.requireNonNull(operation); + this.read = read; + this.cat = cat; + this.there = there; + this.back = back; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + // For the case where the assignment represents a String concatenation + // we must, depending on the Java version, write a StringBuilder or + // track types going onto the stack. This must be done before the + // lhs is read because we need the StringBuilder to be placed on the + // stack ahead of any potential concatenation arguments. + int catElementStackSize = 0; + + if (cat) { + catElementStackSize = methodWriter.writeNewStrings(); + } + + leftNode.setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation + + if (cat) { + // Handle the case where we are doing a compound assignment + // representing a String concatenation. + + methodWriter.writeDup(leftNode.accessElementCount(), catElementStackSize); // dup the top element and insert it + // before concat helper on stack + leftNode.load(classWriter, methodWriter, globals); // read the current lhs's value + methodWriter.writeAppendStrings(leftNode.getType()); // append the lhs's value using the StringBuilder + + rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs + + if (rightNode instanceof MathNode == false || ((MathNode)rightNode).cat == false) { // check to see if the rhs + // has already done a concatenation + methodWriter.writeAppendStrings(rightNode.getType()); // append the rhs's value since + // it's hasn't already + } + + methodWriter.writeToStrings(); // put the value for string concat onto the stack + methodWriter.writeCast(back); // if necessary, cast the String to the lhs actual type + + if (read) { + // if this lhs is also read from dup the value onto the stack + methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + } + + // store the lhs's value from the stack in its respective variable/field/array + leftNode.store(classWriter, methodWriter, globals); + } else if (operation != null) { + // Handle the case where we are doing a compound assignment that + // does not represent a String concatenation. + + methodWriter.writeDup(leftNode.accessElementCount(), 0); // if necessary, dup the previous lhs's value + // to be both loaded from and stored to + leftNode.load(classWriter, methodWriter, globals); // load the current lhs's value + + if (read && post) { + // dup the value if the lhs is also read from and is a post increment + methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + } + + methodWriter.writeCast(there); // if necessary cast the current lhs's value + // to the promotion type between the lhs and rhs types + rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs + + // XXX: fix these types, but first we need def compound assignment tests. + // its tricky here as there are possibly explicit casts, too. + // write the operation instruction for compound assignment + if (getType() == def.class) { + methodWriter.writeDynamicBinaryInstruction( + location, getType(), def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); + } else { + methodWriter.writeBinaryInstruction(location, getType(), operation); + } + + methodWriter.writeCast(back); // if necessary cast the promotion type value back to the lhs's type + + if (read && !post) { + // dup the value if the lhs is also read from and is not a post increment + methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + } + + leftNode.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array + } else { + // Handle the case for a simple write. + + rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs + + if (read) { + // dup the value if the lhs is also read from + methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + } + + // store the lhs's value from the stack in its respective variable/field/array + leftNode.store(classWriter, methodWriter, globals); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java new file mode 100644 index 0000000000000..ee2b29b759aab --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +public class BinaryNode extends ExpressionNode { + + protected ExpressionNode leftNode; + protected ExpressionNode rightNode; + + public BinaryNode() { + // do nothing + } + + public void setLeftNode(ExpressionNode leftNode) { + this.leftNode = leftNode; + } + + public void setRightNode(ExpressionNode rightNode) { + this.rightNode = rightNode; + } + + public ExpressionNode getLeftNode() { + return leftNode; + } + + public ExpressionNode getRightNode() { + return rightNode; + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java similarity index 52% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index c46242ff28aac..05dd959d6acc1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBool.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -21,72 +21,36 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.ir.BinaryNode; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import java.util.Objects; -import java.util.Set; -/** - * Represents a boolean expression. - */ -public final class EBool extends AExpression { +public final class BooleanNode extends BinaryNode { + private final Location location; private final Operation operation; - private AExpression left; - private AExpression right; - - public EBool(Location location, Operation operation, AExpression left, AExpression right) { - super(location); + public BooleanNode(Location location, Operation operation) { + this.location = Objects.requireNonNull(location); this.operation = Objects.requireNonNull(operation); - this.left = Objects.requireNonNull(left); - this.right = Objects.requireNonNull(right); } @Override - void extractVariables(Set variables) { - left.extractVariables(variables); - right.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - left.expected = boolean.class; - left.analyze(scriptRoot, locals); - left = left.cast(scriptRoot, locals); - - right.expected = boolean.class; - right.analyze(scriptRoot, locals); - right = right.cast(scriptRoot, locals); - - if (left.constant != null && right.constant != null) { - if (operation == Operation.AND) { - constant = (boolean)left.constant && (boolean)right.constant; - } else if (operation == Operation.OR) { - constant = (boolean)left.constant || (boolean)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - actual = boolean.class; - } + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { if (operation == Operation.AND) { Label fals = new Label(); Label end = new Label(); - left.write(classWriter, methodWriter, globals); + leftNode.write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - right.write(classWriter, methodWriter, globals); + rightNode.write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.push(true); @@ -99,9 +63,9 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) Label fals = new Label(); Label end = new Label(); - left.write(classWriter, methodWriter, globals); + leftNode.write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFNE, tru); - right.write(classWriter, methodWriter, globals); + rightNode.write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.mark(tru); @@ -111,12 +75,8 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.push(false); methodWriter.mark(end); } else { - throw createError(new IllegalStateException("Illegal tree structure.")); + throw new IllegalStateException("unexpected boolean operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); } } - - @Override - public String toString() { - return singleLineToString(left, operation.symbol, right); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java similarity index 57% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index f8aa598c86397..e87553a9c316a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -17,67 +17,42 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.ir.IRNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import java.util.Objects; -import java.util.Set; import static org.elasticsearch.painless.WriterConstants.EQUALS; import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE; -public class ComparisonNode implements IRNode { +public class ComparisonNode extends BinaryNode { + private final Location location; private final Operation operation; - private final Class promotedType; - private IRNode left; - private IRNode right; - - public ComparisonNode(Operation operation) { + public ComparisonNode(Location location, Operation operation) { + this.location = Objects.requireNonNull(location); this.operation = Objects.requireNonNull(operation); - this.left = Objects.requireNonNull(left); - this.right = Objects.requireNonNull(right); - } - - public void setLeft(IRNode left) { - this.left = Objects.requireNonNull(left); - } - - public void setRight(IRNode right) { - this.right = Objects.requireNonNull(right); - } - - public IRNode getLeft() { - return left; - } - - public IRNode getRight() { - return right; } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - left.write(classWriter, methodWriter, globals); + leftNode.write(classWriter, methodWriter, globals); - if (!right.isNull) { - right.write(classWriter, methodWriter, globals); + if (rightNode instanceof NullNode == false) { + rightNode.write(classWriter, methodWriter, globals); } Label jump = new Label(); @@ -92,48 +67,52 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) boolean writejump = true; - Type type = MethodWriter.getType(promotedType); + Class type = getType(); + Type asmType = MethodWriter.getType(type); - if (promotedType == void.class || promotedType == byte.class || promotedType == short.class || promotedType == char.class) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } else if (promotedType == boolean.class) { - if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); + if (type == void.class || type == byte.class || type == short.class || type == char.class) { + throw new IllegalStateException("unexpected type [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "] for comparison"); + } else if (type == boolean.class) { + if (eq) methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(asmType, MethodWriter.NE, jump); else { - throw createError(new IllegalStateException("Illegal tree structure.")); + throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); } - } else if (promotedType == int.class || promotedType == long.class || promotedType == float.class || promotedType == double.class) { - if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); - else if (lt) methodWriter.ifCmp(type, MethodWriter.LT, jump); - else if (lte) methodWriter.ifCmp(type, MethodWriter.LE, jump); - else if (gt) methodWriter.ifCmp(type, MethodWriter.GT, jump); - else if (gte) methodWriter.ifCmp(type, MethodWriter.GE, jump); + } else if (type == int.class || type == long.class || type == float.class || type == double.class) { + if (eq) methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(asmType, MethodWriter.NE, jump); + else if (lt) methodWriter.ifCmp(asmType, MethodWriter.LT, jump); + else if (lte) methodWriter.ifCmp(asmType, MethodWriter.LE, jump); + else if (gt) methodWriter.ifCmp(asmType, MethodWriter.GT, jump); + else if (gte) methodWriter.ifCmp(asmType, MethodWriter.GE, jump); else { - throw createError(new IllegalStateException("Illegal tree structure.")); + throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); } - } else if (promotedType == def.class) { + } else if (type == def.class) { Type booleanType = Type.getType(boolean.class); - Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(left.actual), MethodWriter.getType(right.actual)); + Type descriptor = Type.getMethodType(booleanType, + MethodWriter.getType(leftNode.getType()), MethodWriter.getType(rightNode.getType())); if (eq) { - if (right.isNull) { + if (rightNode instanceof NullNode) { methodWriter.ifNull(jump); - } else if (!left.isNull && operation == Operation.EQ) { + } else if (leftNode instanceof NullNode == false && operation == Operation.EQ) { methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); writejump = false; } else { - methodWriter.ifCmp(type, MethodWriter.EQ, jump); + methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); } } else if (ne) { - if (right.isNull) { + if (rightNode instanceof NullNode) { methodWriter.ifNonNull(jump); - } else if (!left.isNull && operation == Operation.NE) { + } else if (leftNode instanceof NullNode == false && operation == Operation.NE) { methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { - methodWriter.ifCmp(type, MethodWriter.NE, jump); + methodWriter.ifCmp(asmType, MethodWriter.NE, jump); } } else if (lt) { methodWriter.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); @@ -148,29 +127,31 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.invokeDefCall("gte", descriptor, DefBootstrap.BINARY_OPERATOR, 0); writejump = false; } else { - throw createError(new IllegalStateException("Illegal tree structure.")); + throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); } } else { if (eq) { - if (right.isNull) { + if (rightNode instanceof NullNode) { methodWriter.ifNull(jump); } else if (operation == Operation.EQ) { methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); writejump = false; } else { - methodWriter.ifCmp(type, MethodWriter.EQ, jump); + methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); } } else if (ne) { - if (right.isNull) { + if (rightNode instanceof NullNode) { methodWriter.ifNonNull(jump); } else if (operation == Operation.NE) { methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { - methodWriter.ifCmp(type, MethodWriter.NE, jump); + methodWriter.ifCmp(asmType, MethodWriter.NE, jump); } } else { - throw createError(new IllegalStateException("Illegal tree structure.")); + throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java deleted file mode 100644 index c6fcc9820420e..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EAssignment.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - - -import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.def; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Represents an assignment with the lhs and rhs as child nodes. - */ -public final class EAssignment extends AExpression { - - private AExpression lhs; - private AExpression rhs; - private final boolean pre; - private final boolean post; - private Operation operation; - - private boolean cat = false; - private Class promote = null; - private Class shiftDistance; // for shifts, the RHS is promoted independently - private PainlessCast there = null; - private PainlessCast back = null; - - public EAssignment(Location location, AExpression lhs, AExpression rhs, boolean pre, boolean post, Operation operation) { - super(location); - - this.lhs = Objects.requireNonNull(lhs); - this.rhs = rhs; - this.pre = pre; - this.post = post; - this.operation = operation; - } - - @Override - void extractVariables(Set variables) { - lhs.extractVariables(variables); - - if (rhs != null) { - rhs.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - analyzeLHS(scriptRoot, locals); - analyzeIncrDecr(); - - if (operation != null) { - analyzeCompound(scriptRoot, locals); - } else if (rhs != null) { - analyzeSimple(scriptRoot, locals); - } else { - throw new IllegalStateException("Illegal tree structure."); - } - } - - private void analyzeLHS(ScriptRoot scriptRoot, Locals locals) { - if (lhs instanceof AStoreable) { - AStoreable lhs = (AStoreable)this.lhs; - - lhs.read = read; - lhs.write = true; - lhs.analyze(scriptRoot, locals); - } else { - throw new IllegalArgumentException("Left-hand side cannot be assigned a value."); - } - } - - private void analyzeIncrDecr() { - if (pre && post) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } else if (pre || post) { - if (rhs != null) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - if (operation == Operation.INCR) { - if (lhs.actual == double.class) { - rhs = new EConstant(location, 1D); - } else if (lhs.actual == float.class) { - rhs = new EConstant(location, 1F); - } else if (lhs.actual == long.class) { - rhs = new EConstant(location, 1L); - } else { - rhs = new EConstant(location, 1); - } - - operation = Operation.ADD; - } else if (operation == Operation.DECR) { - if (lhs.actual == double.class) { - rhs = new EConstant(location, 1D); - } else if (lhs.actual == float.class) { - rhs = new EConstant(location, 1F); - } else if (lhs.actual == long.class) { - rhs = new EConstant(location, 1L); - } else { - rhs = new EConstant(location, 1); - } - - operation = Operation.SUB; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeCompound(ScriptRoot scriptRoot, Locals locals) { - rhs.analyze(scriptRoot, locals); - boolean shift = false; - - if (operation == Operation.MUL) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); - } else if (operation == Operation.DIV) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); - } else if (operation == Operation.REM) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); - } else if (operation == Operation.ADD) { - promote = AnalyzerCaster.promoteAdd(lhs.actual, rhs.actual); - } else if (operation == Operation.SUB) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true); - } else if (operation == Operation.LSH) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, false); - shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false); - shift = true; - } else if (operation == Operation.RSH) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, false); - shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false); - shift = true; - } else if (operation == Operation.USH) { - promote = AnalyzerCaster.promoteNumeric(lhs.actual, false); - shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false); - shift = true; - } else if (operation == Operation.BWAND) { - promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual); - } else if (operation == Operation.XOR) { - promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual); - } else if (operation == Operation.BWOR) { - promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - if (promote == null || (shift && shiftDistance == null)) { - throw createError(new ClassCastException("Cannot apply compound assignment " + - "[" + operation.symbol + "=] to types [" + lhs.actual + "] and [" + rhs.actual + "].")); - } - - cat = operation == Operation.ADD && promote == String.class; - - if (cat) { - if (rhs instanceof EBinary && ((EBinary)rhs).operation == Operation.ADD && rhs.actual == String.class) { - ((EBinary)rhs).cat = true; - } - - rhs.expected = rhs.actual; - } else if (shift) { - if (promote == def.class) { - // shifts are promoted independently, but for the def type, we need object. - rhs.expected = promote; - } else if (shiftDistance == long.class) { - rhs.expected = int.class; - rhs.explicit = true; - } else { - rhs.expected = shiftDistance; - } - } else { - rhs.expected = promote; - } - - rhs = rhs.cast(scriptRoot, locals); - - there = AnalyzerCaster.getLegalCast(location, lhs.actual, promote, false, false); - back = AnalyzerCaster.getLegalCast(location, promote, lhs.actual, true, false); - - this.statement = true; - this.actual = read ? lhs.actual : void.class; - } - - private void analyzeSimple(ScriptRoot scriptRoot, Locals locals) { - AStoreable lhs = (AStoreable)this.lhs; - - // If the lhs node is a def optimized node we update the actual type to remove the need for a cast. - if (lhs.isDefOptimized()) { - rhs.analyze(scriptRoot, locals); - - if (rhs.actual == void.class) { - throw createError(new IllegalArgumentException("Right-hand side cannot be a [void] type for assignment.")); - } - - rhs.expected = rhs.actual; - lhs.updateActual(rhs.actual); - // Otherwise, we must adapt the rhs type to the lhs type with a cast. - } else { - rhs.expected = lhs.actual; - rhs.analyze(scriptRoot, locals); - } - - rhs = rhs.cast(scriptRoot, locals); - - this.statement = true; - this.actual = read ? lhs.actual : void.class; - } - - /** - * Handles writing byte code for variable/method chains for all given possibilities - * including String concatenation, compound assignment, regular assignment, and simple - * reads. Includes proper duplication for chained assignments and assignments that are - * also read from. - */ - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - // For the case where the assignment represents a String concatenation - // we must, depending on the Java version, write a StringBuilder or - // track types going onto the stack. This must be done before the - // lhs is read because we need the StringBuilder to be placed on the - // stack ahead of any potential concatenation arguments. - int catElementStackSize = 0; - - if (cat) { - catElementStackSize = methodWriter.writeNewStrings(); - } - - // Cast the lhs to a storeable to perform the necessary operations to store the rhs. - AStoreable lhs = (AStoreable)this.lhs; - lhs.setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation - - if (cat) { - // Handle the case where we are doing a compound assignment - // representing a String concatenation. - - methodWriter.writeDup(lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it - // before concat helper on stack - lhs.load(classWriter, methodWriter, globals); // read the current lhs's value - methodWriter.writeAppendStrings(lhs.actual); // append the lhs's value using the StringBuilder - - rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs - - if (!(rhs instanceof EBinary) || !((EBinary)rhs).cat) { // check to see if the rhs has already done a concatenation - methodWriter.writeAppendStrings(rhs.actual); // append the rhs's value since it's hasn't already - } - - methodWriter.writeToStrings(); // put the value for string concat onto the stack - methodWriter.writeCast(back); // if necessary, cast the String to the lhs actual type - - if (lhs.read) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // if this lhs is also read - // from dup the value onto the stack - } - - lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array - } else if (operation != null) { - // Handle the case where we are doing a compound assignment that - // does not represent a String concatenation. - - methodWriter.writeDup(lhs.accessElementCount(), 0); // if necessary, dup the previous lhs's value - // to be both loaded from and stored to - lhs.load(classWriter, methodWriter, globals); // load the current lhs's value - - if (lhs.read && post) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the - // lhs is also - // read from and is a post - // increment - } - - methodWriter.writeCast(there); // if necessary cast the current lhs's value - // to the promotion type between the lhs and rhs types - rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs - - // XXX: fix these types, but first we need def compound assignment tests. - // its tricky here as there are possibly explicit casts, too. - // write the operation instruction for compound assignment - if (promote == def.class) { - methodWriter.writeDynamicBinaryInstruction( - location, promote, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); - } else { - methodWriter.writeBinaryInstruction(location, promote, operation); - } - - methodWriter.writeCast(back); // if necessary cast the promotion type value back to the lhs's type - - if (lhs.read && !post) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs - // is also - // read from and is not a post - // increment - } - - lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array - } else { - // Handle the case for a simple write. - - rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs - - if (lhs.read) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs - // is also read from - } - - lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array - } - } - - @Override - public String toString() { - List subs = new ArrayList<>(); - subs.add(lhs); - if (rhs != null) { - // Make sure "=" is in the symbol so this is easy to read at a glance - subs.add(operation == null ? "=" : operation.symbol + "="); - subs.add(rhs); - return singleLineToString(subs); - } - subs.add(operation.symbol); - if (pre) { - subs.add("pre"); - } - if (post) { - subs.add("post"); - } - return singleLineToString(subs); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java deleted file mode 100644 index 7f67f16fb3b3c..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBinary.java +++ /dev/null @@ -1,681 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.WriterConstants; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.def; - -import java.util.Objects; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Represents a binary math expression. - */ -public final class EBinary extends AExpression { - - final Operation operation; - private AExpression left; - private AExpression right; - - private Class promote = null; // promoted type - private Class shiftDistance = null; // for shifts, the rhs is promoted independently - boolean cat = false; - private boolean originallyExplicit = false; // record whether there was originally an explicit cast - - public EBinary(Location location, Operation operation, AExpression left, AExpression right) { - super(location); - - this.operation = Objects.requireNonNull(operation); - this.left = Objects.requireNonNull(left); - this.right = Objects.requireNonNull(right); - } - - @Override - void extractVariables(Set variables) { - left.extractVariables(variables); - right.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - originallyExplicit = explicit; - - if (operation == Operation.MUL) { - analyzeMul(scriptRoot, locals); - } else if (operation == Operation.DIV) { - analyzeDiv(scriptRoot, locals); - } else if (operation == Operation.REM) { - analyzeRem(scriptRoot, locals); - } else if (operation == Operation.ADD) { - analyzeAdd(scriptRoot, locals); - } else if (operation == Operation.SUB) { - analyzeSub(scriptRoot, locals); - } else if (operation == Operation.FIND) { - analyzeRegexOp(scriptRoot, locals); - } else if (operation == Operation.MATCH) { - analyzeRegexOp(scriptRoot, locals); - } else if (operation == Operation.LSH) { - analyzeLSH(scriptRoot, locals); - } else if (operation == Operation.RSH) { - analyzeRSH(scriptRoot, locals); - } else if (operation == Operation.USH) { - analyzeUSH(scriptRoot, locals); - } else if (operation == Operation.BWAND) { - analyzeBWAnd(scriptRoot, locals); - } else if (operation == Operation.XOR) { - analyzeXor(scriptRoot, locals); - } else if (operation == Operation.BWOR) { - analyzeBWOr(scriptRoot, locals); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - private void analyzeMul(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply multiply [*] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant * (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant * (long)right.constant; - } else if (promote == float.class) { - constant = (float)left.constant * (float)right.constant; - } else if (promote == double.class) { - constant = (double)left.constant * (double)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeDiv(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply divide [/] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - try { - if (promote == int.class) { - constant = (int)left.constant / (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant / (long)right.constant; - } else if (promote == float.class) { - constant = (float)left.constant / (float)right.constant; - } else if (promote == double.class) { - constant = (double)left.constant / (double)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } catch (ArithmeticException exception) { - throw createError(exception); - } - } - } - - private void analyzeRem(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply remainder [%] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - try { - if (promote == int.class) { - constant = (int)left.constant % (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant % (long)right.constant; - } else if (promote == float.class) { - constant = (float)left.constant % (float)right.constant; - } else if (promote == double.class) { - constant = (double)left.constant % (double)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } catch (ArithmeticException exception) { - throw createError(exception); - } - } - } - - private void analyzeAdd(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteAdd(left.actual, right.actual); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply add [+] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == String.class) { - left.expected = left.actual; - - if (left instanceof EBinary && ((EBinary)left).operation == Operation.ADD && left.actual == String.class) { - ((EBinary)left).cat = true; - } - - right.expected = right.actual; - - if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual == String.class) { - ((EBinary)right).cat = true; - } - } else if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant + (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant + (long)right.constant; - } else if (promote == float.class) { - constant = (float)left.constant + (float)right.constant; - } else if (promote == double.class) { - constant = (double)left.constant + (double)right.constant; - } else if (promote == String.class) { - constant = left.constant.toString() + right.constant.toString(); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - } - - private void analyzeSub(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply subtract [-] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant - (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant - (long)right.constant; - } else if (promote == float.class) { - constant = (float)left.constant - (float)right.constant; - } else if (promote == double.class) { - constant = (double)left.constant - (double)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeRegexOp(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - left.expected = String.class; - right.expected = Pattern.class; - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - promote = boolean.class; - actual = boolean.class; - } - - private void analyzeLSH(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - Class lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false); - Class rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false); - - if (lhspromote == null || rhspromote == null) { - throw createError(new ClassCastException("Cannot apply left shift [<<] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote = lhspromote; - shiftDistance = rhspromote; - - if (lhspromote == def.class || rhspromote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = lhspromote; - - if (rhspromote == long.class) { - right.expected = int.class; - right.explicit = true; - } else { - right.expected = rhspromote; - } - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant << (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant << (int)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeRSH(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - Class lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false); - Class rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false); - - if (lhspromote == null || rhspromote == null) { - throw createError(new ClassCastException("Cannot apply right shift [>>] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote = lhspromote; - shiftDistance = rhspromote; - - if (lhspromote == def.class || rhspromote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = lhspromote; - - if (rhspromote == long.class) { - right.expected = int.class; - right.explicit = true; - } else { - right.expected = rhspromote; - } - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant >> (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant >> (int)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeUSH(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - Class lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false); - Class 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 " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - if (lhspromote == def.class || rhspromote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = lhspromote; - - if (rhspromote == long.class) { - right.expected = int.class; - right.explicit = true; - } else { - right.expected = rhspromote; - } - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant >>> (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant >>> (int)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeBWAnd(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply and [&] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant & (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant & (long)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeXor(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteXor(left.actual, right.actual); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply xor [^] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == boolean.class) { - constant = (boolean)left.constant ^ (boolean)right.constant; - } else if (promote == int.class) { - constant = (int)left.constant ^ (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant ^ (long)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - private void analyzeBWOr(ScriptRoot scriptRoot, Locals variables) { - left.analyze(scriptRoot, variables); - right.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply or [|] to types " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "].")); - } - - actual = promote; - - if (promote == def.class) { - left.expected = left.actual; - right.expected = right.actual; - if (expected != null) { - actual = expected; - } - } else { - left.expected = promote; - right.expected = promote; - } - - left = left.cast(scriptRoot, variables); - right = right.cast(scriptRoot, variables); - - if (left.constant != null && right.constant != null) { - if (promote == int.class) { - constant = (int)left.constant | (int)right.constant; - } else if (promote == long.class) { - constant = (long)left.constant | (long)right.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (promote == String.class && operation == Operation.ADD) { - if (!cat) { - methodWriter.writeNewStrings(); - } - - left.write(classWriter, methodWriter, globals); - - if (!(left instanceof EBinary) || !((EBinary)left).cat) { - methodWriter.writeAppendStrings(left.actual); - } - - right.write(classWriter, methodWriter, globals); - - if (!(right instanceof EBinary) || !((EBinary)right).cat) { - methodWriter.writeAppendStrings(right.actual); - } - - if (!cat) { - methodWriter.writeToStrings(); - } - } else if (operation == Operation.FIND || operation == Operation.MATCH) { - right.write(classWriter, methodWriter, globals); - left.write(classWriter, methodWriter, globals); - methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER); - - if (operation == Operation.FIND) { - methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_FIND); - } else if (operation == Operation.MATCH) { - methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_MATCHES); - } else { - throw new IllegalStateException("Illegal tree structure."); - } - } else { - left.write(classWriter, methodWriter, globals); - right.write(classWriter, methodWriter, globals); - - if (promote == def.class || (shiftDistance != null && shiftDistance == def.class)) { - // def calls adopt the wanted return value. if there was a narrowing cast, - // we need to flag that so that its done at runtime. - int flags = 0; - if (originallyExplicit) { - flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; - } - methodWriter.writeDynamicBinaryInstruction(location, actual, left.actual, right.actual, operation, flags); - } else { - methodWriter.writeBinaryInstruction(location, actual, operation); - } - } - } - - @Override - public String toString() { - return singleLineToString(left, operation.symbol, right); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java deleted file mode 100644 index e1c4fd05745f9..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EBoolean.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Set; - -/** - * Represents a boolean constant. - */ -public final class EBoolean extends AExpression { - - public EBoolean(Location location, boolean constant) { - super(location); - - this.constant = constant; - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from constant [" + constant + "].")); - } - - actual = boolean.class; - } - - @Override - void write(ClassWriter classWriter, MethodWriter adapter, Globals globals) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - public String toString() { - return singleLineToString(constant); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java deleted file mode 100644 index faacb3cdc0282..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EDecimal.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a decimal constant. - */ -public final class EDecimal extends AExpression { - - private final String value; - - public EDecimal(Location location, String value) { - super(location); - - this.value = Objects.requireNonNull(value); - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from constant [" + value + "].")); - } - - if (value.endsWith("f") || value.endsWith("F")) { - try { - constant = Float.parseFloat(value.substring(0, value.length() - 1)); - actual = float.class; - } catch (NumberFormatException exception) { - throw createError(new IllegalArgumentException("Invalid float constant [" + value + "].")); - } - } else { - String toParse = value; - if (toParse.endsWith("d") || value.endsWith("D")) { - toParse = toParse.substring(0, value.length() - 1); - } - try { - constant = Double.parseDouble(toParse); - actual = double.class; - } catch (NumberFormatException exception) { - throw createError(new IllegalArgumentException("Invalid double constant [" + value + "].")); - } - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - public String toString() { - return singleLineToString(value); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java deleted file mode 100644 index 7520700885f9e..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENull.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Opcodes; - -import java.util.Set; - -/** - * Represents a null constant. - */ -public final class ENull extends AExpression { - - public ENull(Location location) { - super(location); - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from null constant.")); - } - - isNull = true; - - if (expected != null) { - if (expected.isPrimitive()) { - throw createError(new IllegalArgumentException( - "Cannot cast null to a primitive type [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "].")); - } - - actual = expected; - } else { - actual = Object.class; - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitInsn(Opcodes.ACONST_NULL); - } - - @Override - public String toString() { - return singleLineToString(); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java new file mode 100644 index 0000000000000..2423379fc9a88 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +public abstract class ExpressionNode implements IRNode { + + protected TypeNode typeNode; + + public ExpressionNode() { + // do nothing + } + + public void setTypeNode(TypeNode typeNode) { + this.typeNode = typeNode; + } + + public TypeNode getTypeNode() { + return typeNode; + } + + public Class getType() { + return typeNode.getType(); + } + + public String getCanonicalTypeName() { + return typeNode.getCanonicalTypeName(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java index acad8a9aab0a4..8c8714c523fc0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java @@ -25,8 +25,7 @@ public interface IRNode { - /** Writes bytecode for Java class creation. */ - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals); + default void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} default int accessElementCount() {throw new UnsupportedOperationException();} default void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java new file mode 100644 index 0000000000000..9458732d7e5c9 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java @@ -0,0 +1,103 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.def; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MathNode extends ShiftNode { + + protected final Location location; + protected final Operation operation; + protected final boolean cat; + protected final boolean originallyExplicit; // record whether there was originally an explicit cast + + public MathNode(Location location, Operation operation, boolean cat, boolean originallyExplicit) { + this.location = Objects.requireNonNull(location); + this.operation = Objects.requireNonNull(operation); + this.cat = cat; + this.originallyExplicit = originallyExplicit; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (getType() == String.class && operation == Operation.ADD) { + if (!cat) { + methodWriter.writeNewStrings(); + } + + leftNode.write(classWriter, methodWriter, globals); + + if ((leftNode instanceof MathNode) == false || ((MathNode)leftNode).cat == false) { + methodWriter.writeAppendStrings(leftNode.getType()); + } + + rightNode.write(classWriter, methodWriter, globals); + + if ((rightNode instanceof MathNode) == false || ((MathNode)rightNode).cat == false) { + methodWriter.writeAppendStrings(rightNode.getType()); + } + + if (!cat) { + methodWriter.writeToStrings(); + } + } else if (operation == Operation.FIND || operation == Operation.MATCH) { + rightNode.write(classWriter, methodWriter, globals); + leftNode.write(classWriter, methodWriter, globals); + methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER); + + if (operation == Operation.FIND) { + methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_FIND); + } else if (operation == Operation.MATCH) { + methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_MATCHES); + } else { + throw new IllegalStateException("unexpected math operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); + } + } else { + leftNode.write(classWriter, methodWriter, globals); + rightNode.write(classWriter, methodWriter, globals); + + if (getType() == def.class || (getShiftTypeNode() != null && getShiftType() == def.class)) { + // def calls adopt the wanted return value. if there was a narrowing cast, + // we need to flag that so that its done at runtime. + int flags = 0; + if (originallyExplicit) { + flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; + } + methodWriter.writeDynamicBinaryInstruction(location, getType(), leftNode.getType(), rightNode.getType(), operation, flags); + } else { + methodWriter.writeBinaryInstruction(location, getType(), operation); + } + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java new file mode 100644 index 0000000000000..7842a8dac8a2c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Opcodes; + +public class NullNode extends ExpressionNode { + + public NullNode() { + // do nothing + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.visitInsn(Opcodes.ACONST_NULL); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java similarity index 100% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java new file mode 100644 index 0000000000000..4b3a2ed5a8f5b --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +public abstract class ShiftNode extends BinaryNode { + + protected TypeNode shiftTypeNode; + + public ShiftNode() { + // do nothing + } + + public void setShiftTypeNode(TypeNode shiftTypeNode) { + this.shiftTypeNode = shiftTypeNode; + } + + public TypeNode getShiftTypeNode() { + return shiftTypeNode; + } + + public Class getShiftType() { + return shiftTypeNode.getType(); + } + + public String getShiftCanonicalTypeName() { + return shiftTypeNode.getCanonicalTypeName(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java new file mode 100644 index 0000000000000..4ab36c97c36dd --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.lookup.PainlessLookupUtility; + +public class TypeNode implements IRNode { + + protected final Class type; + + public TypeNode(Class type) { + this.type = type; + } + + public Class getType() { + return type; + } + + public String getCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(type); + } +} From 71add6c14c61d8635ff062306b535f5c73368239 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sun, 15 Dec 2019 14:23:12 -0800 Subject: [PATCH 03/24] converted more nodes --- .../painless/ir/ArgumentsNode.java | 61 +++++ .../painless/ir/BooleanNode.java | 3 +- ...tionRef.java => CapturingFuncRefNode.java} | 47 +--- .../painless/ir/DefCallNode.java | 70 ++++++ .../elasticsearch/painless/ir/ECallLocal.java | 233 ------------------ .../elasticsearch/painless/ir/ILambda.java | 40 --- .../painless/ir/PSubDefCall.java | 128 ---------- .../painless/ir/UnboundCallNode.java | 131 ++++++++++ .../painless/node/ECapturingFunctionRef.java | 6 +- .../painless/node/EFunctionRef.java | 7 +- .../elasticsearch/painless/node/ELambda.java | 8 +- .../painless/node/ENewArrayFunctionRef.java | 6 +- .../elasticsearch/painless/node/ILambda.java | 6 +- .../painless/node/PSubDefCall.java | 42 ++-- 14 files changed, 302 insertions(+), 486 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{ECapturingFunctionRef.java => CapturingFuncRefNode.java} (67%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java new file mode 100644 index 0000000000000..0c7d6330f9734 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public abstract class ArgumentsNode extends ExpressionNode { + + protected List argumentNodes = new ArrayList<>(); + + public void addArgumentNode(ExpressionNode argumentNode) { + argumentNodes.add(argumentNode); + } + + public void setArgumentNode(int index, ExpressionNode argumentNode) { + argumentNodes.set(index, argumentNode); + } + + public ExpressionNode getArgumentNode(int index) { + return argumentNodes.get(index); + } + + public void removeArgumentNode(ExpressionNode expressionNode) { + argumentNodes.remove(expressionNode); + } + + public void removeArgumentNode(int index) { + argumentNodes.remove(index); + } + + public void setArgumentNodes(List argumentNodes) { + this.argumentNodes = Objects.requireNonNull(argumentNodes); + } + + public List getArgumentsNodes() { + return argumentNodes; + } + + public void clearArgumentNodes() { + argumentNodes.clear(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index 05dd959d6acc1..f7e874178ab58 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -17,14 +17,13 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ir.BinaryNode; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java similarity index 67% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index 00f2283472e49..ddba8ca89314a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; @@ -39,7 +39,7 @@ /** * Represents a capturing function reference. */ -public final class ECapturingFunctionRef extends AExpression implements ILambda { +public final class ECapturingFunctionRef extends AExpression { private final String variable; private final String call; @@ -54,34 +54,6 @@ public ECapturingFunctionRef(Location location, String variable, String call) { this.call = Objects.requireNonNull(call); } - @Override - void extractVariables(Set variables) { - variables.add(variable); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - captured = locals.getVariable(location, variable); - if (expected == null) { - if (captured.clazz == def.class) { - // dynamic implementation - defPointer = "D" + variable + "." + call + ",1"; - } else { - // typed implementation - defPointer = "S" + PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz) + "." + call + ",1"; - } - actual = String.class; - } else { - defPointer = null; - // static case - if (captured.clazz != def.class) { - ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), location, - expected, PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz), call, 1); - } - actual = expected; - } - } - @Override void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); @@ -101,19 +73,4 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.invokeLambdaCall(ref); } } - - @Override - public String getPointer() { - return defPointer; - } - - @Override - public Type[] getCaptures() { - return new Type[] { MethodWriter.getType(captured.clazz) }; - } - - @Override - public String toString() { - return singleLineToString(variable, call); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java new file mode 100644 index 0000000000000..adc0dc7e69310 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java @@ -0,0 +1,70 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Type; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class DefCallNode extends ArgumentsNode { + + protected final Location location; + protected final String name; + protected final String recipe; + protected final List pointers; + protected final List> parameterTypes; + + public DefCallNode(Location location, String name, String recipe, List pointers, List> parameterTypes) { + this.location = location; + this.name = Objects.requireNonNull(name); + this.recipe = Objects.requireNonNull(recipe); + this.pointers = Collections.unmodifiableList(Objects.requireNonNull(pointers)); + this.parameterTypes = Collections.unmodifiableList(Objects.requireNonNull(parameterTypes)); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + for (ExpressionNode argumentNode : argumentNodes) { + argumentNode.write(classWriter, methodWriter, globals); + } + + // create method type from return value and arguments + Type[] asmParameterTypes = new Type[parameterTypes.size()]; + for (int index = 0; index < asmParameterTypes.length; ++index) { + asmParameterTypes[index] = Type.getType(parameterTypes.get(index)); + } + Type methodType = Type.getMethodType(MethodWriter.getType(getType()), asmParameterTypes); + + List args = new ArrayList<>(); + args.add(recipe); + args.addAll(pointers); + methodWriter.invokeDefCall(name, methodType, DefBootstrap.METHOD_CALL, args.toArray()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java deleted file mode 100644 index e386f94d01b69..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECallLocal.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessClassBinding; -import org.elasticsearch.painless.lookup.PainlessInstanceBinding; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.symbol.FunctionTable; -import org.objectweb.asm.Label; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; - -/** - * Represents a user-defined call. - */ -public final class ECallLocal extends AExpression { - - private final String name; - private final List arguments; - - private FunctionTable.LocalFunction localFunction = null; - private PainlessMethod importedMethod = null; - private PainlessClassBinding classBinding = null; - private int classBindingOffset = 0; - private PainlessInstanceBinding instanceBinding = null; - private String bindingName = null; - - public ECallLocal(Location location, String name, List arguments) { - super(location); - - this.name = Objects.requireNonNull(name); - this.arguments = Objects.requireNonNull(arguments); - } - - @Override - void extractVariables(Set variables) { - for (AExpression argument : arguments) { - argument.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - localFunction = scriptRoot.getFunctionTable().getFunction(name, arguments.size()); - - // user cannot call internal functions, reset to null if an internal function is found - if (localFunction != null && localFunction.isInternal()) { - localFunction = null; - } - - if (localFunction == null) { - importedMethod = scriptRoot.getPainlessLookup().lookupImportedPainlessMethod(name, arguments.size()); - - if (importedMethod == null) { - classBinding = scriptRoot.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size()); - - // check to see if this class binding requires an implicit this reference - if (classBinding != null && classBinding.typeParameters.isEmpty() == false && - classBinding.typeParameters.get(0) == scriptRoot.getScriptClassInfo().getBaseClass()) { - classBinding = null; - } - - if (classBinding == null) { - // This extra check looks for a possible match where the class binding requires an implicit this - // reference. This is a temporary solution to allow the class binding access to data from the - // base script class without need for a user to add additional arguments. A long term solution - // will likely involve adding a class instance binding where any instance can have a class binding - // as part of its API. However, the situation at run-time is difficult and will modifications that - // are a substantial change if even possible to do. - classBinding = scriptRoot.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size() + 1); - - if (classBinding != null) { - if (classBinding.typeParameters.isEmpty() == false && - classBinding.typeParameters.get(0) == scriptRoot.getScriptClassInfo().getBaseClass()) { - classBindingOffset = 1; - } else { - classBinding = null; - } - } - - if (classBinding == null) { - instanceBinding = scriptRoot.getPainlessLookup().lookupPainlessInstanceBinding(name, arguments.size()); - - if (instanceBinding == null) { - throw createError(new IllegalArgumentException( - "Unknown call [" + name + "] with [" + arguments.size() + "] arguments.")); - } - } - } - } - } - - List> typeParameters; - - if (localFunction != null) { - typeParameters = new ArrayList<>(localFunction.getTypeParameters()); - actual = localFunction.getReturnType(); - } else if (importedMethod != null) { - typeParameters = new ArrayList<>(importedMethod.typeParameters); - actual = importedMethod.returnType; - } else if (classBinding != null) { - typeParameters = new ArrayList<>(classBinding.typeParameters); - actual = classBinding.returnType; - bindingName = scriptRoot.getNextSyntheticName("class_binding"); - scriptRoot.getClassNode().addField(new SField(location, - Modifier.PRIVATE, bindingName, classBinding.javaConstructor.getDeclaringClass(), null)); - } else if (instanceBinding != null) { - typeParameters = new ArrayList<>(instanceBinding.typeParameters); - actual = instanceBinding.returnType; - bindingName = scriptRoot.getNextSyntheticName("instance_binding"); - scriptRoot.getClassNode().addField(new SField(location, Modifier.STATIC | Modifier.PUBLIC, - bindingName, instanceBinding.targetInstance.getClass(), instanceBinding.targetInstance)); - } else { - throw new IllegalStateException("Illegal tree structure."); - } - - // if the class binding is using an implicit this reference then the arguments counted must - // be incremented by 1 as the this reference will not be part of the arguments passed into - // the class binding call - for (int argument = 0; argument < arguments.size(); ++argument) { - AExpression expression = arguments.get(argument); - - expression.expected = typeParameters.get(argument + classBindingOffset); - expression.internal = true; - expression.analyze(scriptRoot, locals); - arguments.set(argument, expression.cast(scriptRoot, locals)); - } - - statement = true; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (localFunction != null) { - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod()); - } else if (importedMethod != null) { - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - methodWriter.invokeStatic(Type.getType(importedMethod.targetClass), - new Method(importedMethod.javaMethod.getName(), importedMethod.methodType.toMethodDescriptorString())); - } else if (classBinding != null) { - Type type = Type.getType(classBinding.javaConstructor.getDeclaringClass()); - int javaConstructorParameterCount = classBinding.javaConstructor.getParameterCount() - classBindingOffset; - - Label nonNull = new Label(); - - methodWriter.loadThis(); - methodWriter.getField(CLASS_TYPE, bindingName, type); - methodWriter.ifNonNull(nonNull); - methodWriter.loadThis(); - methodWriter.newInstance(type); - methodWriter.dup(); - - if (classBindingOffset == 1) { - methodWriter.loadThis(); - } - - for (int argument = 0; argument < javaConstructorParameterCount; ++argument) { - arguments.get(argument).write(classWriter, methodWriter, globals); - } - - methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor)); - methodWriter.putField(CLASS_TYPE, bindingName, type); - - methodWriter.mark(nonNull); - methodWriter.loadThis(); - methodWriter.getField(CLASS_TYPE, bindingName, type); - - for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) { - arguments.get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); - } - - methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod)); - } else if (instanceBinding != null) { - Type type = Type.getType(instanceBinding.targetInstance.getClass()); - - methodWriter.loadThis(); - methodWriter.getStatic(CLASS_TYPE, bindingName, type); - - for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) { - arguments.get(argument).write(classWriter, methodWriter, globals); - } - - methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod)); - } else { - throw new IllegalStateException("Illegal tree structure."); - } - } - - @Override - public String toString() { - return singleLineToStringWithOptionalArgs(arguments, name); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java deleted file mode 100644 index 5a279b3a162f3..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ILambda.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -/** - * Interface for lambda/method reference nodes. They need special handling by LDefCall. - *

- * This is because they know nothing about the target interface, and can only push - * all their captures onto the stack and defer everything until link-time. - */ -interface ILambda { - - /** Returns reference to resolve at link-time */ - String getPointer(); - - /** Returns the types of captured parameters. Can be empty */ - org.objectweb.asm.Type[] getCaptures(); - - /** Returns the number of captured parameters */ - default int getCaptureCount() { - return getCaptures().length; - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java deleted file mode 100644 index 795ce7d566a49..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefCall.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; - -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Represents a method call made on a def type. (Internal only.) - */ -final class PSubDefCall extends AExpression { - - private final String name; - private final List arguments; - - private StringBuilder recipe = null; - private List pointers = new ArrayList<>(); - - PSubDefCall(Location location, String name, List arguments) { - super(location); - - this.name = Objects.requireNonNull(name); - this.arguments = Objects.requireNonNull(arguments); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - recipe = new StringBuilder(); - int totalCaptures = 0; - - for (int argument = 0; argument < arguments.size(); ++argument) { - AExpression expression = arguments.get(argument); - - expression.internal = true; - expression.analyze(scriptRoot, locals); - - if (expression instanceof ILambda) { - ILambda lambda = (ILambda) expression; - pointers.add(lambda.getPointer()); - // encode this parameter as a deferred reference - char ch = (char) (argument + totalCaptures); - recipe.append(ch); - totalCaptures += lambda.getCaptureCount(); - } - - if (expression.actual == void.class) { - throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "].")); - } - - expression.expected = expression.actual; - arguments.set(argument, expression.cast(scriptRoot, locals)); - } - - // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed - actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - List parameterTypes = new ArrayList<>(); - - // first parameter is the receiver, we never know its type: always Object - parameterTypes.add(org.objectweb.asm.Type.getType(Object.class)); - - // append each argument - for (AExpression argument : arguments) { - parameterTypes.add(MethodWriter.getType(argument.actual)); - - if (argument instanceof ILambda) { - ILambda lambda = (ILambda) argument; - Collections.addAll(parameterTypes, lambda.getCaptures()); - } - - argument.write(classWriter, methodWriter, globals); - } - - // create method type from return value and arguments - Type methodType = Type.getMethodType(MethodWriter.getType(actual), parameterTypes.toArray(new Type[0])); - - List args = new ArrayList<>(); - args.add(recipe.toString()); - args.addAll(pointers); - methodWriter.invokeDefCall(name, methodType, DefBootstrap.METHOD_CALL, args.toArray()); - } - - @Override - public String toString() { - return singleLineToStringWithOptionalArgs(arguments, prefix, name); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java new file mode 100644 index 0000000000000..7c87436fc8c7c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -0,0 +1,131 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessClassBinding; +import org.elasticsearch.painless.lookup.PainlessInstanceBinding; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.FunctionTable.LocalFunction; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.Objects; + +import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; + +public class UnboundCallNode extends ArgumentsNode { + + protected final Location location; + protected final LocalFunction localFunction; + protected final PainlessMethod importedMethod; + protected final PainlessClassBinding classBinding; + protected final int classBindingOffset; + protected final PainlessInstanceBinding instanceBinding; + protected final String bindingName; + + public UnboundCallNode( + Location location, + LocalFunction localFunction, + PainlessMethod importedMethod, + PainlessClassBinding classBinding, + int classBindingOffset, + PainlessInstanceBinding instanceBinding, + String bindingName + ) { + this.location = Objects.requireNonNull(location); + this.localFunction = localFunction; + this.importedMethod = importedMethod; + this.classBinding = classBinding; + this.classBindingOffset = classBindingOffset; + this.instanceBinding = instanceBinding; + this.bindingName = bindingName; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (localFunction != null) { + for (ExpressionNode argumentNode : argumentNodes) { + argumentNode.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod()); + } else if (importedMethod != null) { + for (ExpressionNode argumentNode : argumentNodes) { + argumentNode.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeStatic(Type.getType(importedMethod.targetClass), + new Method(importedMethod.javaMethod.getName(), importedMethod.methodType.toMethodDescriptorString())); + } else if (classBinding != null) { + Type type = Type.getType(classBinding.javaConstructor.getDeclaringClass()); + int javaConstructorParameterCount = classBinding.javaConstructor.getParameterCount() - classBindingOffset; + + Label nonNull = new Label(); + + methodWriter.loadThis(); + methodWriter.getField(CLASS_TYPE, bindingName, type); + methodWriter.ifNonNull(nonNull); + methodWriter.loadThis(); + methodWriter.newInstance(type); + methodWriter.dup(); + + if (classBindingOffset == 1) { + methodWriter.loadThis(); + } + + for (int argument = 0; argument < javaConstructorParameterCount; ++argument) { + argumentNodes.get(argument).write(classWriter, methodWriter, globals); + } + + methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor)); + methodWriter.putField(CLASS_TYPE, bindingName, type); + + methodWriter.mark(nonNull); + methodWriter.loadThis(); + methodWriter.getField(CLASS_TYPE, bindingName, type); + + for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) { + argumentNodes.get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); + } + + methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod)); + } else if (instanceBinding != null) { + Type type = Type.getType(instanceBinding.targetInstance.getClass()); + + methodWriter.loadThis(); + methodWriter.getStatic(CLASS_TYPE, bindingName, type); + + for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) { + argumentNodes.get(argument).write(classWriter, methodWriter, globals); + } + + methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod)); + } else { + throw new IllegalStateException("invalid unbound call"); + } + } +} 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 dd76ddc6d0974..00bd215918393 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 @@ -33,6 +33,8 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -108,8 +110,8 @@ public String getPointer() { } @Override - public Type[] getCaptures() { - return new Type[] { MethodWriter.getType(captured.clazz) }; + public List> getCaptures() { + return Collections.singletonList(captured.clazz); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index 97b496a5985f9..8247ec54215ce 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -26,8 +26,9 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Type; +import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -83,8 +84,8 @@ public String getPointer() { } @Override - public Type[] getCaptures() { - return new Type[0]; // no captures + public List> getCaptures() { + return Collections.emptyList(); } @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 120bbdd744797..4b23ee6fb8f2c 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 @@ -215,10 +215,10 @@ public String getPointer() { } @Override - 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).clazz); + public List> getCaptures() { + List> types = new ArrayList<>(); + for (Variable variable : captures) { + types.add(variable.clazz); } return types; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java index f496dec4321a9..98b471a10360e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java @@ -26,10 +26,10 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Type; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -97,8 +97,8 @@ public String getPointer() { } @Override - public Type[] getCaptures() { - return new Type[0]; // no captures + public List> getCaptures() { + return Collections.emptyList(); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java index 5a279b3a162f3..7a58d18748dc0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java @@ -19,7 +19,9 @@ package org.elasticsearch.painless.node; -/** +import java.util.List; + +/** * Interface for lambda/method reference nodes. They need special handling by LDefCall. *

* This is because they know nothing about the target interface, and can only push @@ -31,7 +33,7 @@ interface ILambda { String getPointer(); /** Returns the types of captured parameters. Can be empty */ - org.objectweb.asm.Type[] getCaptures(); + List> getCaptures(); /** Returns the number of captured parameters */ default int getCaptureCount() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index 795ce7d566a49..268383fd6e557 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -44,8 +44,9 @@ final class PSubDefCall extends AExpression { private final String name; private final List arguments; - private StringBuilder recipe = null; - private List pointers = new ArrayList<>(); + private final StringBuilder recipe = new StringBuilder(); + private final List pointers = new ArrayList<>(); + private final List> parameterTypes = new ArrayList<>(); PSubDefCall(Location location, String name, List arguments) { super(location); @@ -61,7 +62,7 @@ void extractVariables(Set variables) { @Override void analyze(ScriptRoot scriptRoot, Locals locals) { - recipe = new StringBuilder(); + parameterTypes.add(Object.class); int totalCaptures = 0; for (int argument = 0; argument < arguments.size(); ++argument) { @@ -70,6 +71,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { expression.internal = true; expression.analyze(scriptRoot, locals); + if (expression.actual == void.class) { + throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "].")); + } + + expression.expected = expression.actual; + arguments.set(argument, expression.cast(scriptRoot, locals)); + parameterTypes.add(expression.actual); + if (expression instanceof ILambda) { ILambda lambda = (ILambda) expression; pointers.add(lambda.getPointer()); @@ -77,14 +86,8 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { char ch = (char) (argument + totalCaptures); recipe.append(ch); totalCaptures += lambda.getCaptureCount(); + parameterTypes.addAll(lambda.getCaptures()); } - - if (expression.actual == void.class) { - throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "].")); - } - - expression.expected = expression.actual; - arguments.set(argument, expression.cast(scriptRoot, locals)); } // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed @@ -95,25 +98,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - List parameterTypes = new ArrayList<>(); - - // first parameter is the receiver, we never know its type: always Object - parameterTypes.add(org.objectweb.asm.Type.getType(Object.class)); - - // append each argument for (AExpression argument : arguments) { - parameterTypes.add(MethodWriter.getType(argument.actual)); - - if (argument instanceof ILambda) { - ILambda lambda = (ILambda) argument; - Collections.addAll(parameterTypes, lambda.getCaptures()); - } - argument.write(classWriter, methodWriter, globals); } // create method type from return value and arguments - Type methodType = Type.getMethodType(MethodWriter.getType(actual), parameterTypes.toArray(new Type[0])); + Type[] asmParameterTypes = new Type[parameterTypes.size()]; + for (int index = 0; index < asmParameterTypes.length; ++index) { + asmParameterTypes[index] = Type.getType(parameterTypes.get(index)); + } + Type methodType = Type.getMethodType(MethodWriter.getType(actual), asmParameterTypes); List args = new ArrayList<>(); args.add(recipe.toString()); From b6ccc7821c74112b5531526a5b684f19d95502a9 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sun, 15 Dec 2019 14:50:01 -0800 Subject: [PATCH 04/24] checkpoint --- .../painless/ir/CapturingFuncRefNode.java | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index ddba8ca89314a..9f95217626a20 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -23,31 +23,23 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.util.Objects; -import java.util.Set; -/** - * Represents a capturing function reference. - */ -public final class ECapturingFunctionRef extends AExpression { - private final String variable; - private final String call; +public class ECapturingFunctionRef extends ExpressionNode { - private FunctionRef ref; - private Variable captured; - private String defPointer; + protected final String name; + protected final FunctionRef functionRef; + protected final Variable captured; + protected final String pointer; - public ECapturingFunctionRef(Location location, String variable, String call) { + public ECapturingFunctionRef(Location location, FunctionRef functionRef, ) { super(location); this.variable = Objects.requireNonNull(variable); @@ -55,11 +47,10 @@ public ECapturingFunctionRef(Location location, String variable, String call) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (defPointer != null) { - // dynamic interface: push captured parameter on stack - // TODO: don't do this: its just to cutover :) + // dynamic interface: push placeholder onto stack methodWriter.push((String)null); methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); } else if (ref == null) { From 754d2d9ca1748f2bf6e2fda35dda6d61b2e3550c Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 16 Dec 2019 10:09:46 -0800 Subject: [PATCH 05/24] converted more nodes --- .../painless/ir/ArgumentsNode.java | 4 +- .../painless/ir/AssignmentNode.java | 2 +- .../ir/{MathNode.java => BinaryMathNode.java} | 8 +- .../elasticsearch/painless/ir/BinaryNode.java | 2 +- .../painless/ir/CapturingFuncRefNode.java | 29 ++-- .../painless/ir/{ECast.java => CastNode.java} | 40 +---- .../painless/ir/ConditionalNode.java | 65 +++++++++ .../painless/ir/DefCallNode.java | 2 +- .../painless/ir/EConditional.java | 113 --------------- .../org/elasticsearch/painless/ir/EElvis.java | 114 --------------- .../elasticsearch/painless/ir/EExplicit.java | 83 ----------- .../painless/ir/EFunctionRef.java | 94 ------------ .../painless/ir/EInstanceof.java | 105 -------------- .../elasticsearch/painless/ir/EMapInit.java | 137 ------------------ .../elasticsearch/painless/ir/ElvisNode.java | 51 +++++++ .../painless/ir/FuncRefNode.java | 50 +++++++ .../painless/ir/InstanceofNode.java | 69 +++++++++ .../painless/ir/MapInitializationNode.java | 114 +++++++++++++++ .../elasticsearch/painless/ir/UnaryNode.java | 37 +++++ 19 files changed, 418 insertions(+), 701 deletions(-) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{MathNode.java => BinaryMathNode.java} (91%) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{ECast.java => CastNode.java} (50%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java index 0c7d6330f9734..f5d2150f5d8c2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java @@ -47,8 +47,8 @@ public void removeArgumentNode(int index) { argumentNodes.remove(index); } - public void setArgumentNodes(List argumentNodes) { - this.argumentNodes = Objects.requireNonNull(argumentNodes); + public int getArgumentsSize() { + return argumentNodes.size(); } public List getArgumentsNodes() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 4ea4c8a4c8db2..8d2b9c3e53ced 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -90,7 +90,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs - if (rightNode instanceof MathNode == false || ((MathNode)rightNode).cat == false) { // check to see if the rhs + if (rightNode instanceof BinaryMathNode == false || ((BinaryMathNode)rightNode).cat == false) { // check to see if the rhs // has already done a concatenation methodWriter.writeAppendStrings(rightNode.getType()); // append the rhs's value since // it's hasn't already diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java similarity index 91% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index 9458732d7e5c9..76fe731dd019b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -32,14 +32,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class MathNode extends ShiftNode { +public class BinaryMathNode extends ShiftNode { protected final Location location; protected final Operation operation; protected final boolean cat; protected final boolean originallyExplicit; // record whether there was originally an explicit cast - public MathNode(Location location, Operation operation, boolean cat, boolean originallyExplicit) { + public BinaryMathNode(Location location, Operation operation, boolean cat, boolean originallyExplicit) { this.location = Objects.requireNonNull(location); this.operation = Objects.requireNonNull(operation); this.cat = cat; @@ -57,13 +57,13 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl leftNode.write(classWriter, methodWriter, globals); - if ((leftNode instanceof MathNode) == false || ((MathNode)leftNode).cat == false) { + if ((leftNode instanceof BinaryMathNode) == false || ((BinaryMathNode)leftNode).cat == false) { methodWriter.writeAppendStrings(leftNode.getType()); } rightNode.write(classWriter, methodWriter, globals); - if ((rightNode instanceof MathNode) == false || ((MathNode)rightNode).cat == false) { + if ((rightNode instanceof BinaryMathNode) == false || ((BinaryMathNode)rightNode).cat == false) { methodWriter.writeAppendStrings(rightNode.getType()); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java index ee2b29b759aab..eb7f1e9d37b4e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java @@ -19,7 +19,7 @@ package org.elasticsearch.painless.ir; -public class BinaryNode extends ExpressionNode { +public abstract class BinaryNode extends ExpressionNode { protected ExpressionNode leftNode; protected ExpressionNode rightNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index 9f95217626a20..6c4fd52a93d22 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -26,42 +26,43 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.util.Objects; -public class ECapturingFunctionRef extends ExpressionNode { +public class CapturingFuncRefNode extends ExpressionNode { + protected final Location location; protected final String name; - protected final FunctionRef functionRef; protected final Variable captured; + protected final FunctionRef functionRef; protected final String pointer; - public ECapturingFunctionRef(Location location, FunctionRef functionRef, ) { - super(location); - - this.variable = Objects.requireNonNull(variable); - this.call = Objects.requireNonNull(call); + public CapturingFuncRefNode(Location location, String name, Variable captured, FunctionRef functionRef, String pointer) { + this.location = Objects.requireNonNull(location); + this.name = Objects.requireNonNull(name); + this.captured = Objects.requireNonNull(captured); + this.functionRef = functionRef; + this.pointer = pointer; } @Override public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - if (defPointer != null) { - // dynamic interface: push placeholder onto stack + if (pointer != null) { + // dynamic interface: placeholder for run-time lookup methodWriter.push((String)null); methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - } else if (ref == null) { + } else if (functionRef == null) { // typed interface, dynamic implementation methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - Type methodType = Type.getMethodType(MethodWriter.getType(expected), MethodWriter.getType(captured.clazz)); - methodWriter.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookupUtility.typeToCanonicalTypeName(expected)); + Type methodType = Type.getMethodType(MethodWriter.getType(getType()), MethodWriter.getType(captured.clazz)); + methodWriter.invokeDefCall(name, methodType, DefBootstrap.REFERENCE, getCanonicalTypeName()); } else { // typed interface, typed implementation methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - methodWriter.invokeLambdaCall(ref); + methodWriter.invokeLambdaCall(functionRef); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java similarity index 50% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java index d33f37fb6049b..7d412c7c77f5b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java @@ -17,54 +17,30 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.util.Objects; -import java.util.Set; -/** - * Represents a cast that is inserted into the tree replacing other casts. (Internal only.) - */ -final class ECast extends AExpression { - - private AExpression child; - private final PainlessCast cast; +public class CastNode extends UnaryNode { - ECast(Location location, AExpression child, PainlessCast cast) { - super(location); + protected final Location location; + protected final PainlessCast cast; - this.child = Objects.requireNonNull(child); + CastNode(Location location, PainlessCast cast) { + this.location = Objects.requireNonNull(location); this.cast = Objects.requireNonNull(cast); } @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - child.write(classWriter, methodWriter, globals); + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.write(classWriter, methodWriter, globals); methodWriter.writeDebugInfo(location); methodWriter.writeCast(cast); } - - @Override - public String toString() { - return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(cast.targetType), child); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java new file mode 100644 index 0000000000000..1743e05da12f4 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java @@ -0,0 +1,65 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; + +public class ConditionalNode extends BinaryNode { + + protected Location location; + + public ConditionalNode(Location location) { + this.location = Objects.requireNonNull(location); + } + + protected ExpressionNode conditionNode; + + public void setConditionNode(ExpressionNode conditionNode) { + this.conditionNode = conditionNode; + } + + public ExpressionNode getConditionNode() { + return conditionNode; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Label fals = new Label(); + Label end = new Label(); + + conditionNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + leftNode.write(classWriter, methodWriter, globals); + methodWriter.goTo(end); + methodWriter.mark(fals); + rightNode.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java index adc0dc7e69310..74b6bef7efb1d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Objects; -public class DefCallNode extends ArgumentsNode { +public class DefCallNode extends ArgumentsNode { protected final Location location; protected final String name; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java deleted file mode 100644 index c8263b587bb44..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EConditional.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a conditional expression. - */ -public final class EConditional extends AExpression { - - private AExpression condition; - private AExpression left; - private AExpression right; - - public EConditional(Location location, AExpression condition, AExpression left, AExpression right) { - super(location); - - this.condition = Objects.requireNonNull(condition); - this.left = Objects.requireNonNull(left); - this.right = Objects.requireNonNull(right); - } - - @Override - void extractVariables(Set variables) { - condition.extractVariables(variables); - left.extractVariables(variables); - right.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - condition.expected = boolean.class; - condition.analyze(scriptRoot, locals); - condition = condition.cast(scriptRoot, locals); - - if (condition.constant != null) { - throw createError(new IllegalArgumentException("Extraneous conditional statement.")); - } - - left.expected = expected; - left.explicit = explicit; - left.internal = internal; - right.expected = expected; - right.explicit = explicit; - right.internal = internal; - actual = expected; - - left.analyze(scriptRoot, locals); - right.analyze(scriptRoot, locals); - - if (expected == null) { - Class promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant); - - left.expected = promote; - right.expected = promote; - actual = promote; - } - - left = left.cast(scriptRoot, locals); - right = right.cast(scriptRoot, locals); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Label fals = new Label(); - Label end = new Label(); - - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - left.write(classWriter, methodWriter, globals); - methodWriter.goTo(end); - methodWriter.mark(fals); - right.write(classWriter, methodWriter, globals); - methodWriter.mark(end); - } - - @Override - public String toString() { - return singleLineToString(condition, left, right); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java deleted file mode 100644 index d5e494ffa3098..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EElvis.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; - -import java.util.Set; - -import static java.util.Objects.requireNonNull; - -/** - * The Elvis operator ({@code ?:}), a null coalescing operator. Binary operator that evaluates the first expression and return it if it is - * non null. If the first expression is null then it evaluates the second expression and returns it. - */ -public class EElvis extends AExpression { - private AExpression lhs; - private AExpression rhs; - - public EElvis(Location location, AExpression lhs, AExpression rhs) { - super(location); - - this.lhs = requireNonNull(lhs); - this.rhs = requireNonNull(rhs); - } - - @Override - void extractVariables(Set variables) { - lhs.extractVariables(variables); - rhs.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (expected != null && expected.isPrimitive()) { - throw createError(new IllegalArgumentException("Elvis operator cannot return primitives")); - } - lhs.expected = expected; - lhs.explicit = explicit; - lhs.internal = internal; - rhs.expected = expected; - rhs.explicit = explicit; - rhs.internal = internal; - actual = expected; - lhs.analyze(scriptRoot, locals); - rhs.analyze(scriptRoot, locals); - - if (lhs.isNull) { - throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is null.")); - } - if (lhs.constant != null) { - throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a constant.")); - } - if (lhs.actual.isPrimitive()) { - throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a primitive.")); - } - if (rhs.isNull) { - throw createError(new IllegalArgumentException("Extraneous elvis operator. RHS is null.")); - } - - if (expected == null) { - Class promote = AnalyzerCaster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant); - - lhs.expected = promote; - rhs.expected = promote; - actual = promote; - } - - lhs = lhs.cast(scriptRoot, locals); - rhs = rhs.cast(scriptRoot, locals); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Label end = new Label(); - - lhs.write(classWriter, methodWriter, globals); - methodWriter.dup(); - methodWriter.ifNonNull(end); - methodWriter.pop(); - rhs.write(classWriter, methodWriter, globals); - methodWriter.mark(end); - } - - @Override - public String toString() { - return singleLineToString(lhs, rhs); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java deleted file mode 100644 index b092aef87de42..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EExplicit.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents an explicit cast. - */ -public final class EExplicit extends AExpression { - - private final String type; - private AExpression child; - - public EExplicit(Location location, String type, AExpression child) { - super(location); - - this.type = Objects.requireNonNull(type); - this.child = Objects.requireNonNull(child); - } - - @Override - void extractVariables(Set variables) { - child.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(type); - - if (actual == null) { - throw createError(new IllegalArgumentException("Not a type [" + type + "].")); - } - - child.expected = actual; - child.explicit = true; - child.analyze(scriptRoot, locals); - child = child.cast(scriptRoot, locals); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - AExpression cast(ScriptRoot scriptRoot, Locals locals) { - child.expected = expected; - child.explicit = explicit; - child.internal = internal; - - return child.cast(scriptRoot, locals); - } - - @Override - public String toString() { - return singleLineToString(type, child); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java deleted file mode 100644 index 97b496a5985f9..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EFunctionRef.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Type; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a function reference. - */ -public final class EFunctionRef extends AExpression implements ILambda { - private final String type; - private final String call; - - private FunctionRef ref; - private String defPointer; - - public EFunctionRef(Location location, String type, String call) { - super(location); - - this.type = Objects.requireNonNull(type); - this.call = Objects.requireNonNull(call); - } - - @Override - void extractVariables(Set variables) { - // do nothing - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (expected == null) { - ref = null; - actual = String.class; - defPointer = "S" + type + "." + call + ",0"; - } else { - defPointer = null; - ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), location, expected, type, call, 0); - actual = expected; - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (ref != null) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeLambdaCall(ref); - } else { - // TODO: don't do this: its just to cutover :) - methodWriter.push((String)null); - } - } - - @Override - public String getPointer() { - return defPointer; - } - - @Override - public Type[] getCaptures() { - return new Type[0]; // no captures - } - - @Override - public String toString() { - return singleLineToString(type, call); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java deleted file mode 100644 index 88dc36b497cb4..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EInstanceof.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents {@code instanceof} operator. - *

- * Unlike java's, this works for primitive types too. - */ -public final class EInstanceof extends AExpression { - private AExpression expression; - private final String type; - - private Class resolvedType; - private Class expressionType; - private boolean primitiveExpression; - - public EInstanceof(Location location, AExpression expression, String type) { - super(location); - this.expression = Objects.requireNonNull(expression); - this.type = Objects.requireNonNull(type); - } - - @Override - void extractVariables(Set variables) { - expression.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - // ensure the specified type is part of the definition - Class clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); - - if (clazz == null) { - throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); - } - - // map to wrapped type for primitive types - resolvedType = clazz.isPrimitive() ? PainlessLookupUtility.typeToBoxedType(clazz) : - PainlessLookupUtility.typeToJavaType(clazz); - - // analyze and cast the expression - expression.analyze(scriptRoot, locals); - expression.expected = expression.actual; - expression = expression.cast(scriptRoot, locals); - - // record if the expression returns a primitive - primitiveExpression = expression.actual.isPrimitive(); - // map to wrapped type for primitive types - expressionType = expression.actual.isPrimitive() ? - PainlessLookupUtility.typeToBoxedType(expression.actual) : PainlessLookupUtility.typeToJavaType(clazz); - - actual = boolean.class; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // primitive types - if (primitiveExpression) { - // run the expression anyway (who knows what it does) - expression.write(classWriter, methodWriter, globals); - // discard its result - methodWriter.writePop(MethodWriter.getType(expression.actual).getSize()); - // push our result: its a primitive so it cannot be null. - methodWriter.push(resolvedType.isAssignableFrom(expressionType)); - } else { - // ordinary instanceof - expression.write(classWriter, methodWriter, globals); - methodWriter.instanceOf(org.objectweb.asm.Type.getType(resolvedType)); - } - } - - @Override - public String toString() { - return singleLineToString(expression, type); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java deleted file mode 100644 index 6b2c1861bf39d..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EMapInit.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessConstructor; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; - -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; - -/** - * Represents a map initialization shortcut. - */ -public final class EMapInit extends AExpression { - private final List keys; - private final List values; - - private PainlessConstructor constructor = null; - private PainlessMethod method = null; - - public EMapInit(Location location, List keys, List values) { - super(location); - - this.keys = keys; - this.values = values; - } - - @Override - void extractVariables(Set variables) { - for (AExpression key : keys) { - key.extractVariables(variables); - } - - for (AExpression value : values) { - value.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from map initializer.")); - } - - actual = HashMap.class; - - constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, 0); - - if (constructor == null) { - throw createError(new IllegalArgumentException( - "constructor [" + typeToCanonicalTypeName(actual) + ", /0] not found")); - } - - method = scriptRoot.getPainlessLookup().lookupPainlessMethod(actual, false, "put", 2); - - if (method == null) { - throw createError(new IllegalArgumentException("method [" + typeToCanonicalTypeName(actual) + ", put/2] not found")); - } - - if (keys.size() != values.size()) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - for (int index = 0; index < keys.size(); ++index) { - AExpression expression = keys.get(index); - - expression.expected = def.class; - expression.internal = true; - expression.analyze(scriptRoot, locals); - keys.set(index, expression.cast(scriptRoot, locals)); - } - - for (int index = 0; index < values.size(); ++index) { - AExpression expression = values.get(index); - - expression.expected = def.class; - expression.internal = true; - expression.analyze(scriptRoot, locals); - values.set(index, expression.cast(scriptRoot, locals)); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.newInstance(MethodWriter.getType(actual)); - methodWriter.dup(); - methodWriter.invokeConstructor( - Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); - - for (int index = 0; index < keys.size(); ++index) { - AExpression key = keys.get(index); - AExpression value = values.get(index); - - methodWriter.dup(); - key.write(classWriter, methodWriter, globals); - value.write(classWriter, methodWriter, globals); - methodWriter.invokeMethodCall(method); - methodWriter.pop(); - } - } - - @Override - public String toString() { - return singleLineToString(pairwiseToString(keys, values)); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java new file mode 100644 index 0000000000000..85cadbd348f3c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; + +import java.util.Objects; + +public class ElvisNode extends BinaryNode { + + protected Location location; + + public ElvisNode(Location location) { + this.location = Objects.requireNonNull(location); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Label end = new Label(); + + leftNode.write(classWriter, methodWriter, globals); + methodWriter.dup(); + methodWriter.ifNonNull(end); + methodWriter.pop(); + rightNode.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java new file mode 100644 index 0000000000000..17a088c002491 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.FunctionRef; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; + +import java.util.Objects; + +public class FuncRefNode extends ExpressionNode { + + protected final Location location; + protected final FunctionRef functionRef; + + public FuncRefNode(Location location, FunctionRef functionRef) { + this.location = Objects.requireNonNull(location); + this.functionRef = functionRef; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (functionRef != null) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeLambdaCall(functionRef); + } else { + // dynamic interface: placeholder for run-time lookup + methodWriter.push((String)null); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java new file mode 100644 index 0000000000000..c8a5feea17731 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Type; + +public class InstanceofNode extends UnaryNode { + + protected final boolean isPrimitiveResult; + + public InstanceofNode(boolean isPrimitiveResult) { + this.isPrimitiveResult = isPrimitiveResult; + } + + protected TypeNode expressionTypeNode; + protected TypeNode resolvedTypeNode; + + public void setExpressionTypeNode(TypeNode expressionTypeNode) { + this.expressionTypeNode = expressionTypeNode; + } + + public void setResolvedTypeNode(TypeNode resolvedTypeNode) { + this.resolvedTypeNode = resolvedTypeNode; + } + + public TypeNode setExpressionTypeNode() { + return expressionTypeNode; + } + + public TypeNode setResolvedTypeNode() { + return resolvedTypeNode; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.write(classWriter, methodWriter, globals); + + // primitive types + if (isPrimitiveResult) { + // discard child's result result + methodWriter.writePop(MethodWriter.getType(childNode.getType()).getSize()); + // push our result: its' a primitive so it cannot be null + methodWriter.push(resolvedTypeNode.getType().isAssignableFrom(expressionTypeNode.getType())); + } else { + // ordinary instanceof + methodWriter.instanceOf(Type.getType(resolvedTypeNode.getType())); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java new file mode 100644 index 0000000000000..57b799135b89c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class MapInitializationNode extends ExpressionNode { + + protected final Location location; + protected final PainlessConstructor constructor; + protected final PainlessMethod method; + + public MapInitializationNode(Location location, PainlessConstructor constructor, PainlessMethod method) { + this.location = Objects.requireNonNull(location); + this.constructor = Objects.requireNonNull(constructor); + this.method = Objects.requireNonNull(method); + } + + protected final List keyNodes = new ArrayList<>(); + protected final List valueNodes = new ArrayList<>(); + + public void addArgumentNode(ExpressionNode keyNode, ExpressionNode valueNode) { + keyNodes.add(keyNode); + valueNodes.add(valueNode); + } + + public void setArgumentNode(int index, ExpressionNode keyNode, ExpressionNode valueNode) { + keyNodes.set(index, keyNode); + valueNodes.set(index, valueNode); + } + + public ExpressionNode getKeyNode(int index) { + return keyNodes.get(index); + } + + public ExpressionNode getValueNode(int index) { + return keyNodes.get(index); + } + + public ExpressionNode[] getArgumentNode(int index) { + return new ExpressionNode[] { + keyNodes.get(index), + valueNodes.get(index) + }; + } + + public void removeArgumentNode(int index) { + keyNodes.remove(index); + valueNodes.remove(index); + } + + public int getArgumentsSize() { + return keyNodes.size(); + } + + public List getKeyNodes() { + return keyNodes; + } + + public List getValueNodes() { + return valueNodes; + } + + public void clearArgumentNodes() { + keyNodes.clear(); + valueNodes.clear(); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.newInstance(MethodWriter.getType(getType())); + methodWriter.dup(); + methodWriter.invokeConstructor( + Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + + for (int index = 0; index < getArgumentsSize(); ++index) { + methodWriter.dup(); + getKeyNode(index).write(classWriter, methodWriter, globals); + getValueNode(index).write(classWriter, methodWriter, globals); + methodWriter.invokeMethodCall(method); + methodWriter.pop(); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java new file mode 100644 index 0000000000000..ee5c7a67462ec --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +public abstract class UnaryNode extends ExpressionNode { + + protected ExpressionNode childNode; + + public UnaryNode() { + // do nothing + } + + public void setChildNode(ExpressionNode childNode) { + this.childNode = childNode; + } + + public ExpressionNode getChildNode() { + return childNode; + } +} From fd966149d3fb1a15ffe18086e5e8dbe420e6766c Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 16 Dec 2019 14:41:46 -0800 Subject: [PATCH 06/24] completion of expression node conversion --- .../painless/ir/BinaryMathNode.java | 2 +- .../elasticsearch/painless/ir/ELambda.java | 230 ---------------- .../elasticsearch/painless/ir/EListInit.java | 114 -------- .../elasticsearch/painless/ir/ENewArray.java | 114 -------- .../painless/ir/ENewArrayFunctionRef.java | 108 -------- .../elasticsearch/painless/ir/ENewObj.java | 121 --------- .../elasticsearch/painless/ir/ENumeric.java | 131 --------- .../org/elasticsearch/painless/ir/ERegex.java | 137 ---------- .../elasticsearch/painless/ir/EString.java | 66 ----- .../org/elasticsearch/painless/ir/EUnary.java | 257 ------------------ .../elasticsearch/painless/ir/LambdaNode.java | 66 +++++ .../painless/ir/ListInitializationNode.java | 61 +++++ ...{EStatic.java => NewArrayFuncRefNode.java} | 48 +--- .../painless/ir/NewArrayNode.java | 65 +++++ .../painless/ir/NewObjectNode.java | 61 +++++ .../org/elasticsearch/painless/ir/PBrace.java | 37 +-- .../elasticsearch/painless/ir/RegexNode.java | 74 +++++ .../elasticsearch/painless/ir/StaticNode.java | 35 +++ .../painless/ir/UnaryMathNode.java | 111 ++++++++ 19 files changed, 490 insertions(+), 1348 deletions(-) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{EStatic.java => NewArrayFuncRefNode.java} (51%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index 76fe731dd019b..f3da00a263780 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -80,7 +80,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } else if (operation == Operation.MATCH) { methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_MATCHES); } else { - throw new IllegalStateException("unexpected math operation [" + operation + "] " + + throw new IllegalStateException("unexpected binary math operation [" + operation + "] " + "for type [" + getCanonicalTypeName() + "]"); } } else { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java deleted file mode 100644 index 120bbdd744797..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ELambda.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Opcodes; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Lambda expression node. - *

- * This can currently only be the direct argument of a call (method/constructor). - * When the argument is of a known type, it uses - * - * Java's lambda translation. However, if its a def call, then we don't have - * enough information, and have to defer this until link time. In that case a placeholder - * and all captures are pushed onto the stack and folded into the signature of the parent call. - *

- * For example: - *
- * {@code def list = new ArrayList(); int capture = 0; list.sort((x,y) -> x - y + capture)} - *
- * is converted into a call (pseudocode) such as: - *
- * {@code sort(list, lambda$0, capture)} - *
- * At link time, when we know the interface type, this is decomposed with MethodHandle - * combinators back into (pseudocode): - *
- * {@code sort(list, lambda$0(capture))} - */ -public final class ELambda extends AExpression implements ILambda { - - private final List paramTypeStrs; - private final List paramNameStrs; - private final List statements; - - // extracted variables required to determine captures - private final Set extractedVariables; - // desugared synthetic method (lambda body) - private SFunction desugared; - // captured variables - private List captures; - // static parent, static lambda - private FunctionRef ref; - // dynamic parent, deferred until link time - private String defPointer; - - public ELambda(Location location, - List paramTypes, List paramNames, - List statements) { - super(location); - this.paramTypeStrs = Collections.unmodifiableList(paramTypes); - this.paramNameStrs = Collections.unmodifiableList(paramNames); - this.statements = Collections.unmodifiableList(statements); - - this.extractedVariables = new HashSet<>(); - } - - @Override - void extractVariables(Set variables) { - for (AStatement statement : statements) { - statement.extractVariables(extractedVariables); - } - - variables.addAll(extractedVariables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - Class returnType; - List actualParamTypeStrs; - PainlessMethod interfaceMethod; - // inspect the target first, set interface method if we know it. - if (expected == null) { - interfaceMethod = null; - // we don't know anything: treat as def - returnType = def.class; - // don't infer any types, replace any null types with def - actualParamTypeStrs = new ArrayList<>(paramTypeStrs.size()); - for (String type : paramTypeStrs) { - if (type == null) { - actualParamTypeStrs.add("def"); - } else { - actualParamTypeStrs.add(type); - } - } - - } else { - // we know the method statically, infer return type and any unknown/def types - interfaceMethod = scriptRoot.getPainlessLookup().lookupFunctionalInterfacePainlessMethod(expected); - if (interfaceMethod == null) { - throw createError(new IllegalArgumentException("Cannot pass lambda to " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], not a functional interface")); - } - // check arity before we manipulate parameters - if (interfaceMethod.typeParameters.size() != paramTypeStrs.size()) - throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.javaMethod.getName() + - "] in [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "]"); - // for method invocation, its allowed to ignore the return value - if (interfaceMethod.returnType == void.class) { - returnType = def.class; - } else { - returnType = interfaceMethod.returnType; - } - // replace any null types with the actual type - actualParamTypeStrs = new ArrayList<>(paramTypeStrs.size()); - for (int i = 0; i < paramTypeStrs.size(); i++) { - String paramType = paramTypeStrs.get(i); - if (paramType == null) { - actualParamTypeStrs.add(PainlessLookupUtility.typeToCanonicalTypeName(interfaceMethod.typeParameters.get(i))); - } else { - actualParamTypeStrs.add(paramType); - } - } - } - // any of those variables defined in our scope need to be captured - captures = new ArrayList<>(); - for (String variable : extractedVariables) { - if (locals.hasVariable(variable)) { - captures.add(locals.getVariable(location, variable)); - } - } - // prepend capture list to lambda's arguments - List paramTypes = new ArrayList<>(captures.size() + actualParamTypeStrs.size()); - List paramNames = new ArrayList<>(captures.size() + paramNameStrs.size()); - for (Variable var : captures) { - paramTypes.add(PainlessLookupUtility.typeToCanonicalTypeName(var.clazz)); - paramNames.add(var.name); - } - paramTypes.addAll(actualParamTypeStrs); - paramNames.addAll(paramNameStrs); - - // desugar lambda body into a synthetic method - String name = scriptRoot.getNextSyntheticName("lambda"); - desugared = new SFunction( - location, PainlessLookupUtility.typeToCanonicalTypeName(returnType), name, paramTypes, paramNames, - new SBlock(location, statements), true); - desugared.generateSignature(scriptRoot.getPainlessLookup()); - desugared.analyze(scriptRoot, Locals.newLambdaScope(locals.getProgramScope(), desugared.name, returnType, - desugared.parameters, captures.size(), scriptRoot.getCompilerSettings().getMaxLoopCounter())); - scriptRoot.getFunctionTable().addFunction(desugared.name, desugared.returnType, desugared.typeParameters, true); - scriptRoot.getClassNode().addFunction(desugared); - - // setup method reference to synthetic method - if (expected == null) { - ref = null; - actual = String.class; - defPointer = "Sthis." + name + "," + captures.size(); - } else { - defPointer = null; - ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), - location, expected, "this", desugared.name, captures.size()); - actual = expected; - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (ref != null) { - methodWriter.writeDebugInfo(location); - // load captures - for (Variable capture : captures) { - methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); - } - - methodWriter.invokeLambdaCall(ref); - } else { - // placeholder - methodWriter.push((String)null); - // load captures - for (Variable capture : captures) { - methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); - } - } - } - - @Override - public String getPointer() { - return defPointer; - } - - @Override - 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).clazz); - } - return types; - } - - @Override - public String toString() { - return multilineToString(pairwiseToString(paramTypeStrs, paramNameStrs), statements); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java deleted file mode 100644 index b0ad7a1a10112..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EListInit.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessConstructor; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; - -/** - * Represents a list initialization shortcut. - */ -public final class EListInit extends AExpression { - private final List values; - - private PainlessConstructor constructor = null; - private PainlessMethod method = null; - - public EListInit(Location location, List values) { - super(location); - - this.values = values; - } - - @Override - void extractVariables(Set variables) { - for (AExpression value : values) { - value.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from list initializer.")); - } - - actual = ArrayList.class; - - constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, 0); - - if (constructor == null) { - throw createError(new IllegalArgumentException( - "constructor [" + typeToCanonicalTypeName(actual) + ", /0] not found")); - } - - method = scriptRoot.getPainlessLookup().lookupPainlessMethod(actual, false, "add", 1); - - if (method == null) { - throw createError(new IllegalArgumentException("method [" + typeToCanonicalTypeName(actual) + ", add/1] not found")); - } - - for (int index = 0; index < values.size(); ++index) { - AExpression expression = values.get(index); - - expression.expected = def.class; - expression.internal = true; - expression.analyze(scriptRoot, locals); - values.set(index, expression.cast(scriptRoot, locals)); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.newInstance(MethodWriter.getType(actual)); - methodWriter.dup(); - methodWriter.invokeConstructor( - Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); - - for (AExpression value : values) { - methodWriter.dup(); - value.write(classWriter, methodWriter, globals); - methodWriter.invokeMethodCall(method); - methodWriter.pop(); - } - } - - @Override - public String toString() { - return singleLineToString(values); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java deleted file mode 100644 index 03ec8a57fc02d..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArray.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Represents an array instantiation. - */ -public final class ENewArray extends AExpression { - - private final String type; - private final List arguments; - private final boolean initialize; - - public ENewArray(Location location, String type, List arguments, boolean initialize) { - super(location); - - this.type = Objects.requireNonNull(type); - this.arguments = Objects.requireNonNull(arguments); - this.initialize = initialize; - } - - @Override - void extractVariables(Set variables) { - for (AExpression argument : arguments) { - argument.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("A newly created array must be read from.")); - } - - Class clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); - - if (clazz == null) { - throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); - } - - for (int argument = 0; argument < arguments.size(); ++argument) { - AExpression expression = arguments.get(argument); - - expression.expected = initialize ? clazz.getComponentType() : int.class; - expression.internal = true; - expression.analyze(scriptRoot, locals); - arguments.set(argument, expression.cast(scriptRoot, locals)); - } - - actual = clazz; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (initialize) { - methodWriter.push(arguments.size()); - methodWriter.newArray(MethodWriter.getType(actual.getComponentType())); - - for (int index = 0; index < arguments.size(); ++index) { - AExpression argument = arguments.get(index); - - methodWriter.dup(); - methodWriter.push(index); - argument.write(classWriter, methodWriter, globals); - methodWriter.arrayStore(MethodWriter.getType(actual.getComponentType())); - } - } else { - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - if (arguments.size() > 1) { - methodWriter.visitMultiANewArrayInsn(MethodWriter.getType(actual).getDescriptor(), arguments.size()); - } else { - methodWriter.newArray(MethodWriter.getType(actual.getComponentType())); - } - } - } - - @Override - public String toString() { - return singleLineToStringWithOptionalArgs(arguments, type, initialize ? "init" : "dims"); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java deleted file mode 100644 index f496dec4321a9..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewArrayFunctionRef.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Type; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Objects; -import java.util.Set; - -/** - * Represents a function reference. - */ -public final class ENewArrayFunctionRef extends AExpression implements ILambda { - private final String type; - - private SFunction function; - private FunctionRef ref; - private String defPointer; - - public ENewArrayFunctionRef(Location location, String type) { - super(location); - - this.type = Objects.requireNonNull(type); - } - - @Override - void extractVariables(Set variables) { - // do nothing - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - SReturn code = new SReturn(location, new ENewArray(location, type, Arrays.asList(new EVariable(location, "size")), false)); - function = new SFunction( - location, type, scriptRoot.getNextSyntheticName("newarray"), - Collections.singletonList("int"), Collections.singletonList("size"), - new SBlock(location, Collections.singletonList(code)), true); - function.generateSignature(scriptRoot.getPainlessLookup()); - function.extractVariables(null); - function.analyze(scriptRoot, Locals.newLambdaScope(locals.getProgramScope(), function.name, function.returnType, - function.parameters, 0, scriptRoot.getCompilerSettings().getMaxLoopCounter())); - scriptRoot.getFunctionTable().addFunction(function.name, function.returnType, function.typeParameters, true); - scriptRoot.getClassNode().addFunction(function); - - if (expected == null) { - ref = null; - actual = String.class; - defPointer = "Sthis." + function.name + ",0"; - } else { - defPointer = null; - ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), - location, expected, "this", function.name, 0); - actual = expected; - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (ref != null) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeLambdaCall(ref); - } else { - // push a null instruction as a placeholder for future lambda instructions - methodWriter.push((String)null); - } - } - - @Override - public String getPointer() { - return defPointer; - } - - @Override - public Type[] getCaptures() { - return new Type[0]; // no captures - } - - @Override - public String toString() { - return singleLineToString(type + "[]", "new"); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java deleted file mode 100644 index 5f17cd9696473..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENewObj.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessConstructor; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; - -/** - * Represents and object instantiation. - */ -public final class ENewObj extends AExpression { - - private final String type; - private final List arguments; - - private PainlessConstructor constructor; - - public ENewObj(Location location, String type, List arguments) { - super(location); - - this.type = Objects.requireNonNull(type); - this.arguments = Objects.requireNonNull(arguments); - } - - @Override - void extractVariables(Set variables) { - for (AExpression argument : arguments) { - argument.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); - - if (actual == null) { - throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); - } - - constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, arguments.size()); - - if (constructor == null) { - throw createError(new IllegalArgumentException( - "constructor [" + typeToCanonicalTypeName(actual) + ", /" + arguments.size() + "] not found")); - } - - Class[] types = new Class[constructor.typeParameters.size()]; - constructor.typeParameters.toArray(types); - - if (constructor.typeParameters.size() != arguments.size()) { - throw createError(new IllegalArgumentException( - "When calling constructor on type [" + PainlessLookupUtility.typeToCanonicalTypeName(actual) + "] " + - "expected [" + constructor.typeParameters.size() + "] arguments, but found [" + arguments.size() + "].")); - } - - for (int argument = 0; argument < arguments.size(); ++argument) { - AExpression expression = arguments.get(argument); - - expression.expected = types[argument]; - expression.internal = true; - expression.analyze(scriptRoot, locals); - arguments.set(argument, expression.cast(scriptRoot, locals)); - } - - statement = true; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.newInstance(MethodWriter.getType(actual)); - - if (read) { - methodWriter.dup(); - } - - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - methodWriter.invokeConstructor( - Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); - } - - @Override - public String toString() { - return singleLineToStringWithOptionalArgs(arguments, type); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java deleted file mode 100644 index 4778670979c69..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ENumeric.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a non-decimal numeric constant. - */ -public final class ENumeric extends AExpression { - - private final String value; - private int radix; - - public ENumeric(Location location, String value, int radix) { - super(location); - - this.value = Objects.requireNonNull(value); - this.radix = radix; - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from constant [" + value + "].")); - } - - if (value.endsWith("d") || value.endsWith("D")) { - if (radix != 10) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - try { - constant = Double.parseDouble(value.substring(0, value.length() - 1)); - actual = double.class; - } catch (NumberFormatException exception) { - throw createError(new IllegalArgumentException("Invalid double constant [" + value + "].")); - } - } else if (value.endsWith("f") || value.endsWith("F")) { - if (radix != 10) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - try { - constant = Float.parseFloat(value.substring(0, value.length() - 1)); - actual = float.class; - } catch (NumberFormatException exception) { - throw createError(new IllegalArgumentException("Invalid float constant [" + value + "].")); - } - } else if (value.endsWith("l") || value.endsWith("L")) { - try { - constant = Long.parseLong(value.substring(0, value.length() - 1), radix); - actual = long.class; - } catch (NumberFormatException exception) { - throw createError(new IllegalArgumentException("Invalid long constant [" + value + "].")); - } - } else { - try { - Class sort = expected == null ? int.class : expected; - int integer = Integer.parseInt(value, radix); - - if (sort == byte.class && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) { - constant = (byte)integer; - actual = byte.class; - } else if (sort == char.class && integer >= Character.MIN_VALUE && integer <= Character.MAX_VALUE) { - constant = (char)integer; - actual = char.class; - } else if (sort == short.class && integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) { - constant = (short)integer; - actual = short.class; - } else { - constant = integer; - actual = int.class; - } - } catch (NumberFormatException exception) { - try { - // Check if we can parse as a long. If so then hint that the user might prefer that. - Long.parseLong(value, radix); - throw createError(new IllegalArgumentException("Invalid int constant [" + value + "]. If you want a long constant " - + "then change it to [" + value + "L].")); - } catch (NumberFormatException longNoGood) { - // Ignored - } - throw createError(new IllegalArgumentException("Invalid int constant [" + value + "].")); - } - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - public String toString() { - if (radix != 10) { - return singleLineToString(value, radix); - } - return singleLineToString(value); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java deleted file mode 100644 index 210894e86fa4c..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ERegex.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Constant; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.WriterConstants; - -import java.lang.reflect.Modifier; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * Represents a regex constant. All regexes are constants. - */ -public final class ERegex extends AExpression { - - private final String pattern; - private final int flags; - private Constant constant; - - public ERegex(Location location, String pattern, String flagsString) { - super(location); - - this.pattern = pattern; - - int flags = 0; - - for (int c = 0; c < flagsString.length(); c++) { - flags |= flagForChar(flagsString.charAt(c)); - } - - this.flags = flags; - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (scriptRoot.getCompilerSettings().areRegexesEnabled() == false) { - throw createError(new IllegalStateException("Regexes are disabled. Set [script.painless.regex.enabled] to [true] " - + "in elasticsearch.yaml to allow them. Be careful though, regexes break out of Painless's protection against deep " - + "recursion and long loops.")); - } - - if (!read) { - throw createError(new IllegalArgumentException("Regex constant may only be read [" + pattern + "].")); - } - - try { - Pattern.compile(pattern, flags); - } catch (PatternSyntaxException e) { - throw new Location(location.getSourceName(), location.getOffset() + 1 + e.getIndex()).createError( - new IllegalArgumentException("Error compiling regex: " + e.getDescription())); - } - - String name = scriptRoot.getNextSyntheticName("regex"); - scriptRoot.getClassNode().addField( - new SField(location, Modifier.FINAL | Modifier.STATIC | Modifier.PRIVATE, name, Pattern.class, null)); - constant = new Constant(location, MethodWriter.getType(Pattern.class), name, this::initializeConstant); - actual = Pattern.class; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.getStatic(WriterConstants.CLASS_TYPE, constant.name, org.objectweb.asm.Type.getType(Pattern.class)); - globals.addConstantInitializer(constant); - } - - private void initializeConstant(MethodWriter writer) { - writer.push(pattern); - writer.push(flags); - writer.invokeStatic(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_COMPILE); - } - - private int flagForChar(char c) { - switch (c) { - case 'c': return Pattern.CANON_EQ; - case 'i': return Pattern.CASE_INSENSITIVE; - case 'l': return Pattern.LITERAL; - case 'm': return Pattern.MULTILINE; - case 's': return Pattern.DOTALL; - case 'U': return Pattern.UNICODE_CHARACTER_CLASS; - case 'u': return Pattern.UNICODE_CASE; - case 'x': return Pattern.COMMENTS; - default: - throw new IllegalArgumentException("Unknown flag [" + c + "]"); - } - } - - @Override - public String toString() { - StringBuilder f = new StringBuilder(); - if ((flags & Pattern.CANON_EQ) != 0) f.append('c'); - if ((flags & Pattern.CASE_INSENSITIVE) != 0) f.append('i'); - if ((flags & Pattern.LITERAL) != 0) f.append('l'); - if ((flags & Pattern.MULTILINE) != 0) f.append('m'); - if ((flags & Pattern.DOTALL) != 0) f.append('s'); - if ((flags & Pattern.UNICODE_CHARACTER_CLASS) != 0) f.append('U'); - if ((flags & Pattern.UNICODE_CASE) != 0) f.append('u'); - if ((flags & Pattern.COMMENTS) != 0) f.append('x'); - - String p = "/" + pattern + "/"; - if (f.length() == 0) { - return singleLineToString(p); - } - return singleLineToString(p, f); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java deleted file mode 100644 index 79120549de165..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EString.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a string constant. - */ -public final class EString extends AExpression { - - public EString(Location location, String string) { - super(location); - - this.constant = Objects.requireNonNull(string); - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!read) { - throw createError(new IllegalArgumentException("Must read from constant [" + constant + "].")); - } - - actual = String.class; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - public String toString() { - return singleLineToString("'" + constant.toString() + "'"); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java deleted file mode 100644 index 186c11aa70f47..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EUnary.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a unary math expression. - */ -public final class EUnary extends AExpression { - - private final Operation operation; - private AExpression child; - - private Class promote; - private boolean originallyExplicit = false; // record whether there was originally an explicit cast - - public EUnary(Location location, Operation operation, AExpression child) { - super(location); - - this.operation = Objects.requireNonNull(operation); - this.child = Objects.requireNonNull(child); - } - - @Override - void extractVariables(Set variables) { - child.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - originallyExplicit = explicit; - - if (operation == Operation.NOT) { - analyzeNot(scriptRoot, locals); - } else if (operation == Operation.BWNOT) { - analyzeBWNot(scriptRoot, locals); - } else if (operation == Operation.ADD) { - analyzerAdd(scriptRoot, locals); - } else if (operation == Operation.SUB) { - analyzerSub(scriptRoot, locals); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - void analyzeNot(ScriptRoot scriptRoot, Locals variables) { - child.expected = boolean.class; - child.analyze(scriptRoot, variables); - child = child.cast(scriptRoot, variables); - - if (child.constant != null) { - constant = !(boolean)child.constant; - } - - actual = boolean.class; - } - - void analyzeBWNot(ScriptRoot scriptRoot, Locals variables) { - child.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(child.actual, false); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply not [~] to type " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(child.actual) + "].")); - } - - child.expected = promote; - child = child.cast(scriptRoot, variables); - - if (child.constant != null) { - if (promote == int.class) { - constant = ~(int)child.constant; - } else if (promote == long.class) { - constant = ~(long)child.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - if (promote == def.class && expected != null) { - actual = expected; - } else { - actual = promote; - } - } - - void analyzerAdd(ScriptRoot scriptRoot, Locals variables) { - child.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(child.actual, true); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply positive [+] to type " + - "[" + PainlessLookupUtility.typeToJavaType(child.actual) + "].")); - } - - child.expected = promote; - child = child.cast(scriptRoot, variables); - - if (child.constant != null) { - if (promote == int.class) { - constant = +(int)child.constant; - } else if (promote == long.class) { - constant = +(long)child.constant; - } else if (promote == float.class) { - constant = +(float)child.constant; - } else if (promote == double.class) { - constant = +(double)child.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - if (promote == def.class && expected != null) { - actual = expected; - } else { - actual = promote; - } - } - - void analyzerSub(ScriptRoot scriptRoot, Locals variables) { - child.analyze(scriptRoot, variables); - - promote = AnalyzerCaster.promoteNumeric(child.actual, true); - - if (promote == null) { - throw createError(new ClassCastException("Cannot apply negative [-] to type " + - "[" + PainlessLookupUtility.typeToJavaType(child.actual) + "].")); - } - - child.expected = promote; - child = child.cast(scriptRoot, variables); - - if (child.constant != null) { - if (promote == int.class) { - constant = -(int)child.constant; - } else if (promote == long.class) { - constant = -(long)child.constant; - } else if (promote == float.class) { - constant = -(float)child.constant; - } else if (promote == double.class) { - constant = -(double)child.constant; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - if (promote == def.class && expected != null) { - actual = expected; - } else { - actual = promote; - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (operation == Operation.NOT) { - Label fals = new Label(); - Label end = new Label(); - - child.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - methodWriter.push(false); - methodWriter.goTo(end); - methodWriter.mark(fals); - methodWriter.push(true); - methodWriter.mark(end); - } else { - child.write(classWriter, methodWriter, globals); - - // Def calls adopt the wanted return value. If there was a narrowing cast, - // we need to flag that so that it's done at runtime. - int defFlags = 0; - - if (originallyExplicit) { - defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; - } - - Type actualType = MethodWriter.getType(actual); - Type childType = MethodWriter.getType(child.actual); - - if (operation == Operation.BWNOT) { - if (promote == def.class) { - org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); - methodWriter.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); - } else { - if (promote == int.class) { - methodWriter.push(-1); - } else if (promote == long.class) { - methodWriter.push(-1L); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - methodWriter.math(MethodWriter.XOR, actualType); - } - } else if (operation == Operation.SUB) { - if (promote == def.class) { - org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); - methodWriter.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); - } else { - methodWriter.math(MethodWriter.NEG, actualType); - } - } else if (operation == Operation.ADD) { - if (promote == def.class) { - org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); - methodWriter.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); - } - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - @Override - public String toString() { - return singleLineToString(operation.symbol, child); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java new file mode 100644 index 0000000000000..e3ab923ff5f40 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -0,0 +1,66 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.FunctionRef; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Opcodes; + +import java.util.List; +import java.util.Objects; + +public class LambdaNode extends ExpressionNode { + + protected final Location location; + protected final List captures; + protected final FunctionRef functionRef; + + public LambdaNode(Location location, List captures, FunctionRef functionRef) { + this.location = Objects.requireNonNull(location); + this.captures = Objects.requireNonNull(captures); + this.functionRef = Objects.requireNonNull(functionRef); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (functionRef != null) { + methodWriter.writeDebugInfo(location); + // load captures + for (Variable capture : captures) { + methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + } + + methodWriter.invokeLambdaCall(functionRef); + } else { + // placeholder + methodWriter.push((String)null); + // load captures + for (Variable capture : captures) { + methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + } + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java new file mode 100644 index 0000000000000..9ce26728e6d29 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.Objects; + +public class ListInitializationNode extends ArgumentsNode { + + protected final Location location; + protected final PainlessConstructor constructor; + protected final PainlessMethod method; + + public ListInitializationNode(Location location, PainlessConstructor constructor, PainlessMethod method) { + this.location = Objects.requireNonNull(location); + this.constructor = Objects.requireNonNull(constructor); + this.method = Objects.requireNonNull(method); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.newInstance(MethodWriter.getType(getType())); + methodWriter.dup(); + methodWriter.invokeConstructor( + Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + + for (ExpressionNode argument : argumentNodes) { + methodWriter.dup(); + argument.write(classWriter, methodWriter, globals); + methodWriter.invokeMethodCall(method); + methodWriter.pop(); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java similarity index 51% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java index d1d50a5d590eb..531c9ebdb42b2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/EStatic.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java @@ -17,52 +17,34 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; import java.util.Objects; -import java.util.Set; -/** - * Represents a static type target. - */ -public final class EStatic extends AExpression { - - private final String type; - - public EStatic(Location location, String type) { - super(location); +public final class NewArrayFuncRefNode extends ExpressionNode { - this.type = Objects.requireNonNull(type); - } + protected final Location location; + protected final FunctionRef functionRef; - @Override - void extractVariables(Set variables) { - // Do nothing. + public NewArrayFuncRefNode(Location location, FunctionRef functionRef) { + this.location = Objects.requireNonNull(location); + this.functionRef = Objects.requireNonNull(functionRef); } @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(type); - - if (actual == null) { - throw createError(new IllegalArgumentException("Not a type [" + type + "].")); + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (functionRef != null) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeLambdaCall(functionRef); + } else { + // push a null instruction as a placeholder for future lambda instructions + methodWriter.push((String)null); } } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. - } - - @Override - public String toString() { - return singleLineToString(type); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java new file mode 100644 index 0000000000000..8e08f674e0e46 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java @@ -0,0 +1,65 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; + +public class NewArrayNode extends ArgumentsNode { + + protected final Location location; + protected final boolean initialize; + + public NewArrayNode(Location location, boolean initialize) { + this.location = location; + this.initialize = initialize; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (initialize) { + methodWriter.push(argumentNodes.size()); + methodWriter.newArray(MethodWriter.getType(getType().getComponentType())); + + for (int index = 0; index < argumentNodes.size(); ++index) { + ExpressionNode argumentNode = argumentNodes.get(index); + + methodWriter.dup(); + methodWriter.push(index); + argumentNode.write(classWriter, methodWriter, globals); + methodWriter.arrayStore(MethodWriter.getType(getType().getComponentType())); + } + } else { + for (ExpressionNode argumentNode : argumentNodes) { + argumentNode.write(classWriter, methodWriter, globals); + } + + if (argumentNodes.size() > 1) { + methodWriter.visitMultiANewArrayInsn(MethodWriter.getType(getType()).getDescriptor(), argumentNodes.size()); + } else { + methodWriter.newArray(MethodWriter.getType(getType().getComponentType())); + } + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java new file mode 100644 index 0000000000000..bd2b69556f6ed --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.Objects; + +public final class NewObjectNode extends ArgumentsNode { + + protected final Location location; + protected final PainlessConstructor constructor; + protected final boolean read; + + public NewObjectNode(Location location, PainlessConstructor constructor, boolean read) { + this.location = Objects.requireNonNull(location); + this.constructor = Objects.requireNonNull(constructor); + this.read = read; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.newInstance(MethodWriter.getType(getType())); + + if (read) { + methodWriter.dup(); + } + + for (ExpressionNode argumentNode : argumentNodes) { + argumentNode.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeConstructor( + Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java index f029337a3d7e3..073bd2563ab16 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java @@ -33,10 +33,7 @@ import java.util.Objects; import java.util.Set; -/** - * Represents an array load/store and defers to a child subnode. - */ -public final class PBrace extends AStoreable { +public class PBrace extends AStoreable { private AExpression index; @@ -54,33 +51,6 @@ void extractVariables(Set variables) { index.extractVariables(variables); } - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - prefix.analyze(scriptRoot, locals); - prefix.expected = prefix.actual; - prefix = prefix.cast(scriptRoot, locals); - - if (prefix.actual.isArray()) { - sub = new PSubBrace(location, prefix.actual, index); - } else if (prefix.actual == def.class) { - sub = new PSubDefArray(location, index); - } else if (Map.class.isAssignableFrom(prefix.actual)) { - sub = new PSubMapShortcut(location, prefix.actual, index); - } else if (List.class.isAssignableFrom(prefix.actual)) { - sub = new PSubListShortcut(location, prefix.actual, index); - } else { - throw createError(new IllegalArgumentException("Illegal array access on type " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "].")); - } - - sub.write = write; - sub.read = read; - sub.expected = expected; - sub.explicit = explicit; - sub.analyze(scriptRoot, locals); - actual = sub.actual; - } - @Override void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { prefix.write(classWriter, methodWriter, globals); @@ -118,9 +88,4 @@ void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { sub.store(classWriter, methodWriter, globals); } - - @Override - public String toString() { - return singleLineToString(prefix, index); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java new file mode 100644 index 0000000000000..723e0d1e0638b --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Constant; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.WriterConstants; + +import java.util.Objects; +import java.util.regex.Pattern; + +public class RegexNode extends ExpressionNode { + + protected final Location location; + protected final String pattern; + protected final int flags; + protected final Constant constant; + + public RegexNode(Location location, String pattern, int flags, Constant constant) { + this.location = Objects.requireNonNull(location); + this.pattern = Objects.requireNonNull(pattern); + this.flags = flags; + this.constant = Objects.requireNonNull(constant); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.getStatic(WriterConstants.CLASS_TYPE, constant.name, org.objectweb.asm.Type.getType(Pattern.class)); + globals.addConstantInitializer(constant); + } + + public void initializeConstant(MethodWriter writer) { + writer.push(pattern); + writer.push(flags); + writer.invokeStatic(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_COMPILE); + } + + private int flagForChar(char c) { + switch (c) { + case 'c': return Pattern.CANON_EQ; + case 'i': return Pattern.CASE_INSENSITIVE; + case 'l': return Pattern.LITERAL; + case 'm': return Pattern.MULTILINE; + case 's': return Pattern.DOTALL; + case 'U': return Pattern.UNICODE_CHARACTER_CLASS; + case 'u': return Pattern.UNICODE_CASE; + case 'x': return Pattern.COMMENTS; + default: + throw new IllegalArgumentException("Unknown flag [" + c + "]"); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java new file mode 100644 index 0000000000000..51ca53680312e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class StaticNode extends ExpressionNode { + + public StaticNode() { + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // do nothing + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java new file mode 100644 index 0000000000000..03c3ff7996061 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -0,0 +1,111 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.def; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.util.Objects; + +public class UnaryMathNode extends UnaryNode { + + protected final Location location; + protected final Operation operation; + protected final boolean originallyExplicit; // record whether there was originally an explicit cast + + public UnaryMathNode(Location location, Operation operation, boolean originallyExplicit) { + this.location = Objects.requireNonNull(location); + this.operation = Objects.requireNonNull(operation); + this.originallyExplicit = originallyExplicit; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (operation == Operation.NOT) { + Label fals = new Label(); + Label end = new Label(); + + childNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + methodWriter.push(false); + methodWriter.goTo(end); + methodWriter.mark(fals); + methodWriter.push(true); + methodWriter.mark(end); + } else { + childNode.write(classWriter, methodWriter, globals); + + // Def calls adopt the wanted return value. If there was a narrowing cast, + // we need to flag that so that it's done at runtime. + int defFlags = 0; + + if (originallyExplicit) { + defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; + } + + Type actualType = MethodWriter.getType(getType()); + Type childType = MethodWriter.getType(childNode.getType()); + + if (operation == Operation.BWNOT) { + if (getType() == def.class) { + org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); + methodWriter.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); + } else { + if (getType() == int.class) { + methodWriter.push(-1); + } else if (getType() == long.class) { + methodWriter.push(-1L); + } else { + throw new IllegalStateException("unexpected unary math operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); + } + + methodWriter.math(MethodWriter.XOR, actualType); + } + } else if (operation == Operation.SUB) { + if (getType() == def.class) { + org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); + methodWriter.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); + } else { + methodWriter.math(MethodWriter.NEG, actualType); + } + } else if (operation == Operation.ADD) { + if (getType() == def.class) { + org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); + methodWriter.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); + } + } else { + throw new IllegalStateException("unexpected unary math operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); + } + } + } +} From b6c7d8ea2a065473abbdb11904adf10fad1f7e62 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 17 Dec 2019 10:50:26 -0800 Subject: [PATCH 07/24] convert all prefix nodes --- .../elasticsearch/painless/ir/BraceNode.java | 58 ++++++ .../painless/ir/BraceSubDefNode.java | 76 ++++++++ .../painless/ir/BraceSubNode.java | 75 ++++++++ .../ir/{DefCallNode.java => CallDefNode.java} | 4 +- .../elasticsearch/painless/ir/CallNode.java | 37 ++++ .../painless/ir/CallSubNode.java | 56 ++++++ .../elasticsearch/painless/ir/DotNode.java | 58 ++++++ .../painless/ir/DotSubArrayLengthNode.java | 43 +++++ .../{PSubDefField.java => DotSubDefNode.java} | 64 ++----- .../ir/{PSubField.java => DotSubNode.java} | 60 ++---- .../painless/ir/DotSubShortcutNode.java | 82 +++++++++ .../painless/ir/ListSubShortcutNode.java | 87 +++++++++ .../painless/ir/MapSubShortcutNode.java | 80 ++++++++ .../painless/ir/NullSafeSubNode.java | 48 +++++ .../org/elasticsearch/painless/ir/PBrace.java | 91 ---------- .../painless/ir/PCallInvoke.java | 107 ----------- .../org/elasticsearch/painless/ir/PField.java | 171 ------------------ .../painless/ir/PSubArrayLength.java | 105 ----------- .../elasticsearch/painless/ir/PSubBrace.java | 104 ----------- .../painless/ir/PSubCallInvoke.java | 90 --------- .../painless/ir/PSubDefArray.java | 116 ------------ .../painless/ir/PSubListShortcut.java | 140 -------------- .../painless/ir/PSubMapShortcut.java | 141 --------------- .../painless/ir/PSubNullSafeCallInvoke.java | 77 -------- .../painless/ir/PSubNullSafeField.java | 105 ----------- .../painless/ir/PSubShortcut.java | 134 -------------- .../elasticsearch/painless/ir/PrefixNode.java | 37 ++++ 27 files changed, 765 insertions(+), 1481 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{DefCallNode.java => CallDefNode.java} (95%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{PSubDefField.java => DotSubDefNode.java} (52%) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{PSubField.java => DotSubNode.java} (61%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java new file mode 100644 index 0000000000000..cb1c8dbc6d0ed --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class BraceNode extends PrefixNode { + + public BraceNode() { + + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefixNode.write(classWriter, methodWriter, globals); + childNode.write(classWriter, methodWriter, globals); + } + + @Override + public int accessElementCount() { + return childNode.accessElementCount(); + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefixNode.write(classWriter, methodWriter, globals); + childNode.setup(classWriter, methodWriter, globals); + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.load(classWriter, methodWriter, globals); + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.store(classWriter, methodWriter, globals); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java new file mode 100644 index 0000000000000..a836937797697 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Type; + +import java.util.Objects; + +public class BraceSubDefNode extends UnaryNode { + + protected final Location location; + + public BraceSubDefNode(Location location) { + this.location = Objects.requireNonNull(location); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + setup(classWriter, methodWriter, globals); + load(classWriter, methodWriter, globals); + } + + @Override + public int accessElementCount() { + return 2; + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.dup(); + childNode.write(classWriter, methodWriter, globals); + Type methodType = Type.getMethodType( + MethodWriter.getType(childNode.getType()), Type.getType(Object.class), MethodWriter.getType(childNode.getType())); + methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Type methodType = + Type.getMethodType(MethodWriter.getType(getType()), Type.getType(Object.class), MethodWriter.getType(childNode.getType())); + methodWriter.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD); + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Type methodType = Type.getMethodType(Type.getType(void.class), Type.getType(Object.class), + MethodWriter.getType(childNode.getType()), MethodWriter.getType(getType())); + methodWriter.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java new file mode 100644 index 0000000000000..5ce2030eca257 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; + +public class BraceSubNode extends UnaryNode { + + protected final Location location; + + public BraceSubNode(Location location) { + this.location = Objects.requireNonNull(location); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + setup(classWriter, methodWriter, globals); + load(classWriter, methodWriter, globals); + } + + @Override + public int accessElementCount() { + return 2; + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.write(classWriter, methodWriter, globals); + + Label noFlip = new Label(); + methodWriter.dup(); + methodWriter.ifZCmp(Opcodes.IFGE, noFlip); + methodWriter.swap(); + methodWriter.dupX1(); + methodWriter.arrayLength(); + methodWriter.visitInsn(Opcodes.IADD); + methodWriter.mark(noFlip); + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.arrayLoad(MethodWriter.getType(getType())); + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.arrayStore(MethodWriter.getType(getType())); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java similarity index 95% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java index 74b6bef7efb1d..d94fe0abe0516 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DefCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Objects; -public class DefCallNode extends ArgumentsNode { +public class CallDefNode extends ArgumentsNode { protected final Location location; protected final String name; @@ -39,7 +39,7 @@ public class DefCallNode extends ArgumentsNode { protected final List pointers; protected final List> parameterTypes; - public DefCallNode(Location location, String name, String recipe, List pointers, List> parameterTypes) { + public CallDefNode(Location location, String name, String recipe, List pointers, List> parameterTypes) { this.location = location; this.name = Objects.requireNonNull(name); this.recipe = Objects.requireNonNull(recipe); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java new file mode 100644 index 0000000000000..c0d042714e386 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class CallNode extends PrefixNode { + + public CallNode() { + // do nothing + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefixNode.write(classWriter, methodWriter, globals); + childNode.write(classWriter, methodWriter, globals); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java new file mode 100644 index 0000000000000..acfa8d2b12d90 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.Objects; + +public class CallSubNode extends ArgumentsNode { + + protected final Location location; + protected final PainlessMethod method; + protected final Class box; + + public CallSubNode(Location location, PainlessMethod method, Class box) { + this.location = Objects.requireNonNull(location); + this.method = Objects.requireNonNull(method); + this.box = Objects.requireNonNull(box); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + if (box.isPrimitive()) { + methodWriter.box(MethodWriter.getType(box)); + } + + for (ExpressionNode argumentNode : argumentNodes) { + argumentNode.write(classWriter, methodWriter, globals); + } + + methodWriter.invokeMethodCall(method); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java new file mode 100644 index 0000000000000..969ff0c5c0f21 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class DotNode extends PrefixNode { + + public DotNode() { + + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefixNode.write(classWriter, methodWriter, globals); + childNode.write(classWriter, methodWriter, globals); + } + + @Override + public int accessElementCount() { + return childNode.accessElementCount(); + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + prefixNode.write(classWriter, methodWriter, globals); + childNode.setup(classWriter, methodWriter, globals); + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.load(classWriter, methodWriter, globals); + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.store(classWriter, methodWriter, globals); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java new file mode 100644 index 0000000000000..11851ea86863e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ExpressionNode; + +import java.util.Objects; + +public class DotSubArrayLengthNode extends ExpressionNode { + + protected final Location location; + + public DotSubArrayLengthNode(Location location) { + this.location = Objects.requireNonNull(location); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.arrayLength(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java similarity index 52% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java index 441762a0c58cf..7ca9221c98abb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java @@ -17,94 +17,60 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.def; -import java.time.ZonedDateTime; import java.util.Objects; -import java.util.Set; -/** - * Represents a field load/store or shortcut on a def type. (Internal only.) - */ -final class PSubDefField extends AStoreable { - - private final String value; +public class DotSubDefNode extends ExpressionNode { - PSubDefField(Location location, String value) { - super(location); + protected final Location location; + protected final String value; + public DotSubDefNode(Location location, String value) { + this.location = Objects.requireNonNull(location); this.value = Objects.requireNonNull(value); } @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed - actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); org.objectweb.asm.Type methodType = - org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class)); + org.objectweb.asm.Type.getMethodType(MethodWriter.getType(getType()), org.objectweb.asm.Type.getType(Object.class)); methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); } @Override - int accessElementCount() { + public int accessElementCount() { return 1; } @Override - boolean isDefOptimized() { - return true; + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // do nothing } @Override - void updateActual(Class actual) { - this.actual = actual; - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); org.objectweb.asm.Type methodType = - org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class)); + org.objectweb.asm.Type.getMethodType(MethodWriter.getType(getType()), org.objectweb.asm.Type.getType(Object.class)); methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); } @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( - org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(actual)); + org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(getType())); methodWriter.invokeDefCall(value, methodType, DefBootstrap.STORE); } - - @Override - public String toString() { - return singleLineToString(prefix, value); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java similarity index 61% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java index b6d683edcee4e..4a9d11208490e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java @@ -17,52 +17,29 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessField; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Type; -import java.lang.reflect.Modifier; import java.util.Objects; -import java.util.Set; -/** - * Represents a field load/store. - */ -final class PSubField extends AStoreable { - - private final PainlessField field; +public class DotSubNode extends ExpressionNode { - PSubField(Location location, PainlessField field) { - super(location); + protected final Location location; + protected final PainlessField field; + public DotSubNode(Location location, PainlessField field) { + this.location = Objects.requireNonNull(location); this.field = Objects.requireNonNull(field); } @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (write && Modifier.isFinal(field.javaField.getModifiers())) { - throw createError(new IllegalArgumentException("Cannot write to read-only field [" + field.javaField.getName() + "] " + - "for type [" + PainlessLookupUtility.typeToCanonicalTypeName(field.javaField.getDeclaringClass()) + "].")); - } - - actual = field.typeParameter; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -75,27 +52,17 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) } @Override - int accessElementCount() { + public int accessElementCount() { return 1; } @Override - boolean isDefOptimized() { - return false; - } - - @Override - void updateActual(Class actual) { - throw new IllegalArgumentException("Illegal tree structure."); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + public void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { // Do nothing. } @Override - void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + public void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -108,7 +75,7 @@ void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { } @Override - void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + public void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -119,9 +86,4 @@ void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); } } - - @Override - public String toString() { - return singleLineToString(prefix, field.javaField.getName()); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java new file mode 100644 index 0000000000000..2339ac34f3363 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java @@ -0,0 +1,82 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.Objects; + +public class DotSubShortcutNode extends ExpressionNode { + + protected final Location location; + protected final PainlessMethod getter; + protected final PainlessMethod setter; + + public DotSubShortcutNode(Location location, String value, String type, PainlessMethod getter, PainlessMethod setter) { + this.location = Objects.requireNonNull(location); + this.getter = getter; + this.setter = setter; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.invokeMethodCall(getter); + + if (!getter.returnType.equals(getter.javaMethod.getReturnType())) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + public int accessElementCount() { + return 1; + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + // do nothing + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.invokeMethodCall(getter); + + if (getter.returnType != getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + methodWriter.invokeMethodCall(setter); + + methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java new file mode 100644 index 0000000000000..f81c4538b67a9 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +import java.util.Objects; + +public class ListSubShortcutNode extends UnaryNode { + + protected final Location location; + protected final PainlessMethod setter; + protected final PainlessMethod getter; + + public ListSubShortcutNode(Location location, PainlessMethod setter, PainlessMethod getter) { + + this.location = Objects.requireNonNull(location); + this.setter = setter; + this.getter = getter; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + setup(classWriter, methodWriter, globals); + load(classWriter, methodWriter, globals); + } + + @Override + public int accessElementCount() { + return 2; + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.write(classWriter, methodWriter, globals); + + Label noFlip = new Label(); + methodWriter.dup(); + methodWriter.ifZCmp(Opcodes.IFGE, noFlip); + methodWriter.swap(); + methodWriter.dupX1(); + methodWriter.invokeInterface(WriterConstants.COLLECTION_TYPE, WriterConstants.COLLECTION_SIZE); + methodWriter.visitInsn(Opcodes.IADD); + methodWriter.mark(noFlip); + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(getter); + + if (getter.returnType == getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(setter); + methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java new file mode 100644 index 0000000000000..828d5f7770a4a --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; + +import java.util.Objects; + +public class MapSubShortcutNode extends UnaryNode { + + protected final Location location; + protected final PainlessMethod setter; + protected final PainlessMethod getter; + + public MapSubShortcutNode(Location location, PainlessMethod setter, PainlessMethod getter) { + this.location = Objects.requireNonNull(location); + this.setter = setter; + this.getter = getter; + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.write(classWriter, methodWriter, globals); + + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(getter); + + if (getter.returnType != getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + public int accessElementCount() { + return 2; + } + + @Override + public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + childNode.write(classWriter, methodWriter, globals); + } + + @Override + public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(getter); + + if (getter.returnType != getter.javaMethod.getReturnType()) { + methodWriter.checkCast(MethodWriter.getType(getter.returnType)); + } + } + + @Override + public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + methodWriter.invokeMethodCall(setter); + methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java new file mode 100644 index 0000000000000..7eeceedfde47c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java @@ -0,0 +1,48 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; + +import java.util.Objects; + +public class NullSafeSubNode extends UnaryNode { + + protected Location location; + + public NullSafeSubNode(Location location) { + this.location = Objects.requireNonNull(location); + } + + @Override + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeDebugInfo(location); + + Label end = new Label(); + methodWriter.dup(); + methodWriter.ifNull(end); + childNode.write(classWriter, methodWriter, globals); + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java deleted file mode 100644 index 073bd2563ab16..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PBrace.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.def; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -public class PBrace extends AStoreable { - - private AExpression index; - - private AStoreable sub = null; - - public PBrace(Location location, AExpression prefix, AExpression index) { - super(location, prefix); - - this.index = Objects.requireNonNull(index); - } - - @Override - void extractVariables(Set variables) { - prefix.extractVariables(variables); - index.extractVariables(variables); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.write(classWriter, methodWriter, globals); - } - - @Override - boolean isDefOptimized() { - return sub.isDefOptimized(); - } - - @Override - void updateActual(Class actual) { - sub.updateActual(actual); - this.actual = actual; - } - - @Override - int accessElementCount() { - return sub.accessElementCount(); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.setup(classWriter, methodWriter, globals); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.load(classWriter, methodWriter, globals); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.store(classWriter, methodWriter, globals); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java deleted file mode 100644 index 47bd54c288640..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PCallInvoke.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; - -/** - * Represents a method call and defers to a child subnode. - */ -public final class PCallInvoke extends AExpression { - - private final String name; - private final boolean nullSafe; - private final List arguments; - - private AExpression sub = null; - - public PCallInvoke(Location location, AExpression prefix, String name, boolean nullSafe, List arguments) { - super(location, prefix); - - this.name = Objects.requireNonNull(name); - this.nullSafe = nullSafe; - this.arguments = Objects.requireNonNull(arguments); - } - - @Override - void extractVariables(Set variables) { - prefix.extractVariables(variables); - - for (AExpression argument : arguments) { - argument.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - prefix.analyze(scriptRoot, locals); - prefix.expected = prefix.actual; - prefix = prefix.cast(scriptRoot, locals); - - if (prefix.actual == def.class) { - sub = new PSubDefCall(location, name, arguments); - } else { - PainlessMethod method = - scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, prefix instanceof EStatic, name, arguments.size()); - - if (method == null) { - throw createError(new IllegalArgumentException( - "method [" + typeToCanonicalTypeName(prefix.actual) + ", " + name + "/" + arguments.size() + "] not found")); - } - - sub = new PSubCallInvoke(location, method, prefix.actual, arguments); - } - - if (nullSafe) { - sub = new PSubNullSafeCallInvoke(location, sub); - } - - sub.expected = expected; - sub.explicit = explicit; - sub.analyze(scriptRoot, locals); - actual = sub.actual; - - statement = true; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.write(classWriter, methodWriter, globals); - } - - @Override - public String toString() { - return singleLineToStringWithOptionalArgs(arguments, prefix, name); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java deleted file mode 100644 index a5486524585b6..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PField.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessField; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; - -/** - * Represents a field load/store and defers to a child subnode. - */ -public final class PField extends AStoreable { - - private final boolean nullSafe; - private final String value; - - private AStoreable sub = null; - - public PField(Location location, AExpression prefix, boolean nullSafe, String value) { - super(location, prefix); - - this.nullSafe = nullSafe; - this.value = Objects.requireNonNull(value); - } - - @Override - void extractVariables(Set variables) { - prefix.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - prefix.analyze(scriptRoot, locals); - prefix.expected = prefix.actual; - prefix = prefix.cast(scriptRoot, locals); - - if (prefix.actual.isArray()) { - sub = new PSubArrayLength(location, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), value); - } else if (prefix.actual == def.class) { - sub = new PSubDefField(location, value); - } else { - PainlessField field = scriptRoot.getPainlessLookup().lookupPainlessField(prefix.actual, prefix instanceof EStatic, value); - - if (field == null) { - PainlessMethod getter; - PainlessMethod setter; - - getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false, - "get" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0); - - if (getter == null) { - getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false, - "is" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0); - } - - setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false, - "set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0); - - if (getter != null || setter != null) { - sub = new PSubShortcut(location, value, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), getter, setter); - } else { - EConstant index = new EConstant(location, value); - index.analyze(scriptRoot, locals); - - if (Map.class.isAssignableFrom(prefix.actual)) { - sub = new PSubMapShortcut(location, prefix.actual, index); - } - - if (List.class.isAssignableFrom(prefix.actual)) { - sub = new PSubListShortcut(location, prefix.actual, index); - } - } - - if (sub == null) { - throw createError(new IllegalArgumentException( - "field [" + typeToCanonicalTypeName(prefix.actual) + ", " + value + "] not found")); - } - } else { - sub = new PSubField(location, field); - } - } - - if (nullSafe) { - sub = new PSubNullSafeField(location, sub); - } - - sub.write = write; - sub.read = read; - sub.expected = expected; - sub.explicit = explicit; - sub.analyze(scriptRoot, locals); - actual = sub.actual; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.write(classWriter, methodWriter, globals); - } - - @Override - boolean isDefOptimized() { - return sub.isDefOptimized(); - } - - @Override - void updateActual(Class actual) { - sub.updateActual(actual); - this.actual = actual; - } - - @Override - int accessElementCount() { - return sub.accessElementCount(); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.setup(classWriter, methodWriter, globals); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.load(classWriter, methodWriter, globals); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.store(classWriter, methodWriter, globals); - } - - @Override - public String toString() { - if (nullSafe) { - return singleLineToString("nullSafe", prefix, value); - } - return singleLineToString(prefix, value); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java deleted file mode 100644 index 07f5e690e2373..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubArrayLength.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents an array length field load. - */ -final class PSubArrayLength extends AStoreable { - - private final String type; - private final String value; - - PSubArrayLength(Location location, String type, String value) { - super(location); - - this.type = Objects.requireNonNull(type); - this.value = Objects.requireNonNull(value); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if ("length".equals(value)) { - if (write) { - throw createError(new IllegalArgumentException("Cannot write to read-only field [length] for an array.")); - } - - actual = int.class; - } else { - throw createError(new IllegalArgumentException("Field [" + value + "] does not exist for type [" + type + "].")); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.arrayLength(); - } - - @Override - int accessElementCount() { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - boolean isDefOptimized() { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - void updateActual(Class actual) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - public String toString() { - return singleLineToString(prefix); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java deleted file mode 100644 index a793c55f81b6c..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubBrace.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents an array load/store. - */ -final class PSubBrace extends AStoreable { - - private final Class clazz; - private AExpression index; - - PSubBrace(Location location, Class clazz, AExpression index) { - super(location); - - this.clazz = Objects.requireNonNull(clazz); - this.index = Objects.requireNonNull(index); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("illegal tree structure")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - index.expected = int.class; - index.analyze(scriptRoot, locals); - index = index.cast(scriptRoot, locals); - - actual = clazz.getComponentType(); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); - } - - @Override - int accessElementCount() { - return 2; - } - - @Override - boolean isDefOptimized() { - return false; - } - - @Override - void updateActual(Class actual) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - writeIndexFlip(methodWriter, MethodWriter::arrayLength); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.arrayLoad(MethodWriter.getType(actual)); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.arrayStore(MethodWriter.getType(actual)); - } - - @Override - public String toString() { - return singleLineToString(prefix, index); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java deleted file mode 100644 index 34ff18ffec338..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubCallInvoke.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessMethod; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Represents a method call. - */ -final class PSubCallInvoke extends AExpression { - - private final PainlessMethod method; - private final Class box; - private final List arguments; - - PSubCallInvoke(Location location, PainlessMethod method, Class box, List arguments) { - super(location); - - this.method = Objects.requireNonNull(method); - this.box = box; - this.arguments = Objects.requireNonNull(arguments); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - for (int argument = 0; argument < arguments.size(); ++argument) { - AExpression expression = arguments.get(argument); - - expression.expected = method.typeParameters.get(argument); - expression.internal = true; - expression.analyze(scriptRoot, locals); - arguments.set(argument, expression.cast(scriptRoot, locals)); - } - - statement = true; - actual = method.returnType; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (box.isPrimitive()) { - methodWriter.box(MethodWriter.getType(box)); - } - - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - methodWriter.invokeMethodCall(method); - } - - @Override - public String toString() { - return singleLineToStringWithOptionalArgs(arguments, prefix, method.javaMethod.getName()); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java deleted file mode 100644 index 8ac360b200237..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubDefArray.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; - -import java.time.ZonedDateTime; -import java.util.Objects; -import java.util.Set; - -/** - * Represents an array load/store or shortcut on a def type. (Internal only.) - */ -final class PSubDefArray extends AStoreable { - private AExpression index; - - PSubDefArray(Location location, AExpression index) { - super(location); - - this.index = Objects.requireNonNull(index); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - index.analyze(scriptRoot, locals); - index.expected = index.actual; - index = index.cast(scriptRoot, locals); - - // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed - actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); - } - - @Override - int accessElementCount() { - return 2; - } - - @Override - boolean isDefOptimized() { - return true; - } - - @Override - void updateActual(Class actual) { - this.actual = actual; - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.dup(); - index.write(classWriter, methodWriter, globals); - Type methodType = Type.getMethodType( - MethodWriter.getType(index.actual), Type.getType(Object.class), MethodWriter.getType(index.actual)); - methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Type methodType = - Type.getMethodType(MethodWriter.getType(actual), Type.getType(Object.class), MethodWriter.getType(index.actual)); - methodWriter.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Type methodType = - Type.getMethodType( - Type.getType(void.class), Type.getType(Object.class), MethodWriter.getType(index.actual), MethodWriter.getType(actual)); - methodWriter.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE); - } - - @Override - public String toString() { - return singleLineToString(prefix, index); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java deleted file mode 100644 index 9471ea8c56d64..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubListShortcut.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.WriterConstants; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.PainlessMethod; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a list load/store shortcut. (Internal only.) - */ -final class PSubListShortcut extends AStoreable { - - private final Class targetClass; - private AExpression index; - - private PainlessMethod getter; - private PainlessMethod setter; - - PSubListShortcut(Location location, Class targetClass, AExpression index) { - super(location); - - this.targetClass = Objects.requireNonNull(targetClass); - this.index = Objects.requireNonNull(index); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass); - - getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1); - setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "set", 2); - - if (getter != null && (getter.returnType == void.class || getter.typeParameters.size() != 1 || - getter.typeParameters.get(0) != int.class)) { - throw createError(new IllegalArgumentException("Illegal list get shortcut for type [" + canonicalClassName + "].")); - } - - if (setter != null && (setter.typeParameters.size() != 2 || setter.typeParameters.get(0) != int.class)) { - throw createError(new IllegalArgumentException("Illegal list set shortcut for type [" + canonicalClassName + "].")); - } - - if (getter != null && setter != null && (!getter.typeParameters.get(0).equals(setter.typeParameters.get(0)) - || !getter.returnType.equals(setter.typeParameters.get(1)))) { - throw createError(new IllegalArgumentException("Shortcut argument types must match.")); - } - - if ((read || write) && (!read || getter != null) && (!write || setter != null)) { - index.expected = int.class; - index.analyze(scriptRoot, locals); - index = index.cast(scriptRoot, locals); - - actual = setter != null ? setter.typeParameters.get(1) : getter.returnType; - } else { - throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + canonicalClassName + "].")); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); - } - - @Override - int accessElementCount() { - return 2; - } - - @Override - boolean isDefOptimized() { - return false; - } - - @Override - void updateActual(Class actual) { - throw new IllegalArgumentException("Illegal tree structure."); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - writeIndexFlip(methodWriter, w -> { - w.invokeInterface(WriterConstants.COLLECTION_TYPE, WriterConstants.COLLECTION_SIZE); - }); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(getter); - - if (getter.returnType == getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(setter); - methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); - } - - @Override - public String toString() { - return singleLineToString(prefix, index); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java deleted file mode 100644 index 1558d4ce94bb3..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubMapShortcut.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.PainlessMethod; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a map load/store shortcut. (Internal only.) - */ -final class PSubMapShortcut extends AStoreable { - - private final Class targetClass; - private AExpression index; - - private PainlessMethod getter; - private PainlessMethod setter; - - PSubMapShortcut(Location location, Class targetClass, AExpression index) { - super(location); - - this.targetClass = Objects.requireNonNull(targetClass); - this.index = Objects.requireNonNull(index); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass); - - getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1); - setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "put", 2); - - if (getter != null && (getter.returnType == void.class || getter.typeParameters.size() != 1)) { - throw createError(new IllegalArgumentException("Illegal map get shortcut for type [" + canonicalClassName + "].")); - } - - if (setter != null && setter.typeParameters.size() != 2) { - throw createError(new IllegalArgumentException("Illegal map set shortcut for type [" + canonicalClassName + "].")); - } - - if (getter != null && setter != null && (!getter.typeParameters.get(0).equals(setter.typeParameters.get(0)) || - !getter.returnType.equals(setter.typeParameters.get(1)))) { - throw createError(new IllegalArgumentException("Shortcut argument types must match.")); - } - - if ((read || write) && (!read || getter != null) && (!write || setter != null)) { - index.expected = setter != null ? setter.typeParameters.get(0) : getter.typeParameters.get(0); - index.analyze(scriptRoot, locals); - index = index.cast(scriptRoot, locals); - - actual = setter != null ? setter.typeParameters.get(1) : getter.returnType; - } else { - throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + canonicalClassName + "].")); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(getter); - - if (getter.returnType != getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - int accessElementCount() { - return 2; - } - - @Override - boolean isDefOptimized() { - return false; - } - - @Override - void updateActual(Class actual) { - throw new IllegalArgumentException("Illegal tree structure."); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(getter); - - if (getter.returnType != getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(setter); - methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); - } - - @Override - public String toString() { - return singleLineToString(prefix, index); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java deleted file mode 100644 index 7ce2a6a8cd889..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeCallInvoke.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; - -import java.util.Set; - -import static java.util.Objects.requireNonNull; - -/** - * Implements a call who's value is null if the prefix is null rather than throwing an NPE. - */ -public class PSubNullSafeCallInvoke extends AExpression { - /** - * The expression gaurded by the null check. Required at construction time and replaced at analysis time. - */ - private AExpression guarded; - - public PSubNullSafeCallInvoke(Location location, AExpression guarded) { - super(location); - this.guarded = requireNonNull(guarded); - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("illegal tree structure")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - guarded.analyze(scriptRoot, locals); - actual = guarded.actual; - if (actual.isPrimitive()) { - throw new IllegalArgumentException("Result of null safe operator must be nullable"); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Label end = new Label(); - methodWriter.dup(); - methodWriter.ifNull(end); - guarded.write(classWriter, methodWriter, globals); - methodWriter.mark(end); - } - - @Override - public String toString() { - return singleLineToString(guarded); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java deleted file mode 100644 index bc9a7ac3f96b4..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubNullSafeField.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; - -import java.util.Set; - -/** - * Implements a field who's value is null if the prefix is null rather than throwing an NPE. - */ -public class PSubNullSafeField extends AStoreable { - private AStoreable guarded; - - public PSubNullSafeField(Location location, AStoreable guarded) { - super(location); - this.guarded = guarded; - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("illegal tree structure")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (write) { - throw createError(new IllegalArgumentException("Can't write to null safe reference")); - } - guarded.read = read; - guarded.analyze(scriptRoot, locals); - actual = guarded.actual; - if (actual.isPrimitive()) { - throw new IllegalArgumentException("Result of null safe operator must be nullable"); - } - } - - - @Override - int accessElementCount() { - return guarded.accessElementCount(); - } - - @Override - boolean isDefOptimized() { - return guarded.isDefOptimized(); - } - - @Override - void updateActual(Class actual) { - guarded.updateActual(actual); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - Label end = new Label(); - methodWriter.dup(); - methodWriter.ifNull(end); - guarded.write(classWriter, methodWriter, globals); - methodWriter.mark(end); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalArgumentException("Can't write to null safe field")); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalArgumentException("Can't write to null safe field")); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalArgumentException("Can't write to null safe field")); - } - - @Override - public String toString() { - return singleLineToString(guarded); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java deleted file mode 100644 index 181a04aa02b1a..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PSubShortcut.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessMethod; - -import java.util.Set; - -/** - * Represents a field load/store shortcut. (Internal only.) - */ -final class PSubShortcut extends AStoreable { - - private final String value; - private final String type; - private final PainlessMethod getter; - private final PainlessMethod setter; - - PSubShortcut(Location location, String value, String type, PainlessMethod getter, PainlessMethod setter) { - super(location); - - this.value = value; - this.type = type; - this.getter = getter; - this.setter = setter; - } - - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (getter != null && (getter.returnType == void.class || !getter.typeParameters.isEmpty())) { - throw createError(new IllegalArgumentException( - "Illegal get shortcut on field [" + value + "] for type [" + type + "].")); - } - - if (setter != null && (setter.returnType != void.class || setter.typeParameters.size() != 1)) { - throw createError(new IllegalArgumentException( - "Illegal set shortcut on field [" + value + "] for type [" + type + "].")); - } - - if (getter != null && setter != null && setter.typeParameters.get(0) != getter.returnType) { - throw createError(new IllegalArgumentException("Shortcut argument types must match.")); - } - - if ((getter != null || setter != null) && (!read || getter != null) && (!write || setter != null)) { - actual = setter != null ? setter.typeParameters.get(0) : getter.returnType; - } else { - throw createError(new IllegalArgumentException("Illegal shortcut on field [" + value + "] for type [" + type + "].")); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.invokeMethodCall(getter); - - if (!getter.returnType.equals(getter.javaMethod.getReturnType())) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - int accessElementCount() { - return 1; - } - - @Override - boolean isDefOptimized() { - return false; - } - - @Override - void updateActual(Class actual) { - throw new IllegalArgumentException("Illegal tree structure."); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.invokeMethodCall(getter); - - if (getter.returnType != getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.invokeMethodCall(setter); - - methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); - } - - @Override - public String toString() { - return singleLineToString(prefix, value); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java new file mode 100644 index 0000000000000..68812c7624a24 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +public abstract class PrefixNode extends UnaryNode { + + protected ExpressionNode prefixNode; + + public PrefixNode() { + // do nothing + } + + public void setPrefixNode(ExpressionNode prefixNode) { + this.prefixNode = prefixNode; + } + + public ExpressionNode getPrefixNode() { + return prefixNode; + } +} From f68872a5a542c0ea88bba8c2d6f2f98cb1e4fca1 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 18 Dec 2019 11:44:02 -0800 Subject: [PATCH 08/24] partially changed node data to user getters/setters --- .../painless/ir/ArgumentsNode.java | 26 +++- .../painless/ir/AssignmentNode.java | 97 ++++++++++---- .../painless/ir/BinaryMathNode.java | 45 +++++-- .../elasticsearch/painless/ir/BinaryNode.java | 24 ++-- .../elasticsearch/painless/ir/BlockNode.java | 86 +++++++++++++ .../painless/ir/BooleanNode.java | 26 ++-- .../elasticsearch/painless/ir/BraceNode.java | 12 +- .../painless/ir/BraceSubDefNode.java | 19 +-- .../painless/ir/BraceSubNode.java | 19 +-- .../elasticsearch/painless/ir/BreakNode.java | 36 ++++++ .../painless/ir/CallDefNode.java | 120 +++++++++++++++--- .../elasticsearch/painless/ir/CallNode.java | 2 +- .../painless/ir/CallSubNode.java | 38 ++++-- .../painless/ir/CapturingFuncRefNode.java | 66 +++++++--- .../elasticsearch/painless/ir/CastNode.java | 26 ++-- .../painless/ir/ComparisonNode.java | 26 ++-- ...SDeclaration.java => DeclarationNode.java} | 62 +++------ .../org/elasticsearch/painless/ir/IRNode.java | 32 ++++- .../org/elasticsearch/painless/ir/SBlock.java | 97 -------------- .../org/elasticsearch/painless/ir/SBreak.java | 66 ---------- .../org/elasticsearch/painless/ir/SCatch.java | 74 +++-------- .../painless/ir/StatementNode.java | 28 ++++ 22 files changed, 605 insertions(+), 422 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{SDeclaration.java => DeclarationNode.java} (53%) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java index f5d2150f5d8c2..49f1cf2b5a129 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java @@ -21,30 +21,35 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; public abstract class ArgumentsNode extends ExpressionNode { + /* ---- begin tree structure ---- */ + protected List argumentNodes = new ArrayList<>(); - public void addArgumentNode(ExpressionNode argumentNode) { + public ArgumentsNode addArgumentNode(ExpressionNode argumentNode) { argumentNodes.add(argumentNode); + return this; } - public void setArgumentNode(int index, ExpressionNode argumentNode) { + public ArgumentsNode setArgumentNode(int index, ExpressionNode argumentNode) { argumentNodes.set(index, argumentNode); + return this; } public ExpressionNode getArgumentNode(int index) { return argumentNodes.get(index); } - public void removeArgumentNode(ExpressionNode expressionNode) { - argumentNodes.remove(expressionNode); + public ArgumentsNode removeArgumentNode(ExpressionNode argumentNode) { + argumentNodes.remove(argumentNode); + return this; } - public void removeArgumentNode(int index) { + public ArgumentsNode removeArgumentNode(int index) { argumentNodes.remove(index); + return this; } public int getArgumentsSize() { @@ -55,7 +60,14 @@ public List getArgumentsNodes() { return argumentNodes; } - public void clearArgumentNodes() { + public ArgumentsNode clearArgumentNodes() { argumentNodes.clear(); + return this; + } + + /* ---- end tree structure ---- */ + + public ArgumentsNode() { + // do nothing } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 8d2b9c3e53ced..554a765f2fa42 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -23,47 +23,94 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.def; -import java.util.Objects; - public class AssignmentNode extends BinaryNode { - protected final Location location; - protected final boolean pre; - protected final boolean post; - protected final Operation operation; - protected final boolean read; - protected final boolean cat; - protected final PainlessCast there; - protected final PainlessCast back; - - public AssignmentNode( - Location location, - boolean pre, - boolean post, - Operation operation, - boolean read, - boolean cat, - PainlessCast there, - PainlessCast back - ) { - this.location = Objects.requireNonNull(location); + /* ---- begin node data ---- */ + + protected boolean pre; + protected boolean post; + protected Operation operation; + protected boolean read; + protected boolean cat; + protected PainlessCast there; + protected PainlessCast back; + + public AssignmentNode setPre(boolean pre) { this.pre = pre; + return this; + } + + public boolean getPre() { + return pre; + } + + public AssignmentNode setPost(boolean post) { this.post = post; - this.operation = Objects.requireNonNull(operation); + return this; + } + + public boolean getPost() { + return post; + } + + public AssignmentNode setOperation(Operation operation) { + this.operation = operation; + return this; + } + + public Operation getOperation() { + return operation; + } + + public AssignmentNode setRead(boolean read) { this.read = read; + return this; + } + + public boolean getRead() { + return read; + } + + public AssignmentNode setCat(boolean cat) { this.cat = cat; + return this; + } + + public boolean getCat() { + return cat; + } + + public AssignmentNode setThere(PainlessCast there) { this.there = there; + return this; + } + + public PainlessCast getThere() { + return there; + } + + public AssignmentNode setBack(PainlessCast back) { this.back = back; + return this; + } + + public PainlessCast getBack() { + return back; + } + + /* ---- end node data ---- */ + + public AssignmentNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); // For the case where the assignment represents a String concatenation diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index f3da00a263780..d0eaf9fe76128 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -22,32 +22,57 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.def; -import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; public class BinaryMathNode extends ShiftNode { - protected final Location location; - protected final Operation operation; - protected final boolean cat; - protected final boolean originallyExplicit; // record whether there was originally an explicit cast + /* ---- begin node data ---- */ - public BinaryMathNode(Location location, Operation operation, boolean cat, boolean originallyExplicit) { - this.location = Objects.requireNonNull(location); - this.operation = Objects.requireNonNull(operation); + protected Operation operation; + protected boolean cat; + protected boolean originallyExplicit; // record whether there was originally an explicit cast + + public BinaryMathNode setOperation(Operation operation) { + this.operation = operation; + return this; + } + + public Operation getOperation() { + return operation; + } + + public BinaryMathNode setCat(boolean cat) { this.cat = cat; + return this; + } + + public boolean getCat() { + return cat; + } + + public BinaryMathNode setOriginallExplicit(boolean originallyExplicit) { this.originallyExplicit = originallyExplicit; + return this; + } + + public boolean getOriginallyExplicit() { + return originallyExplicit; + } + + /* ---- end node data ---- */ + + public BinaryMathNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (getType() == String.class && operation == Operation.ADD) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java index eb7f1e9d37b4e..990f5c2e42a76 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java @@ -21,26 +21,32 @@ public abstract class BinaryNode extends ExpressionNode { + /* ---- begin tree structure ---- */ + protected ExpressionNode leftNode; protected ExpressionNode rightNode; - public BinaryNode() { - // do nothing - } - - public void setLeftNode(ExpressionNode leftNode) { + public BinaryNode setLeftNode(ExpressionNode leftNode) { this.leftNode = leftNode; - } - - public void setRightNode(ExpressionNode rightNode) { - this.rightNode = rightNode; + return this; } public ExpressionNode getLeftNode() { return leftNode; } + public BinaryNode setRightNode(ExpressionNode rightNode) { + this.rightNode = rightNode; + return this; + } + public ExpressionNode getRightNode() { return rightNode; } + + /* ---- end tree structure ---- */ + + public BinaryNode() { + // do nothing + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java new file mode 100644 index 0000000000000..ff0d337a3417a --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java @@ -0,0 +1,86 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +import java.util.ArrayList; +import java.util.List; + +public class BlockNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected List statementNodes = new ArrayList<>(); + + public BlockNode addStatementNode(StatementNode statementNode) { + statementNodes.add(statementNode); + return this; + } + + public BlockNode setStatementNode(int index, StatementNode statementNode) { + statementNodes.set(index, statementNode); + return this; + } + + public StatementNode getStatementNode(int index) { + return statementNodes.get(index); + } + + public BlockNode removeStatementNode(StatementNode statementNode) { + statementNodes.remove(statementNode); + return this; + } + + public BlockNode removeStatementNode(int index) { + statementNodes.remove(index); + return this; + } + + public int getStatementsSize() { + return statementNodes.size(); + } + + public List getStatementsNodes() { + return statementNodes; + } + + public BlockNode clearStatementNodes() { + statementNodes.clear(); + return this; + } + + /* ---- end tree structure ---- */ + + public BlockNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + for (StatementNode statementNode : statementNodes) { + statementNode.continueLabel = continueLabel; + statementNode.breakLabel = breakLabel; + statementNode.write(classWriter, methodWriter, globals); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index f7e874178ab58..2e366e9cf051d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -21,26 +21,34 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import java.util.Objects; +public class BooleanNode extends BinaryNode { -public final class BooleanNode extends BinaryNode { + /* ---- begin node data ---- */ - private final Location location; - private final Operation operation; + protected Operation operation; - public BooleanNode(Location location, Operation operation) { - this.location = Objects.requireNonNull(location); - this.operation = Objects.requireNonNull(operation); + public BooleanNode setOperation(Operation operation) { + this.operation = operation; + return this; + } + + public Operation getOperation() { + return operation; + } + + /* ---- end node data ---- */ + + public BooleanNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (operation == Operation.AND) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java index cb1c8dbc6d0ed..04e42c9b27fdb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java @@ -26,33 +26,33 @@ public class BraceNode extends PrefixNode { public BraceNode() { - + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { prefixNode.write(classWriter, methodWriter, globals); childNode.write(classWriter, methodWriter, globals); } @Override - public int accessElementCount() { + protected int accessElementCount() { return childNode.accessElementCount(); } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { prefixNode.write(classWriter, methodWriter, globals); childNode.setup(classWriter, methodWriter, globals); } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.load(classWriter, methodWriter, globals); } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.store(classWriter, methodWriter, globals); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java index a836937797697..d084d402819d9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java @@ -22,33 +22,28 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; -import java.util.Objects; - public class BraceSubDefNode extends UnaryNode { - protected final Location location; - - public BraceSubDefNode(Location location) { - this.location = Objects.requireNonNull(location); + public BraceSubDefNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { setup(classWriter, methodWriter, globals); load(classWriter, methodWriter, globals); } @Override - public int accessElementCount() { + protected int accessElementCount() { return 2; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.dup(); childNode.write(classWriter, methodWriter, globals); Type methodType = Type.getMethodType( @@ -57,7 +52,7 @@ public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); Type methodType = @@ -66,7 +61,7 @@ public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals glo } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType(Type.getType(void.class), Type.getType(Object.class), diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java index 5ce2030eca257..b8cf42a49d92d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java @@ -21,34 +21,29 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import java.util.Objects; - public class BraceSubNode extends UnaryNode { - protected final Location location; - - public BraceSubNode(Location location) { - this.location = Objects.requireNonNull(location); + public BraceSubNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { setup(classWriter, methodWriter, globals); load(classWriter, methodWriter, globals); } @Override - public int accessElementCount() { + protected int accessElementCount() { return 2; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.write(classWriter, methodWriter, globals); Label noFlip = new Label(); @@ -62,13 +57,13 @@ public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.arrayLoad(MethodWriter.getType(getType())); } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.arrayStore(MethodWriter.getType(getType())); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java new file mode 100644 index 0000000000000..296e31f381f67 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class BreakNode extends StatementNode { + + public BreakNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.goTo(breakLabel); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java index d94fe0abe0516..6fa521225c91e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java @@ -22,33 +22,121 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Objects; -public class CallDefNode extends ArgumentsNode { +public class CallDefNode extends ArgumentsNode { - protected final Location location; - protected final String name; - protected final String recipe; - protected final List pointers; - protected final List> parameterTypes; + /* ---- begin node data ---- */ - public CallDefNode(Location location, String name, String recipe, List pointers, List> parameterTypes) { - this.location = location; - this.name = Objects.requireNonNull(name); - this.recipe = Objects.requireNonNull(recipe); - this.pointers = Collections.unmodifiableList(Objects.requireNonNull(pointers)); - this.parameterTypes = Collections.unmodifiableList(Objects.requireNonNull(parameterTypes)); + protected String name; + protected String recipe; + protected List pointers; + protected List> parameterTypes; + + public CallDefNode setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + public CallDefNode setRecipe(String recipe) { + this.recipe = recipe; + return this; + } + + public String getRecipe() { + return recipe; + } + + public CallDefNode addPointer(String pointer) { + pointers.add(pointer); + return this; + } + + public CallDefNode setPointer(int index, String pointer) { + pointers.set(index, pointer); + return this; + } + + public String getPointer(int index) { + return pointers.get(index); + } + + public CallDefNode removePointer(String pointer) { + pointers.remove(pointer); + return this; + } + + public CallDefNode removePointer(int index) { + pointers.remove(index); + return this; + } + + public int getPointersSize() { + return pointers.size(); + } + + public List getPointers() { + return pointers; + } + + public CallDefNode clearPointers() { + pointers.clear(); + return this; + } + + public CallDefNode addParameterType(Class parameterType) { + parameterTypes.add(parameterType); + return this; + } + + public CallDefNode setParameterType(int index, Class parameterType) { + parameterTypes.set(index, parameterType); + return this; + } + + public Class getParameterType(int index) { + return parameterTypes.get(index); + } + + public CallDefNode removeParameterType(Class parameterType) { + parameterTypes.remove(parameterType); + return this; + } + + public CallDefNode removeParameterType(int index) { + parameterTypes.remove(index); + return this; + } + + public int getParameterTypesSize() { + return parameterTypes.size(); + } + + public List> getParameterTypes() { + return parameterTypes; + } + + public CallDefNode clearParameterTypes() { + parameterTypes.clear(); + return this; + } + + /* ---- end node data ---- */ + + public CallDefNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); for (ExpressionNode argumentNode : argumentNodes) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java index c0d042714e386..5636a3611181c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java @@ -30,7 +30,7 @@ public CallNode() { } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { prefixNode.write(classWriter, methodWriter, globals); childNode.write(classWriter, methodWriter, globals); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java index acfa8d2b12d90..b24ca48b7d30c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java @@ -21,26 +21,42 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; -import java.util.Objects; - public class CallSubNode extends ArgumentsNode { - protected final Location location; - protected final PainlessMethod method; - protected final Class box; + /* ---- begin node data ---- */ + + protected PainlessMethod method; + protected Class box; + + public CallSubNode setMethod(PainlessMethod method) { + this.method = method; + return this; + } + + public PainlessMethod getMethod() { + return method; + } + + public CallSubNode setBox(Class box) { + this.box = box; + return this; + } + + public Class getPost() { + return box; + } + + /* ---- end node data ---- */ - public CallSubNode(Location location, PainlessMethod method, Class box) { - this.location = Objects.requireNonNull(location); - this.method = Objects.requireNonNull(method); - this.box = Objects.requireNonNull(box); + public CallSubNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (box.isPrimitive()) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index 6c4fd52a93d22..bda28f2ec442c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -24,37 +24,69 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -import java.util.Objects; - public class CapturingFuncRefNode extends ExpressionNode { - protected final Location location; - protected final String name; - protected final Variable captured; - protected final FunctionRef functionRef; - protected final String pointer; - - public CapturingFuncRefNode(Location location, String name, Variable captured, FunctionRef functionRef, String pointer) { - this.location = Objects.requireNonNull(location); - this.name = Objects.requireNonNull(name); - this.captured = Objects.requireNonNull(captured); - this.functionRef = functionRef; + /* ---- begin node data ---- */ + + protected String name; + protected Variable captured; + protected FunctionRef funcRef; + protected String pointer; + + public CapturingFuncRefNode setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + public CapturingFuncRefNode setCaptured(Variable captured) { + this.captured = captured; + return this; + } + + public Variable getCaptured() { + return captured; + } + + public CapturingFuncRefNode setFuncRef(FunctionRef funcRef) { + this.funcRef = funcRef; + return this; + } + + public FunctionRef getFuncRef() { + return funcRef; + } + + public CapturingFuncRefNode setPointer(String pointer) { this.pointer = pointer; + return this; + } + + public String getPointer() { + return pointer; + } + + /* ---- end node data ---- */ + + public CapturingFuncRefNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (pointer != null) { // dynamic interface: placeholder for run-time lookup methodWriter.push((String)null); methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - } else if (functionRef == null) { + } else if (funcRef == null) { // typed interface, dynamic implementation methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); Type methodType = Type.getMethodType(MethodWriter.getType(getType()), MethodWriter.getType(captured.clazz)); @@ -62,7 +94,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } else { // typed interface, typed implementation methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - methodWriter.invokeLambdaCall(functionRef); + methodWriter.invokeLambdaCall(funcRef); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java index 7d412c7c77f5b..68fdeef71f110 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java @@ -21,24 +21,32 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; -import java.util.Objects; - public class CastNode extends UnaryNode { - protected final Location location; - protected final PainlessCast cast; + /* ---- begin node data ---- */ + + protected PainlessCast cast; + + public CastNode setCast(PainlessCast cast) { + this.cast = cast; + return this; + } + + public PainlessCast getCast() { + return cast; + } + + /* ---- end node data ---- */ - CastNode(Location location, PainlessCast cast) { - this.location = Objects.requireNonNull(location); - this.cast = Objects.requireNonNull(cast); + public CastNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.write(classWriter, methodWriter, globals); methodWriter.writeDebugInfo(location); methodWriter.writeCast(cast); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index e87553a9c316a..edc34a7bdb982 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessLookupUtility; @@ -30,23 +29,32 @@ import org.objectweb.asm.Label; import org.objectweb.asm.Type; -import java.util.Objects; - import static org.elasticsearch.painless.WriterConstants.EQUALS; import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE; public class ComparisonNode extends BinaryNode { - private final Location location; - private final Operation operation; + /* ---- begin node data ---- */ + + protected Operation operation; + + public ComparisonNode setOperation(Operation operation) { + this.operation = operation; + return this; + } + + public Operation getOperation() { + return operation; + } + + /* ---- end node data ---- */ - public ComparisonNode(Location location, Operation operation) { - this.location = Objects.requireNonNull(location); - this.operation = Objects.requireNonNull(operation); + public ComparisonNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); leftNode.write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java similarity index 53% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index bcc2036aaffd4..1b1e6c85b3b0f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclaration.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -17,66 +17,42 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; import org.objectweb.asm.Opcodes; import java.util.Objects; -import java.util.Set; -/** - * Represents a single variable declaration. - */ -public final class SDeclaration extends AStatement { - - private final DType type; - private final String name; - private AExpression expression; +public class DeclarationNode extends StatementNode { - Variable variable = null; + protected ExpressionNode expressionNode; - public SDeclaration(Location location, DType type, String name, AExpression expression) { - super(location); - - this.type = Objects.requireNonNull(type); - this.name = Objects.requireNonNull(name); - this.expression = expression; + public void setExpressionNode(ExpressionNode childNode) { + this.expressionNode = childNode; } - @Override - void extractVariables(Set variables) { - variables.add(name); - - if (expression != null) { - expression.extractVariables(variables); - } + public ExpressionNode getExpressionNode() { + return expressionNode; } - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - DResolvedType resolvedType = type.resolveType(scriptRoot.getPainlessLookup()); + protected final Location location; + protected final Variable variable; - if (expression != null) { - expression.expected = resolvedType.getType(); - expression.analyze(scriptRoot, locals); - expression = expression.cast(scriptRoot, locals); - } - - variable = locals.addVariable(location, resolvedType.getType(), name, false); + public DeclarationNode(Location location, Variable variable) { + this.location = Objects.requireNonNull(location); + this.variable = Objects.requireNonNull(variable); } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); - if (expression == null) { + if (expressionNode == null) { Class sort = variable.clazz; if (sort == void.class || sort == boolean.class || sort == byte.class || @@ -92,17 +68,9 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.visitInsn(Opcodes.ACONST_NULL); } } else { - expression.write(classWriter, methodWriter, globals); + expressionNode.write(classWriter, methodWriter, globals); } methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); } - - @Override - public String toString() { - if (expression == null) { - return singleLineToString(type, name); - } - return singleLineToString(type, name, expression); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java index 8c8714c523fc0..e98ffa5bf1c69 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java @@ -21,14 +21,34 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -public interface IRNode { +public abstract class IRNode { - default void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + /* begin node data */ - default int accessElementCount() {throw new UnsupportedOperationException();} - default void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} - default void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} - default void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + protected Location location; + + public IRNode setLocation(Location location) { + this.location = location; + return this; + } + + public Location getLocation() { + return location; + } + + /* end node data */ + + public IRNode() { + // do nothing + } + + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + + protected int accessElementCount() {throw new UnsupportedOperationException();} + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java deleted file mode 100644 index effa818280668..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBlock.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static java.util.Collections.emptyList; - -/** - * Represents a set of statements as a branch of control-flow. - */ -public final class SBlock extends AStatement { - - final List statements; - - public SBlock(Location location, List statements) { - super(location); - - this.statements = Collections.unmodifiableList(statements); - } - - @Override - void extractVariables(Set variables) { - for (AStatement statement : statements) { - statement.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (statements == null || statements.isEmpty()) { - throw createError(new IllegalArgumentException("A block must contain at least one statement.")); - } - - AStatement last = statements.get(statements.size() - 1); - - for (AStatement statement : statements) { - // Note that we do not need to check after the last statement because - // there is no statement that can be unreachable after the last. - if (allEscape) { - throw createError(new IllegalArgumentException("Unreachable statement.")); - } - - statement.inLoop = inLoop; - statement.lastSource = lastSource && statement == last; - statement.lastLoop = (beginLoop || lastLoop) && statement == last; - statement.analyze(scriptRoot, locals); - - methodEscape = statement.methodEscape; - loopEscape = statement.loopEscape; - allEscape = statement.allEscape; - anyContinue |= statement.anyContinue; - anyBreak |= statement.anyBreak; - statementCount += statement.statementCount; - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - for (AStatement statement : statements) { - statement.continu = continu; - statement.brake = brake; - statement.write(classWriter, methodWriter, globals); - } - } - - @Override - public String toString() { - return multilineToString(emptyList(), statements); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java deleted file mode 100644 index cc49ac7561bff..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SBreak.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Set; - -/** - * Represents a break statement. - */ -public final class SBreak extends AStatement { - - public SBreak(Location location) { - super(location); - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!inLoop) { - throw createError(new IllegalArgumentException("Break statement outside of a loop.")); - } - - loopEscape = true; - allEscape = true; - anyBreak = true; - statementCount = 1; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.goTo(brake); - } - - @Override - public String toString() { - return singleLineToString(); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java index 9fc6dc29fe217..2dc3f987d192c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; @@ -32,66 +32,39 @@ import java.util.Objects; import java.util.Set; -/** - * Represents a catch block as part of a try-catch block. - */ -public final class SCatch extends AStatement { - - private final DType baseException; - private final SDeclaration declaration; - private final SBlock block; +public class CatchNode extends StatementNode { - Label begin = null; - Label end = null; - Label exception = null; + /* --- begin tree structure --- */ - public SCatch(Location location, DType baseException, SDeclaration declaration, SBlock block) { - super(location); + protected DeclarationNode declarationNode; - this.baseException = Objects.requireNonNull(baseException); - this.declaration = Objects.requireNonNull(declaration); - this.block = block; + public void setChildNode(ExpressionNode declarationNode) { + this.declarationNode = declarationNode; } - @Override - void extractVariables(Set variables) { - declaration.extractVariables(variables); - - if (block != null) { - block.extractVariables(variables); - } + public ExpressionNode getChildNode() { + return declarationNode; } - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - declaration.analyze(scriptRoot, locals); + /* --- end tree structure, begin node data --- */ - Class baseType = baseException.resolveType(scriptRoot.getPainlessLookup()).getType(); - Class type = declaration.variable.clazz; + protected final Location location; + protected boolean allEscape; - if (baseType.isAssignableFrom(type) == false) { - throw createError(new ClassCastException( - "cannot cast from [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "] " + - "to [" + PainlessLookupUtility.typeToCanonicalTypeName(baseType) + "]")); - } + /* --- end node date --- */ - if (block != null) { - block.lastSource = lastSource; - block.inLoop = inLoop; - block.lastLoop = lastLoop; - block.analyze(scriptRoot, locals); - - methodEscape = block.methodEscape; - loopEscape = block.loopEscape; - allEscape = block.allEscape; - anyContinue = block.anyContinue; - anyBreak = block.anyBreak; - statementCount = block.statementCount; - } + public CatchNode(Location location) { + this.location = Objects.requireNonNull(location); } + + + Label begin = null; + Label end = null; + Label exception = null; + @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); Label jump = new Label(); @@ -112,9 +85,4 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.goTo(exception); } } - - @Override - public String toString() { - return singleLineToString(baseException, declaration, block); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java new file mode 100644 index 0000000000000..6f33799be7d14 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java @@ -0,0 +1,28 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.objectweb.asm.Label; + +public abstract class StatementNode implements IRNode { + + protected Label continueLabel = null; + protected Label breakLabel = null; +} From c18a18248003c20086b6452e37f6d43e8751cf46 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 18 Dec 2019 15:22:22 -0800 Subject: [PATCH 09/24] partially changed data to be mutable --- .../painless/ir/ConditionalNode.java | 20 +++--- .../painless/ir/ConstantNode.java | 23 +++++-- .../painless/ir/DeclarationNode.java | 31 ++++++--- .../elasticsearch/painless/ir/DotNode.java | 12 ++-- .../painless/ir/DotSubArrayLengthNode.java | 14 ++-- .../painless/ir/DotSubDefNode.java | 34 +++++---- .../elasticsearch/painless/ir/DotSubNode.java | 34 +++++---- .../painless/ir/DotSubShortcutNode.java | 44 ++++++++---- .../elasticsearch/painless/ir/ElvisNode.java | 11 +-- .../painless/ir/ExpressionNode.java | 14 ++-- .../painless/ir/FuncRefNode.java | 30 +++++--- .../painless/ir/InstanceofNode.java | 33 ++++++--- .../elasticsearch/painless/ir/LambdaNode.java | 69 +++++++++++++++---- .../painless/ir/ListInitializationNode.java | 38 +++++++--- .../painless/ir/ListSubShortcutNode.java | 41 +++++++---- .../painless/ir/MapInitializationNode.java | 55 ++++++++++----- .../painless/ir/MapSubShortcutNode.java | 39 ++++++++--- .../painless/ir/NewArrayFuncRefNode.java | 30 +++++--- .../painless/ir/NewArrayNode.java | 22 ++++-- .../painless/ir/NewObjectNode.java | 36 +++++++--- .../elasticsearch/painless/ir/NullNode.java | 2 +- .../painless/ir/NullSafeSubNode.java | 11 +-- .../elasticsearch/painless/ir/PrefixNode.java | 12 ++-- 23 files changed, 439 insertions(+), 216 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java index 1743e05da12f4..59e457b88d855 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java @@ -21,33 +21,33 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import java.util.Objects; - public class ConditionalNode extends BinaryNode { - protected Location location; - - public ConditionalNode(Location location) { - this.location = Objects.requireNonNull(location); - } + /* ---- begin tree structure ---- */ protected ExpressionNode conditionNode; - public void setConditionNode(ExpressionNode conditionNode) { + public ConditionalNode setConditionNode(ExpressionNode conditionNode) { this.conditionNode = conditionNode; + return this; } public ExpressionNode getConditionNode() { return conditionNode; } + /* ---- end tree structure ---- */ + + public ConditionalNode() { + // do nothing + } + @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); Label fals = new Label(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java index 35686ab2a9965..352955385645b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -23,18 +23,29 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; -import java.util.Objects; +public class ConstantNode extends ExpressionNode { -public class ConstantNode implements IRNode { + /* ---- begin node data ---- */ - protected final Object constant; + protected Object constant; + + public ConstantNode setConstant(Object constant) { + this.constant = constant; + return this; + } + + public Object getConstant() { + return constant; + } + + /* ---- end node data ---- */ - ConstantNode(Object constant) { - this.constant = Objects.requireNonNull(constant); + ConstantNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { if (constant instanceof String) methodWriter.push((String)constant); else if (constant instanceof Double) methodWriter.push((double)constant); else if (constant instanceof Float) methodWriter.push((float)constant); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index 1b1e6c85b3b0f..5cb18d53dfb36 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -22,34 +22,45 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; -import java.util.Objects; - public class DeclarationNode extends StatementNode { + /* ---- begin tree structure ---- */ + protected ExpressionNode expressionNode; - public void setExpressionNode(ExpressionNode childNode) { + public DeclarationNode setExpressionNode(ExpressionNode childNode) { this.expressionNode = childNode; + return this; } public ExpressionNode getExpressionNode() { return expressionNode; } - protected final Location location; - protected final Variable variable; + /* ---- end tree structure, begin node data ---- */ + + protected Variable variable; + + public DeclarationNode setCaptured(Variable variable) { + this.variable = variable; + return this; + } + + public Variable getCaptured() { + return variable; + } + + /* ---- end node data ---- */ - public DeclarationNode(Location location, Variable variable) { - this.location = Objects.requireNonNull(location); - this.variable = Objects.requireNonNull(variable); + public DeclarationNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); if (expressionNode == null) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java index 969ff0c5c0f21..6069f6a909a47 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java @@ -26,33 +26,33 @@ public class DotNode extends PrefixNode { public DotNode() { - + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { prefixNode.write(classWriter, methodWriter, globals); childNode.write(classWriter, methodWriter, globals); } @Override - public int accessElementCount() { + protected int accessElementCount() { return childNode.accessElementCount(); } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { prefixNode.write(classWriter, methodWriter, globals); childNode.setup(classWriter, methodWriter, globals); } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.load(classWriter, methodWriter, globals); } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.store(classWriter, methodWriter, globals); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java index 11851ea86863e..5fc43114279a3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java @@ -17,26 +17,20 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ir.ExpressionNode; - -import java.util.Objects; public class DotSubArrayLengthNode extends ExpressionNode { - protected final Location location; - - public DotSubArrayLengthNode(Location location) { - this.location = Objects.requireNonNull(location); + public DotSubArrayLengthNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.arrayLength(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java index 7ca9221c98abb..2032593e365a3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java @@ -22,23 +22,31 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import java.util.Objects; - public class DotSubDefNode extends ExpressionNode { - protected final Location location; - protected final String value; + /* ---- begin node data ---- */ + + protected String value; + + public DotSubDefNode setValue(String value) { + this.value = value; + return this; + } + + public String getValue() { + return value; + } + + /* ---- end node data ---- */ - public DotSubDefNode(Location location, String value) { - this.location = Objects.requireNonNull(location); - this.value = Objects.requireNonNull(value); + public DotSubDefNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); org.objectweb.asm.Type methodType = @@ -47,17 +55,17 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public int accessElementCount() { + protected int accessElementCount() { return 1; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { // do nothing } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); org.objectweb.asm.Type methodType = @@ -66,7 +74,7 @@ public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals glo } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java index 4a9d11208490e..ab07dc44d69d9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java @@ -21,25 +21,33 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessField; import org.objectweb.asm.Type; -import java.util.Objects; - public class DotSubNode extends ExpressionNode { - protected final Location location; - protected final PainlessField field; + /* ---- begin node data ---- */ + + protected PainlessField field; + + public DotSubNode setField(PainlessField field) { + this.field = field; + return this; + } + + public PainlessField getField() { + return field; + } - public DotSubNode(Location location, PainlessField field) { - this.location = Objects.requireNonNull(location); - this.field = Objects.requireNonNull(field); + /* ---- end node data ---- */ + + public DotSubNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -52,17 +60,17 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public int accessElementCount() { + protected int accessElementCount() { return 1; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { // Do nothing. } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -75,7 +83,7 @@ public void load(ClassWriter classWriter, MethodWriter methodWriter,Globals glob } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java index 2339ac34f3363..2cc75a109b3b7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java @@ -21,26 +21,42 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; -import java.util.Objects; - public class DotSubShortcutNode extends ExpressionNode { - protected final Location location; - protected final PainlessMethod getter; - protected final PainlessMethod setter; + /* ---- begin node data ---- */ - public DotSubShortcutNode(Location location, String value, String type, PainlessMethod getter, PainlessMethod setter) { - this.location = Objects.requireNonNull(location); - this.getter = getter; + protected PainlessMethod setter; + protected PainlessMethod getter; + + public DotSubShortcutNode setSetter(PainlessMethod setter) { this.setter = setter; + return this; + } + + public PainlessMethod getSetter() { + return setter; + } + + public DotSubShortcutNode setGetter(PainlessMethod getter) { + this.getter = getter; + return this; + } + + public PainlessMethod getGetter() { + return getter; + } + + /* ---- end node data ---- */ + + public DotSubShortcutNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -51,17 +67,17 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public int accessElementCount() { + protected int accessElementCount() { return 1; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { // do nothing } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -72,7 +88,7 @@ public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals glo } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(setter); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java index 85cadbd348f3c..978f02acc20ff 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java @@ -21,22 +21,17 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; -import java.util.Objects; - public class ElvisNode extends BinaryNode { - protected Location location; - - public ElvisNode(Location location) { - this.location = Objects.requireNonNull(location); + public ElvisNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); Label end = new Label(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java index 2423379fc9a88..ac66075bb3e44 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java @@ -19,13 +19,11 @@ package org.elasticsearch.painless.ir; -public abstract class ExpressionNode implements IRNode { +public abstract class ExpressionNode extends IRNode { - protected TypeNode typeNode; + /* ---- begin tree structure ---- */ - public ExpressionNode() { - // do nothing - } + protected TypeNode typeNode; public void setTypeNode(TypeNode typeNode) { this.typeNode = typeNode; @@ -42,4 +40,10 @@ public Class getType() { public String getCanonicalTypeName() { return typeNode.getCanonicalTypeName(); } + + /* ---- end tree structure ---- */ + + public ExpressionNode() { + // do nothing + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java index 17a088c002491..7968c3840819e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java @@ -22,26 +22,34 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import java.util.Objects; - public class FuncRefNode extends ExpressionNode { - protected final Location location; - protected final FunctionRef functionRef; + /* ---- begin node data ---- */ + + protected FunctionRef funcRef; + + public FuncRefNode setFuncRef(FunctionRef funcRef) { + this.funcRef = funcRef; + return this; + } + + public FunctionRef getFuncRef() { + return funcRef; + } + + /* ---- end node data ---- */ - public FuncRefNode(Location location, FunctionRef functionRef) { - this.location = Objects.requireNonNull(location); - this.functionRef = functionRef; + public FuncRefNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (functionRef != null) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (funcRef != null) { methodWriter.writeDebugInfo(location); - methodWriter.invokeLambdaCall(functionRef); + methodWriter.invokeLambdaCall(funcRef); } else { // dynamic interface: placeholder for run-time lookup methodWriter.push((String)null); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java index c8a5feea17731..437d7b7fdc0a0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -26,21 +26,19 @@ public class InstanceofNode extends UnaryNode { - protected final boolean isPrimitiveResult; - - public InstanceofNode(boolean isPrimitiveResult) { - this.isPrimitiveResult = isPrimitiveResult; - } + /* ---- begin tree structure ---- */ protected TypeNode expressionTypeNode; protected TypeNode resolvedTypeNode; - public void setExpressionTypeNode(TypeNode expressionTypeNode) { + public InstanceofNode setExpressionTypeNode(TypeNode expressionTypeNode) { this.expressionTypeNode = expressionTypeNode; + return this; } - public void setResolvedTypeNode(TypeNode resolvedTypeNode) { + public InstanceofNode setResolvedTypeNode(TypeNode resolvedTypeNode) { this.resolvedTypeNode = resolvedTypeNode; + return this; } public TypeNode setExpressionTypeNode() { @@ -51,8 +49,27 @@ public TypeNode setResolvedTypeNode() { return resolvedTypeNode; } + /* ---- end tree structure, begin node data ---- */ + + protected boolean isPrimitiveResult; + + public InstanceofNode setPrimitiveResult(boolean isPrimitiveResult) { + this.isPrimitiveResult = isPrimitiveResult; + return this; + } + + public boolean isPrimitiveResult() { + return isPrimitiveResult; + } + + /* ---- end node data ---- */ + + public InstanceofNode() { + // do nothing + } + @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.write(classWriter, methodWriter, globals); // primitive types diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index e3ab923ff5f40..2228bb50cc0ef 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -23,37 +23,82 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import java.util.List; -import java.util.Objects; public class LambdaNode extends ExpressionNode { - protected final Location location; - protected final List captures; - protected final FunctionRef functionRef; + /* ---- begin node data ---- */ - public LambdaNode(Location location, List captures, FunctionRef functionRef) { - this.location = Objects.requireNonNull(location); - this.captures = Objects.requireNonNull(captures); - this.functionRef = Objects.requireNonNull(functionRef); + protected List captures; + protected FunctionRef funcRef; + + public LambdaNode setFuncRef(FunctionRef funcRef) { + this.funcRef = funcRef; + return this; + } + + public FunctionRef getFuncRef() { + return funcRef; + } + + public LambdaNode addCaptureNode(Variable capture) { + captures.add(capture); + return this; + } + + public LambdaNode setCaptureNode(int index, Variable capture) { + captures.set(index, capture); + return this; + } + + public Variable getCaptureNode(int index) { + return captures.get(index); + } + + public LambdaNode removeCaptureNode(Variable capture) { + captures.remove(capture); + return this; + } + + public LambdaNode removeCaptureNode(int index) { + captures.remove(index); + return this; + } + + public int getCapturesSize() { + return captures.size(); + } + + public List getCaptures() { + return captures; + } + + public LambdaNode clearCaptures() { + captures.clear(); + return this; + } + + /* ---- end node data ---- */ + + public LambdaNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - if (functionRef != null) { + if (funcRef != null) { methodWriter.writeDebugInfo(location); // load captures for (Variable capture : captures) { methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); } - methodWriter.invokeLambdaCall(functionRef); + methodWriter.invokeLambdaCall(funcRef); } else { // placeholder methodWriter.push((String)null); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java index 9ce26728e6d29..8350c464f855a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java @@ -21,29 +21,45 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import java.util.Objects; - public class ListInitializationNode extends ArgumentsNode { - protected final Location location; - protected final PainlessConstructor constructor; - protected final PainlessMethod method; + /* ---- begin node data ---- */ + + protected PainlessConstructor constructor; + protected PainlessMethod method; + + public ListInitializationNode setConstructor(PainlessConstructor constructor) { + this.constructor = constructor; + return this; + } + + public PainlessConstructor getConstructor() { + return constructor; + } + + public ListInitializationNode setMethod(PainlessMethod method) { + this.method = method; + return this; + } + + public PainlessMethod getMethod() { + return method; + } + + /* ---- end node data ---- */ - public ListInitializationNode(Location location, PainlessConstructor constructor, PainlessMethod method) { - this.location = Objects.requireNonNull(location); - this.constructor = Objects.requireNonNull(constructor); - this.method = Objects.requireNonNull(method); + public ListInitializationNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.newInstance(MethodWriter.getType(getType())); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java index f81c4538b67a9..c595a678f5543 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java @@ -21,41 +21,56 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessMethod; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import java.util.Objects; - public class ListSubShortcutNode extends UnaryNode { - protected final Location location; - protected final PainlessMethod setter; - protected final PainlessMethod getter; + /* ---- begin node data ---- */ - public ListSubShortcutNode(Location location, PainlessMethod setter, PainlessMethod getter) { + protected PainlessMethod setter; + protected PainlessMethod getter; - this.location = Objects.requireNonNull(location); + public ListSubShortcutNode setSetter(PainlessMethod setter) { this.setter = setter; + return this; + } + + public PainlessMethod getSetter() { + return setter; + } + + public ListSubShortcutNode setGetter(PainlessMethod getter) { this.getter = getter; + return this; + } + + public PainlessMethod getGetter() { + return getter; + } + + /* ---- end node data ---- */ + + public ListSubShortcutNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { setup(classWriter, methodWriter, globals); load(classWriter, methodWriter, globals); } @Override - public int accessElementCount() { + protected int accessElementCount() { return 2; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.write(classWriter, methodWriter, globals); Label noFlip = new Label(); @@ -69,7 +84,7 @@ public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -79,7 +94,7 @@ public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals glo } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(setter); methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java index 57b799135b89c..f015c78f0c03e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -30,31 +29,24 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; public class MapInitializationNode extends ExpressionNode { - protected final Location location; - protected final PainlessConstructor constructor; - protected final PainlessMethod method; - - public MapInitializationNode(Location location, PainlessConstructor constructor, PainlessMethod method) { - this.location = Objects.requireNonNull(location); - this.constructor = Objects.requireNonNull(constructor); - this.method = Objects.requireNonNull(method); - } + /* ---- begin tree structure ---- */ protected final List keyNodes = new ArrayList<>(); protected final List valueNodes = new ArrayList<>(); - public void addArgumentNode(ExpressionNode keyNode, ExpressionNode valueNode) { + public MapInitializationNode addArgumentNode(ExpressionNode keyNode, ExpressionNode valueNode) { keyNodes.add(keyNode); valueNodes.add(valueNode); + return this; } - public void setArgumentNode(int index, ExpressionNode keyNode, ExpressionNode valueNode) { + public MapInitializationNode setArgumentNode(int index, ExpressionNode keyNode, ExpressionNode valueNode) { keyNodes.set(index, keyNode); valueNodes.set(index, valueNode); + return this; } public ExpressionNode getKeyNode(int index) { @@ -72,9 +64,10 @@ public ExpressionNode[] getArgumentNode(int index) { }; } - public void removeArgumentNode(int index) { + public MapInitializationNode removeArgumentNode(int index) { keyNodes.remove(index); valueNodes.remove(index); + return this; } public int getArgumentsSize() { @@ -89,13 +82,43 @@ public List getValueNodes() { return valueNodes; } - public void clearArgumentNodes() { + public MapInitializationNode clearArgumentNodes() { keyNodes.clear(); valueNodes.clear(); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + protected PainlessConstructor constructor; + protected PainlessMethod method; + + public MapInitializationNode setConstructor(PainlessConstructor constructor) { + this.constructor = constructor; + return this; + } + + public PainlessConstructor getConstructor() { + return constructor; + } + + public MapInitializationNode setMethod(PainlessMethod method) { + this.method = method; + return this; + } + + public PainlessMethod getMethod() { + return method; + } + + /* ---- end node data ---- */ + + public MapInitializationNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.newInstance(MethodWriter.getType(getType())); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java index 828d5f7770a4a..c7fd59c8f02cd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -29,18 +29,37 @@ public class MapSubShortcutNode extends UnaryNode { - protected final Location location; - protected final PainlessMethod setter; - protected final PainlessMethod getter; + /* ---- begin node data ---- */ - public MapSubShortcutNode(Location location, PainlessMethod setter, PainlessMethod getter) { - this.location = Objects.requireNonNull(location); + protected PainlessMethod setter; + protected PainlessMethod getter; + + public MapSubShortcutNode setSetter(PainlessMethod setter) { this.setter = setter; + return this; + } + + public PainlessMethod getSetter() { + return setter; + } + + public MapSubShortcutNode setGetter(PainlessMethod getter) { this.getter = getter; + return this; + } + + public PainlessMethod getGetter() { + return getter; + } + + /* ---- end node data ---- */ + + public MapSubShortcutNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.write(classWriter, methodWriter, globals); methodWriter.writeDebugInfo(location); @@ -52,17 +71,17 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } @Override - public int accessElementCount() { + protected int accessElementCount() { return 2; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { childNode.write(classWriter, methodWriter, globals); } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -72,7 +91,7 @@ public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals glo } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(setter); methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java index 531c9ebdb42b2..2fca22a069f46 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java @@ -22,26 +22,34 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import java.util.Objects; +public class NewArrayFuncRefNode extends ExpressionNode { -public final class NewArrayFuncRefNode extends ExpressionNode { + /* ---- begin node data ---- */ - protected final Location location; - protected final FunctionRef functionRef; + protected FunctionRef funcRef; - public NewArrayFuncRefNode(Location location, FunctionRef functionRef) { - this.location = Objects.requireNonNull(location); - this.functionRef = Objects.requireNonNull(functionRef); + public NewArrayFuncRefNode setFuncRef(FunctionRef funcRef) { + this.funcRef = funcRef; + return this; + } + + public FunctionRef getFuncRef() { + return funcRef; + } + + /* ---- end node data ---- */ + + public NewArrayFuncRefNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (functionRef != null) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + if (funcRef != null) { methodWriter.writeDebugInfo(location); - methodWriter.invokeLambdaCall(functionRef); + methodWriter.invokeLambdaCall(funcRef); } else { // push a null instruction as a placeholder for future lambda instructions methodWriter.push((String)null); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java index 8e08f674e0e46..9c3628e024328 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java @@ -21,21 +21,31 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class NewArrayNode extends ArgumentsNode { - protected final Location location; - protected final boolean initialize; + /* ---- begin node data ---- */ - public NewArrayNode(Location location, boolean initialize) { - this.location = location; + protected boolean initialize; + + public NewArrayNode setInitialize(boolean initialize) { this.initialize = initialize; + return this; + } + + public boolean getInitialize() { + return initialize; + } + + /* ---- end node data ---- */ + + public NewArrayNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); if (initialize) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java index bd2b69556f6ed..44476b5163293 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java @@ -21,28 +21,44 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import java.util.Objects; - public final class NewObjectNode extends ArgumentsNode { - protected final Location location; - protected final PainlessConstructor constructor; - protected final boolean read; + /* ---- begin node data ---- */ + + protected PainlessConstructor constructor; + protected boolean read; + + public NewObjectNode setConstructor(PainlessConstructor constructor) { + this.constructor = constructor; + return this; + } + + public PainlessConstructor getConstructor() { + return constructor; + } - public NewObjectNode(Location location, PainlessConstructor constructor, boolean read) { - this.location = Objects.requireNonNull(location); - this.constructor = Objects.requireNonNull(constructor); + public NewObjectNode setRead(boolean read) { this.read = read; + return this; + } + + public boolean getRead() { + return read; + } + + /* ---- end node data ---- */ + + public NewObjectNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.newInstance(MethodWriter.getType(getType())); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java index 7842a8dac8a2c..59ee2b72cf8e0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java @@ -31,7 +31,7 @@ public NullNode() { } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.visitInsn(Opcodes.ACONST_NULL); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java index 7eeceedfde47c..da989e2f369b8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java @@ -21,22 +21,17 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; -import java.util.Objects; - public class NullSafeSubNode extends UnaryNode { - protected Location location; - - public NullSafeSubNode(Location location) { - this.location = Objects.requireNonNull(location); + public NullSafeSubNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); Label end = new Label(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java index 68812c7624a24..9f9d186f32350 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java @@ -21,11 +21,9 @@ public abstract class PrefixNode extends UnaryNode { - protected ExpressionNode prefixNode; + /* ---- begin tree structure ---- */ - public PrefixNode() { - // do nothing - } + protected ExpressionNode prefixNode; public void setPrefixNode(ExpressionNode prefixNode) { this.prefixNode = prefixNode; @@ -34,4 +32,10 @@ public void setPrefixNode(ExpressionNode prefixNode) { public ExpressionNode getPrefixNode() { return prefixNode; } + + /* ---- end tree structure ---- */ + + public PrefixNode() { + // do nothing + } } From 0bcc0c7cdecd12f268295b4f23af673195dea673 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 18 Dec 2019 18:13:27 -0800 Subject: [PATCH 10/24] converted more nodes to ir --- .../org/elasticsearch/painless/Constant.java | 2 +- .../org/elasticsearch/painless/Globals.java | 4 +- .../painless/antlr/PainlessParser.java | 2 +- .../elasticsearch/painless/ir/BlockNode.java | 25 +- .../{CallDefNode.java => CallSubDefNode.java} | 56 ++--- .../ir/{SCatch.java => CatchNode.java} | 54 ++--- .../painless/ir/ConditionNode.java | 52 ++++ .../painless/ir/ContinueNode.java | 36 +++ .../painless/ir/DeclarationBlockNode.java | 84 +++++++ .../elasticsearch/painless/ir/DoLoopNode.java | 62 +++++ .../elasticsearch/painless/ir/FieldNode.java | 83 +++++++ .../painless/ir/ForEachLoopNode.java | 51 ++++ ...achArray.java => ForEachSubArrayNode.java} | 122 ++++++---- .../painless/ir/ForLoopNode.java | 118 ++++++++++ .../painless/ir/FunctionNode.java | 194 +++++++++++++++ .../elasticsearch/painless/ir/IfElseNode.java | 75 ++++++ .../org/elasticsearch/painless/ir/IfNode.java | 49 ++++ .../elasticsearch/painless/ir/LoopNode.java | 54 +++++ .../elasticsearch/painless/ir/RegexNode.java | 49 +++- .../elasticsearch/painless/ir/ReturnNode.java | 53 +++++ .../org/elasticsearch/painless/ir/SClass.java | 2 +- .../elasticsearch/painless/ir/SContinue.java | 69 ------ .../elasticsearch/painless/ir/SDeclBlock.java | 75 ------ .../org/elasticsearch/painless/ir/SDo.java | 133 ----------- .../org/elasticsearch/painless/ir/SEach.java | 122 ---------- .../painless/ir/SExpression.java | 90 ------- .../org/elasticsearch/painless/ir/SField.java | 91 ------- .../org/elasticsearch/painless/ir/SFor.java | 222 ------------------ .../elasticsearch/painless/ir/SFunction.java | 186 --------------- .../org/elasticsearch/painless/ir/SIf.java | 103 -------- .../elasticsearch/painless/ir/SIfElse.java | 140 ----------- .../elasticsearch/painless/ir/SReturn.java | 89 ------- .../painless/ir/SSubEachIterable.java | 39 +-- .../painless/ir/StatementExpressionNode.java | 71 ++++++ .../painless/ir/StatementNode.java | 6 +- .../elasticsearch/painless/ir/TypeNode.java | 15 +- .../painless/node/EListInit.java | 2 +- .../elasticsearch/painless/node/EMapInit.java | 2 +- .../elasticsearch/painless/node/SClass.java | 2 +- 39 files changed, 1198 insertions(+), 1486 deletions(-) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{CallDefNode.java => CallSubDefNode.java} (67%) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{SCatch.java => CatchNode.java} (56%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{SSubEachArray.java => ForEachSubArrayNode.java} (52%) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java index d42c267fc3fef..e4874a8a69baf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; /** - * A constant initializer to be added to the class file. + * A constant initializerNode to be added to the class file. */ public class Constant { public final Location location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java index 31cefbcf0c21f..075e1181d2e90 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java @@ -35,10 +35,10 @@ public Globals(BitSet statements) { this.statements = statements; } - /** Adds a new constant initializer to be written */ + /** Adds a new constant initializerNode to be written */ public void addConstantInitializer(Constant constant) { if (constantInitializers.put(constant.name, constant) != null) { - throw new IllegalStateException("constant initializer: " + constant.name + " already exists"); + throw new IllegalStateException("constant initializerNode: " + constant.name + " already exists"); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java index dff6674591ba7..d3bb437ac9883 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java @@ -52,7 +52,7 @@ class PainlessParser extends Parser { RULE_lamtype = 31, RULE_funcref = 32; public static final String[] ruleNames = { "source", "function", "parameters", "statement", "rstatement", "dstatement", - "trailer", "block", "empty", "initializer", "afterthought", "declaration", + "trailer", "block", "empty", "initializerNode", "afterthoughtNode", "declaration", "decltype", "declvar", "trap", "expression", "unary", "chain", "primary", "postfix", "postdot", "callinvoke", "fieldaccess", "braceaccess", "arrayinitializer", "listinitializer", "mapinitializer", "maptoken", "arguments", "argument", diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java index ff0d337a3417a..28722bfa2cc82 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java @@ -69,7 +69,30 @@ public BlockNode clearStatementNodes() { return this; } - /* ---- end tree structure ---- */ + /* ---- end tree structure, begin node data ---- */ + + protected boolean doAllEscape; + protected int statementCount; + + public BlockNode setAllEscape(boolean doAllEscape) { + this.doAllEscape = doAllEscape; + return this; + } + + public boolean doAllEscape() { + return doAllEscape; + } + + public BlockNode setStatementCount(int statementCount) { + this.statementCount = statementCount; + return this; + } + + public int getStatementCount() { + return statementCount; + } + + /* ---- end node data ---- */ public BlockNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java similarity index 67% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java index 6fa521225c91e..ca4d09f20e76c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java @@ -28,16 +28,16 @@ import java.util.ArrayList; import java.util.List; -public class CallDefNode extends ArgumentsNode { +public class CallSubDefNode extends ArgumentsNode { /* ---- begin node data ---- */ protected String name; protected String recipe; protected List pointers; - protected List> parameterTypes; + protected List> typeParameters; - public CallDefNode setName(String name) { + public CallSubDefNode setName(String name) { this.name = name; return this; } @@ -46,7 +46,7 @@ public String getName() { return name; } - public CallDefNode setRecipe(String recipe) { + public CallSubDefNode setRecipe(String recipe) { this.recipe = recipe; return this; } @@ -55,12 +55,12 @@ public String getRecipe() { return recipe; } - public CallDefNode addPointer(String pointer) { + public CallSubDefNode addPointer(String pointer) { pointers.add(pointer); return this; } - public CallDefNode setPointer(int index, String pointer) { + public CallSubDefNode setPointer(int index, String pointer) { pointers.set(index, pointer); return this; } @@ -69,12 +69,12 @@ public String getPointer(int index) { return pointers.get(index); } - public CallDefNode removePointer(String pointer) { + public CallSubDefNode removePointer(String pointer) { pointers.remove(pointer); return this; } - public CallDefNode removePointer(int index) { + public CallSubDefNode removePointer(int index) { pointers.remove(index); return this; } @@ -87,51 +87,51 @@ public List getPointers() { return pointers; } - public CallDefNode clearPointers() { + public CallSubDefNode clearPointers() { pointers.clear(); return this; } - public CallDefNode addParameterType(Class parameterType) { - parameterTypes.add(parameterType); + public CallSubDefNode addTypeParameter(Class typeParameter) { + typeParameters.add(typeParameter); return this; } - public CallDefNode setParameterType(int index, Class parameterType) { - parameterTypes.set(index, parameterType); + public CallSubDefNode setTypeParameter(int index, Class typeParameter) { + typeParameters.set(index, typeParameter); return this; } - public Class getParameterType(int index) { - return parameterTypes.get(index); + public Class getTypeParameter(int index) { + return typeParameters.get(index); } - public CallDefNode removeParameterType(Class parameterType) { - parameterTypes.remove(parameterType); + public CallSubDefNode removeTypeParameter(Class typeParameter) { + typeParameters.remove(typeParameter); return this; } - public CallDefNode removeParameterType(int index) { - parameterTypes.remove(index); + public CallSubDefNode removeTypeParameter(int index) { + typeParameters.remove(index); return this; } - public int getParameterTypesSize() { - return parameterTypes.size(); + public int getTypeParametersSize() { + return typeParameters.size(); } - public List> getParameterTypes() { - return parameterTypes; + public List> getTypeParameters() { + return typeParameters; } - public CallDefNode clearParameterTypes() { - parameterTypes.clear(); + public CallSubDefNode clearTypeParameters() { + typeParameters.clear(); return this; } /* ---- end node data ---- */ - public CallDefNode() { + public CallSubDefNode() { // do nothing } @@ -144,9 +144,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } // create method type from return value and arguments - Type[] asmParameterTypes = new Type[parameterTypes.size()]; + Type[] asmParameterTypes = new Type[typeParameters.size()]; for (int index = 0; index < asmParameterTypes.length; ++index) { - asmParameterTypes[index] = Type.getType(parameterTypes.get(index)); + asmParameterTypes[index] = Type.getType(typeParameters.get(index)); } Type methodType = Type.getMethodType(MethodWriter.getType(getType()), asmParameterTypes); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java similarity index 56% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index 2dc3f987d192c..ed6194486bf67 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SCatch.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -21,67 +21,65 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import java.util.Objects; -import java.util.Set; - public class CatchNode extends StatementNode { - /* --- begin tree structure --- */ + /* ---- begin tree structure ---- */ protected DeclarationNode declarationNode; + protected BlockNode blockNode; - public void setChildNode(ExpressionNode declarationNode) { + public CatchNode setDeclarationNode(DeclarationNode declarationNode) { this.declarationNode = declarationNode; + return this; } - public ExpressionNode getChildNode() { + public DeclarationNode getDeclarationNode() { return declarationNode; } - /* --- end tree structure, begin node data --- */ - - protected final Location location; - protected boolean allEscape; - - /* --- end node date --- */ + public CatchNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } - public CatchNode(Location location) { - this.location = Objects.requireNonNull(location); + public BlockNode getBlockNode() { + return blockNode; } + /* ---- end tree structure ---- */ + public CatchNode() { + // do nothing + } Label begin = null; Label end = null; Label exception = null; @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); Label jump = new Label(); methodWriter.mark(jump); - methodWriter.visitVarInsn( - MethodWriter.getType(declaration.variable.clazz).getOpcode(Opcodes.ISTORE), declaration.variable.getSlot()); - - if (block != null) { - block.continu = continu; - block.brake = brake; - block.write(classWriter, methodWriter, globals); + methodWriter.visitVarInsn(MethodWriter.getType( + declarationNode.getCaptured().clazz).getOpcode(Opcodes.ISTORE), + declarationNode.getCaptured().getSlot()); + + if (blockNode != null) { + blockNode.continueLabel = continueLabel; + blockNode.breakLabel = breakLabel; + blockNode.write(classWriter, methodWriter, globals); } - methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declaration.variable.clazz).getInternalName()); + methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declarationNode.getCaptured().clazz).getInternalName()); - if (exception != null && (block == null || !block.allEscape)) { + if (exception != null && (blockNode == null || blockNode.allEscape == false)) { methodWriter.goTo(exception); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java new file mode 100644 index 0000000000000..5af516182630b --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +public abstract class ConditionNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected ExpressionNode conditionNode; + protected BlockNode blockNode; + + public ConditionNode setConditionNode(ExpressionNode conditionNode) { + this.conditionNode = conditionNode; + return this; + } + + public ExpressionNode getConditionNode() { + return conditionNode; + } + + public ConditionNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } + + public BlockNode getBlockNode() { + return blockNode; + } + + /* ---- end tree structure ---- */ + + public ConditionNode() { + // do nothing + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java new file mode 100644 index 0000000000000..fd182caf3bf81 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class ContinueNode extends StatementNode { + + public ContinueNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.goTo(continueLabel); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java new file mode 100644 index 0000000000000..54e433df1b3b5 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java @@ -0,0 +1,84 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +import java.util.ArrayList; +import java.util.List; + +public final class DeclarationBlockNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected List declarationNodes = new ArrayList<>(); + + public DeclarationBlockNode addStatementNode(DeclarationNode declarationNode) { + declarationNodes.add(declarationNode); + return this; + } + + public DeclarationBlockNode setStatementNode(int index, DeclarationNode declarationNode) { + declarationNodes.set(index, declarationNode); + return this; + } + + public DeclarationNode getStatementNode(int index) { + return declarationNodes.get(index); + } + + public DeclarationBlockNode removeStatementNode(DeclarationNode declarationNode) { + declarationNodes.remove(declarationNode); + return this; + } + + public DeclarationBlockNode removeStatementNode(int index) { + declarationNodes.remove(index); + return this; + } + + public int getStatementsSize() { + return declarationNodes.size(); + } + + public List getStatementsNodes() { + return declarationNodes; + } + + public DeclarationBlockNode clearStatementNodes() { + declarationNodes.clear(); + return this; + } + + /* ---- end tree structure ---- */ + + public DeclarationBlockNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + for (DeclarationNode declarationNode : declarationNodes) { + declarationNode.write(classWriter, methodWriter, globals); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java new file mode 100644 index 0000000000000..653eaaa2f9ac7 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +public class DoLoopNode extends LoopNode { + + public DoLoopNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label start = new Label(); + Label begin = new Label(); + Label end = new Label(); + + methodWriter.mark(start); + + blockNode.continueLabel = begin; + blockNode.breakLabel = end; + blockNode.write(classWriter, methodWriter, globals); + + methodWriter.mark(begin); + + if (!isContinuous) { + conditionNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, end); + } + + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, blockNode.getStatementCount()), location); + } + + methodWriter.goTo(start); + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java new file mode 100644 index 0000000000000..0c511206b1470 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -0,0 +1,83 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Type; + +public class FieldNode extends IRNode { + + /* ---- begin tree structure ---- */ + + protected TypeNode typeNode; + + public void setTypeNode(TypeNode typeNode) { + this.typeNode = typeNode; + } + + public TypeNode getTypeNode() { + return typeNode; + } + + public Class getType() { + return typeNode.getType(); + } + + public String getCanonicalTypeName() { + return typeNode.getCanonicalTypeName(); + } + + /* ---- end tree structure, begin node data ---- */ + + protected int modifiers; + protected String name; + + public FieldNode setModifiers(int modifiers) { + this.modifiers = modifiers; + return this; + } + + public int getModifiers(int modifiers) { + return modifiers; + } + + public FieldNode setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + /* ---- end node data ---- */ + + public FieldNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + classWriter.getClassVisitor().visitField( + ClassWriter.buildAccess(modifiers, true), name, Type.getType(getType()).getDescriptor(), null, null).visitEnd(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java new file mode 100644 index 0000000000000..7a7b014a9ced8 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class ForEachLoopNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected ConditionNode conditionNode; + + public ForEachLoopNode setConditionNode(ConditionNode conditionNode) { + this.conditionNode = conditionNode; + return this; + } + + public ConditionNode getConditionNode() { + return conditionNode; + } + + /* ---- end tree structure ---- */ + + public ForEachLoopNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + conditionNode.write(classWriter, methodWriter, globals); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java similarity index 52% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java index c0ce95ea68adb..5756b9ea325c6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java @@ -17,65 +17,92 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import java.util.Objects; -import java.util.Set; +public class ForEachSubArrayNode extends LoopNode { -/** - * Represents a for-each loop for arrays. - */ -final class SSubEachArray extends AStatement { - private final Variable variable; - private AExpression expression; - private final SBlock block; - - private PainlessCast cast = null; - private Variable array = null; - private Variable index = null; - private Class indexed = null; - - SSubEachArray(Location location, Variable variable, AExpression expression, SBlock block) { - super(location); - - this.variable = Objects.requireNonNull(variable); - this.expression = Objects.requireNonNull(expression); - this.block = block; + /* ---- being tree structure ---- */ + + protected TypeNode indexedTypeNode; + + public void setIndexedTypeNode(TypeNode indexedTypeNode) { + this.indexedTypeNode = indexedTypeNode; } - @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); + public TypeNode getIndexedTypeNode() { + return indexedTypeNode; } - @Override - void analyze(ScriptRoot scriptRoot, 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. - 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); + public Class getIndexedType() { + return indexedTypeNode.getType(); + } + + public String getIndexedCanonicalTypeName() { + return indexedTypeNode.getCanonicalTypeName(); + } + + /* ---- begin node data ---- */ + + protected Variable variable; + protected PainlessCast cast; + protected Variable array; + protected Variable index; + + public ForEachSubArrayNode setVariable(Variable variable) { + this.variable = variable; + return this; + } + + public Variable getVariable() { + return this.variable; + } + + public ForEachSubArrayNode setCast(PainlessCast cast) { + this.cast = cast; + return this; + } + + public PainlessCast getCast() { + return cast; + } + + public ForEachSubArrayNode setArray(Variable array) { + this.array = array; + return this; + } + + public Variable getArray() { + return this.array; + } + + public ForEachSubArrayNode setIndex(Variable index) { + this.index = index; + return this; + } + + public Variable getIndex() { + return this.index; + } + + /* ---- end node data ---- */ + + ForEachSubArrayNode() { + // do nothing } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); - expression.write(classWriter, methodWriter, globals); + conditionNode.write(classWriter, methodWriter, globals); methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ISTORE), array.getSlot()); methodWriter.push(-1); methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ISTORE), index.getSlot()); @@ -93,24 +120,19 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); - methodWriter.arrayLoad(MethodWriter.getType(indexed)); + methodWriter.arrayLoad(MethodWriter.getType(getIndexedType())); methodWriter.writeCast(cast); methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + methodWriter.writeLoopCounter(loopCounter.getSlot(), blockNode.getStatementCount(), location); } - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); + blockNode.continueLabel = begin; + blockNode.breakLabel = end; + blockNode.write(classWriter, methodWriter, globals); methodWriter.goTo(begin); methodWriter.mark(end); } - - @Override - public String toString() { - return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(variable.clazz), variable.name, expression, block); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java new file mode 100644 index 0000000000000..3d49ceeb4468c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +public class ForLoopNode extends LoopNode { + + /* ---- begin tree structure ---- */ + + protected IRNode initializerNode; + protected ExpressionNode afterthoughtNode; + + public ForLoopNode setInitialzerNode(IRNode initializerNode) { + this.initializerNode = initializerNode; + return this; + } + + public IRNode getInitializerNode() { + return initializerNode; + } + + public ForLoopNode setAfterthoughtNode(ExpressionNode afterthoughtNode) { + this.afterthoughtNode = afterthoughtNode; + return this; + } + + public ExpressionNode getAfterthoughtNode() { + return afterthoughtNode; + } + + /* ---- end tree structure ---- */ + + public ForLoopNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label start = new Label(); + Label begin = afterthoughtNode == null ? start : new Label(); + Label end = new Label(); + + if (initializerNode instanceof DeclarationBlockNode) { + initializerNode.write(classWriter, methodWriter, globals); + } else if (initializerNode instanceof ExpressionNode) { + ExpressionNode initializer = (ExpressionNode)this.initializerNode; + initializer.write(classWriter, methodWriter, globals); + methodWriter.writePop(MethodWriter.getType(initializer.getType()).getSize()); + } + + methodWriter.mark(start); + + if (conditionNode != null && isContinuous == false) { + conditionNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, end); + } + + boolean allEscape = false; + + if (blockNode != null) { + allEscape = blockNode.doAllEscape(); + + int statementCount = Math.max(1, blockNode.statementCount); + + if (afterthoughtNode != null) { + ++statementCount; + } + + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + } + + blockNode.continueLabel = begin; + blockNode.breakLabel = end; + blockNode.write(classWriter, methodWriter, globals); + } else { + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); + } + } + + if (afterthoughtNode != null) { + methodWriter.mark(begin); + afterthoughtNode.write(classWriter, methodWriter, globals); + methodWriter.writePop(MethodWriter.getType(afterthoughtNode.getType()).getSize()); + } + + if (afterthoughtNode != null || !allEscape) { + methodWriter.goTo(start); + } + + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java new file mode 100644 index 0000000000000..e5198f244467d --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -0,0 +1,194 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.List; + +public class FunctionNode extends IRNode { + + /* ---- begin tree structure ---- */ + + protected BlockNode blockNode; + + public FunctionNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } + + public BlockNode getBlockNode() { + return blockNode; + } + + /* ---- end tree structure, begin node data ---- */ + + protected String name; + Class returnType; + List> typeParameters; + protected boolean isSynthetic; + protected boolean doesMethodEscape; + protected Variable loopCounter; + protected int maxLoopCounter; + + public FunctionNode setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + public FunctionNode setReturnType(Class returnType) { + this.returnType = returnType; + return this; + } + + public Class getReturnType() { + return returnType; + } + + public FunctionNode addTypeParameter(Class typeParameter) { + typeParameters.add(typeParameter); + return this; + } + + public FunctionNode setTypeParameter(int index, Class typeParameter) { + typeParameters.set(index, typeParameter); + return this; + } + + public Class getTypeParameter(int index) { + return typeParameters.get(index); + } + + public FunctionNode removeTypeParameter(Class typeParameter) { + typeParameters.remove(typeParameter); + return this; + } + + public FunctionNode removeTypeParameter(int index) { + typeParameters.remove(index); + return this; + } + + public int getTypeParametersSize() { + return typeParameters.size(); + } + + public List> getTypeParameters() { + return typeParameters; + } + + public FunctionNode clearTypeParameters() { + typeParameters.clear(); + return this; + } + + public FunctionNode setSynthetic(boolean isSythetic) { + this.name = name; + return this; + } + + public boolean isSynthetic() { + return isSynthetic; + } + + public FunctionNode setMethodEscape(boolean doesMethodEscape) { + this.doesMethodEscape = doesMethodEscape; + return this; + } + + public boolean doesMethodEscape() { + return doesMethodEscape; + } + + public FunctionNode setLoopCounter(Variable loopCounter) { + this.loopCounter = loopCounter; + return this; + } + + public Variable getLoopCounter() { + return loopCounter; + } + + public FunctionNode setMaxLoopCounter(int maxLoopCounter) { + this.maxLoopCounter = maxLoopCounter; + return this; + } + + public int getMaxLoopCounter() { + return maxLoopCounter; + } + + /* ---- end node data ---- */ + + public FunctionNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; + + if (isSynthetic) { + access |= Opcodes.ACC_SYNTHETIC; + } + + Type asmReturnType = Type.getType(returnType); + Type[] asmParameterTypes = new Type[typeParameters.size()]; + + for (int index = 0; index < asmParameterTypes.length; ++index) { + asmParameterTypes[index] = Type.getType(typeParameters.get(index)); + } + + Method method = new Method(name, asmReturnType, asmParameterTypes); + + methodWriter = classWriter.newMethodWriter(access, method); + methodWriter.visitCode(); + + if (maxLoopCounter > 0) { + // if there is infinite loop protection, we do this once: + // int #loop = settings.getMaxLoopCounter() + methodWriter.push(maxLoopCounter); + methodWriter.visitVarInsn(Opcodes.ISTORE, loopCounter.getSlot()); + } + + blockNode.write(classWriter, methodWriter, globals); + + if (!doesMethodEscape) { + if (returnType == void.class) { + methodWriter.returnValue(); + } else { + throw new IllegalStateException("not all paths provide a return value " + + "for method [" + name + "] with [" + typeParameters.size() + "] parameters"); + } + } + + methodWriter.endMethod(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java new file mode 100644 index 0000000000000..465d934f4717b --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +public class IfElseNode extends ConditionNode { + + /* ---- begin tree structure ---- */ + + protected BlockNode elseBlockNode; + + public IfElseNode setElseBlockNode(BlockNode elseBlockNode) { + this.elseBlockNode = elseBlockNode; + return this; + } + + public BlockNode getElseBlockNode() { + return elseBlockNode; + } + + /* ---- end tree structure ---- */ + + public IfElseNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label fals = new Label(); + Label end = new Label(); + + conditionNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + blockNode.continueLabel = continueLabel; + blockNode.breakLabel = breakLabel; + blockNode.write(classWriter, methodWriter, globals); + + if (blockNode.doAllEscape() == false) { + methodWriter.goTo(end); + } + + methodWriter.mark(fals); + + elseBlockNode.continueLabel = continueLabel; + elseBlockNode.breakLabel = breakLabel; + elseBlockNode.write(classWriter, methodWriter, globals); + + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java new file mode 100644 index 0000000000000..6e131d24903fe --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +public class IfNode extends ConditionNode { + + public IfNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label fals = new Label(); + + conditionNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, fals); + + blockNode.continueLabel = continueLabel; + blockNode.breakLabel = breakLabel; + blockNode.write(classWriter, methodWriter, globals); + + methodWriter.mark(fals); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java new file mode 100644 index 0000000000000..099a094196443 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java @@ -0,0 +1,54 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.Locals.Variable; + +public abstract class LoopNode extends ConditionNode { + + /* ---- begin node data ---- */ + + protected boolean isContinuous; + protected Variable loopCounter; + + public LoopNode setContinuous(boolean isContinuous) { + this.isContinuous = isContinuous; + return this; + } + + public boolean isContinuous() { + return isContinuous; + } + + public LoopNode setLoopCounter(Variable loopCounter) { + this.loopCounter = loopCounter; + return this; + } + + public Variable getLoopCounter() { + return loopCounter; + } + + /* ---- end node data ---- */ + + public LoopNode() { + // do nothing + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java index 723e0d1e0638b..c3ecf91ba0d42 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java @@ -22,29 +22,54 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; -import java.util.Objects; import java.util.regex.Pattern; public class RegexNode extends ExpressionNode { - protected final Location location; - protected final String pattern; - protected final int flags; - protected final Constant constant; + /* ---- begin node data ---- */ - public RegexNode(Location location, String pattern, int flags, Constant constant) { - this.location = Objects.requireNonNull(location); - this.pattern = Objects.requireNonNull(pattern); + protected String pattern; + protected int flags; + protected Constant constant; + + public RegexNode setPattern(String pattern) { + this.pattern = pattern; + return this; + } + + public String getPattern() { + return pattern; + } + + public RegexNode setFlags(int flags) { this.flags = flags; - this.constant = Objects.requireNonNull(constant); + return this; + } + + public int getFlags() { + return flags; + } + + public RegexNode setConstant(Constant constant) { + this.constant = constant; + return this; + } + + public Object getConstant() { + return constant; + } + + /* ---- end node data ---- */ + + public RegexNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); methodWriter.getStatic(WriterConstants.CLASS_TYPE, constant.name, org.objectweb.asm.Type.getType(Pattern.class)); @@ -57,7 +82,7 @@ public void initializeConstant(MethodWriter writer) { writer.invokeStatic(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_COMPILE); } - private int flagForChar(char c) { + protected int flagForChar(char c) { switch (c) { case 'c': return Pattern.CANON_EQ; case 'i': return Pattern.CASE_INSENSITIVE; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java new file mode 100644 index 0000000000000..d0085245098e7 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class ReturnNode extends StatementNode { + + protected ExpressionNode expressionNode; + + public ReturnNode setExpressionNode(ExpressionNode expressionNode) { + this.expressionNode = expressionNode; + return this; + } + + public ExpressionNode getExpressionNode() { + return expressionNode; + } + + public ReturnNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + if (expressionNode != null) { + expressionNode.write(classWriter, methodWriter, globals); + } + + methodWriter.returnValue(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java index 6068d0f8f09fb..05f2347a7bd62 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java @@ -200,7 +200,7 @@ public Map write() { if (false == globals.getConstantInitializers().isEmpty()) { Collection inits = globals.getConstantInitializers().values(); - // Initialize the constants in a static initializer + // Initialize the constants in a static initializerNode final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC, WriterConstants.CLINIT, classVisitor, globals.getStatements(), settings); clinit.visitCode(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java deleted file mode 100644 index 2a9ea5319b6a4..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SContinue.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Set; - -/** - * Represents a continue statement. - */ -public final class SContinue extends AStatement { - - public SContinue(Location location) { - super(location); - } - - @Override - void extractVariables(Set variables) { - // Do nothing. - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (!inLoop) { - throw createError(new IllegalArgumentException("Continue statement outside of a loop.")); - } - - if (lastLoop) { - throw createError(new IllegalArgumentException("Extraneous continue statement.")); - } - - allEscape = true; - anyContinue = true; - statementCount = 1; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.goTo(continu); - } - - @Override - public String toString() { - return singleLineToString(); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java deleted file mode 100644 index 220c9ec3d012c..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDeclBlock.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static java.util.Collections.emptyList; - -/** - * Represents a series of declarations. - */ -public final class SDeclBlock extends AStatement { - - private final List declarations; - - public SDeclBlock(Location location, List declarations) { - super(location); - - this.declarations = Collections.unmodifiableList(declarations); - } - - @Override - void extractVariables(Set variables) { - for (SDeclaration declaration : declarations) { - declaration.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - for (SDeclaration declaration : declarations) { - declaration.analyze(scriptRoot, locals); - } - - statementCount = declarations.size(); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - for (AStatement declaration : declarations) { - declaration.write(classWriter, methodWriter, globals); - } - } - - @Override - public String toString() { - return multilineToString(emptyList(), declarations); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java deleted file mode 100644 index a6c9c2eb30c24..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SDo.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a do-while loop. - */ -public final class SDo extends AStatement { - - private final SBlock block; - private AExpression condition; - - private boolean continuous = false; - - public SDo(Location location, SBlock block, AExpression condition) { - super(location); - - this.condition = Objects.requireNonNull(condition); - this.block = block; - } - - @Override - void extractVariables(Set variables) { - condition.extractVariables(variables); - - if (block != null) { - block.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - locals = Locals.newLocalScope(locals); - - if (block == null) { - throw createError(new IllegalArgumentException("Extraneous do while loop.")); - } - - block.beginLoop = true; - block.inLoop = true; - block.analyze(scriptRoot, locals); - - if (block.loopEscape && !block.anyContinue) { - throw createError(new IllegalArgumentException("Extraneous do while loop.")); - } - - condition.expected = boolean.class; - condition.analyze(scriptRoot, locals); - condition = condition.cast(scriptRoot, locals); - - if (condition.constant != null) { - continuous = (boolean)condition.constant; - - if (!continuous) { - throw createError(new IllegalArgumentException("Extraneous do while loop.")); - } - - if (!block.anyBreak) { - methodEscape = true; - allEscape = true; - } - } - - statementCount = 1; - - if (locals.hasVariable(Locals.LOOP)) { - loopCounter = locals.getVariable(location, Locals.LOOP); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label start = new Label(); - Label begin = new Label(); - Label end = new Label(); - - methodWriter.mark(start); - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - - methodWriter.mark(begin); - - if (!continuous) { - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, end); - } - - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, block.statementCount), location); - } - - methodWriter.goTo(start); - methodWriter.mark(end); - } - - @Override - public String toString() { - return singleLineToString(condition, block); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java deleted file mode 100644 index 65377aaa6e59d..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SEach.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.elasticsearch.painless.lookup.def; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a for-each loop and defers to subnodes depending on type. - */ -public class SEach extends AStatement { - - private final String type; - private final String name; - private AExpression expression; - private final SBlock block; - - private AStatement sub = null; - - public SEach(Location location, String type, String name, AExpression expression, SBlock block) { - super(location); - - this.type = Objects.requireNonNull(type); - this.name = Objects.requireNonNull(name); - this.expression = Objects.requireNonNull(expression); - this.block = block; - } - - @Override - void extractVariables(Set variables) { - variables.add(name); - - expression.extractVariables(variables); - - if (block != null) { - block.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - expression.analyze(scriptRoot, locals); - expression.expected = expression.actual; - expression = expression.cast(scriptRoot, locals); - - Class clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type); - - if (clazz == null) { - throw createError(new IllegalArgumentException("Not a type [" + this.type + "].")); - } - - locals = Locals.newLocalScope(locals); - Variable variable = locals.addVariable(location, clazz, name, true); - - if (expression.actual.isArray()) { - sub = new SSubEachArray(location, variable, expression, block); - } else if (expression.actual == def.class || Iterable.class.isAssignableFrom(expression.actual)) { - sub = new SSubEachIterable(location, variable, expression, block); - } else { - throw createError(new IllegalArgumentException("Illegal for each type " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(expression.actual) + "].")); - } - - sub.analyze(scriptRoot, locals); - - if (block == null) { - throw createError(new IllegalArgumentException("Extraneous for each loop.")); - } - - block.beginLoop = true; - block.inLoop = true; - block.analyze(scriptRoot, locals); - block.statementCount = Math.max(1, block.statementCount); - - if (block.loopEscape && !block.anyContinue) { - throw createError(new IllegalArgumentException("Extraneous for loop.")); - } - - statementCount = 1; - - if (locals.hasVariable(Locals.LOOP)) { - sub.loopCounter = locals.getVariable(location, Locals.LOOP); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.write(classWriter, methodWriter, globals); - } - - @Override - public String toString() { - return singleLineToString(type, name, expression, block); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java deleted file mode 100644 index 3057cd689b07f..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SExpression.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents the top-level node for an expression as a statement. - */ -public final class SExpression extends AStatement { - - private AExpression expression; - - public SExpression(Location location, AExpression expression) { - super(location); - - this.expression = Objects.requireNonNull(expression); - } - - @Override - void extractVariables(Set variables) { - expression.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - Class rtnType = locals.getReturnType(); - boolean isVoid = rtnType == void.class; - - expression.read = lastSource && !isVoid; - expression.analyze(scriptRoot, locals); - - if (!lastSource && !expression.statement) { - throw createError(new IllegalArgumentException("Not a statement.")); - } - - boolean rtn = lastSource && !isVoid && expression.actual != void.class; - - expression.expected = rtn ? rtnType : expression.actual; - expression.internal = rtn; - expression = expression.cast(scriptRoot, locals); - - methodEscape = rtn; - loopEscape = rtn; - allEscape = rtn; - statementCount = 1; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - expression.write(classWriter, methodWriter, globals); - - if (methodEscape) { - methodWriter.returnValue(); - } else { - methodWriter.writePop(MethodWriter.getType(expression.expected).getSize()); - } - } - - @Override - public String toString() { - return singleLineToString(expression); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java deleted file mode 100644 index 569ca608b4502..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SField.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Type; - -import java.util.Set; - -/** - * Represents a member field for its parent class (internal only). - */ -public class SField extends ANode { - - private final int modifiers; - private final String name; - private final Class type; - private final Object instance; - - /** - * Standard constructor. - * @param location original location in the source - * @param modifiers java modifiers for the field - * @param name name of the field - * @param type type of the field - * @param instance initial value for the field - */ - public SField(Location location, int modifiers, String name, Class type, Object instance) { - super(location); - - this.modifiers = modifiers; - this.name = name; - this.type = type; - this.instance = instance; - } - - public String getName() { - return name; - } - - public Object getInstance() { - return instance; - } - - @Override - void extractVariables(Set variables) { - throw createError(new UnsupportedOperationException("unexpected node")); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - throw createError(new UnsupportedOperationException("unexpected node")); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new UnsupportedOperationException("unexpected node")); - } - - void write(ClassWriter classWriter) { - classWriter.getClassVisitor().visitField( - ClassWriter.buildAccess(modifiers, true), name, Type.getType(type).getDescriptor(), null, null).visitEnd(); - } - - @Override - public String toString() { - return singleLineToString(name, type); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java deleted file mode 100644 index 93ba16a41e1ce..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFor.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Arrays; -import java.util.Set; - -import static java.util.Collections.emptyList; - -/** - * Represents a for loop. - */ -public final class SFor extends AStatement { - - private ANode initializer; - private AExpression condition; - private AExpression afterthought; - private final SBlock block; - - private boolean continuous = false; - - public SFor(Location location, ANode initializer, AExpression condition, AExpression afterthought, SBlock block) { - super(location); - - this.initializer = initializer; - this.condition = condition; - this.afterthought = afterthought; - this.block = block; - } - - @Override - void extractVariables(Set variables) { - if (initializer != null) { - initializer.extractVariables(variables); - } - - if (condition != null) { - condition.extractVariables(variables); - } - - if (afterthought != null) { - afterthought.extractVariables(variables); - } - - if (block != null) { - block.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - locals = Locals.newLocalScope(locals); - - if (initializer != null) { - if (initializer instanceof SDeclBlock) { - initializer.analyze(scriptRoot, locals); - } else if (initializer instanceof AExpression) { - AExpression initializer = (AExpression)this.initializer; - - initializer.read = false; - initializer.analyze(scriptRoot, locals); - - if (!initializer.statement) { - throw createError(new IllegalArgumentException("Not a statement.")); - } - - initializer.expected = initializer.actual; - this.initializer = initializer.cast(scriptRoot, locals); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - if (condition != null) { - condition.expected = boolean.class; - condition.analyze(scriptRoot, locals); - condition = condition.cast(scriptRoot, locals); - - if (condition.constant != null) { - continuous = (boolean)condition.constant; - - if (!continuous) { - throw createError(new IllegalArgumentException("Extraneous for loop.")); - } - - if (block == null) { - throw createError(new IllegalArgumentException("For loop has no escape.")); - } - } - } else { - continuous = true; - } - - if (afterthought != null) { - afterthought.read = false; - afterthought.analyze(scriptRoot, locals); - - if (!afterthought.statement) { - throw createError(new IllegalArgumentException("Not a statement.")); - } - - afterthought.expected = afterthought.actual; - afterthought = afterthought.cast(scriptRoot, locals); - } - - if (block != null) { - block.beginLoop = true; - block.inLoop = true; - - block.analyze(scriptRoot, locals); - - if (block.loopEscape && !block.anyContinue) { - throw createError(new IllegalArgumentException("Extraneous for loop.")); - } - - if (continuous && !block.anyBreak) { - methodEscape = true; - allEscape = true; - } - - block.statementCount = Math.max(1, block.statementCount); - } - - statementCount = 1; - - if (locals.hasVariable(Locals.LOOP)) { - loopCounter = locals.getVariable(location, Locals.LOOP); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label start = new Label(); - Label begin = afterthought == null ? start : new Label(); - Label end = new Label(); - - if (initializer instanceof SDeclBlock) { - initializer.write(classWriter, methodWriter, globals); - } else if (initializer instanceof AExpression) { - AExpression initializer = (AExpression)this.initializer; - - initializer.write(classWriter, methodWriter, globals); - methodWriter.writePop(MethodWriter.getType(initializer.expected).getSize()); - } - - methodWriter.mark(start); - - if (condition != null && !continuous) { - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, end); - } - - boolean allEscape = false; - - if (block != null) { - allEscape = block.allEscape; - - int statementCount = Math.max(1, block.statementCount); - - if (afterthought != null) { - ++statementCount; - } - - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); - } - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - } else { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); - } - } - - if (afterthought != null) { - methodWriter.mark(begin); - afterthought.write(classWriter, methodWriter, globals); - methodWriter.writePop(MethodWriter.getType(afterthought.expected).getSize()); - } - - if (afterthought != null || !allEscape) { - methodWriter.goTo(start); - } - - methodWriter.mark(end); - } - - @Override - public String toString() { - return multilineToString(emptyList(), Arrays.asList(initializer, condition, afterthought, block)); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java deleted file mode 100644 index 75122903ef12f..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SFunction.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Locals.Parameter; -import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Opcodes; - -import java.lang.invoke.MethodType; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static java.util.Collections.emptyList; - -/** - * Represents a user-defined function. - */ -public final class SFunction extends AStatement { - - private final String rtnTypeStr; - public final String name; - private final List paramTypeStrs; - private final List paramNameStrs; - private final SBlock block; - public final boolean synthetic; - - private int maxLoopCounter; - - Class returnType; - List> typeParameters; - MethodType methodType; - - org.objectweb.asm.commons.Method method; - List parameters = new ArrayList<>(); - - private Variable loop = null; - - public SFunction(Location location, String rtnType, String name, - List paramTypes, List paramNames, SBlock block, - boolean synthetic) { - super(location); - - this.rtnTypeStr = Objects.requireNonNull(rtnType); - this.name = Objects.requireNonNull(name); - this.paramTypeStrs = Collections.unmodifiableList(paramTypes); - this.paramNameStrs = Collections.unmodifiableList(paramNames); - this.block = Objects.requireNonNull(block); - this.synthetic = synthetic; - } - - @Override - void extractVariables(Set variables) { - // we reset the list for function scope - // note this is not stored for this node - // but still required for lambdas - block.extractVariables(new HashSet<>()); - } - - void generateSignature(PainlessLookup painlessLookup) { - returnType = painlessLookup.canonicalTypeNameToType(rtnTypeStr); - - if (returnType == null) { - throw createError(new IllegalArgumentException("Illegal return type [" + rtnTypeStr + "] for function [" + name + "].")); - } - - if (paramTypeStrs.size() != paramNameStrs.size()) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - Class[] paramClasses = new Class[this.paramTypeStrs.size()]; - List> paramTypes = new ArrayList<>(); - - for (int param = 0; param < this.paramTypeStrs.size(); ++param) { - Class paramType = painlessLookup.canonicalTypeNameToType(this.paramTypeStrs.get(param)); - - if (paramType == null) { - throw createError(new IllegalArgumentException( - "Illegal parameter type [" + this.paramTypeStrs.get(param) + "] for function [" + name + "].")); - } - - paramClasses[param] = PainlessLookupUtility.typeToJavaType(paramType); - paramTypes.add(paramType); - parameters.add(new Parameter(location, paramNameStrs.get(param), paramType)); - } - - typeParameters = paramTypes; - methodType = MethodType.methodType(PainlessLookupUtility.typeToJavaType(returnType), paramClasses); - method = new org.objectweb.asm.commons.Method(name, MethodType.methodType( - PainlessLookupUtility.typeToJavaType(returnType), paramClasses).toMethodDescriptorString()); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - maxLoopCounter = scriptRoot.getCompilerSettings().getMaxLoopCounter(); - - if (block.statements.isEmpty()) { - throw createError(new IllegalArgumentException("Cannot generate an empty function [" + name + "].")); - } - - locals = Locals.newLocalScope(locals); - - block.lastSource = true; - block.analyze(scriptRoot, locals); - methodEscape = block.methodEscape; - - if (!methodEscape && returnType != void.class) { - throw createError(new IllegalArgumentException("Not all paths provide a return value for method [" + name + "].")); - } - - if (maxLoopCounter > 0) { - loop = locals.getVariable(null, Locals.LOOP); - } - } - - /** Writes the function to given ClassVisitor. */ - void write(ClassWriter classWriter, Globals globals) { - int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; - if (synthetic) { - access |= Opcodes.ACC_SYNTHETIC; - } - final MethodWriter methodWriter = classWriter.newMethodWriter(access, method); - methodWriter.visitCode(); - write(classWriter, methodWriter, globals); - methodWriter.endMethod(); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (maxLoopCounter > 0) { - // if there is infinite loop protection, we do this once: - // int #loop = settings.getMaxLoopCounter() - methodWriter.push(maxLoopCounter); - methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); - } - - block.write(classWriter, methodWriter, globals); - - if (!methodEscape) { - if (returnType == void.class) { - methodWriter.returnValue(); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - } - - @Override - public String toString() { - List description = new ArrayList<>(); - description.add(rtnTypeStr); - description.add(name); - if (false == (paramTypeStrs.isEmpty() && paramNameStrs.isEmpty())) { - description.add(joinWithName("Args", pairwiseToString(paramTypeStrs, paramNameStrs), emptyList())); - } - return multilineToString(description, block.statements); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java deleted file mode 100644 index 1f4350297dc3a..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIf.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents an if block. - */ -public final class SIf extends AStatement { - - AExpression condition; - final SBlock ifblock; - - public SIf(Location location, AExpression condition, SBlock ifblock) { - super(location); - - this.condition = Objects.requireNonNull(condition); - this.ifblock = ifblock; - } - - @Override - void extractVariables(Set variables) { - condition.extractVariables(variables); - - if (ifblock != null) { - ifblock.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - condition.expected = boolean.class; - condition.analyze(scriptRoot, locals); - condition = condition.cast(scriptRoot, locals); - - if (condition.constant != null) { - throw createError(new IllegalArgumentException("Extraneous if statement.")); - } - - if (ifblock == null) { - throw createError(new IllegalArgumentException("Extraneous if statement.")); - } - - ifblock.lastSource = lastSource; - ifblock.inLoop = inLoop; - ifblock.lastLoop = lastLoop; - - ifblock.analyze(scriptRoot, Locals.newLocalScope(locals)); - - anyContinue = ifblock.anyContinue; - anyBreak = ifblock.anyBreak; - statementCount = ifblock.statementCount; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label fals = new Label(); - - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - ifblock.continu = continu; - ifblock.brake = brake; - ifblock.write(classWriter, methodWriter, globals); - - methodWriter.mark(fals); - } - - @Override - public String toString() { - return singleLineToString(condition, ifblock); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java deleted file mode 100644 index 85c23977fa5a0..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SIfElse.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Arrays; -import java.util.Objects; -import java.util.Set; - -import static java.util.Collections.singleton; - -/** - * Represents an if/else block. - */ -public final class SIfElse extends AStatement { - - private AExpression condition; - private final SBlock ifblock; - private final SBlock elseblock; - - public SIfElse(Location location, AExpression condition, SBlock ifblock, SBlock elseblock) { - super(location); - - this.condition = Objects.requireNonNull(condition); - this.ifblock = ifblock; - this.elseblock = elseblock; - } - - @Override - void extractVariables(Set variables) { - condition.extractVariables(variables); - - if (ifblock != null) { - ifblock.extractVariables(variables); - } - - if (elseblock != null) { - elseblock.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - condition.expected = boolean.class; - condition.analyze(scriptRoot, locals); - condition = condition.cast(scriptRoot, locals); - - if (condition.constant != null) { - throw createError(new IllegalArgumentException("Extraneous if statement.")); - } - - if (ifblock == null) { - throw createError(new IllegalArgumentException("Extraneous if statement.")); - } - - ifblock.lastSource = lastSource; - ifblock.inLoop = inLoop; - ifblock.lastLoop = lastLoop; - - ifblock.analyze(scriptRoot, Locals.newLocalScope(locals)); - - anyContinue = ifblock.anyContinue; - anyBreak = ifblock.anyBreak; - statementCount = ifblock.statementCount; - - if (elseblock == null) { - throw createError(new IllegalArgumentException("Extraneous else statement.")); - } - - elseblock.lastSource = lastSource; - elseblock.inLoop = inLoop; - elseblock.lastLoop = lastLoop; - - elseblock.analyze(scriptRoot, Locals.newLocalScope(locals)); - - methodEscape = ifblock.methodEscape && elseblock.methodEscape; - loopEscape = ifblock.loopEscape && elseblock.loopEscape; - allEscape = ifblock.allEscape && elseblock.allEscape; - anyContinue |= elseblock.anyContinue; - anyBreak |= elseblock.anyBreak; - statementCount = Math.max(ifblock.statementCount, elseblock.statementCount); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label fals = new Label(); - Label end = new Label(); - - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - ifblock.continu = continu; - ifblock.brake = brake; - ifblock.write(classWriter, methodWriter, globals); - - if (!ifblock.allEscape) { - methodWriter.goTo(end); - } - - methodWriter.mark(fals); - - elseblock.continu = continu; - elseblock.brake = brake; - elseblock.write(classWriter, methodWriter, globals); - - methodWriter.mark(end); - } - - @Override - public String toString() { - return multilineToString(singleton(condition), Arrays.asList(ifblock, elseblock)); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java deleted file mode 100644 index cfc1dd1e6da9b..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SReturn.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; - -import java.util.Set; - -/** - * Represents a return statement. - */ -public final class SReturn extends AStatement { - - private AExpression expression; - - public SReturn(Location location, AExpression expression) { - super(location); - - this.expression = expression; - } - - @Override - void extractVariables(Set variables) { - if (expression != null) { - expression.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (expression == null) { - if (locals.getReturnType() != void.class) { - throw location.createError(new ClassCastException("Cannot cast from " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(locals.getReturnType()) + "] to " + - "[" + PainlessLookupUtility.typeToCanonicalTypeName(void.class) + "].")); - } - } else { - expression.expected = locals.getReturnType(); - expression.internal = true; - expression.analyze(scriptRoot, locals); - expression = expression.cast(scriptRoot, locals); - } - - methodEscape = true; - loopEscape = true; - allEscape = true; - - statementCount = 1; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - if (expression != null) { - expression.write(classWriter, methodWriter, globals); - } - - methodWriter.returnValue(); - } - - @Override - public String toString() { - return expression == null ? singleLineToString() : singleLineToString(expression); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java index b6b97503555b1..05715fedcd538 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.painless.node; +package org.elasticsearch.painless.ir; import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.ClassWriter; @@ -28,6 +28,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.ir.LoopNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -47,10 +48,8 @@ /** * Represents a for-each loop for iterables. */ -final class SSubEachIterable extends AStatement { +final class ForEachSubIterableNode extends LoopNode { - private AExpression expression; - private final SBlock block; private final Variable variable; private PainlessCast cast = null; @@ -66,32 +65,7 @@ final class SSubEachIterable extends AStatement { } @Override - void extractVariables(Set variables) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - @Override - void analyze(ScriptRoot scriptRoot, 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, Iterator.class, "#itr" + location.getOffset(), true); - - if (expression.actual == def.class) { - method = null; - } else { - method = scriptRoot.getPainlessLookup().lookupPainlessMethod(expression.actual, false, "iterator", 0); - - if (method == null) { - throw createError(new IllegalArgumentException( - "method [" + typeToCanonicalTypeName(expression.actual) + ", iterator/0] not found")); - } - } - - cast = AnalyzerCaster.getLegalCast(location, def.class, variable.clazz, true, true); - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); expression.write(classWriter, methodWriter, globals); @@ -131,9 +105,4 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) methodWriter.goTo(begin); methodWriter.mark(end); } - - @Override - public String toString() { - return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(variable.clazz), variable.name, expression, block); - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java new file mode 100644 index 0000000000000..e5825e64d968e --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java @@ -0,0 +1,71 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class StatementExpressionNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected ExpressionNode expressionNode; + + public StatementExpressionNode setExpressionNode(ExpressionNode expressionNode) { + this.expressionNode = expressionNode; + return this; + } + + public ExpressionNode getExpressionNode() { + return expressionNode; + } + + /* ---- end tree structure, begin node data ---- */ + + protected boolean methodEscape; + + public StatementExpressionNode setMethodEscape(boolean methodEscape) { + this.methodEscape = methodEscape; + return this; + } + + public boolean getMethodEscape() { + return methodEscape; + } + + /* ---- end node data ---- */ + + public StatementExpressionNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + expressionNode.write(classWriter, methodWriter, globals); + + if (methodEscape) { + methodWriter.returnValue(); + } else { + methodWriter.writePop(MethodWriter.getType(expressionNode.getType()).getSize()); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java index 6f33799be7d14..cda9353b7dd10 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java @@ -21,8 +21,12 @@ import org.objectweb.asm.Label; -public abstract class StatementNode implements IRNode { +public abstract class StatementNode extends IRNode { protected Label continueLabel = null; protected Label breakLabel = null; + + public StatementNode() { + // do nothing + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java index 4ab36c97c36dd..d688541bf0f78 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java @@ -21,12 +21,15 @@ import org.elasticsearch.painless.lookup.PainlessLookupUtility; -public class TypeNode implements IRNode { +public class TypeNode extends IRNode { - protected final Class type; + /* ---- begin node data ---- */ - public TypeNode(Class type) { + protected Class type; + + public TypeNode setType(Class type) { this.type = type; + return this; } public Class getType() { @@ -36,4 +39,10 @@ public Class getType() { public String getCanonicalTypeName() { return PainlessLookupUtility.typeToCanonicalTypeName(type); } + + /* ---- end node data ---- */ + + public TypeNode() { + // do nothing + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index b0ad7a1a10112..c495ff0360362 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -62,7 +62,7 @@ void extractVariables(Set variables) { @Override void analyze(ScriptRoot scriptRoot, Locals locals) { if (!read) { - throw createError(new IllegalArgumentException("Must read from list initializer.")); + throw createError(new IllegalArgumentException("Must read from list initializerNode.")); } actual = ArrayList.class; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index 6b2c1861bf39d..d57059269c0da 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -68,7 +68,7 @@ void extractVariables(Set variables) { @Override void analyze(ScriptRoot scriptRoot, Locals locals) { if (!read) { - throw createError(new IllegalArgumentException("Must read from map initializer.")); + throw createError(new IllegalArgumentException("Must read from map initializerNode.")); } actual = HashMap.class; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java index 7145a4a9e33ad..2e45e2dfc356e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java @@ -292,7 +292,7 @@ public Map write() { if (false == globals.getConstantInitializers().isEmpty()) { Collection inits = globals.getConstantInitializers().values(); - // Initialize the constants in a static initializer + // Initialize the constants in a static initializerNode final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC, WriterConstants.CLINIT, classVisitor, globals.getStatements(), settings); clinit.visitCode(); From 58f8e6ddb64ee74a404c8ef9ea1f7fb841973622 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 19 Dec 2019 13:23:56 -0800 Subject: [PATCH 11/24] completeion of first pass of splitting nodes --- .../ir/{SClass.java => ClassNode.java} | 352 +++++++++++++++--- .../elasticsearch/painless/ir/FieldNode.java | 10 + ...rable.java => ForEachSubIterableNode.java} | 73 ++-- .../elasticsearch/painless/ir/LambdaNode.java | 28 +- .../org/elasticsearch/painless/ir/SThrow.java | 73 ---- .../org/elasticsearch/painless/ir/STry.java | 136 ------- .../org/elasticsearch/painless/ir/SWhile.java | 143 ------- .../elasticsearch/painless/ir/StaticNode.java | 3 +- .../elasticsearch/painless/ir/ThrowNode.java | 53 +++ .../elasticsearch/painless/ir/TryNode.java | 120 ++++++ .../painless/ir/UnaryMathNode.java | 44 ++- .../elasticsearch/painless/ir/UnaryNode.java | 12 +- .../painless/ir/UnboundCallNode.java | 79 +++- .../painless/ir/VariableNode.java | 31 +- .../elasticsearch/painless/ir/WhileNode.java | 68 ++++ .../painless/ir/package-info.java | 158 -------- 16 files changed, 733 insertions(+), 650 deletions(-) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{SClass.java => ClassNode.java} (64%) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{SSubEachIterable.java => ForEachSubIterableNode.java} (70%) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java similarity index 64% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index 05f2347a7bd62..21356a701106c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -20,7 +20,6 @@ package org.elasticsearch.painless.ir; import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -40,12 +39,10 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import static org.elasticsearch.painless.WriterConstants.BASE_INTERFACE_TYPE; @@ -71,42 +68,284 @@ import static org.elasticsearch.painless.WriterConstants.STACK_OVERFLOW_ERROR_TYPE; import static org.elasticsearch.painless.WriterConstants.STRING_TYPE; -/** - * The root of all Painless trees. Contains a series of statements. - */ -public final class ClassNode implements IRNode { - - private final ScriptClassInfo scriptClassInfo; - private final String name; - private final Printer debugStream; - private final List functions = new ArrayList<>(); - private final List fields = new ArrayList<>(); - private final List statements = new ArrayList<>(); - private final Globals globals; - - private CompilerSettings settings; - - private ScriptRoot table; - private Locals mainMethod; - private final Set extractedVariables; - private final List getMethods; - private byte[] bytes; - - public SClass(ScriptClassInfo scriptClassInfo, String name, String sourceText, Printer debugStream, - Location location) { - super(location); - this.scriptClassInfo = Objects.requireNonNull(scriptClassInfo); - this.name = Objects.requireNonNull(name); +public class ClassNode extends IRNode { + + /* ---- begin tree structure ---- */ + + protected final List fieldNodes = new ArrayList<>(); + protected final List functionNodes = new ArrayList<>(); + protected final List statementNodes = new ArrayList<>(); + + public ClassNode addFieldNode(FieldNode fieldNode) { + fieldNodes.add(fieldNode); + return this; + } + + public ClassNode setFieldNode(int index, FieldNode fieldNode) { + fieldNodes.set(index, fieldNode); + return this; + } + + public FieldNode getFieldNode(int index) { + return fieldNodes.get(index); + } + + public ClassNode removeFieldNode(FieldNode fieldNode) { + fieldNodes.remove(fieldNode); + return this; + } + + public ClassNode removeFieldNode(int index) { + fieldNodes.remove(index); + return this; + } + + public int getFieldsSize() { + return fieldNodes.size(); + } + + public List getFieldsNodes() { + return fieldNodes; + } + + public ClassNode clearFieldNodes() { + fieldNodes.clear(); + return this; + } + + public ClassNode addFunctionNode(FunctionNode functionNode) { + functionNodes.add(functionNode); + return this; + } + + public ClassNode setFunctionNode(int index, FunctionNode functionNode) { + functionNodes.set(index, functionNode); + return this; + } + + public FunctionNode getFunctionNode(int index) { + return functionNodes.get(index); + } + + public ClassNode removeFunctionNode(FunctionNode functionNode) { + functionNodes.remove(functionNode); + return this; + } + + public ClassNode removeFunctionNode(int index) { + functionNodes.remove(index); + return this; + } + + public int getFunctionsSize() { + return functionNodes.size(); + } + + public List getFunctionsNodes() { + return functionNodes; + } + + public ClassNode clearFunctionNodes() { + functionNodes.clear(); + return this; + } + + public ClassNode addStatementNode(StatementNode statementNode) { + statementNodes.add(statementNode); + return this; + } + + public ClassNode setStatementNode(int index, StatementNode statementNode) { + statementNodes.set(index, statementNode); + return this; + } + + public StatementNode getStatementNode(int index) { + return statementNodes.get(index); + } + + public ClassNode removeStatementNode(StatementNode statementNode) { + statementNodes.remove(statementNode); + return this; + } + + public ClassNode removeStatementNode(int index) { + statementNodes.remove(index); + return this; + } + + public int getStatementsSize() { + return statementNodes.size(); + } + + public List getStatementsNodes() { + return statementNodes; + } + + public ClassNode clearStatementNodes() { + statementNodes.clear(); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + protected ScriptClassInfo scriptClassInfo; + protected String name; + protected String sourceText; + protected Printer debugStream; + protected ScriptRoot scriptRoot; + protected Locals mainMethod; + protected boolean doesMethodEscape; + protected final Set extractedVariables = new HashSet<>(); + protected final List getMethods = new ArrayList<>(); + + public ClassNode setScriptClassInfo(ScriptClassInfo scriptClassInfo) { + this.scriptClassInfo = scriptClassInfo; + return this; + } + + public ScriptClassInfo getScriptClassInfo() { + return scriptClassInfo; + } + + public ClassNode setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + public ClassNode setSourceText(String sourceText) { + this.sourceText = sourceText; + return this; + } + + public String getSourceText() { + return sourceText; + } + + public ClassNode setDebugStream(Printer debugStream) { this.debugStream = debugStream; - this.functions.addAll(Objects.requireNonNull(functions)); - this.statements = Collections.unmodifiableList(statements); - this.globals = new Globals(new BitSet(sourceText.length())); + return this; + } - this.extractedVariables = new HashSet<>(); - this.getMethods = new ArrayList<>(); + public Printer getDebugStream() { + return debugStream; + } + + public ClassNode setScriptRoot(ScriptRoot scriptRoot) { + this.scriptRoot = scriptRoot; + return this; + } + + public ScriptRoot getScriptRoot() { + return scriptRoot; + } + + public ClassNode setMainMethod(Locals mainMethod) { + this.mainMethod = mainMethod; + return this; + } + + public Locals getMainMethod() { + return mainMethod; + } + + public ClassNode setMethodEscape(boolean doesMethodEscape) { + this.doesMethodEscape = doesMethodEscape; + return this; + } + + public boolean doesMethodEscape() { + return doesMethodEscape; + } + + public ClassNode addExtractedVariable(String extractedVariable) { + extractedVariables.add(extractedVariable); + return this; + } + + public boolean containsExtractedVariable(String extractedVariable) { + return extractedVariables.contains(extractedVariable); + } + + public ClassNode removeExtractedVariable(String extractedVariable) { + extractedVariables.remove(extractedVariable); + return this; + } + + public int getExtractedVariablesSize() { + return extractedVariables.size(); + } + + public Set getExtractedVariables() { + return extractedVariables; + } + + public ClassNode clearExtractedVariables() { + extractedVariables.clear(); + return this; + } + + public ClassNode addGetMethod(org.objectweb.asm.commons.Method getMethod) { + getMethods.add(getMethod); + return this; + } + + public ClassNode setGetMethod(int index, org.objectweb.asm.commons.Method getMethod) { + getMethods.set(index, getMethod); + return this; + } + + public org.objectweb.asm.commons.Method getGetMethod(int index) { + return getMethods.get(index); + } + + public ClassNode removeGetMethod(org.objectweb.asm.commons.Method getMethod) { + getMethods.remove(getMethod); + return this; + } + + public ClassNode removeGetMethod(int index) { + getMethods.remove(index); + return this; + } + + public int getGetMethodsSize() { + return getMethods.size(); + } + + public List getGetMethods() { + return getMethods; + } + + public ClassNode clearGetMethods() { + getMethods.clear(); + return this; + } + + /* ---- end node data ---- */ + + protected Globals globals; + protected byte[] bytes; + + public ClassNode() { + // do nothing + } + + public BitSet getStatements() { + return globals.getStatements(); + } + + public byte[] getBytes() { + return bytes; } public Map write() { + this.globals = new Globals(new BitSet(sourceText.length())); + // Create the ClassWriter. int classFrames = org.objectweb.asm.ClassWriter.COMPUTE_FRAMES | org.objectweb.asm.ClassWriter.COMPUTE_MAXS; @@ -115,7 +354,7 @@ public Map write() { String className = CLASS_TYPE.getInternalName(); String[] classInterfaces = new String[] { interfaceBase }; - ClassWriter classWriter = new ClassWriter(settings, globals.getStatements(), debugStream, + ClassWriter classWriter = new ClassWriter(scriptRoot.getCompilerSettings(), globals.getStatements(), debugStream, scriptClassInfo.getBaseClass(), classFrames, classAccess, className, classInterfaces); ClassVisitor classVisitor = classWriter.getClassVisitor(); classVisitor.visitSource(Location.computeSourceName(name), null); @@ -186,14 +425,14 @@ public Map write() { write(classWriter, executeMethod, globals); executeMethod.endMethod(); - // Write all functions: - for (SFunction function : functions) { - function.write(classWriter, globals); + // Write all fields: + for (FieldNode fieldNode : fieldNodes) { + fieldNode.write(classWriter, null, null); } - // Write all fields: - for (SField field : fields) { - field.write(classWriter); + // Write all functions: + for (FunctionNode functionNode : functionNodes) { + functionNode.write(classWriter, null, globals); } // Write the constants @@ -202,7 +441,7 @@ public Map write() { // Initialize the constants in a static initializerNode final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC, - WriterConstants.CLINIT, classVisitor, globals.getStatements(), settings); + WriterConstants.CLINIT, classVisitor, globals.getStatements(), scriptRoot.getCompilerSettings()); clinit.visitCode(); for (Constant constant : inits) { constant.initializer.accept(clinit); @@ -230,11 +469,11 @@ public Map write() { bytes = classWriter.getClassBytes(); Map statics = new HashMap<>(); - statics.put("$FUNCTIONS", table.getFunctionTable()); + statics.put("$FUNCTIONS", scriptRoot.getFunctionTable()); - for (SField field : fields) { - if (field.getInstance() != null) { - statics.put(field.getName(), field.getInstance()); + for (FieldNode fieldNode : fieldNodes) { + if (fieldNode.getInstance() != null) { + statics.put(fieldNode.getName(), fieldNode.getInstance()); } } @@ -242,7 +481,7 @@ public Map write() { } @Override - void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { // We wrap the whole method in a few try/catches to handle and/or convert other exceptions to ScriptException Label startTry = new Label(); Label endTry = new Label(); @@ -251,13 +490,13 @@ void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter meth Label endCatch = new Label(); methodWriter.mark(startTry); - if (settings.getMaxLoopCounter() > 0) { + if (scriptRoot.getCompilerSettings().getMaxLoopCounter() > 0) { // if there is infinite loop protection, we do this once: // int #loop = settings.getMaxLoopCounter() Variable loop = mainMethod.getVariable(null, Locals.LOOP); - methodWriter.push(settings.getMaxLoopCounter()); + methodWriter.push(scriptRoot.getCompilerSettings().getMaxLoopCounter()); methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); } @@ -271,10 +510,11 @@ void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter meth methodWriter.visitVarInsn(method.getReturnType().getOpcode(Opcodes.ISTORE), variable.getSlot()); } - for (AStatement statement : statements) { - statement.write(classWriter, methodWriter, globals); + for (StatementNode statementNode : statementNodes) { + statementNode.write(classWriter, methodWriter, globals); } - if (!methodEscape) { + + if (doesMethodEscape == false) { switch (scriptClassInfo.getExecuteMethod().getReturnType().getSort()) { case org.objectweb.asm.Type.VOID: break; @@ -338,12 +578,4 @@ void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter meth methodWriter.throwException(); methodWriter.mark(endCatch); } - - public BitSet getStatements() { - return globals.getStatements(); - } - - public byte[] getBytes() { - return bytes; - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java index 0c511206b1470..59e9de06b6d06 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -50,6 +50,7 @@ public String getCanonicalTypeName() { protected int modifiers; protected String name; + protected Object instance; public FieldNode setModifiers(int modifiers) { this.modifiers = modifiers; @@ -69,6 +70,15 @@ public String getName() { return name; } + public FieldNode setInstance(Object instance) { + this.instance = instance; + return this; + } + + public Object getInstance() { + return instance; + } + /* ---- end node data ---- */ public FieldNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java similarity index 70% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java index 05715fedcd538..4891675031ae4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java @@ -19,56 +19,81 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.elasticsearch.painless.ir.LoopNode; import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import java.util.Iterator; -import java.util.Objects; -import java.util.Set; import static org.elasticsearch.painless.WriterConstants.ITERATOR_HASNEXT; import static org.elasticsearch.painless.WriterConstants.ITERATOR_NEXT; import static org.elasticsearch.painless.WriterConstants.ITERATOR_TYPE; -import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; /** * Represents a for-each loop for iterables. */ final class ForEachSubIterableNode extends LoopNode { - private final Variable variable; + /* ---- begin node data ---- */ - private PainlessCast cast = null; - private Variable iterator = null; - private PainlessMethod method = null; + protected Variable variable; + protected PainlessCast cast; + protected Variable iterator; + protected PainlessMethod method; - SSubEachIterable(Location location, Variable variable, AExpression expression, SBlock block) { - super(location); + public ForEachSubIterableNode setVariable(Variable variable) { + this.variable = variable; + return this; + } + + public Variable getVariable() { + return this.variable; + } + + public ForEachSubIterableNode setCast(PainlessCast cast) { + this.cast = cast; + return this; + } + + public PainlessCast getCast() { + return cast; + } + + public ForEachSubIterableNode setIterator(Variable iterator) { + this.iterator = iterator; + return this; + } + + public Variable getIterator() { + return this.iterator; + } + + public ForEachSubIterableNode setMethod(PainlessMethod method) { + this.method = method; + return this; + } + + public PainlessMethod getMethod() { + return method; + } + + /* ---- end node data ---- */ - this.variable = Objects.requireNonNull(variable); - this.expression = Objects.requireNonNull(expression); - this.block = block; + public ForEachSubIterableNode() { + // do nothing } @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); - expression.write(classWriter, methodWriter, globals); + conditionNode.write(classWriter, methodWriter, globals); if (method == null) { org.objectweb.asm.Type methodType = org.objectweb.asm.Type @@ -95,12 +120,12 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + methodWriter.writeLoopCounter(loopCounter.getSlot(), blockNode.getStatementCount(), location); } - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); + blockNode.continueLabel = begin; + blockNode.breakLabel = end; + blockNode.write(classWriter, methodWriter, globals); methodWriter.goTo(begin); methodWriter.mark(end); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index 2228bb50cc0ef..6f904b62e4001 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -35,35 +35,26 @@ public class LambdaNode extends ExpressionNode { protected List captures; protected FunctionRef funcRef; - public LambdaNode setFuncRef(FunctionRef funcRef) { - this.funcRef = funcRef; - return this; - } - - public FunctionRef getFuncRef() { - return funcRef; - } - - public LambdaNode addCaptureNode(Variable capture) { + public LambdaNode addCapture(Variable capture) { captures.add(capture); return this; } - public LambdaNode setCaptureNode(int index, Variable capture) { + public LambdaNode setCapture(int index, Variable capture) { captures.set(index, capture); return this; } - public Variable getCaptureNode(int index) { + public Variable getCapture(int index) { return captures.get(index); } - public LambdaNode removeCaptureNode(Variable capture) { + public LambdaNode removeCapture(Variable capture) { captures.remove(capture); return this; } - public LambdaNode removeCaptureNode(int index) { + public LambdaNode removeCapture(int index) { captures.remove(index); return this; } @@ -80,6 +71,15 @@ public LambdaNode clearCaptures() { captures.clear(); return this; } + + public LambdaNode setFuncRef(FunctionRef funcRef) { + this.funcRef = funcRef; + return this; + } + + public FunctionRef getFuncRef() { + return funcRef; + } /* ---- end node data ---- */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java deleted file mode 100644 index a8309c7f7f8a7..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SThrow.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a throw statement. - */ -public final class SThrow extends AStatement { - - private AExpression expression; - - public SThrow(Location location, AExpression expression) { - super(location); - - this.expression = Objects.requireNonNull(expression); - } - - @Override - void extractVariables(Set variables) { - expression.extractVariables(variables); - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - expression.expected = Exception.class; - expression.analyze(scriptRoot, locals); - expression = expression.cast(scriptRoot, locals); - - methodEscape = true; - loopEscape = true; - allEscape = true; - statementCount = 1; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - expression.write(classWriter, methodWriter, globals); - methodWriter.throwException(); - } - - @Override - public String toString() { - return singleLineToString(expression); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java deleted file mode 100644 index 67b038158cbc1..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/STry.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; - -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static java.util.Collections.singleton; - -/** - * Represents the try block as part of a try-catch block. - */ -public final class STry extends AStatement { - - private final SBlock block; - private final List catches; - - public STry(Location location, SBlock block, List catches) { - super(location); - - this.block = block; - this.catches = Collections.unmodifiableList(catches); - } - - @Override - void extractVariables(Set variables) { - if (block != null) { - block.extractVariables(variables); - } - for (SCatch expr : catches) { - expr.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - if (block == null) { - throw createError(new IllegalArgumentException("Extraneous try statement.")); - } - - block.lastSource = lastSource; - block.inLoop = inLoop; - block.lastLoop = lastLoop; - - block.analyze(scriptRoot, Locals.newLocalScope(locals)); - - methodEscape = block.methodEscape; - loopEscape = block.loopEscape; - allEscape = block.allEscape; - anyContinue = block.anyContinue; - anyBreak = block.anyBreak; - - int statementCount = 0; - - for (SCatch catc : catches) { - catc.lastSource = lastSource; - catc.inLoop = inLoop; - catc.lastLoop = lastLoop; - - catc.analyze(scriptRoot, Locals.newLocalScope(locals)); - - methodEscape &= catc.methodEscape; - loopEscape &= catc.loopEscape; - allEscape &= catc.allEscape; - anyContinue |= catc.anyContinue; - anyBreak |= catc.anyBreak; - - statementCount = Math.max(statementCount, catc.statementCount); - } - - this.statementCount = block.statementCount + statementCount; - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label begin = new Label(); - Label end = new Label(); - Label exception = new Label(); - - methodWriter.mark(begin); - - block.continu = continu; - block.brake = brake; - block.write(classWriter, methodWriter, globals); - - if (!block.allEscape) { - methodWriter.goTo(exception); - } - - methodWriter.mark(end); - - for (SCatch catc : catches) { - catc.begin = begin; - catc.end = end; - catc.exception = catches.size() > 1 ? exception : null; - catc.write(classWriter, methodWriter, globals); - } - - if (!block.allEscape || catches.size() > 1) { - methodWriter.mark(exception); - } - } - - @Override - public String toString() { - return multilineToString(singleton(block), catches); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java deleted file mode 100644 index ab1f29fad4a5d..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/SWhile.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.node; - -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; - -import java.util.Objects; -import java.util.Set; - -/** - * Represents a while loop. - */ -public final class SWhile extends AStatement { - - private AExpression condition; - private final SBlock block; - - private boolean continuous = false; - - public SWhile(Location location, AExpression condition, SBlock block) { - super(location); - - this.condition = Objects.requireNonNull(condition); - this.block = block; - } - - @Override - void extractVariables(Set variables) { - condition.extractVariables(variables); - if (block != null) { - block.extractVariables(variables); - } - } - - @Override - void analyze(ScriptRoot scriptRoot, Locals locals) { - locals = Locals.newLocalScope(locals); - - condition.expected = boolean.class; - condition.analyze(scriptRoot, locals); - condition = condition.cast(scriptRoot, locals); - - if (condition.constant != null) { - continuous = (boolean)condition.constant; - - if (!continuous) { - throw createError(new IllegalArgumentException("Extraneous while loop.")); - } - - if (block == null) { - throw createError(new IllegalArgumentException("While loop has no escape.")); - } - } - - if (block != null) { - block.beginLoop = true; - block.inLoop = true; - - block.analyze(scriptRoot, locals); - - if (block.loopEscape && !block.anyContinue) { - throw createError(new IllegalArgumentException("Extraneous while loop.")); - } - - if (continuous && !block.anyBreak) { - methodEscape = true; - allEscape = true; - } - - block.statementCount = Math.max(1, block.statementCount); - } - - statementCount = 1; - - if (locals.hasVariable(Locals.LOOP)) { - loopCounter = locals.getVariable(location, Locals.LOOP); - } - } - - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label begin = new Label(); - Label end = new Label(); - - methodWriter.mark(begin); - - if (!continuous) { - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, end); - } - - if (block != null) { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, block.statementCount), location); - } - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - } else { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); - } - } - - if (block == null || !block.allEscape) { - methodWriter.goTo(begin); - } - - methodWriter.mark(end); - } - - @Override - public String toString() { - return singleLineToString(condition, block); - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java index 51ca53680312e..631406a11307e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java @@ -26,10 +26,11 @@ public class StaticNode extends ExpressionNode { public StaticNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { // do nothing } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java new file mode 100644 index 0000000000000..89c19193bb195 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; + +public class ThrowNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected ExpressionNode expressionNode; + + public ThrowNode setExpressionNode(ExpressionNode expressionNode) { + this.expressionNode = expressionNode; + return this; + } + + public ExpressionNode getExpressionNode() { + return expressionNode; + } + + /* ---- end tree structure, begin node data ---- */ + + public ThrowNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + expressionNode.write(classWriter, methodWriter, globals); + methodWriter.throwException(); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java new file mode 100644 index 0000000000000..af916ae8a1e63 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; + +import java.util.ArrayList; +import java.util.List; + +public class TryNode extends StatementNode { + + /* ---- begin tree structure ---- */ + + protected BlockNode blockNode; + protected List catchNodes = new ArrayList<>(); + + public TryNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } + + public BlockNode getBlockNode() { + return blockNode; + } + + public TryNode addCatchNode(CatchNode catchNode) { + catchNodes.add(catchNode); + return this; + } + + public TryNode setCatchNode(int index, CatchNode catchNode) { + catchNodes.set(index, catchNode); + return this; + } + + public CatchNode getCatchNode(int index) { + return catchNodes.get(index); + } + + public TryNode removeCatchNode(CatchNode catchNode) { + catchNodes.remove(catchNode); + return this; + } + + public TryNode removeCatchNode(int index) { + catchNodes.remove(index); + return this; + } + + public int getCatchsSize() { + return catchNodes.size(); + } + + public List getCatchsNodes() { + return catchNodes; + } + + public TryNode clearCatchNodes() { + catchNodes.clear(); + return this; + } + + /* ---- end tree structure ---- */ + + public TryNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label begin = new Label(); + Label end = new Label(); + Label exception = new Label(); + + methodWriter.mark(begin); + + blockNode.continueLabel = continueLabel; + blockNode.breakLabel = breakLabel; + blockNode.write(classWriter, methodWriter, globals); + + if (blockNode.doAllEscape() == false) { + methodWriter.goTo(exception); + } + + methodWriter.mark(end); + + for (CatchNode catchNode : catchNodes) { + catchNode.begin = begin; + catchNode.end = end; + catchNode.exception = catchNodes.size() > 1 ? exception : null; + catchNode.write(classWriter, methodWriter, globals); + } + + if (blockNode.doAllEscape() == false || catchNodes.size() > 1) { + methodWriter.mark(exception); + } + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index 03c3ff7996061..8d98dc6a2f478 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.def; @@ -30,18 +29,45 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -import java.util.Objects; - public class UnaryMathNode extends UnaryNode { - protected final Location location; - protected final Operation operation; - protected final boolean originallyExplicit; // record whether there was originally an explicit cast + /* ---- begin node data ---- */ + + protected Operation operation; + protected boolean cat; + protected boolean originallyExplicit; // record whether there was originally an explicit cast + + public UnaryMathNode setOperation(Operation operation) { + this.operation = operation; + return this; + } + + public Operation getOperation() { + return operation; + } + + public UnaryMathNode setCat(boolean cat) { + this.cat = cat; + return this; + } - public UnaryMathNode(Location location, Operation operation, boolean originallyExplicit) { - this.location = Objects.requireNonNull(location); - this.operation = Objects.requireNonNull(operation); + public boolean getCat() { + return cat; + } + + public UnaryMathNode setOriginallExplicit(boolean originallyExplicit) { this.originallyExplicit = originallyExplicit; + return this; + } + + public boolean getOriginallyExplicit() { + return originallyExplicit; + } + + /* ---- end node data ---- */ + + public UnaryMathNode() { + // do nothing } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java index ee5c7a67462ec..22abb8f6fa1e4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java @@ -21,11 +21,9 @@ public abstract class UnaryNode extends ExpressionNode { - protected ExpressionNode childNode; + /* ---- begin tree structure ---- */ - public UnaryNode() { - // do nothing - } + protected ExpressionNode childNode; public void setChildNode(ExpressionNode childNode) { this.childNode = childNode; @@ -34,4 +32,10 @@ public void setChildNode(ExpressionNode childNode) { public ExpressionNode getChildNode() { return childNode; } + + /* ---- end tree structure ---- */ + + public UnaryNode() { + // do nothing + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java index 7c87436fc8c7c..650dfa43688cd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -37,30 +37,73 @@ public class UnboundCallNode extends ArgumentsNode { - protected final Location location; - protected final LocalFunction localFunction; - protected final PainlessMethod importedMethod; - protected final PainlessClassBinding classBinding; - protected final int classBindingOffset; - protected final PainlessInstanceBinding instanceBinding; - protected final String bindingName; - - public UnboundCallNode( - Location location, - LocalFunction localFunction, - PainlessMethod importedMethod, - PainlessClassBinding classBinding, - int classBindingOffset, - PainlessInstanceBinding instanceBinding, - String bindingName - ) { - this.location = Objects.requireNonNull(location); + /* ---- begin node data ---- */ + + protected LocalFunction localFunction; + protected PainlessMethod importedMethod; + protected PainlessClassBinding classBinding; + protected int classBindingOffset; + protected PainlessInstanceBinding instanceBinding; + protected String bindingName; + + public UnboundCallNode setLocalFunction(LocalFunction localFunction) { this.localFunction = localFunction; + return this; + } + + public LocalFunction getLocalFunction() { + return localFunction; + } + + public UnboundCallNode setImportedMethod(PainlessMethod importedMethod) { this.importedMethod = importedMethod; + return this; + } + + public PainlessMethod getImportedMethod() { + return importedMethod; + } + + public UnboundCallNode setClassBinding(PainlessClassBinding classBinding) { this.classBinding = classBinding; + return this; + } + + public PainlessClassBinding getClassBinding() { + return classBinding; + } + + public UnboundCallNode setClassBindingOffset(int classBindingOffset) { this.classBindingOffset = classBindingOffset; + return this; + } + + public int getClassBindingOffset() { + return classBindingOffset; + } + + public UnboundCallNode setInstanceBinding(PainlessInstanceBinding instanceBinding) { this.instanceBinding = instanceBinding; + return this; + } + + public PainlessInstanceBinding getInstanceBinding() { + return instanceBinding; + } + + public UnboundCallNode setBindingName(String bindingName) { this.bindingName = bindingName; + return this; + } + + public String getBindingName() { + return bindingName; + } + + /* ---- end node data ---- */ + + public UnboundCallNode() { + // do nothing } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java index 04fde14823d24..dd2b30ed5936d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java @@ -25,38 +25,49 @@ import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; -import java.util.Objects; +public class VariableNode extends ExpressionNode { -public class VariableNode implements IRNode { + /* ---- begin node data ---- */ - protected final Variable variable; + protected Variable variable; - public VariableNode(Variable variable) { - this.variable = Objects.requireNonNull(variable); + public VariableNode setVariable(Variable variable) { + this.variable = variable; + return this; + } + + public Variable getVariable() { + return variable; + } + + /* ---- end node data ---- */ + + public VariableNode() { + // do nothing } @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); } @Override - public int accessElementCount() { + protected int accessElementCount() { return 0; } @Override - public void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { // do nothing } @Override - public void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); } @Override - public void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java new file mode 100644 index 0000000000000..67ce56a314e85 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.ir; + +import org.elasticsearch.painless.ClassWriter; +import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; + +public class WhileNode extends LoopNode { + + public WhileNode() { + // do nothing + } + + @Override + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + methodWriter.writeStatementOffset(location); + + Label begin = new Label(); + Label end = new Label(); + + methodWriter.mark(begin); + + if (isContinuous == false) { + conditionNode.write(classWriter, methodWriter, globals); + methodWriter.ifZCmp(Opcodes.IFEQ, end); + } + + if (blockNode != null) { + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, blockNode.getStatementCount()), location); + } + + blockNode.continueLabel = begin; + blockNode.breakLabel = end; + blockNode.write(classWriter, methodWriter, globals); + } else { + if (loopCounter != null) { + methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); + } + } + + if (blockNode == null || blockNode.doAllEscape() == false) { + methodWriter.goTo(begin); + } + + methodWriter.mark(end); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java deleted file mode 100644 index 266968b39cd1d..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/package-info.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * A painless tree is composed of the node classes found in this package. - *

- * The following are the types of nodes: - * A* (abstract) - These are the abstract nodes that are the superclasses for the other types. - * I* (interface) - These are marker interfaces to denote a property of the node. - * S* (statement) - These are nodes that represent a statement in Painless. - * E* (expression) - These are nodes that represent an expression in Painless. - * P* (postfix) - These are nodes that represent a postfix of a variable chain. - * E/P* (storeable) - These are nodes that are allowed to store a value to memory. - * *Sub* (sub) - These are partial nodes with a parent (S/E/P)* node used to split up logic into smaller pieces. - *

- * The following is a brief description of each node: - * {@link org.elasticsearch.painless.node.AExpression} - The superclass for all E* (expression) and P* (postfix) nodes. - * {@link org.elasticsearch.painless.node.ANode} - The superclass for all nodes. - * {@link org.elasticsearch.painless.node.AStatement} - The superclass for all S* (statement) nodes. - * {@link org.elasticsearch.painless.node.AStoreable} - The super class for an expression that can store a value in local memory. - * {@link org.elasticsearch.painless.node.EAssignment} - Represents an assignment with the lhs and rhs as child nodes. - * {@link org.elasticsearch.painless.node.EBinary} - Represents a binary math expression. - * {@link org.elasticsearch.painless.node.EBool} - Represents a boolean expression. - * {@link org.elasticsearch.painless.node.EBoolean} - Represents a boolean constant. - * {@link org.elasticsearch.painless.node.ECallLocal} - Represents a user-defined call. - * {@link org.elasticsearch.painless.node.ECapturingFunctionRef} - Represents a function reference (capturing). - * {@link org.elasticsearch.painless.node.ECast} - Represents a cast inserted into the tree replacing others. (Internal only.) - * {@link org.elasticsearch.painless.node.EComp} - Represents a comparison expression. - * {@link org.elasticsearch.painless.node.EConditional} - Represents a conditional expression. - * {@link org.elasticsearch.painless.node.EConstant} - Represents a constant inserted into the tree replacing others. (Internal only.) - * {@link org.elasticsearch.painless.node.EDecimal} - Represents a decimal constant. - * {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast. - * {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference (non-capturing). - * {@link org.elasticsearch.painless.node.EInstanceof} - Represents an instanceof check. - * {@link org.elasticsearch.painless.node.ELambda} - Represents a lambda function. - * {@link org.elasticsearch.painless.node.EListInit} - Represents a list initialization shortcut. - * {@link org.elasticsearch.painless.node.EMapInit} - Represents a map initialization shortcut. - * {@link org.elasticsearch.painless.node.ENewArray} - Represents an array instantiation. - * {@link org.elasticsearch.painless.node.ENewObj} - Represents and object instantiation. - * {@link org.elasticsearch.painless.node.ENull} - Represents a null constant. - * {@link org.elasticsearch.painless.node.ENumeric} - Represents a non-decimal numeric constant. - * {@link org.elasticsearch.painless.node.ERegex} - Represents a regular expression constant. - * {@link org.elasticsearch.painless.node.EStatic} - Represents a static type target. - * {@link org.elasticsearch.painless.node.EString} - Represents a string constant. - * {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression. - * {@link org.elasticsearch.painless.node.EVariable} - Represents a variable load/store. - * {@link org.elasticsearch.painless.node.ILambda} - Represents a marker to signify this node is a lambda function. - * {@link org.elasticsearch.painless.node.PBrace} - Represents an array load/store and defers to a child subnode. - * {@link org.elasticsearch.painless.node.PCallInvoke} - Represents a method call and defers to a child subnode. - * {@link org.elasticsearch.painless.node.PField} - Represents a field load/store and defers to a child subnode. - * {@link org.elasticsearch.painless.node.PSubArrayLength} - Represents an array length field load. - * {@link org.elasticsearch.painless.node.PSubBrace} - Represents an array load/store. - * {@link org.elasticsearch.painless.node.PSubCallInvoke} - Represents a method call. - * {@link org.elasticsearch.painless.node.PSubDefArray} - Represents an array load/store or shortcut on a def type. (Internal only.) - * {@link org.elasticsearch.painless.node.PSubDefCall} - Represents a method call made on a def type. (Internal only.) - * {@link org.elasticsearch.painless.node.PSubDefField} - Represents a field load/store or shortcut on a def type. (Internal only.) - * {@link org.elasticsearch.painless.node.PSubField} - Represents a field load/store. - * {@link org.elasticsearch.painless.node.PSubListShortcut} - Represents a list load/store shortcut. (Internal only.) - * {@link org.elasticsearch.painless.node.PSubMapShortcut} - Represents a map load/store shortcut. (Internal only.) - * {@link org.elasticsearch.painless.node.PSubShortcut} - Represents a field load/store shortcut. (Internal only.) - * {@link org.elasticsearch.painless.node.SBlock} - Represents a set of statements as a branch of control-flow. - * {@link org.elasticsearch.painless.node.SBreak} - Represents a break statement. - * {@link org.elasticsearch.painless.node.SCatch} - Represents a catch block as part of a try-catch block. - * {@link org.elasticsearch.painless.node.SContinue} - Represents a continue statement. - * {@link org.elasticsearch.painless.node.SDeclaration} - Represents a single variable declaration. - * {@link org.elasticsearch.painless.node.SDeclBlock} - Represents a series of declarations. - * {@link org.elasticsearch.painless.node.SDo} - Represents a do-while loop. - * {@link org.elasticsearch.painless.node.SEach} - Represents a for-each loop and defers to subnodes depending on type. - * {@link org.elasticsearch.painless.node.SExpression} - Represents the top-level node for an expression as a statement. - * {@link org.elasticsearch.painless.node.SFor} - Represents a for loop. - * {@link org.elasticsearch.painless.node.SFunction} - Represents a user-defined function. - * {@link org.elasticsearch.painless.node.SIf} - Represents an if block. - * {@link org.elasticsearch.painless.node.SIfElse} - Represents an if/else block. - * {@link org.elasticsearch.painless.node.SReturn} - Represents a return statement. - * {@link org.elasticsearch.painless.node.SClass} - The root of all Painless trees. Contains a series of statements. - * {@link org.elasticsearch.painless.node.SSubEachArray} - Represents a for-each loop for arrays. - * {@link org.elasticsearch.painless.node.SSubEachIterable} - Represents a for-each loop for iterables. - * {@link org.elasticsearch.painless.node.SThrow} - Represents a throw statement. - * {@link org.elasticsearch.painless.node.STry} - Represents the try block as part of a try-catch block. - * {@link org.elasticsearch.painless.node.SWhile} - Represents a while loop. - *

- * Note that internal nodes are generated during the analysis phase by modifying the tree on-the-fly - * for clarity of development and convenience during the writing phase. - *

- * All Painless trees must start with an SClass node at the root. Each node has a constructor that requires - * all of its values and children be passed in at the time of instantiation. This means that Painless trees - * are build bottom-up; however, this helps enforce tree structure correctness and fits naturally with a - * standard recursive-descent parser. - *

- * Generally, statement nodes have member data that evaluate legal control-flow during the analysis phase. - * The typical order for statement nodes is for each node to call analyze on it's children during the analysis phase - * and write on it's children during the writing phase. - *

- * Generally, expression nodes have member data that evaluate static and def types. The typical order for an expression node - * during the analysis phase looks like the following: - *

{@code
- * For known expected types:
- *
- * expression.child.expected = expectedType      // set the known expected type
- *
- * expression.child.analyze(...)                 // analyze the child node to set the child's actual type
- *
- * expression.child = expression.child.cast(...) // add an implicit cast node if the child node's
- *                                               // actual type is not the expected type and set the
- *                                               // expression's child to the implicit cast node
- *
- * For unknown expected types that need promotion:
- *
- * expression.child.analyze(...)                 // analyze the child node to set the child's actual type
- *
- * Type promote = Caster.promote(...)            // get the promotion type for the child based on
- *                                               // the current operation and child's actual type
- *
- * expression.child.expected = promote           // set the expected type to the promotion type
- *
- * expression.child = expression.child.cast(...) // add an implicit cast node if the child node's
- *                                               // actual type is not the expected type and set the
- *                                               // expression's child to the implicit cast node
- * }
- * Expression nodes just call each child during the writing phase. - *

- * Postfix nodes represent postfixes in a variable/method chain including braces, calls, or fields. - * Postfix nodes will always have a prefix node that is the prior piece of the variable/method chain. - * Analysis of a postfix node will cause a chain of analysis calls to happen where the prefix will - * be analyzed first and continue until the prefix is not a postfix node. Writing out a series of - * loads from a postfix node works in the same fashion. Stores work somewhat differently as - * described by later documentation. - *

- * Storebable nodes have three methods for writing -- setup, load, and store. These methods - * are used in conjunction with a parent node aware of the storeable node (lhs) that has a node - * representing a value to store (rhs). The setup method is always once called before a store - * to give storeable nodes a chance to write any prefixes they may have and any values such as - * array indices before the store happens. Load is called on a storeable node that must also - * be read from, and store is called to write a value to memory. - *

- * Sub nodes are partial nodes that require a parent to work correctly. These nodes can really - * represent anything the parent node would like to split up into logical pieces and don't really - * have any distinct set of rules. The currently existing subnodes all have ANode as a super class - * somewhere in their class hierarchy so the parent node can defer some analysis and writing to - * the sub node. - */ -package org.elasticsearch.painless.node; From 6349c67d8916660f509da820133bf7e458281872 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 19 Dec 2019 14:12:58 -0800 Subject: [PATCH 12/24] fixes --- .../java/org/elasticsearch/painless/ir/AssignmentNode.java | 3 ++- .../src/main/java/org/elasticsearch/painless/ir/CatchNode.java | 2 +- .../org/elasticsearch/painless/ir/ForEachSubIterableNode.java | 2 +- .../java/org/elasticsearch/painless/ir/MapSubShortcutNode.java | 3 --- .../java/org/elasticsearch/painless/ir/UnboundCallNode.java | 3 --- .../src/main/java/org/elasticsearch/painless/node/ILambda.java | 2 +- .../main/java/org/elasticsearch/painless/node/PSubDefCall.java | 1 - 7 files changed, 5 insertions(+), 11 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 554a765f2fa42..04b0c3afc7af7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -187,7 +187,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); } - leftNode.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array + // store the lhs's value from the stack in its respective variable/field/array + leftNode.store(classWriter, methodWriter, globals); } else { // Handle the case for a simple write. diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index ed6194486bf67..492e3c552281f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -79,7 +79,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declarationNode.getCaptured().clazz).getInternalName()); - if (exception != null && (blockNode == null || blockNode.allEscape == false)) { + if (exception != null && (blockNode == null || blockNode.doAllEscape() == false)) { methodWriter.goTo(exception); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java index 4891675031ae4..b2175148dfab3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java @@ -38,7 +38,7 @@ /** * Represents a for-each loop for iterables. */ -final class ForEachSubIterableNode extends LoopNode { +public class ForEachSubIterableNode extends LoopNode { /* ---- begin node data ---- */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java index c7fd59c8f02cd..d514d198f07ee 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -21,12 +21,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; -import java.util.Objects; - public class MapSubShortcutNode extends UnaryNode { /* ---- begin node data ---- */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java index 650dfa43688cd..ff6fd3c6c0db0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessClassBinding; import org.elasticsearch.painless.lookup.PainlessInstanceBinding; @@ -31,8 +30,6 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import java.util.Objects; - import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; public class UnboundCallNode extends ArgumentsNode { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java index 7a58d18748dc0..884d31cd9d546 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ILambda.java @@ -37,6 +37,6 @@ interface ILambda { /** Returns the number of captured parameters */ default int getCaptureCount() { - return getCaptures().length; + return getCaptures().size(); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index 268383fd6e557..c6ef8997e7923 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -31,7 +31,6 @@ import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; From ab969e4c82b68c76c4dc37285a5fc4f6ea9ac5b8 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 19 Dec 2019 14:24:42 -0800 Subject: [PATCH 13/24] fix subtle issue with unboxing def --- .../main/java/org/elasticsearch/painless/node/PSubDefCall.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index c6ef8997e7923..8f92754000fb0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -104,7 +104,7 @@ void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) // create method type from return value and arguments Type[] asmParameterTypes = new Type[parameterTypes.size()]; for (int index = 0; index < asmParameterTypes.length; ++index) { - asmParameterTypes[index] = Type.getType(parameterTypes.get(index)); + asmParameterTypes[index] = MethodWriter.getType(parameterTypes.get(index)); } Type methodType = Type.getMethodType(MethodWriter.getType(actual), asmParameterTypes); From 86dc9a7bcb7b0daecdc91c8580767b0ce9df8286 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sat, 21 Dec 2019 15:04:43 -0800 Subject: [PATCH 14/24] move script root --- .../org/elasticsearch/painless/Compiler.java | 1 + .../painless/PainlessScriptEngine.java | 1 + .../elasticsearch/painless/ScriptBuilder.java | 31 +++++++++++++++++++ .../elasticsearch/painless/ir/ClassNode.java | 2 +- .../painless/node/AExpression.java | 2 +- .../elasticsearch/painless/node/ANode.java | 2 +- .../painless/node/EAssignment.java | 2 +- .../elasticsearch/painless/node/EBinary.java | 2 +- .../elasticsearch/painless/node/EBool.java | 2 +- .../elasticsearch/painless/node/EBoolean.java | 2 +- .../painless/node/ECallLocal.java | 2 +- .../painless/node/ECapturingFunctionRef.java | 2 +- .../elasticsearch/painless/node/ECast.java | 2 +- .../elasticsearch/painless/node/EComp.java | 2 +- .../painless/node/EConditional.java | 2 +- .../painless/node/EConstant.java | 2 +- .../elasticsearch/painless/node/EDecimal.java | 2 +- .../elasticsearch/painless/node/EElvis.java | 2 +- .../painless/node/EExplicit.java | 2 +- .../painless/node/EFunctionRef.java | 2 +- .../painless/node/EInstanceof.java | 2 +- .../elasticsearch/painless/node/ELambda.java | 2 +- .../painless/node/EListInit.java | 2 +- .../elasticsearch/painless/node/EMapInit.java | 2 +- .../painless/node/ENewArray.java | 2 +- .../painless/node/ENewArrayFunctionRef.java | 2 +- .../elasticsearch/painless/node/ENewObj.java | 2 +- .../elasticsearch/painless/node/ENull.java | 2 +- .../elasticsearch/painless/node/ENumeric.java | 2 +- .../elasticsearch/painless/node/ERegex.java | 2 +- .../elasticsearch/painless/node/EStatic.java | 2 +- .../elasticsearch/painless/node/EString.java | 2 +- .../elasticsearch/painless/node/EUnary.java | 2 +- .../painless/node/EVariable.java | 2 +- .../elasticsearch/painless/node/PBrace.java | 2 +- .../painless/node/PCallInvoke.java | 2 +- .../elasticsearch/painless/node/PField.java | 2 +- .../painless/node/PSubArrayLength.java | 2 +- .../painless/node/PSubBrace.java | 2 +- .../painless/node/PSubCallInvoke.java | 2 +- .../painless/node/PSubDefArray.java | 2 +- .../painless/node/PSubDefCall.java | 2 +- .../painless/node/PSubDefField.java | 2 +- .../painless/node/PSubField.java | 2 +- .../painless/node/PSubListShortcut.java | 2 +- .../painless/node/PSubMapShortcut.java | 2 +- .../painless/node/PSubNullSafeCallInvoke.java | 2 +- .../painless/node/PSubNullSafeField.java | 2 +- .../painless/node/PSubShortcut.java | 2 +- .../elasticsearch/painless/node/SBlock.java | 2 +- .../elasticsearch/painless/node/SBreak.java | 2 +- .../elasticsearch/painless/node/SCatch.java | 2 +- .../elasticsearch/painless/node/SClass.java | 2 +- .../painless/node/SContinue.java | 2 +- .../painless/node/SDeclBlock.java | 2 +- .../painless/node/SDeclaration.java | 2 +- .../org/elasticsearch/painless/node/SDo.java | 2 +- .../elasticsearch/painless/node/SEach.java | 2 +- .../painless/node/SExpression.java | 2 +- .../elasticsearch/painless/node/SField.java | 2 +- .../org/elasticsearch/painless/node/SFor.java | 2 +- .../painless/node/SFunction.java | 2 +- .../org/elasticsearch/painless/node/SIf.java | 2 +- .../elasticsearch/painless/node/SIfElse.java | 2 +- .../elasticsearch/painless/node/SReturn.java | 2 +- .../painless/node/SSubEachArray.java | 2 +- .../painless/node/SSubEachIterable.java | 2 +- .../elasticsearch/painless/node/SThrow.java | 2 +- .../org/elasticsearch/painless/node/STry.java | 2 +- .../elasticsearch/painless/node/SWhile.java | 2 +- .../painless/{ => symbol}/ScriptRoot.java | 4 ++- 71 files changed, 103 insertions(+), 68 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java rename modules/lang-painless/src/main/java/org/elasticsearch/painless/{ => symbol}/ScriptRoot.java (94%) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java index 174936ec6ff40..b6a30fc7c34fc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.node.SClass; import org.elasticsearch.painless.spi.Whitelist; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.util.Printer; import java.lang.reflect.Method; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java index c72a98b8633d6..c09d411888a51 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java @@ -25,6 +25,7 @@ import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptException; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java new file mode 100644 index 0000000000000..2f1118d976cf8 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java @@ -0,0 +1,31 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless; + +import org.elasticsearch.painless.ir.ClassNode; + +import java.util.HashMap; +import java.util.Map; + +public class ScriptBuilder { + + Map classNodes = new HashMap<>(); + +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index 21356a701106c..63379b69c56a1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptClassInfo; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java index d1281b1ea3963..3fa62b8454ed8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java @@ -22,7 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java index d6cc2f3c18508..8053ae28fe177 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.ArrayList; import java.util.Arrays; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index c6fcc9820420e..74c0288297e25 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -28,7 +28,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.def; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index 7f67f16fb3b3c..b0abae3ba7d2d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java index c46242ff28aac..f9052e1649b65 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java index e1c4fd05745f9..4f3f78e075d59 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java index b96782f14855f..4033d42feb1b0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessClassBinding; import org.elasticsearch.painless.lookup.PainlessInstanceBinding; import org.elasticsearch.painless.lookup.PainlessMethod; 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 00bd215918393..d269e5c20bb23 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 @@ -27,7 +27,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 0e50368bf7c3b..b423d7069ed1f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 9ec21874234a0..4048cf7fcadcb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java index c8263b587bb44..fb3ad1846b8a5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java index 8698635359b9a..3378710c1ea1a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java index faacb3cdc0282..f57cf2d43d5e2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java index d5e494ffa3098..a423f85e147ee 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java index b092aef87de42..933464b41a94b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index 8247ec54215ce..9eb4fb178de12 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java index 88dc36b497cb4..2dee22125249b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.util.Objects; 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 4b23ee6fb8f2c..40bd4295a88f5 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 @@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index c495ff0360362..c0884853de44e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index d57059269c0da..d1e9c9166138f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java index 03ec8a57fc02d..b7bd13bbe55e9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java index 98b471a10360e..1fa2d1a2cd49f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Arrays; import java.util.Collections; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java index 0bc5b751f8831..e09eee2aad917 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java index 7520700885f9e..7b9fc29d7575a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java index 4778670979c69..065d0b3a1843c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java index 210894e86fa4c..aa22452719271 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; import java.lang.reflect.Modifier; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java index d1d50a5d590eb..35cca3cb2af90 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java index 79120549de165..7d52660a7ab22 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index 186c11aa70f47..9e8ada2a5b9c6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; 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 b19be1d67c228..eb900eafab83d 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 @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Opcodes; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java index f029337a3d7e3..eaa11a6833ac8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java index e71f70d632579..c13ca5765bbec 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java index a5486524585b6..92218a21aebe1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java index 07f5e690e2373..d004cc30a6a89 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java index a793c55f81b6c..60c025ecba548 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java index 34ff18ffec338..307607ee36aab 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessMethod; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java index 8ac360b200237..620c0fd6aca60 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Type; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index 8f92754000fb0..61f99b57d72ee 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Type; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java index 441762a0c58cf..071b6515d3971 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.def; import java.time.ZonedDateTime; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java index b6d683edcee4e..7f0be343842e7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Type; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java index 9471ea8c56d64..e0e566306bc69 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java index 1558d4ce94bb3..888044cd31686 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java index 7ce2a6a8cd889..0f6875762a681 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java index bc9a7ac3f96b4..d4260677f832d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java index 181a04aa02b1a..7388aca1a8d47 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessMethod; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java index effa818280668..a270bcc615d7f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java index cc49ac7561bff..5794e833ec9cf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; 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 9fc6dc29fe217..ad5382ad9f888 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 @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java index 2e45e2dfc356e..e3dda3cd58f31 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java @@ -28,7 +28,7 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptClassInfo; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.symbol.FunctionTable; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java index 2a9ea5319b6a4..91d73b30f1d54 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java index 220c9ec3d012c..14d91ad1b984c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; import java.util.List; 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 bcc2036aaffd4..da4b7d19c3031 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 @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Opcodes; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java index a6c9c2eb30c24..0cb52f57c0249 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; 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 65377aaa6e59d..3850aa8987756 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 @@ -25,7 +25,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; 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 3057cd689b07f..49bfb9e808e03 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 @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java index 569ca608b4502..2bb3b41a2b9da 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Type; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java index 93ba16a41e1ce..54c34a3cd43b4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; 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 75122903ef12f..5fa430a7f29f1 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 @@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java index 1f4350297dc3a..5098daad11ce7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java index 85c23977fa5a0..1ab347d074c1e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; 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 cfc1dd1e6da9b..60aa2fad60a5f 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 @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.util.Set; 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 c0ce95ea68adb..8424628e7e34f 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 @@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Label; 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 b6b97503555b1..1ad1b01ccfc4d 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 @@ -27,7 +27,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java index a8309c7f7f8a7..bb25793095a88 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java index 67b038158cbc1..5a026e1c74c0b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import java.util.Collections; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java index ab1f29fad4a5d..991b1f08a4699 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java @@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.ScriptRoot; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptRoot.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java similarity index 94% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptRoot.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java index 775da59795b94..8598280bf6ee0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptRoot.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java @@ -17,8 +17,10 @@ * under the License. */ -package org.elasticsearch.painless; +package org.elasticsearch.painless.symbol; +import org.elasticsearch.painless.CompilerSettings; +import org.elasticsearch.painless.ScriptClassInfo; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.node.SClass; import org.elasticsearch.painless.symbol.FunctionTable; From 6149e43955a88ee7a397fb64fd3cb5539dd72498 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sat, 21 Dec 2019 18:01:00 -0800 Subject: [PATCH 15/24] remove class --- .../elasticsearch/painless/ScriptBuilder.java | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java deleted file mode 100644 index 2f1118d976cf8..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless; - -import org.elasticsearch.painless.ir.ClassNode; - -import java.util.HashMap; -import java.util.Map; - -public class ScriptBuilder { - - Map classNodes = new HashMap<>(); - -} From 32b8b8bc78197b7d3fa2d313b3a46a3b02fd849b Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 23 Dec 2019 18:50:20 -0800 Subject: [PATCH 16/24] add setters with covariant return types for all nodes --- .../painless/PainlessScriptEngine.java | 2 +- .../painless/ir/ArgumentsNode.java | 24 ++++++- .../painless/ir/AssignmentNode.java | 29 +++++++- .../painless/ir/BinaryMathNode.java | 33 ++++++++++ .../elasticsearch/painless/ir/BinaryNode.java | 18 ++++- .../elasticsearch/painless/ir/BlockNode.java | 13 ++++ .../painless/ir/BooleanNode.java | 29 +++++++- .../elasticsearch/painless/ir/BraceNode.java | 31 +++++++++ .../painless/ir/BraceSubDefNode.java | 25 +++++++ .../painless/ir/BraceSubNode.java | 25 +++++++ .../elasticsearch/painless/ir/BreakNode.java | 11 ++++ .../elasticsearch/painless/ir/CallNode.java | 31 +++++++++ .../painless/ir/CallSubDefNode.java | 66 ++++++++++++++++++- .../painless/ir/CallSubNode.java | 57 +++++++++++++++- .../painless/ir/CapturingFuncRefNode.java | 17 ++++- .../elasticsearch/painless/ir/CastNode.java | 23 +++++++ .../elasticsearch/painless/ir/CatchNode.java | 11 +++- .../elasticsearch/painless/ir/ClassNode.java | 35 +++++++++- .../painless/ir/ComparisonNode.java | 29 +++++++- .../painless/ir/ConditionNode.java | 12 +++- .../painless/ir/ConditionalNode.java | 29 +++++++- .../painless/ir/ConstantNode.java | 17 ++++- .../painless/ir/ContinueNode.java | 11 ++++ .../painless/ir/DeclarationBlockNode.java | 33 +++++++--- .../painless/ir/DeclarationNode.java | 7 ++ .../{DoLoopNode.java => DoWhileLoopNode.java} | 42 +++++++++++- .../elasticsearch/painless/ir/DotNode.java | 31 +++++++++ .../painless/ir/DotSubArrayLengthNode.java | 19 ++++++ .../painless/ir/DotSubDefNode.java | 17 ++++- .../elasticsearch/painless/ir/DotSubNode.java | 15 +++++ .../painless/ir/DotSubShortcutNode.java | 18 ++++- .../elasticsearch/painless/ir/ElvisNode.java | 31 +++++++++ .../painless/ir/ExpressionNode.java | 15 ++++- .../elasticsearch/painless/ir/FieldNode.java | 7 ++ .../painless/ir/ForEachLoopNode.java | 11 +++- .../painless/ir/ForEachSubArrayNode.java | 34 +++++++++- .../painless/ir/ForEachSubIterableNode.java | 35 +++++++++- .../painless/ir/ForLoopNode.java | 37 ++++++++++- .../painless/ir/FuncRefNode.java | 17 ++++- .../painless/ir/FunctionNode.java | 7 ++ .../elasticsearch/painless/ir/IfElseNode.java | 23 ++++++- .../org/elasticsearch/painless/ir/IfNode.java | 25 +++++++ .../painless/ir/InstanceofNode.java | 19 ++++++ .../elasticsearch/painless/ir/LambdaNode.java | 25 ++++++- .../painless/ir/ListInitializationNode.java | 55 +++++++++++++++- .../painless/ir/ListSubShortcutNode.java | 23 ++++++- .../elasticsearch/painless/ir/LoopNode.java | 23 ++++++- .../painless/ir/MapInitializationNode.java | 13 ++++ .../painless/ir/MapSubShortcutNode.java | 23 ++++++- .../painless/ir/NewArrayFuncRefNode.java | 17 ++++- .../painless/ir/NewArrayNode.java | 55 +++++++++++++++- .../painless/ir/NewObjectNode.java | 55 +++++++++++++++- .../elasticsearch/painless/ir/NullNode.java | 19 ++++++ .../painless/ir/NullSafeSubNode.java | 25 +++++++ .../elasticsearch/painless/ir/PrefixNode.java | 27 +++++++- .../elasticsearch/painless/ir/RegexNode.java | 17 ++++- .../elasticsearch/painless/ir/ReturnNode.java | 13 ++++ .../elasticsearch/painless/ir/ShiftNode.java | 43 ++++++++++-- .../painless/ir/StatementExpressionNode.java | 7 ++ .../painless/ir/StatementNode.java | 11 ++++ .../elasticsearch/painless/ir/StaticNode.java | 19 ++++++ .../elasticsearch/painless/ir/ThrowNode.java | 9 +++ .../elasticsearch/painless/ir/TryNode.java | 17 ++++- .../elasticsearch/painless/ir/TypeNode.java | 7 ++ .../painless/ir/UnaryMathNode.java | 23 ++++++- .../elasticsearch/painless/ir/UnaryNode.java | 21 +++++- .../painless/ir/UnboundCallNode.java | 55 +++++++++++++++- .../painless/ir/VariableNode.java | 17 ++++- .../elasticsearch/painless/ir/WhileNode.java | 38 +++++++++++ .../painless/symbol/ScriptRoot.java | 8 ++- 70 files changed, 1624 insertions(+), 62 deletions(-) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/{DoLoopNode.java => DoWhileLoopNode.java} (64%) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java index c09d411888a51..342fbbb060cbe 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java @@ -341,7 +341,7 @@ private T generateFactory( GeneratorAdapter deterAdapter = new GeneratorAdapter(Opcodes.ASM5, isResultDeterministic, writer.visitMethod(Opcodes.ACC_PUBLIC, methodName, isResultDeterministic.getDescriptor(), null, null)); deterAdapter.visitCode(); - deterAdapter.push(scriptRoot.deterministic); + deterAdapter.push(scriptRoot.isDeterministic()); deterAdapter.returnValue(); deterAdapter.endMethod(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java index 49f1cf2b5a129..b8921813f9a0c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java @@ -19,7 +19,10 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + import java.util.ArrayList; +import java.util.Collection; import java.util.List; public abstract class ArgumentsNode extends ExpressionNode { @@ -33,6 +36,11 @@ public ArgumentsNode addArgumentNode(ExpressionNode argumentNode) { return this; } + public ArgumentsNode addArgumentNodes(Collection argumentNodes) { + this.argumentNodes.addAll(argumentNodes); + return this; + } + public ArgumentsNode setArgumentNode(int index, ExpressionNode argumentNode) { argumentNodes.set(index, argumentNode); return this; @@ -65,7 +73,21 @@ public ArgumentsNode clearArgumentNodes() { return this; } - /* ---- end tree structure ---- */ + @Override + public ArgumentsNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public ArgumentsNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public ArgumentsNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 04b0c3afc7af7..473b4f3ef6645 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessCast; @@ -30,7 +31,27 @@ public class AssignmentNode extends BinaryNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public AssignmentNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public AssignmentNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public AssignmentNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected boolean pre; protected boolean post; @@ -103,6 +124,12 @@ public PainlessCast getBack() { return back; } + @Override + public AssignmentNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public AssignmentNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index d0eaf9fe76128..6b962be861ae1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.WriterConstants; @@ -32,6 +33,32 @@ public class BinaryMathNode extends ShiftNode { + /* ---- begin tree structure ---- */ + + @Override + public BinaryMathNode setShiftTypeNode(TypeNode shiftTypeNode) { + super.setShiftTypeNode(shiftTypeNode); + return this; + } + + @Override + public BinaryMathNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public BinaryMathNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public BinaryMathNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + /* ---- begin node data ---- */ protected Operation operation; @@ -65,6 +92,12 @@ public boolean getOriginallyExplicit() { return originallyExplicit; } + @Override + public BinaryMathNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public BinaryMathNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java index 990f5c2e42a76..85096d13e0768 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java @@ -19,6 +19,8 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + public abstract class BinaryNode extends ExpressionNode { /* ---- begin tree structure ---- */ @@ -44,7 +46,21 @@ public ExpressionNode getRightNode() { return rightNode; } - /* ---- end tree structure ---- */ + @Override + public BinaryNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public BinaryNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public BinaryNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java index 28722bfa2cc82..4ce94b803c2f9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java @@ -21,9 +21,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class BlockNode extends StatementNode { @@ -37,6 +39,11 @@ public BlockNode addStatementNode(StatementNode statementNode) { return this; } + public BlockNode addStatementNodes(Collection statementNodes) { + this.statementNodes.addAll(statementNodes); + return this; + } + public BlockNode setStatementNode(int index, StatementNode statementNode) { statementNodes.set(index, statementNode); return this; @@ -92,6 +99,12 @@ public int getStatementCount() { return statementCount; } + @Override + public BlockNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public BlockNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index 2e366e9cf051d..a67c7a52ed788 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.objectweb.asm.Label; @@ -28,7 +29,27 @@ public class BooleanNode extends BinaryNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public BooleanNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public BooleanNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public BooleanNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected Operation operation; @@ -41,6 +62,12 @@ public Operation getOperation() { return operation; } + @Override + public BooleanNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public BooleanNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java index 04e42c9b27fdb..f6898a5dcb74a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java @@ -21,10 +21,41 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class BraceNode extends PrefixNode { + /* ---- begin tree structure ---- */ + + @Override + public BraceNode setPrefixNode(ExpressionNode prefixNode) { + this.prefixNode = prefixNode; + return this; + } + + @Override + public BraceNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public BraceNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public BraceNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public BraceNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java index d084d402819d9..0995501cd9f3b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java @@ -22,11 +22,36 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; public class BraceSubDefNode extends UnaryNode { + /* ---- begin tree structure ---- */ + + @Override + public BraceSubDefNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public BraceSubDefNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public BraceSubDefNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public BraceSubDefNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java index b8cf42a49d92d..04852bc8b3d6f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java @@ -21,12 +21,37 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class BraceSubNode extends UnaryNode { + /* ---- begin tree structure ---- */ + + @Override + public BraceSubNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public BraceSubNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public BraceSubNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public BraceSubNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java index 296e31f381f67..6239e23dbd24e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java @@ -21,10 +21,21 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class BreakNode extends StatementNode { + /* ---- begin node data ---- */ + + @Override + public BreakNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public BreakNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java index 5636a3611181c..3f009e65ca367 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java @@ -21,10 +21,41 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class CallNode extends PrefixNode { + /* ---- begin tree structure ---- */ + + @Override + public CallNode setPrefixNode(ExpressionNode prefixNode) { + this.prefixNode = prefixNode; + return this; + } + + @Override + public CallNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public CallNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public CallNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public CallNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java index ca4d09f20e76c..59fde24f34748 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java @@ -22,15 +22,61 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class CallSubDefNode extends ArgumentsNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public CallSubDefNode addArgumentNode(ExpressionNode argumentNode) { + super.addArgumentNode(argumentNode); + return this; + } + + @Override + public CallSubDefNode addArgumentNodes(Collection argumentNodes) { + super.addArgumentNodes(argumentNodes); + return this; + } + + @Override + public CallSubDefNode setArgumentNode(int index, ExpressionNode argumentNode) { + super.setArgumentNode(index, argumentNode); + return this; + } + + @Override + public CallSubDefNode removeArgumentNode(ExpressionNode argumentNode) { + super.removeArgumentNode(argumentNode); + return this; + } + + @Override + public CallSubDefNode removeArgumentNode(int index) { + super.removeArgumentNode(index); + return this; + } + + @Override + public CallSubDefNode clearArgumentNodes() { + super.clearArgumentNodes(); + return this; + } + + @Override + public CallSubDefNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected String name; protected String recipe; @@ -60,6 +106,11 @@ public CallSubDefNode addPointer(String pointer) { return this; } + public CallSubDefNode addPointers(Collection pointers) { + this.pointers.addAll(pointers); + return this; + } + public CallSubDefNode setPointer(int index, String pointer) { pointers.set(index, pointer); return this; @@ -97,6 +148,11 @@ public CallSubDefNode addTypeParameter(Class typeParameter) { return this; } + public CallSubDefNode addTypeParameters(Collection> typeParameters) { + this.typeParameters.addAll(typeParameters); + return this; + } + public CallSubDefNode setTypeParameter(int index, Class typeParameter) { typeParameters.set(index, typeParameter); return this; @@ -128,7 +184,13 @@ public CallSubDefNode clearTypeParameters() { typeParameters.clear(); return this; } - + + @Override + public CallSubDefNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public CallSubDefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java index b24ca48b7d30c..e87740296b1af 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java @@ -21,12 +21,59 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; +import java.util.Collection; + public class CallSubNode extends ArgumentsNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public CallSubNode addArgumentNode(ExpressionNode argumentNode) { + super.addArgumentNode(argumentNode); + return this; + } + + @Override + public CallSubNode addArgumentNodes(Collection argumentNodes) { + super.addArgumentNodes(argumentNodes); + return this; + } + + @Override + public CallSubNode setArgumentNode(int index, ExpressionNode argumentNode) { + super.setArgumentNode(index, argumentNode); + return this; + } + + @Override + public CallSubNode removeArgumentNode(ExpressionNode argumentNode) { + super.removeArgumentNode(argumentNode); + return this; + } + + @Override + public CallSubNode removeArgumentNode(int index) { + super.removeArgumentNode(index); + return this; + } + + @Override + public CallSubNode clearArgumentNodes() { + super.clearArgumentNodes(); + return this; + } + + @Override + public CallSubNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected PainlessMethod method; protected Class box; @@ -45,10 +92,16 @@ public CallSubNode setBox(Class box) { return this; } - public Class getPost() { + public Class getBox() { return box; } + @Override + public CallSubNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public CallSubNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index bda28f2ec442c..c62f127fb98c1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -24,13 +24,22 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; public class CapturingFuncRefNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public CapturingFuncRefNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected String name; protected Variable captured; @@ -73,6 +82,12 @@ public String getPointer() { return pointer; } + @Override + public CapturingFuncRefNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public CapturingFuncRefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java index 68fdeef71f110..92189be6c80d9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java @@ -21,11 +21,28 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; public class CastNode extends UnaryNode { + /* ---- begin tree structure ---- */ + + @Override + public CastNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public CastNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + /* ---- begin node data ---- */ protected PainlessCast cast; @@ -39,6 +56,12 @@ public PainlessCast getCast() { return cast; } + @Override + public CastNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public CastNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index 492e3c552281f..1ea907fa9ed50 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -50,7 +51,15 @@ public BlockNode getBlockNode() { return blockNode; } - /* ---- end tree structure ---- */ + /* ---- end tree structure, begin node data ---- */ + + @Override + public CatchNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public CatchNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index 63379b69c56a1..9411666ee9adc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -27,8 +27,8 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptClassInfo; -import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -81,6 +81,11 @@ public ClassNode addFieldNode(FieldNode fieldNode) { return this; } + public ClassNode addFieldNodes(Collection fieldNodes) { + this.fieldNodes.addAll(fieldNodes); + return this; + } + public ClassNode setFieldNode(int index, FieldNode fieldNode) { fieldNodes.set(index, fieldNode); return this; @@ -118,6 +123,11 @@ public ClassNode addFunctionNode(FunctionNode functionNode) { return this; } + public ClassNode addFunctionNode(Collection functionNodes) { + this.functionNodes.addAll(functionNodes); + return this; + } + public ClassNode setFunctionNode(int index, FunctionNode functionNode) { functionNodes.set(index, functionNode); return this; @@ -155,6 +165,11 @@ public ClassNode addStatementNode(StatementNode statementNode) { return this; } + public ClassNode addStatementNodes(Collection statementNodes) { + this.statementNodes.addAll(statementNodes); + return this; + } + public ClassNode setStatementNode(int index, StatementNode statementNode) { statementNodes.set(index, statementNode); return this; @@ -267,6 +282,11 @@ public ClassNode addExtractedVariable(String extractedVariable) { return this; } + public ClassNode addExtractedVariables(Collection extractedVariables) { + this.extractedVariables.addAll(extractedVariables); + return this; + } + public boolean containsExtractedVariable(String extractedVariable) { return extractedVariables.contains(extractedVariable); } @@ -294,6 +314,11 @@ public ClassNode addGetMethod(org.objectweb.asm.commons.Method getMethod) { return this; } + public ClassNode addGetMethods(Collection getMethods) { + this.getMethods.addAll(getMethods); + return this; + } + public ClassNode setGetMethod(int index, org.objectweb.asm.commons.Method getMethod) { getMethods.set(index, getMethod); return this; @@ -325,7 +350,13 @@ public ClassNode clearGetMethods() { getMethods.clear(); return this; } - + + @Override + public ClassNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ protected Globals globals; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index edc34a7bdb982..4e2a443b064a4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessLookupUtility; @@ -34,7 +35,27 @@ public class ComparisonNode extends BinaryNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public ComparisonNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public ComparisonNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public ComparisonNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected Operation operation; @@ -47,6 +68,12 @@ public Operation getOperation() { return operation; } + @Override + public ComparisonNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public ComparisonNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java index 5af516182630b..b5df4e89e1259 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java @@ -19,6 +19,8 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + public abstract class ConditionNode extends StatementNode { /* ---- begin tree structure ---- */ @@ -44,7 +46,15 @@ public BlockNode getBlockNode() { return blockNode; } - /* ---- end tree structure ---- */ + /* ---- end tree structure, begin node data ---- */ + + @Override + public ConditionNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public ConditionNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java index 59e457b88d855..961ad32f3cd69 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -40,7 +41,33 @@ public ExpressionNode getConditionNode() { return conditionNode; } - /* ---- end tree structure ---- */ + @Override + public ConditionalNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public ConditionalNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public ConditionalNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public ConditionalNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public ConditionalNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java index 352955385645b..148487709c205 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -21,11 +21,20 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ConstantNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public ConstantNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected Object constant; @@ -38,6 +47,12 @@ public Object getConstant() { return constant; } + @Override + public ConstantNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ ConstantNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java index fd182caf3bf81..24e39e3fc9000 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java @@ -21,10 +21,21 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ContinueNode extends StatementNode { + /* ---- begin node data ---- */ + + @Override + public ContinueNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public ContinueNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java index 54e433df1b3b5..3e8d2201864be 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java @@ -21,9 +21,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public final class DeclarationBlockNode extends StatementNode { @@ -32,44 +34,57 @@ public final class DeclarationBlockNode extends StatementNode { protected List declarationNodes = new ArrayList<>(); - public DeclarationBlockNode addStatementNode(DeclarationNode declarationNode) { + public DeclarationBlockNode addDeclarationNode(DeclarationNode declarationNode) { declarationNodes.add(declarationNode); return this; } - public DeclarationBlockNode setStatementNode(int index, DeclarationNode declarationNode) { + public DeclarationBlockNode addDeclarationNodes(Collection declarationNodes) { + this.declarationNodes.addAll(declarationNodes); + return this; + } + + public DeclarationBlockNode setDeclarationNode(int index, DeclarationNode declarationNode) { declarationNodes.set(index, declarationNode); return this; } - public DeclarationNode getStatementNode(int index) { + public DeclarationNode getDeclarationNode(int index) { return declarationNodes.get(index); } - public DeclarationBlockNode removeStatementNode(DeclarationNode declarationNode) { + public DeclarationBlockNode removeDeclarationNode(DeclarationNode declarationNode) { declarationNodes.remove(declarationNode); return this; } - public DeclarationBlockNode removeStatementNode(int index) { + public DeclarationBlockNode removeDeclarationNode(int index) { declarationNodes.remove(index); return this; } - public int getStatementsSize() { + public int getDeclarationsSize() { return declarationNodes.size(); } - public List getStatementsNodes() { + public List getDeclarationsNodes() { return declarationNodes; } - public DeclarationBlockNode clearStatementNodes() { + public DeclarationBlockNode clearDeclarationNodes() { declarationNodes.clear(); return this; } - /* ---- end tree structure ---- */ + /* ---- end tree structure, begin node data ---- */ + + @Override + public DeclarationBlockNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public DeclarationBlockNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index 5cb18d53dfb36..b0f2227f56d67 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; @@ -53,6 +54,12 @@ public Variable getCaptured() { return variable; } + @Override + public DeclarationNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public DeclarationNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java similarity index 64% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java index 653eaaa2f9ac7..21ea0651986a3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java @@ -21,13 +21,51 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -public class DoLoopNode extends LoopNode { +public class DoWhileLoopNode extends LoopNode { - public DoLoopNode() { + /* ---- begin tree structure ---- */ + + @Override + public DoWhileLoopNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public DoWhileLoopNode setBlockNode(BlockNode blockNode) { + super.setBlockNode(blockNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public DoWhileLoopNode setContinuous(boolean isContinuous) { + super.setContinuous(isContinuous); + return this; + } + + @Override + public DoWhileLoopNode setLoopCounter(Locals.Variable loopCounter) { + super.setLoopCounter(loopCounter); + return this; + } + + @Override + public DoWhileLoopNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + + public DoWhileLoopNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java index 6069f6a909a47..e21658d7412ce 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java @@ -21,10 +21,41 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class DotNode extends PrefixNode { + /* ---- begin tree structure ---- */ + + @Override + public DotNode setPrefixNode(ExpressionNode prefixNode) { + this.prefixNode = prefixNode; + return this; + } + + @Override + public DotNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public DotNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public DotNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public DotNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java index 5fc43114279a3..eddc60695c3b3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java @@ -21,10 +21,29 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class DotSubArrayLengthNode extends ExpressionNode { + /* ---- begin tree structure ---- */ + + @Override + public DotSubArrayLengthNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public DotSubArrayLengthNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public DotSubArrayLengthNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java index 2032593e365a3..75387fff23c90 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java @@ -22,11 +22,20 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class DotSubDefNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public DotSubDefNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected String value; @@ -39,6 +48,12 @@ public String getValue() { return value; } + @Override + public DotSubDefNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public DotSubDefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java index ab07dc44d69d9..6072f3ae0626b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java @@ -21,12 +21,21 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessField; import org.objectweb.asm.Type; public class DotSubNode extends ExpressionNode { + /* ---- begin tree structure ---- */ + + @Override + public DotSubNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + /* ---- begin node data ---- */ protected PainlessField field; @@ -40,6 +49,12 @@ public PainlessField getField() { return field; } + @Override + public DotSubNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public DotSubNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java index 2cc75a109b3b7..55d16258b3335 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java @@ -21,12 +21,21 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; public class DotSubShortcutNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* begin tree structure */ + + @Override + public DotSubShortcutNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected PainlessMethod setter; protected PainlessMethod getter; @@ -49,6 +58,13 @@ public PainlessMethod getGetter() { return getter; } + + @Override + public DotSubShortcutNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public DotSubShortcutNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java index 978f02acc20ff..aea59edb03313 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java @@ -21,11 +21,42 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; public class ElvisNode extends BinaryNode { + /* ---- begin tree structure ---- */ + + @Override + public ElvisNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public ElvisNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public ElvisNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public ElvisNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public ElvisNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java index ac66075bb3e44..55bce8eda4356 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java @@ -19,14 +19,17 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + public abstract class ExpressionNode extends IRNode { /* ---- begin tree structure ---- */ protected TypeNode typeNode; - public void setTypeNode(TypeNode typeNode) { + public ExpressionNode setTypeNode(TypeNode typeNode) { this.typeNode = typeNode; + return this; } public TypeNode getTypeNode() { @@ -41,7 +44,15 @@ public String getCanonicalTypeName() { return typeNode.getCanonicalTypeName(); } - /* ---- end tree structure ---- */ + /* ---- end tree structure, begin node data ---- */ + + @Override + public ExpressionNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public ExpressionNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java index 59e9de06b6d06..3641ff7bb67b5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; @@ -79,6 +80,12 @@ public Object getInstance() { return instance; } + @Override + public FieldNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public FieldNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java index 7a7b014a9ced8..6ee0500d6e9fd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ForEachLoopNode extends StatementNode { @@ -38,7 +39,15 @@ public ConditionNode getConditionNode() { return conditionNode; } - /* ---- end tree structure ---- */ + /* ---- end tree structure, being node data ---- */ + + @Override + public ForEachLoopNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public ForEachLoopNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java index 5756b9ea325c6..da5c19d983dc3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; import org.objectweb.asm.Label; @@ -33,8 +34,9 @@ public class ForEachSubArrayNode extends LoopNode { protected TypeNode indexedTypeNode; - public void setIndexedTypeNode(TypeNode indexedTypeNode) { + public ForEachSubArrayNode setIndexedTypeNode(TypeNode indexedTypeNode) { this.indexedTypeNode = indexedTypeNode; + return this; } public TypeNode getIndexedTypeNode() { @@ -49,6 +51,18 @@ public String getIndexedCanonicalTypeName() { return indexedTypeNode.getCanonicalTypeName(); } + @Override + public ForEachSubArrayNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public ForEachSubArrayNode setBlockNode(BlockNode blockNode) { + super.setBlockNode(blockNode); + return this; + } + /* ---- begin node data ---- */ protected Variable variable; @@ -92,6 +106,24 @@ public Variable getIndex() { return this.index; } + @Override + public ForEachSubArrayNode setContinuous(boolean isContinuous) { + super.setContinuous(isContinuous); + return this; + } + + @Override + public ForEachSubArrayNode setLoopCounter(Variable loopCounter) { + super.setLoopCounter(loopCounter); + return this; + } + + @Override + public ForEachSubArrayNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ ForEachSubArrayNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java index b2175148dfab3..ec97ff6be5d6d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -40,7 +41,21 @@ */ public class ForEachSubIterableNode extends LoopNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public ForEachSubIterableNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public ForEachSubIterableNode setBlockNode(BlockNode blockNode) { + super.setBlockNode(blockNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected Variable variable; protected PainlessCast cast; @@ -83,6 +98,24 @@ public PainlessMethod getMethod() { return method; } + @Override + public ForEachSubIterableNode setContinuous(boolean isContinuous) { + super.setContinuous(isContinuous); + return this; + } + + @Override + public ForEachSubIterableNode setLoopCounter(Variable loopCounter) { + super.setLoopCounter(loopCounter); + return this; + } + + @Override + public ForEachSubIterableNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public ForEachSubIterableNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java index 3d49ceeb4468c..dd051f6ad52d6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java @@ -21,10 +21,13 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; +import static org.elasticsearch.painless.Locals.Variable; + public class ForLoopNode extends LoopNode { /* ---- begin tree structure ---- */ @@ -50,7 +53,39 @@ public ExpressionNode getAfterthoughtNode() { return afterthoughtNode; } - /* ---- end tree structure ---- */ + @Override + public ForLoopNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public ForLoopNode setBlockNode(BlockNode blockNode) { + super.setBlockNode(blockNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public ForLoopNode setContinuous(boolean isContinuous) { + super.setContinuous(isContinuous); + return this; + } + + @Override + public ForLoopNode setLoopCounter(Variable loopCounter) { + super.setLoopCounter(loopCounter); + return this; + } + + @Override + public ForLoopNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public ForLoopNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java index 7968c3840819e..37e8bb83a7743 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java @@ -22,11 +22,20 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class FuncRefNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public FuncRefNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected FunctionRef funcRef; @@ -39,6 +48,12 @@ public FunctionRef getFuncRef() { return funcRef; } + @Override + public FuncRefNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public FuncRefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java index e5198f244467d..88e66a0fc7786 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -145,6 +146,12 @@ public int getMaxLoopCounter() { return maxLoopCounter; } + @Override + public FunctionNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public FunctionNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java index 465d934f4717b..d3fc99e738057 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -40,7 +41,27 @@ public BlockNode getElseBlockNode() { return elseBlockNode; } - /* ---- end tree structure ---- */ + @Override + public IfElseNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public IfElseNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public IfElseNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public IfElseNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java index 6e131d24903fe..8e1d5fc48f250 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java @@ -21,12 +21,37 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class IfNode extends ConditionNode { + /* ---- begin tree structure ---- */ + + @Override + public IfNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public IfNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public IfNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public IfNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java index 437d7b7fdc0a0..e5f1d5522495d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; @@ -49,6 +50,18 @@ public TypeNode setResolvedTypeNode() { return resolvedTypeNode; } + @Override + public InstanceofNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public InstanceofNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + /* ---- end tree structure, begin node data ---- */ protected boolean isPrimitiveResult; @@ -62,6 +75,12 @@ public boolean isPrimitiveResult() { return isPrimitiveResult; } + @Override + public InstanceofNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public InstanceofNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index 6f904b62e4001..0b8ad80485aab 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -23,14 +23,24 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; +import java.util.Collection; import java.util.List; public class LambdaNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public LambdaNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected List captures; protected FunctionRef funcRef; @@ -40,6 +50,11 @@ public LambdaNode addCapture(Variable capture) { return this; } + public LambdaNode addCaptures(Collection captures) { + this.captures.addAll(captures); + return this; + } + public LambdaNode setCapture(int index, Variable capture) { captures.set(index, capture); return this; @@ -80,7 +95,13 @@ public LambdaNode setFuncRef(FunctionRef funcRef) { public FunctionRef getFuncRef() { return funcRef; } - + + @Override + public LambdaNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public LambdaNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java index 8350c464f855a..684cdfc0a2143 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java @@ -21,15 +21,62 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; +import java.util.Collection; + public class ListInitializationNode extends ArgumentsNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public ListInitializationNode addArgumentNode(ExpressionNode argumentNode) { + super.addArgumentNode(argumentNode); + return this; + } + + @Override + public ListInitializationNode addArgumentNodes(Collection argumentNodes) { + super.addArgumentNodes(argumentNodes); + return this; + } + + @Override + public ListInitializationNode setArgumentNode(int index, ExpressionNode argumentNode) { + super.setArgumentNode(index, argumentNode); + return this; + } + + @Override + public ListInitializationNode removeArgumentNode(ExpressionNode argumentNode) { + super.removeArgumentNode(argumentNode); + return this; + } + + @Override + public ListInitializationNode removeArgumentNode(int index) { + super.removeArgumentNode(index); + return this; + } + + @Override + public ListInitializationNode clearArgumentNodes() { + super.clearArgumentNodes(); + return this; + } + + @Override + public ListInitializationNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected PainlessConstructor constructor; protected PainlessMethod method; @@ -52,6 +99,12 @@ public PainlessMethod getMethod() { return method; } + @Override + public ListInitializationNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public ListInitializationNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java index c595a678f5543..a60aa461af287 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -29,7 +30,21 @@ public class ListSubShortcutNode extends UnaryNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public ListSubShortcutNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public ListSubShortcutNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected PainlessMethod setter; protected PainlessMethod getter; @@ -52,6 +67,12 @@ public PainlessMethod getGetter() { return getter; } + @Override + public ListSubShortcutNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public ListSubShortcutNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java index 099a094196443..9d42857ae3cb9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java @@ -20,10 +20,25 @@ package org.elasticsearch.painless.ir; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; public abstract class LoopNode extends ConditionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public LoopNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public LoopNode setBlockNode(BlockNode blockNode) { + this.blockNode = blockNode; + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected boolean isContinuous; protected Variable loopCounter; @@ -46,6 +61,12 @@ public Variable getLoopCounter() { return loopCounter; } + @Override + public LoopNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public LoopNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java index f015c78f0c03e..621afa8cd5a9d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -88,6 +89,12 @@ public MapInitializationNode clearArgumentNodes() { return this; } + @Override + public MapInitializationNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + /* ---- end tree structure, begin node data ---- */ protected PainlessConstructor constructor; @@ -111,6 +118,12 @@ public PainlessMethod getMethod() { return method; } + @Override + public MapInitializationNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public MapInitializationNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java index d514d198f07ee..4fb2c2cb16d43 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -21,12 +21,27 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; public class MapSubShortcutNode extends UnaryNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public MapSubShortcutNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public MapSubShortcutNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected PainlessMethod setter; protected PainlessMethod getter; @@ -49,6 +64,12 @@ public PainlessMethod getGetter() { return getter; } + @Override + public MapSubShortcutNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public MapSubShortcutNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java index 2fca22a069f46..4d522023525fa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java @@ -22,11 +22,20 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class NewArrayFuncRefNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public NewArrayFuncRefNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected FunctionRef funcRef; @@ -39,6 +48,12 @@ public FunctionRef getFuncRef() { return funcRef; } + @Override + public NewArrayFuncRefNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public NewArrayFuncRefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java index 9c3628e024328..36ac3eea2735f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java @@ -21,11 +21,58 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import java.util.Collection; + public class NewArrayNode extends ArgumentsNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public NewArrayNode addArgumentNode(ExpressionNode argumentNode) { + super.addArgumentNode(argumentNode); + return this; + } + + @Override + public NewArrayNode addArgumentNodes(Collection argumentNodes) { + super.addArgumentNodes(argumentNodes); + return this; + } + + @Override + public NewArrayNode setArgumentNode(int index, ExpressionNode argumentNode) { + super.setArgumentNode(index, argumentNode); + return this; + } + + @Override + public NewArrayNode removeArgumentNode(ExpressionNode argumentNode) { + super.removeArgumentNode(argumentNode); + return this; + } + + @Override + public NewArrayNode removeArgumentNode(int index) { + super.removeArgumentNode(index); + return this; + } + + @Override + public NewArrayNode clearArgumentNodes() { + super.clearArgumentNodes(); + return this; + } + + @Override + public NewArrayNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected boolean initialize; @@ -38,6 +85,12 @@ public boolean getInitialize() { return initialize; } + @Override + public NewArrayNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public NewArrayNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java index 44476b5163293..03657989a8733 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java @@ -21,14 +21,61 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; +import java.util.Collection; + public final class NewObjectNode extends ArgumentsNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public NewObjectNode addArgumentNode(ExpressionNode argumentNode) { + super.addArgumentNode(argumentNode); + return this; + } + + @Override + public NewObjectNode addArgumentNodes(Collection argumentNodes) { + super.addArgumentNodes(argumentNodes); + return this; + } + + @Override + public NewObjectNode setArgumentNode(int index, ExpressionNode argumentNode) { + super.setArgumentNode(index, argumentNode); + return this; + } + + @Override + public NewObjectNode removeArgumentNode(ExpressionNode argumentNode) { + super.removeArgumentNode(argumentNode); + return this; + } + + @Override + public NewObjectNode removeArgumentNode(int index) { + super.removeArgumentNode(index); + return this; + } + + @Override + public NewObjectNode clearArgumentNodes() { + super.clearArgumentNodes(); + return this; + } + + @Override + public NewObjectNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected PainlessConstructor constructor; protected boolean read; @@ -51,6 +98,12 @@ public boolean getRead() { return read; } + @Override + public NewObjectNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public NewObjectNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java index 59ee2b72cf8e0..74577f00c5d92 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java @@ -21,11 +21,30 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; public class NullNode extends ExpressionNode { + /* ---- begin tree structure ---- */ + + @Override + public NullNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public NullNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public NullNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java index da989e2f369b8..3164a0eb10589 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java @@ -21,11 +21,36 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; public class NullSafeSubNode extends UnaryNode { + /* ---- begin tree structure ---- */ + + @Override + public NullSafeSubNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public NullSafeSubNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public NullSafeSubNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public NullSafeSubNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java index 9f9d186f32350..88c62f6e4a040 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java @@ -19,21 +19,44 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + public abstract class PrefixNode extends UnaryNode { /* ---- begin tree structure ---- */ protected ExpressionNode prefixNode; - public void setPrefixNode(ExpressionNode prefixNode) { + public PrefixNode setPrefixNode(ExpressionNode prefixNode) { this.prefixNode = prefixNode; + return this; } public ExpressionNode getPrefixNode() { return prefixNode; } - /* ---- end tree structure ---- */ + @Override + public PrefixNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + @Override + public PrefixNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public PrefixNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public PrefixNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java index c3ecf91ba0d42..f6a1b786981a2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; @@ -29,7 +30,15 @@ public class RegexNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public RegexNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected String pattern; protected int flags; @@ -62,6 +71,12 @@ public Object getConstant() { return constant; } + @Override + public RegexNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public RegexNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java index d0085245098e7..e0427cef0055d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java @@ -21,10 +21,13 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ReturnNode extends StatementNode { + /* ---- begin tree structure ---- */ + protected ExpressionNode expressionNode; public ReturnNode setExpressionNode(ExpressionNode expressionNode) { @@ -36,6 +39,16 @@ public ExpressionNode getExpressionNode() { return expressionNode; } + /* ---- end tree structure, begin node data ---- */ + + @Override + public ReturnNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public ReturnNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java index 4b3a2ed5a8f5b..2f3971b043c08 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java @@ -19,16 +19,17 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + public abstract class ShiftNode extends BinaryNode { - protected TypeNode shiftTypeNode; + /* ---- begin tree structure ---- */ - public ShiftNode() { - // do nothing - } + protected TypeNode shiftTypeNode; - public void setShiftTypeNode(TypeNode shiftTypeNode) { + public ShiftNode setShiftTypeNode(TypeNode shiftTypeNode) { this.shiftTypeNode = shiftTypeNode; + return this; } public TypeNode getShiftTypeNode() { @@ -42,4 +43,36 @@ public Class getShiftType() { public String getShiftCanonicalTypeName() { return shiftTypeNode.getCanonicalTypeName(); } + + @Override + public ShiftNode setLeftNode(ExpressionNode leftNode) { + super.setLeftNode(leftNode); + return this; + } + + @Override + public ShiftNode setRightNode(ExpressionNode rightNode) { + super.setRightNode(rightNode); + return this; + } + + @Override + public ShiftNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public ShiftNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + + public ShiftNode() { + // do nothing + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java index e5825e64d968e..d1bd0e5eb62cc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class StatementExpressionNode extends StatementNode { @@ -51,6 +52,12 @@ public boolean getMethodEscape() { return methodEscape; } + @Override + public StatementExpressionNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public StatementExpressionNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java index cda9353b7dd10..4f4eae7a479e3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java @@ -19,10 +19,21 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; import org.objectweb.asm.Label; public abstract class StatementNode extends IRNode { + /* ---- begin node data ---- */ + + @Override + public StatementNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + protected Label continueLabel = null; protected Label breakLabel = null; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java index 631406a11307e..31a5dc1f90dc2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java @@ -21,10 +21,29 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class StaticNode extends ExpressionNode { + /* ---- begin tree structure ---- */ + + @Override + public StaticNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public StaticNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public StaticNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java index 89c19193bb195..9ddcc132f166f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ThrowNode extends StatementNode { @@ -40,6 +41,14 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure, begin node data ---- */ + @Override + public ThrowNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public ThrowNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java index af916ae8a1e63..23aad69fc70f0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java @@ -21,10 +21,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class TryNode extends StatementNode { @@ -48,6 +50,11 @@ public TryNode addCatchNode(CatchNode catchNode) { return this; } + public TryNode addCatchNodes(Collection catchNodes) { + this.catchNodes.addAll(catchNodes); + return this; + } + public TryNode setCatchNode(int index, CatchNode catchNode) { catchNodes.set(index, catchNode); return this; @@ -80,7 +87,15 @@ public TryNode clearCatchNodes() { return this; } - /* ---- end tree structure ---- */ + /* ---- end tree structure, begin node data ---- */ + + @Override + public TryNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public TryNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java index d688541bf0f78..c973449d10372 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.lookup.PainlessLookupUtility; public class TypeNode extends IRNode { @@ -40,6 +41,12 @@ public String getCanonicalTypeName() { return PainlessLookupUtility.typeToCanonicalTypeName(type); } + @Override + public TypeNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public TypeNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index 8d98dc6a2f478..2139c0f6e83ed 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.def; @@ -31,7 +32,21 @@ public class UnaryMathNode extends UnaryNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public UnaryMathNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + @Override + public UnaryMathNode setChildNode(ExpressionNode childNode) { + super.setChildNode(childNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected Operation operation; protected boolean cat; @@ -64,6 +79,12 @@ public boolean getOriginallyExplicit() { return originallyExplicit; } + @Override + public UnaryMathNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public UnaryMathNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java index 22abb8f6fa1e4..70df3ed6dd2b0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java @@ -19,21 +19,38 @@ package org.elasticsearch.painless.ir; +import org.elasticsearch.painless.Location; + public abstract class UnaryNode extends ExpressionNode { /* ---- begin tree structure ---- */ protected ExpressionNode childNode; - public void setChildNode(ExpressionNode childNode) { + public UnaryNode setChildNode(ExpressionNode childNode) { this.childNode = childNode; + return this; } public ExpressionNode getChildNode() { return childNode; } - /* ---- end tree structure ---- */ + @Override + public UnaryNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public UnaryNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ public UnaryNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java index ff6fd3c6c0db0..d2b19291f5fde 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessClassBinding; import org.elasticsearch.painless.lookup.PainlessInstanceBinding; @@ -30,11 +31,57 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; +import java.util.Collection; + import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; public class UnboundCallNode extends ArgumentsNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public UnboundCallNode addArgumentNode(ExpressionNode argumentNode) { + super.addArgumentNode(argumentNode); + return this; + } + + @Override + public UnboundCallNode addArgumentNodes(Collection argumentNodes) { + super.addArgumentNodes(argumentNodes); + return this; + } + + @Override + public UnboundCallNode setArgumentNode(int index, ExpressionNode argumentNode) { + super.setArgumentNode(index, argumentNode); + return this; + } + + @Override + public UnboundCallNode removeArgumentNode(ExpressionNode argumentNode) { + super.removeArgumentNode(argumentNode); + return this; + } + + @Override + public UnboundCallNode removeArgumentNode(int index) { + super.removeArgumentNode(index); + return this; + } + + @Override + public UnboundCallNode clearArgumentNodes() { + super.clearArgumentNodes(); + return this; + } + + @Override + public UnboundCallNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected LocalFunction localFunction; protected PainlessMethod importedMethod; @@ -97,6 +144,12 @@ public String getBindingName() { return bindingName; } + @Override + public UnboundCallNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public UnboundCallNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java index dd2b30ed5936d..5b15527f9205d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java @@ -22,12 +22,21 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; public class VariableNode extends ExpressionNode { - /* ---- begin node data ---- */ + /* ---- begin tree structure ---- */ + + @Override + public VariableNode setTypeNode(TypeNode typeNode) { + super.setTypeNode(typeNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ protected Variable variable; @@ -40,6 +49,12 @@ public Variable getVariable() { return variable; } + @Override + public VariableNode setLocation(Location location) { + super.setLocation(location); + return this; + } + /* ---- end node data ---- */ public VariableNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java index 67ce56a314e85..e229162fd09cc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java @@ -21,12 +21,50 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; +import org.elasticsearch.painless.Locals; +import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class WhileNode extends LoopNode { + /* ---- begin tree structure ---- */ + + @Override + public WhileNode setConditionNode(ExpressionNode conditionNode) { + super.setConditionNode(conditionNode); + return this; + } + + @Override + public WhileNode setBlockNode(BlockNode blockNode) { + super.setBlockNode(blockNode); + return this; + } + + /* ---- end tree structure, begin node data ---- */ + + @Override + public WhileNode setContinuous(boolean isContinuous) { + super.setContinuous(isContinuous); + return this; + } + + @Override + public WhileNode setLoopCounter(Locals.Variable loopCounter) { + super.setLoopCounter(loopCounter); + return this; + } + + @Override + public WhileNode setLocation(Location location) { + super.setLocation(location); + return this; + } + + /* ---- end node data ---- */ + public WhileNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java index 8598280bf6ee0..b59ea77e8c8a6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java @@ -76,5 +76,11 @@ public String getNextSyntheticName(String prefix) { return prefix + "$synthetic$" + syntheticCounter++; } - public void markNonDeterministic(boolean nondeterministic) { this.deterministic &= !nondeterministic; } + public void markNonDeterministic(boolean nondeterministic) { + this.deterministic &= !nondeterministic; + } + + public boolean isDeterministic() { + return deterministic; + } } From a9118e7068bfa5713fdaebf46799b62d60ac02fe Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 24 Dec 2019 14:23:41 -0800 Subject: [PATCH 17/24] build ir tree from ast --- .../org/elasticsearch/painless/Compiler.java | 13 +- .../elasticsearch/painless/ir/CatchNode.java | 6 +- .../painless/ir/ComparisonNode.java | 59 ++-- .../painless/ir/ConstantNode.java | 2 +- .../painless/ir/DeclarationNode.java | 4 +- .../elasticsearch/painless/ir/FieldNode.java | 3 +- .../painless/ir/ForEachSubArrayNode.java | 2 +- .../painless/ir/FunctionNode.java | 5 + .../painless/ir/InstanceofNode.java | 10 +- .../painless/ir/UnaryMathNode.java | 19 ++ .../painless/node/AExpression.java | 8 +- .../elasticsearch/painless/node/ANode.java | 6 +- .../painless/node/AStatement.java | 19 +- .../painless/node/AStoreable.java | 56 ---- .../painless/node/DResolvedType.java | 10 + .../painless/node/EAssignment.java | 117 ++----- .../elasticsearch/painless/node/EBinary.java | 77 ++--- .../elasticsearch/painless/node/EBool.java | 51 +-- .../elasticsearch/painless/node/EBoolean.java | 6 +- .../painless/node/ECallLocal.java | 90 ++---- .../painless/node/ECapturingFunctionRef.java | 38 +-- .../elasticsearch/painless/node/ECast.java | 20 +- .../elasticsearch/painless/node/EComp.java | 137 +------- .../painless/node/EConditional.java | 31 +- .../painless/node/EConstant.java | 26 +- .../elasticsearch/painless/node/EDecimal.java | 6 +- .../elasticsearch/painless/node/EElvis.java | 26 +- .../painless/node/EExplicit.java | 6 +- .../painless/node/EFunctionRef.java | 21 +- .../painless/node/EInstanceof.java | 38 +-- .../elasticsearch/painless/node/ELambda.java | 36 +-- .../painless/node/EListInit.java | 32 +- .../elasticsearch/painless/node/EMapInit.java | 36 +-- .../painless/node/ENewArray.java | 43 +-- .../painless/node/ENewArrayFunctionRef.java | 21 +- .../elasticsearch/painless/node/ENewObj.java | 31 +- .../elasticsearch/painless/node/ENull.java | 17 +- .../elasticsearch/painless/node/ENumeric.java | 6 +- .../elasticsearch/painless/node/ERegex.java | 21 +- .../elasticsearch/painless/node/EStatic.java | 14 +- .../elasticsearch/painless/node/EString.java | 6 +- .../elasticsearch/painless/node/EUnary.java | 85 +---- .../painless/node/EVariable.java | 36 +-- .../elasticsearch/painless/node/PBrace.java | 40 +-- .../painless/node/PCallInvoke.java | 19 +- .../elasticsearch/painless/node/PField.java | 40 +-- .../painless/node/PSubArrayLength.java | 35 +- .../painless/node/PSubBrace.java | 40 +-- .../painless/node/PSubCallInvoke.java | 26 +- .../painless/node/PSubDefArray.java | 53 +-- .../painless/node/PSubDefCall.java | 36 +-- .../painless/node/PSubDefField.java | 50 +-- .../painless/node/PSubField.java | 62 +--- .../painless/node/PSubListShortcut.java | 51 +-- .../painless/node/PSubMapShortcut.java | 53 +-- .../painless/node/PSubNullSafeCallInvoke.java | 21 +- .../painless/node/PSubNullSafeField.java | 40 +-- .../painless/node/PSubShortcut.java | 54 +--- .../elasticsearch/painless/node/SBlock.java | 17 +- .../elasticsearch/painless/node/SBreak.java | 9 +- .../elasticsearch/painless/node/SCatch.java | 32 +- .../elasticsearch/painless/node/SClass.java | 301 ++---------------- .../painless/node/SContinue.java | 9 +- .../painless/node/SDeclBlock.java | 15 +- .../painless/node/SDeclaration.java | 33 +- .../org/elasticsearch/painless/node/SDo.java | 39 +-- .../elasticsearch/painless/node/SEach.java | 13 +- .../painless/node/SExpression.java | 18 +- .../elasticsearch/painless/node/SField.java | 24 +- .../org/elasticsearch/painless/node/SFor.java | 73 +---- .../painless/node/SFunction.java | 50 +-- .../org/elasticsearch/painless/node/SIf.java | 24 +- .../elasticsearch/painless/node/SIfElse.java | 36 +-- .../elasticsearch/painless/node/SReturn.java | 18 +- .../painless/node/SSubEachArray.java | 59 ++-- .../painless/node/SSubEachIterable.java | 62 +--- .../elasticsearch/painless/node/SThrow.java | 12 +- .../org/elasticsearch/painless/node/STry.java | 36 +-- .../elasticsearch/painless/node/SWhile.java | 45 +-- 79 files changed, 814 insertions(+), 2027 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java index b6a30fc7c34fc..f7418df9d8e74 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java @@ -21,6 +21,7 @@ import org.elasticsearch.bootstrap.BootstrapInfo; import org.elasticsearch.painless.antlr.Walker; +import org.elasticsearch.painless.ir.ClassNode; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.node.SClass; import org.elasticsearch.painless.spi.Whitelist; @@ -213,13 +214,14 @@ ScriptRoot compile(Loader loader, Set extractedVariables, String name, S SClass root = Walker.buildPainlessTree(scriptClassInfo, name, source, settings, painlessLookup, null); root.extractVariables(extractedVariables); ScriptRoot scriptRoot = root.analyze(painlessLookup, settings); - Map statics = root.write(); + ClassNode classNode = root.writeClass(); + Map statics = classNode.write(); try { - Class clazz = loader.defineScript(CLASS_NAME, root.getBytes()); + Class clazz = loader.defineScript(CLASS_NAME, classNode.getBytes()); clazz.getField("$NAME").set(null, name); clazz.getField("$SOURCE").set(null, source); - clazz.getField("$STATEMENTS").set(null, root.getStatements()); + clazz.getField("$STATEMENTS").set(null, classNode.getStatements()); clazz.getField("$DEFINITION").set(null, painlessLookup); for (Map.Entry statik : statics.entrySet()) { @@ -245,8 +247,9 @@ byte[] compile(String name, String source, CompilerSettings settings, Printer de debugStream); root.extractVariables(new HashSet<>()); root.analyze(painlessLookup, settings); - root.write(); + ClassNode classNode = root.writeClass(); + classNode.write(); - return root.getBytes(); + return classNode.getBytes(); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index 1ea907fa9ed50..b8fbda1a1d782 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -77,8 +77,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.mark(jump); methodWriter.visitVarInsn(MethodWriter.getType( - declarationNode.getCaptured().clazz).getOpcode(Opcodes.ISTORE), - declarationNode.getCaptured().getSlot()); + declarationNode.getVariable().clazz).getOpcode(Opcodes.ISTORE), + declarationNode.getVariable().getSlot()); if (blockNode != null) { blockNode.continueLabel = continueLabel; @@ -86,7 +86,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals blockNode.write(classWriter, methodWriter, globals); } - methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declarationNode.getCaptured().clazz).getInternalName()); + methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declarationNode.getVariable().clazz).getInternalName()); if (exception != null && (blockNode == null || blockNode.doAllEscape() == false)) { methodWriter.goTo(exception); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index 4e2a443b064a4..cbff1b9c088eb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -25,7 +25,6 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Type; @@ -37,6 +36,25 @@ public class ComparisonNode extends BinaryNode { /* ---- begin tree structure ---- */ + protected TypeNode comparisonTypeNode; + + public ComparisonNode setComparisonTypeNode(TypeNode comparisonTypeNode) { + this.comparisonTypeNode = comparisonTypeNode; + return this; + } + + public TypeNode getComparisonTypeNode() { + return comparisonTypeNode; + } + + public Class getComparisonType() { + return comparisonTypeNode.getType(); + } + + public String getComparisonCanonicalTypeName() { + return comparisonTypeNode.getCanonicalTypeName(); + } + @Override public ComparisonNode setLeftNode(ExpressionNode leftNode) { super.setLeftNode(leftNode); @@ -102,31 +120,32 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals boolean writejump = true; - Class type = getType(); - Type asmType = MethodWriter.getType(type); + Class comparisonType = getComparisonType(); + Type asmComparisonType = MethodWriter.getType(comparisonType); - if (type == void.class || type == byte.class || type == short.class || type == char.class) { - throw new IllegalStateException("unexpected type [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "] for comparison"); - } else if (type == boolean.class) { - if (eq) methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(asmType, MethodWriter.NE, jump); + if (comparisonType == void.class || comparisonType == byte.class || comparisonType == short.class || comparisonType == char.class) { + throw new IllegalStateException("unexpected type [" + getComparisonCanonicalTypeName() + "] for comparison"); + } else if (comparisonType == boolean.class) { + if (eq) methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + "for type [" + getCanonicalTypeName() + "]"); } - } else if (type == int.class || type == long.class || type == float.class || type == double.class) { - if (eq) methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(asmType, MethodWriter.NE, jump); - else if (lt) methodWriter.ifCmp(asmType, MethodWriter.LT, jump); - else if (lte) methodWriter.ifCmp(asmType, MethodWriter.LE, jump); - else if (gt) methodWriter.ifCmp(asmType, MethodWriter.GT, jump); - else if (gte) methodWriter.ifCmp(asmType, MethodWriter.GE, jump); + } else if (comparisonType == int.class || comparisonType == long.class + || comparisonType == float.class || comparisonType == double.class) { + if (eq) methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); + else if (lt) methodWriter.ifCmp(asmComparisonType, MethodWriter.LT, jump); + else if (lte) methodWriter.ifCmp(asmComparisonType, MethodWriter.LE, jump); + else if (gt) methodWriter.ifCmp(asmComparisonType, MethodWriter.GT, jump); + else if (gte) methodWriter.ifCmp(asmComparisonType, MethodWriter.GE, jump); else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + "for type [" + getCanonicalTypeName() + "]"); } - } else if (type == def.class) { + } else if (comparisonType == def.class) { Type booleanType = Type.getType(boolean.class); Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(leftNode.getType()), MethodWriter.getType(rightNode.getType())); @@ -138,7 +157,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); writejump = false; } else { - methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); + methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); } } else if (ne) { if (rightNode instanceof NullNode) { @@ -147,7 +166,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { - methodWriter.ifCmp(asmType, MethodWriter.NE, jump); + methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); } } else if (lt) { methodWriter.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); @@ -173,7 +192,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); writejump = false; } else { - methodWriter.ifCmp(asmType, MethodWriter.EQ, jump); + methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); } } else if (ne) { if (rightNode instanceof NullNode) { @@ -182,7 +201,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { - methodWriter.ifCmp(asmType, MethodWriter.NE, jump); + methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); } } else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java index 148487709c205..296eab6cbe074 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -55,7 +55,7 @@ public ConstantNode setLocation(Location location) { /* ---- end node data ---- */ - ConstantNode() { + public ConstantNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index b0f2227f56d67..34fed3882317a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -45,12 +45,12 @@ public ExpressionNode getExpressionNode() { protected Variable variable; - public DeclarationNode setCaptured(Variable variable) { + public DeclarationNode setVariable(Variable variable) { this.variable = variable; return this; } - public Variable getCaptured() { + public Variable getVariable() { return variable; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java index 3641ff7bb67b5..b66d539b6133e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -31,8 +31,9 @@ public class FieldNode extends IRNode { protected TypeNode typeNode; - public void setTypeNode(TypeNode typeNode) { + public FieldNode setTypeNode(TypeNode typeNode) { this.typeNode = typeNode; + return this; } public TypeNode getTypeNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java index da5c19d983dc3..dfeeb64ba53f8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java @@ -126,7 +126,7 @@ public ForEachSubArrayNode setLocation(Location location) { /* ---- end node data ---- */ - ForEachSubArrayNode() { + public ForEachSubArrayNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java index 88e66a0fc7786..342a493770f5c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -78,6 +78,11 @@ public FunctionNode addTypeParameter(Class typeParameter) { return this; } + public FunctionNode addTypeParameters(List> typeParameters) { + this.typeParameters.addAll(typeParameters); + return this; + } + public FunctionNode setTypeParameter(int index, Class typeParameter) { typeParameters.set(index, typeParameter); return this; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java index e5f1d5522495d..3ee6bfab688e9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -37,16 +37,16 @@ public InstanceofNode setExpressionTypeNode(TypeNode expressionTypeNode) { return this; } + public TypeNode getExpressionTypeNode() { + return expressionTypeNode; + } + public InstanceofNode setResolvedTypeNode(TypeNode resolvedTypeNode) { this.resolvedTypeNode = resolvedTypeNode; return this; } - public TypeNode setExpressionTypeNode() { - return expressionTypeNode; - } - - public TypeNode setResolvedTypeNode() { + public TypeNode getResolvedTypeNode() { return resolvedTypeNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index 2139c0f6e83ed..971420a245abd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -34,6 +34,25 @@ public class UnaryMathNode extends UnaryNode { /* ---- begin tree structure ---- */ + protected TypeNode unaryTypeNode; + + public UnaryMathNode setUnaryTypeNode(TypeNode unaryTypeNode) { + this.unaryTypeNode = unaryTypeNode; + return this; + } + + public TypeNode getUnaryTypeNode() { + return unaryTypeNode; + } + + public Class getUnaryType() { + return unaryTypeNode.getType(); + } + + public String getUnaryCanonicalTypeName() { + return unaryTypeNode.getCanonicalTypeName(); + } + @Override public UnaryMathNode setTypeNode(TypeNode typeNode) { super.setTypeNode(typeNode); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java index 3fa62b8454ed8..8d58e41874330 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java @@ -22,9 +22,10 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ExpressionNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -113,6 +114,11 @@ public abstract class AExpression extends ANode { this.prefix = Objects.requireNonNull(prefix); } + /** + * Writes ASM based on the data collected during the analysis phase. + */ + abstract ExpressionNode write(); + /** * Inserts {@link ECast} nodes into the tree for implicit casts. Also replaces * nodes with the constant variable set to a non-null value with {@link EConstant}. diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java index 8053ae28fe177..8ae2a57a362a1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.IRNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.ArrayList; @@ -71,7 +69,7 @@ public abstract class ANode { /** * Writes ASM based on the data collected during the analysis phase. */ - abstract void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals); + abstract IRNode write(); /** * Create an error with location information pointing to this node. diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStatement.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStatement.java index 629449c1a58bf..57316cd995935 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStatement.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStatement.java @@ -21,7 +21,7 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.objectweb.asm.Label; +import org.elasticsearch.painless.ir.StatementNode; /** * The superclass for all S* (statement) nodes. @@ -95,22 +95,15 @@ public abstract class AStatement extends ANode { */ int statementCount = 0; - /** - * Set to the beginning of a loop so a continue statement knows where to - * jump to. Only used during the writing phase. - */ - Label continu = null; - - /** - * Set to the beginning of a loop so a break statement knows where to - * jump to. Only used during the writing phase. - */ - Label brake = null; - /** * Standard constructor with location used for error tracking. */ AStatement(Location location) { super(location); } + + /** + * Writes ASM based on the data collected during the analysis phase. + */ + abstract StatementNode write(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStoreable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStoreable.java index 7299a14677d9e..7f5beda267959 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStoreable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStoreable.java @@ -19,15 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; -import java.util.function.Consumer; /** * The super class for an expression that can store a value in local memory. @@ -58,23 +52,6 @@ abstract class AStoreable extends AExpression { this.prefix = Objects.requireNonNull(prefix); } - /** - * Returns a value based on the number of elements previously placed on the - * stack to load/store a certain piece of a variable/method chain. This is - * used during the writing phase to dup stack values from this storeable as - * necessary during certain store operations. - *

- * Examples: - * {@link EVariable} returns 0 because it requires nothing extra to perform - * a load/store - * {@link PSubField} returns 1 because it requires the name of the field as - * an index on the stack to perform a load/store - * {@link PSubBrace} returns 2 because it requires both the variable slot and - * an index into the array on the stack to perform a - * load/store - */ - abstract int accessElementCount(); - /** * Returns true if this node or a sub-node of this node can be optimized with * rhs actual type to avoid an unnecessary cast. @@ -87,37 +64,4 @@ abstract class AStoreable extends AExpression { * during assignment to def type targets. */ abstract void updateActual(Class actual); - - /** - * Called before a storeable node is loaded or stored. Used to load prefixes and - * push load/store constants onto the stack if necessary. - */ - abstract void setup(ClassWriter classWriter, MethodWriter writer, Globals globals); - - /** - * Called to load a storable used for compound assignments. - */ - abstract void load(ClassWriter classWriter, MethodWriter writer, Globals globals); - - /** - * Called to store a storabable to local memory. - */ - abstract void store(ClassWriter classWriter, MethodWriter writer, Globals globals); - - /** - * Writes the opcodes to flip a negative array index (meaning slots from the end of the array) into a 0-based one (meaning slots from - * the start of the array). - */ - static void writeIndexFlip(MethodWriter writer, Consumer writeGetLength) { - Label noFlip = new Label(); - // Everywhere when it says 'array' below that could also be a list - // The stack after each instruction: array, unnormalized_index - writer.dup(); // array, unnormalized_index, unnormalized_index - writer.ifZCmp(Opcodes.IFGE, noFlip); // array, unnormalized_index - writer.swap(); // negative_index, array - writer.dupX1(); // array, negative_index, array - writeGetLength.accept(writer); // array, negative_index, length - writer.visitInsn(Opcodes.IADD); // array, noralized_index - writer.mark(noFlip); // array, noralized_index - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java index c1917944f260e..f3e8a9c950f53 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java @@ -20,6 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupUtility; @@ -74,6 +75,15 @@ public Class getType() { return type; } + /** + * Writes ASM based on the data collected during the analysis phase. + */ + TypeNode write() { + return new TypeNode() + .setLocation(location) + .setType(type); + } + @Override public String toString() { return "(DResolvedType [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "])"; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index 74c0288297e25..c494a846e936e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -21,16 +21,14 @@ import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.AssignmentNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.ArrayList; import java.util.List; @@ -241,99 +239,22 @@ private void analyzeSimple(ScriptRoot scriptRoot, Locals locals) { * also read from. */ @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - // For the case where the assignment represents a String concatenation - // we must, depending on the Java version, write a StringBuilder or - // track types going onto the stack. This must be done before the - // lhs is read because we need the StringBuilder to be placed on the - // stack ahead of any potential concatenation arguments. - int catElementStackSize = 0; - - if (cat) { - catElementStackSize = methodWriter.writeNewStrings(); - } - - // Cast the lhs to a storeable to perform the necessary operations to store the rhs. - AStoreable lhs = (AStoreable)this.lhs; - lhs.setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation - - if (cat) { - // Handle the case where we are doing a compound assignment - // representing a String concatenation. - - methodWriter.writeDup(lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it - // before concat helper on stack - lhs.load(classWriter, methodWriter, globals); // read the current lhs's value - methodWriter.writeAppendStrings(lhs.actual); // append the lhs's value using the StringBuilder - - rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs - - if (!(rhs instanceof EBinary) || !((EBinary)rhs).cat) { // check to see if the rhs has already done a concatenation - methodWriter.writeAppendStrings(rhs.actual); // append the rhs's value since it's hasn't already - } - - methodWriter.writeToStrings(); // put the value for string concat onto the stack - methodWriter.writeCast(back); // if necessary, cast the String to the lhs actual type - - if (lhs.read) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // if this lhs is also read - // from dup the value onto the stack - } - - lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array - } else if (operation != null) { - // Handle the case where we are doing a compound assignment that - // does not represent a String concatenation. - - methodWriter.writeDup(lhs.accessElementCount(), 0); // if necessary, dup the previous lhs's value - // to be both loaded from and stored to - lhs.load(classWriter, methodWriter, globals); // load the current lhs's value - - if (lhs.read && post) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the - // lhs is also - // read from and is a post - // increment - } - - methodWriter.writeCast(there); // if necessary cast the current lhs's value - // to the promotion type between the lhs and rhs types - rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs - - // XXX: fix these types, but first we need def compound assignment tests. - // its tricky here as there are possibly explicit casts, too. - // write the operation instruction for compound assignment - if (promote == def.class) { - methodWriter.writeDynamicBinaryInstruction( - location, promote, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); - } else { - methodWriter.writeBinaryInstruction(location, promote, operation); - } - - methodWriter.writeCast(back); // if necessary cast the promotion type value back to the lhs's type - - if (lhs.read && !post) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs - // is also - // read from and is not a post - // increment - } - - lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array - } else { - // Handle the case for a simple write. - - rhs.write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs - - if (lhs.read) { - methodWriter.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs - // is also read from - } - - lhs.store(classWriter, methodWriter, globals); // store the lhs's value from the stack in its respective variable/field/array - } + AssignmentNode write() { + return new AssignmentNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLeftNode(lhs.write()) + .setRightNode(rhs.write()) + .setLocation(location) + .setPre(pre) + .setPost(post) + .setOperation(operation) + .setRead(read) + .setCat(cat) + .setThere(there) + .setBack(back); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index b0abae3ba7d2d..1902d4889546a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -20,21 +20,17 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.symbol.ScriptRoot; -import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.ir.BinaryMathNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -621,57 +617,22 @@ private void analyzeBWOr(ScriptRoot scriptRoot, Locals variables) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (promote == String.class && operation == Operation.ADD) { - if (!cat) { - methodWriter.writeNewStrings(); - } - - left.write(classWriter, methodWriter, globals); - - if (!(left instanceof EBinary) || !((EBinary)left).cat) { - methodWriter.writeAppendStrings(left.actual); - } - - right.write(classWriter, methodWriter, globals); - - if (!(right instanceof EBinary) || !((EBinary)right).cat) { - methodWriter.writeAppendStrings(right.actual); - } - - if (!cat) { - methodWriter.writeToStrings(); - } - } else if (operation == Operation.FIND || operation == Operation.MATCH) { - right.write(classWriter, methodWriter, globals); - left.write(classWriter, methodWriter, globals); - methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER); - - if (operation == Operation.FIND) { - methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_FIND); - } else if (operation == Operation.MATCH) { - methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_MATCHES); - } else { - throw new IllegalStateException("Illegal tree structure."); - } - } else { - left.write(classWriter, methodWriter, globals); - right.write(classWriter, methodWriter, globals); - - if (promote == def.class || (shiftDistance != null && shiftDistance == def.class)) { - // def calls adopt the wanted return value. if there was a narrowing cast, - // we need to flag that so that its done at runtime. - int flags = 0; - if (originallyExplicit) { - flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; - } - methodWriter.writeDynamicBinaryInstruction(location, actual, left.actual, right.actual, operation, flags); - } else { - methodWriter.writeBinaryInstruction(location, actual, operation); - } - } + BinaryMathNode write() { + return new BinaryMathNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLeftNode(left.write()) + .setRightNode(right.write()) + .setShiftTypeNode(new TypeNode() + .setLocation(location) + .setType(shiftDistance) + ) + .setLocation(location) + .setOperation(operation) + .setCat(cat) + .setOriginallExplicit(originallyExplicit); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java index f9052e1649b65..eaf1cc193ce50 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java @@ -19,15 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.ir.BooleanNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -79,40 +76,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (operation == Operation.AND) { - Label fals = new Label(); - Label end = new Label(); - - left.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - right.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - methodWriter.push(true); - methodWriter.goTo(end); - methodWriter.mark(fals); - methodWriter.push(false); - methodWriter.mark(end); - } else if (operation == Operation.OR) { - Label tru = new Label(); - Label fals = new Label(); - Label end = new Label(); - - left.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFNE, tru); - right.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - methodWriter.mark(tru); - methodWriter.push(true); - methodWriter.goTo(end); - methodWriter.mark(fals); - methodWriter.push(false); - methodWriter.mark(end); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } + BooleanNode write() { + return new BooleanNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLeftNode(left.write()) + .setRightNode(right.write()) + .setLocation(location) + .setOperation(operation); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java index 4f3f78e075d59..9bc8f5f18fb9f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ExpressionNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -54,7 +52,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter adapter, Globals globals) { + ExpressionNode write() { throw createError(new IllegalStateException("Illegal tree structure.")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java index 4033d42feb1b0..adaaecac126bb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java @@ -19,20 +19,16 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.TypeNode; +import org.elasticsearch.painless.ir.UnboundCallNode; import org.elasticsearch.painless.lookup.PainlessClassBinding; import org.elasticsearch.painless.lookup.PainlessInstanceBinding; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; import org.elasticsearch.painless.symbol.FunctionTable; -import org.objectweb.asm.Label; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -40,8 +36,6 @@ import java.util.Objects; import java.util.Set; -import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; - /** * Represents a user-defined call. */ @@ -164,69 +158,25 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (localFunction != null) { - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod()); - } else if (importedMethod != null) { - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - methodWriter.invokeStatic(Type.getType(importedMethod.targetClass), - new Method(importedMethod.javaMethod.getName(), importedMethod.methodType.toMethodDescriptorString())); - } else if (classBinding != null) { - Type type = Type.getType(classBinding.javaConstructor.getDeclaringClass()); - int javaConstructorParameterCount = classBinding.javaConstructor.getParameterCount() - classBindingOffset; - - Label nonNull = new Label(); - - methodWriter.loadThis(); - methodWriter.getField(CLASS_TYPE, bindingName, type); - methodWriter.ifNonNull(nonNull); - methodWriter.loadThis(); - methodWriter.newInstance(type); - methodWriter.dup(); - - if (classBindingOffset == 1) { - methodWriter.loadThis(); - } + UnboundCallNode write() { + UnboundCallNode unboundCallNode = new UnboundCallNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setLocalFunction(localFunction) + .setImportedMethod(importedMethod) + .setClassBinding(classBinding) + .setClassBindingOffset(classBindingOffset) + .setBindingName(bindingName) + .setInstanceBinding(instanceBinding); - for (int argument = 0; argument < javaConstructorParameterCount; ++argument) { - arguments.get(argument).write(classWriter, methodWriter, globals); - } - - methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor)); - methodWriter.putField(CLASS_TYPE, bindingName, type); - - methodWriter.mark(nonNull); - methodWriter.loadThis(); - methodWriter.getField(CLASS_TYPE, bindingName, type); - - for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) { - arguments.get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); - } - - methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod)); - } else if (instanceBinding != null) { - Type type = Type.getType(instanceBinding.targetInstance.getClass()); - - methodWriter.loadThis(); - methodWriter.getStatic(CLASS_TYPE, bindingName, type); - - for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) { - arguments.get(argument).write(classWriter, methodWriter, globals); - } - - methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod)); - } else { - throw new IllegalStateException("Illegal tree structure."); + for (AExpression argument : arguments) { + unboundCallNode.addArgumentNode(argument.write()); } + + return unboundCallNode; } @Override 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 d269e5c20bb23..007d0d07f700d 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 @@ -19,19 +19,15 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.CapturingFuncRefNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; import java.util.List; @@ -85,23 +81,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - if (defPointer != null) { - // dynamic interface: push captured parameter on stack - // TODO: don't do this: its just to cutover :) - methodWriter.push((String)null); - methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - } else if (ref == null) { - // typed interface, dynamic implementation - methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - Type methodType = Type.getMethodType(MethodWriter.getType(expected), MethodWriter.getType(captured.clazz)); - methodWriter.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookupUtility.typeToCanonicalTypeName(expected)); - } else { - // typed interface, typed implementation - methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - methodWriter.invokeLambdaCall(ref); - } + CapturingFuncRefNode write() { + return new CapturingFuncRefNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setCaptured(captured) + .setName(call) + .setPointer(defPointer) + .setFuncRef(ref); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index b423d7069ed1f..5ee6e17e91269 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -19,14 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.CastNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -57,10 +56,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - child.write(classWriter, methodWriter, globals); - methodWriter.writeDebugInfo(location); - methodWriter.writeCast(cast); + CastNode write() { + return new CastNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(child.write()) + .setLocation(location) + .setCast(cast); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 4048cf7fcadcb..2f8f1739aebaa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -20,25 +20,18 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ComparisonNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Label; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; -import static org.elasticsearch.painless.WriterConstants.EQUALS; -import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE; - /** * Represents a comparison expression. */ @@ -430,116 +423,20 @@ private void analyzeLT(ScriptRoot scriptRoot, Locals variables) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - left.write(classWriter, methodWriter, globals); - - if (!right.isNull) { - right.write(classWriter, methodWriter, globals); - } - - Label jump = new Label(); - Label end = new Label(); - - boolean eq = (operation == Operation.EQ || operation == Operation.EQR); - boolean ne = (operation == Operation.NE || operation == Operation.NER); - boolean lt = operation == Operation.LT; - boolean lte = operation == Operation.LTE; - boolean gt = operation == Operation.GT; - boolean gte = operation == Operation.GTE; - - boolean writejump = true; - - Type type = MethodWriter.getType(promotedType); - - if (promotedType == void.class || promotedType == byte.class || promotedType == short.class || promotedType == char.class) { - throw createError(new IllegalStateException("Illegal tree structure.")); - } else if (promotedType == boolean.class) { - if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); - else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } else if (promotedType == int.class || promotedType == long.class || promotedType == float.class || promotedType == double.class) { - if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); - else if (lt) methodWriter.ifCmp(type, MethodWriter.LT, jump); - else if (lte) methodWriter.ifCmp(type, MethodWriter.LE, jump); - else if (gt) methodWriter.ifCmp(type, MethodWriter.GT, jump); - else if (gte) methodWriter.ifCmp(type, MethodWriter.GE, jump); - else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - } else if (promotedType == def.class) { - Type booleanType = Type.getType(boolean.class); - Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(left.actual), MethodWriter.getType(right.actual)); - - if (eq) { - if (right.isNull) { - methodWriter.ifNull(jump); - } else if (!left.isNull && operation == Operation.EQ) { - methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); - writejump = false; - } else { - methodWriter.ifCmp(type, MethodWriter.EQ, jump); - } - } else if (ne) { - if (right.isNull) { - methodWriter.ifNonNull(jump); - } else if (!left.isNull && operation == Operation.NE) { - methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); - methodWriter.ifZCmp(MethodWriter.EQ, jump); - } else { - methodWriter.ifCmp(type, MethodWriter.NE, jump); - } - } else if (lt) { - methodWriter.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); - writejump = false; - } else if (lte) { - methodWriter.invokeDefCall("lte", descriptor, DefBootstrap.BINARY_OPERATOR, 0); - writejump = false; - } else if (gt) { - methodWriter.invokeDefCall("gt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); - writejump = false; - } else if (gte) { - methodWriter.invokeDefCall("gte", descriptor, DefBootstrap.BINARY_OPERATOR, 0); - writejump = false; - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } else { - if (eq) { - if (right.isNull) { - methodWriter.ifNull(jump); - } else if (operation == Operation.EQ) { - methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); - writejump = false; - } else { - methodWriter.ifCmp(type, MethodWriter.EQ, jump); - } - } else if (ne) { - if (right.isNull) { - methodWriter.ifNonNull(jump); - } else if (operation == Operation.NE) { - methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); - methodWriter.ifZCmp(MethodWriter.EQ, jump); - } else { - methodWriter.ifCmp(type, MethodWriter.NE, jump); - } - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } - - if (writejump) { - methodWriter.push(false); - methodWriter.goTo(end); - methodWriter.mark(jump); - methodWriter.push(true); - methodWriter.mark(end); - } + ComparisonNode write() { + return new ComparisonNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLeftNode(left.write()) + .setRightNode(right.write()) + .setComparisonTypeNode(new TypeNode() + .setLocation(location) + .setType(promotedType) + ) + .setLocation(location) + .setOperation(operation); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java index fb3ad1846b8a5..849cfa05e53f6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java @@ -20,14 +20,11 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ConditionalNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -90,20 +87,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Label fals = new Label(); - Label end = new Label(); - - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - left.write(classWriter, methodWriter, globals); - methodWriter.goTo(end); - methodWriter.mark(fals); - right.write(classWriter, methodWriter, globals); - methodWriter.mark(end); + ConditionalNode write() { + return new ConditionalNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLeftNode(left.write()) + .setRightNode(right.write()) + .setConditionNode(condition.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java index 3378710c1ea1a..4064a08232491 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java @@ -19,11 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ConstantNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -71,19 +70,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (actual == String.class) methodWriter.push((String)constant); - else if (actual == double.class) methodWriter.push((double)constant); - else if (actual == float.class) methodWriter.push((float)constant); - else if (actual == long.class) methodWriter.push((long)constant); - else if (actual == int.class) methodWriter.push((int)constant); - else if (actual == char.class) methodWriter.push((char)constant); - else if (actual == short.class) methodWriter.push((short)constant); - else if (actual == byte.class) methodWriter.push((byte)constant); - else if (actual == boolean.class) methodWriter.push((boolean)constant); - else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } + ConstantNode write() { + return new ConstantNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setConstant(constant); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java index f57cf2d43d5e2..35bf201445b04 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ExpressionNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -75,7 +73,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + ExpressionNode write() { throw createError(new IllegalStateException("Illegal tree structure.")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java index a423f85e147ee..56b347c590e36 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java @@ -20,13 +20,11 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ElvisNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; import java.util.Set; @@ -94,17 +92,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Label end = new Label(); - - lhs.write(classWriter, methodWriter, globals); - methodWriter.dup(); - methodWriter.ifNonNull(end); - methodWriter.pop(); - rhs.write(classWriter, methodWriter, globals); - methodWriter.mark(end); + ElvisNode write() { + return new ElvisNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLeftNode(lhs.write()) + .setRightNode(rhs.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java index 933464b41a94b..05b1091542876 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ExpressionNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -64,7 +62,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + ExpressionNode write() { throw createError(new IllegalStateException("Illegal tree structure.")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index 9eb4fb178de12..f4aae11cf5d21 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -19,12 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.FuncRefNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; @@ -68,14 +67,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (ref != null) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeLambdaCall(ref); - } else { - // TODO: don't do this: its just to cutover :) - methodWriter.push((String)null); - } + FuncRefNode write() { + return new FuncRefNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setFuncRef(ref); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java index 2dee22125249b..a7f2357443c05 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java @@ -19,13 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.InstanceofNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -82,20 +81,23 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // primitive types - if (primitiveExpression) { - // run the expression anyway (who knows what it does) - expression.write(classWriter, methodWriter, globals); - // discard its result - methodWriter.writePop(MethodWriter.getType(expression.actual).getSize()); - // push our result: its a primitive so it cannot be null. - methodWriter.push(resolvedType.isAssignableFrom(expressionType)); - } else { - // ordinary instanceof - expression.write(classWriter, methodWriter, globals); - methodWriter.instanceOf(org.objectweb.asm.Type.getType(resolvedType)); - } + InstanceofNode write() { + return new InstanceofNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(expression.write()) + .setExpressionTypeNode(new TypeNode() + .setLocation(location) + .setType(expressionType) + ) + .setResolvedTypeNode(new TypeNode() + .setLocation(location) + .setType(resolvedType) + ) + .setLocation(location) + .setPrimitiveResult(primitiveExpression); } @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 40bd4295a88f5..f4195f45c5aae 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 @@ -19,18 +19,16 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.LambdaNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Opcodes; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.ArrayList; import java.util.Collections; @@ -188,25 +186,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (ref != null) { - methodWriter.writeDebugInfo(location); - // load captures - for (Variable capture : captures) { - methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); - } - - methodWriter.invokeLambdaCall(ref); - } else { - // placeholder - methodWriter.push((String)null); - // load captures - for (Variable capture : captures) { - methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); - } - } + LambdaNode write() { + return new LambdaNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setFuncRef(ref) + .addCaptures(captures); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index c0884853de44e..2016e76c2d3e3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -19,17 +19,14 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ListInitializationNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.ArrayList; import java.util.List; @@ -91,20 +88,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.newInstance(MethodWriter.getType(actual)); - methodWriter.dup(); - methodWriter.invokeConstructor( - Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + ListInitializationNode write() { + ListInitializationNode listInitializationNode = new ListInitializationNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setConstructor(constructor) + .setMethod(method); for (AExpression value : values) { - methodWriter.dup(); - value.write(classWriter, methodWriter, globals); - methodWriter.invokeMethodCall(method); - methodWriter.pop(); + listInitializationNode.addArgumentNode(value.write()); } + + return listInitializationNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index d1e9c9166138f..9ea26d8c06351 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -19,17 +19,14 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.MapInitializationNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.HashMap; import java.util.List; @@ -110,24 +107,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.newInstance(MethodWriter.getType(actual)); - methodWriter.dup(); - methodWriter.invokeConstructor( - Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + MapInitializationNode write() { + MapInitializationNode mapInitializationNode = new MapInitializationNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setConstructor(constructor) + .setMethod(method); for (int index = 0; index < keys.size(); ++index) { - AExpression key = keys.get(index); - AExpression value = values.get(index); - - methodWriter.dup(); - key.write(classWriter, methodWriter, globals); - value.write(classWriter, methodWriter, globals); - methodWriter.invokeMethodCall(method); - methodWriter.pop(); + mapInitializationNode.addArgumentNode(keys.get(index).write(), values.get(index).write()); } + + return mapInitializationNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java index b7bd13bbe55e9..f4cd0481a0604 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java @@ -19,11 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.NewArrayNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; @@ -79,32 +78,20 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (initialize) { - methodWriter.push(arguments.size()); - methodWriter.newArray(MethodWriter.getType(actual.getComponentType())); - - for (int index = 0; index < arguments.size(); ++index) { - AExpression argument = arguments.get(index); - - methodWriter.dup(); - methodWriter.push(index); - argument.write(classWriter, methodWriter, globals); - methodWriter.arrayStore(MethodWriter.getType(actual.getComponentType())); - } - } else { - for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - if (arguments.size() > 1) { - methodWriter.visitMultiANewArrayInsn(MethodWriter.getType(actual).getDescriptor(), arguments.size()); - } else { - methodWriter.newArray(MethodWriter.getType(actual.getComponentType())); - } + NewArrayNode write() { + NewArrayNode newArrayNode = new NewArrayNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setInitialize(initialize); + + for (AExpression argument : arguments) { + newArrayNode.addArgumentNode(argument.write()); } + + return newArrayNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java index 1fa2d1a2cd49f..6391f9ea98aeb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java @@ -19,12 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.NewArrayFuncRefNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Arrays; @@ -81,14 +80,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (ref != null) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeLambdaCall(ref); - } else { - // push a null instruction as a placeholder for future lambda instructions - methodWriter.push((String)null); - } + NewArrayFuncRefNode write() { + return new NewArrayFuncRefNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setFuncRef(ref); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java index e09eee2aad917..d514f3c1872a3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java @@ -19,17 +19,14 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.NewObjectNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; import java.util.Objects; @@ -100,21 +97,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.newInstance(MethodWriter.getType(actual)); - - if (read) { - methodWriter.dup(); - } + NewObjectNode write() { + NewObjectNode newObjectNode = new NewObjectNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setRead(read) + .setConstructor(constructor); for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); + newObjectNode.addArgumentNode(argument.write()); } - methodWriter.invokeConstructor( - Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); + return newObjectNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java index 7b9fc29d7575a..83412a27f6cfa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java @@ -19,14 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.NullNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Opcodes; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -65,8 +63,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitInsn(Opcodes.ACONST_NULL); + NullNode write() { + return new NullNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java index 065d0b3a1843c..e809e5262c11f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ExpressionNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -117,7 +115,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + ExpressionNode write() { throw createError(new IllegalStateException("Illegal tree structure.")); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java index aa22452719271..697d0464e6e4e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java @@ -19,14 +19,14 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Constant; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.ir.RegexNode; +import org.elasticsearch.painless.ir.TypeNode; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.lang.reflect.Modifier; import java.util.Set; @@ -88,11 +88,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.getStatic(WriterConstants.CLASS_TYPE, constant.name, org.objectweb.asm.Type.getType(Pattern.class)); - globals.addConstantInitializer(constant); + RegexNode write() { + return new RegexNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setFlags(flags) + .setPattern(pattern) + .setConstant(constant); } private void initializeConstant(MethodWriter writer) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java index 35cca3cb2af90..9ed44451e2abf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java @@ -19,11 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.StaticNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -57,8 +56,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. + StaticNode write() { + return new StaticNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java index 7d52660a7ab22..f806827fea1ac 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ExpressionNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -55,7 +53,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + ExpressionNode write() { throw new IllegalStateException("Illegal tree structure."); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index 9e8ada2a5b9c6..dabb3af74eaf2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -20,19 +20,15 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.TypeNode; +import org.elasticsearch.painless.ir.UnaryMathNode; +import org.elasticsearch.painless.ir.UnaryNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -188,66 +184,19 @@ void analyzerSub(ScriptRoot scriptRoot, Locals variables) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (operation == Operation.NOT) { - Label fals = new Label(); - Label end = new Label(); - - child.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - methodWriter.push(false); - methodWriter.goTo(end); - methodWriter.mark(fals); - methodWriter.push(true); - methodWriter.mark(end); - } else { - child.write(classWriter, methodWriter, globals); - - // Def calls adopt the wanted return value. If there was a narrowing cast, - // we need to flag that so that it's done at runtime. - int defFlags = 0; - - if (originallyExplicit) { - defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; - } - - Type actualType = MethodWriter.getType(actual); - Type childType = MethodWriter.getType(child.actual); - - if (operation == Operation.BWNOT) { - if (promote == def.class) { - org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); - methodWriter.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); - } else { - if (promote == int.class) { - methodWriter.push(-1); - } else if (promote == long.class) { - methodWriter.push(-1L); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - - methodWriter.math(MethodWriter.XOR, actualType); - } - } else if (operation == Operation.SUB) { - if (promote == def.class) { - org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); - methodWriter.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); - } else { - methodWriter.math(MethodWriter.NEG, actualType); - } - } else if (operation == Operation.ADD) { - if (promote == def.class) { - org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); - methodWriter.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); - } - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } + UnaryNode write() { + return new UnaryMathNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(child.write()) + .setUnaryTypeNode(new TypeNode() + .setLocation(location) + .setType(promote) + ) + .setLocation(location) + .setOperation(operation); } @Override 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 eb900eafab83d..38b8a72b27d3f 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 @@ -19,14 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.TypeNode; +import org.elasticsearch.painless.ir.VariableNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -63,13 +61,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ILOAD), variable.getSlot()); - } - - @Override - int accessElementCount() { - return 0; + VariableNode write() { + return new VariableNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setVariable(variable); } @Override @@ -82,21 +81,6 @@ void updateActual(Class actual) { throw new IllegalArgumentException("Illegal tree structure."); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ILOAD), variable.getSlot()); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ISTORE), variable.getSlot()); - } - @Override public String toString() { return singleLineToString(name); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java index eaa11a6833ac8..ecdb9b8eed1e5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java @@ -19,14 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.BraceNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; import java.util.Map; @@ -82,9 +81,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.write(classWriter, methodWriter, globals); + BraceNode write() { + return new BraceNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(sub.write()) + .setPrefixNode(prefix.write()) + .setLocation(location); } @Override @@ -98,27 +103,6 @@ void updateActual(Class actual) { this.actual = actual; } - @Override - int accessElementCount() { - return sub.accessElementCount(); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.setup(classWriter, methodWriter, globals); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.load(classWriter, methodWriter, globals); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.store(classWriter, methodWriter, globals); - } - @Override public String toString() { return singleLineToString(prefix, index); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java index c13ca5765bbec..cc3c3a34bde1e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java @@ -19,15 +19,14 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.CallNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; import java.util.Objects; @@ -98,9 +97,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.write(classWriter, methodWriter, globals); + CallNode write() { + return new CallNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(sub.write()) + .setPrefixNode(prefix.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java index 92218a21aebe1..3a687d0bad07c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java @@ -19,16 +19,15 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.DotNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; import java.util.Map; @@ -124,9 +123,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.write(classWriter, methodWriter, globals); + DotNode write() { + return new DotNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(sub.write()) + .setPrefixNode(prefix.write()) + .setLocation(location); } @Override @@ -140,27 +145,6 @@ void updateActual(Class actual) { this.actual = actual; } - @Override - int accessElementCount() { - return sub.accessElementCount(); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefix.write(classWriter, methodWriter, globals); - sub.setup(classWriter, methodWriter, globals); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.load(classWriter, methodWriter, globals); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.store(classWriter, methodWriter, globals); - } - @Override public String toString() { if (nullSafe) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java index d004cc30a6a89..9c6a3d2b9a2c9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java @@ -19,11 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.DotSubArrayLengthNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -63,14 +62,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.arrayLength(); - } - - @Override - int accessElementCount() { - throw new IllegalStateException("Illegal tree structure."); + DotSubArrayLengthNode write() { + return new DotSubArrayLengthNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location); } @Override @@ -83,21 +81,6 @@ void updateActual(Class actual) { throw new IllegalStateException("Illegal tree structure."); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw new IllegalStateException("Illegal tree structure."); - } - @Override public String toString() { return singleLineToString(prefix); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java index 60c025ecba548..465f4e3fc306b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java @@ -19,11 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.BraceSubNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -58,15 +57,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { actual = clazz.getComponentType(); } - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); - } - - @Override - int accessElementCount() { - return 2; + BraceSubNode write() { + return new BraceSubNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(index.write()) + .setLocation(location); } @Override @@ -79,24 +77,6 @@ void updateActual(Class actual) { throw createError(new IllegalStateException("Illegal tree structure.")); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - writeIndexFlip(methodWriter, MethodWriter::arrayLength); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.arrayLoad(MethodWriter.getType(actual)); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.arrayStore(MethodWriter.getType(actual)); - } - @Override public String toString() { return singleLineToString(prefix, index); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java index 307607ee36aab..5e3d118de50b5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java @@ -19,13 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.CallSubNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; import java.util.Objects; @@ -69,18 +68,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (box.isPrimitive()) { - methodWriter.box(MethodWriter.getType(box)); - } + CallSubNode write() { + CallSubNode callSubNode = new CallSubNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setMethod(method) + .setBox(box); for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); + callSubNode.addArgumentNode(argument.write()); } - methodWriter.invokeMethodCall(method); + return callSubNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java index 620c0fd6aca60..1b22d9066616e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java @@ -19,15 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.BraceSubDefNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.time.ZonedDateTime; import java.util.Objects; @@ -61,14 +58,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); - } - - @Override - int accessElementCount() { - return 2; + BraceSubDefNode write() { + return new BraceSubDefNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(index.write()) + .setLocation(location); } @Override @@ -81,34 +78,6 @@ void updateActual(Class actual) { this.actual = actual; } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.dup(); - index.write(classWriter, methodWriter, globals); - Type methodType = Type.getMethodType( - MethodWriter.getType(index.actual), Type.getType(Object.class), MethodWriter.getType(index.actual)); - methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Type methodType = - Type.getMethodType(MethodWriter.getType(actual), Type.getType(Object.class), MethodWriter.getType(index.actual)); - methodWriter.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Type methodType = - Type.getMethodType( - Type.getType(void.class), Type.getType(Object.class), MethodWriter.getType(index.actual), MethodWriter.getType(actual)); - methodWriter.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE); - } - @Override public String toString() { return singleLineToString(prefix, index); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index 61f99b57d72ee..4fb3570137b8b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -19,15 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.CallSubDefNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -94,24 +91,23 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); + CallSubDefNode write() { + CallSubDefNode callSubDefNode = new CallSubDefNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setName(name) + .setRecipe(recipe.toString()) + .addPointers(pointers) + .addTypeParameters(parameterTypes); for (AExpression argument : arguments) { - argument.write(classWriter, methodWriter, globals); - } - - // create method type from return value and arguments - Type[] asmParameterTypes = new Type[parameterTypes.size()]; - for (int index = 0; index < asmParameterTypes.length; ++index) { - asmParameterTypes[index] = MethodWriter.getType(parameterTypes.get(index)); + callSubDefNode.addArgumentNode(argument.write()); } - Type methodType = Type.getMethodType(MethodWriter.getType(actual), asmParameterTypes); - List args = new ArrayList<>(); - args.add(recipe.toString()); - args.addAll(pointers); - methodWriter.invokeDefCall(name, methodType, DefBootstrap.METHOD_CALL, args.toArray()); + return callSubDefNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java index 071b6515d3971..cc87eecae1fe4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java @@ -19,14 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.DotSubDefNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.time.ZonedDateTime; import java.util.Objects; @@ -57,17 +55,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - org.objectweb.asm.Type methodType = - org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class)); - methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); - } - - @Override - int accessElementCount() { - return 1; + DotSubDefNode write() { + return new DotSubDefNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setValue(value); } @Override @@ -80,29 +75,6 @@ void updateActual(Class actual) { this.actual = actual; } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - org.objectweb.asm.Type methodType = - org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class)); - methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( - org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(actual)); - methodWriter.invokeDefCall(value, methodType, DefBootstrap.STORE); - } - @Override public String toString() { return singleLineToString(prefix, value); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java index 7f0be343842e7..f43400db520fa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java @@ -19,15 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.DotSubNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.lang.reflect.Modifier; import java.util.Objects; @@ -62,21 +60,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { - methodWriter.getStatic(Type.getType( - field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); - } else { - methodWriter.getField(Type.getType( - field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); - } - } - - @Override - int accessElementCount() { - return 1; + DotSubNode write() { + return new DotSubNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setField(field); } @Override @@ -89,37 +80,6 @@ void updateActual(Class actual) { throw new IllegalArgumentException("Illegal tree structure."); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { - // Do nothing. - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { - methodWriter.writeDebugInfo(location); - - if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { - methodWriter.getStatic(Type.getType( - field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); - } else { - methodWriter.getField(Type.getType( - field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { - methodWriter.writeDebugInfo(location); - - if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { - methodWriter.putStatic(Type.getType( - field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); - } else { - methodWriter.putField(Type.getType( - field.javaField.getDeclaringClass()), field.javaField.getName(), MethodWriter.getType(field.typeParameter)); - } - } - @Override public String toString() { return singleLineToString(prefix, field.javaField.getName()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java index e0e566306bc69..e0386c0a7c2b0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java @@ -19,15 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; -import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.ir.ListSubShortcutNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -88,14 +86,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); - } - - @Override - int accessElementCount() { - return 2; + ListSubShortcutNode write() { + return new ListSubShortcutNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(index.write()) + .setLocation(location) + .setGetter(getter) + .setSetter(setter); } @Override @@ -108,31 +108,6 @@ void updateActual(Class actual) { throw new IllegalArgumentException("Illegal tree structure."); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - writeIndexFlip(methodWriter, w -> { - w.invokeInterface(WriterConstants.COLLECTION_TYPE, WriterConstants.COLLECTION_SIZE); - }); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(getter); - - if (getter.returnType == getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(setter); - methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); - } - @Override public String toString() { return singleLineToString(prefix, index); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java index 888044cd31686..9d4930db2405c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java @@ -19,14 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.MapSubShortcutNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -86,20 +85,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(getter); - - if (getter.returnType != getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - int accessElementCount() { - return 2; + MapSubShortcutNode write() { + return new MapSubShortcutNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(index.write()) + .setLocation(location) + .setGetter(getter) + .setSetter(setter); } @Override @@ -112,28 +107,6 @@ void updateActual(Class actual) { throw new IllegalArgumentException("Illegal tree structure."); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - index.write(classWriter, methodWriter, globals); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(getter); - - if (getter.returnType != getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - methodWriter.invokeMethodCall(setter); - methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); - } - @Override public String toString() { return singleLineToString(prefix, index); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java index 0f6875762a681..5ed3871ec5e1d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java @@ -19,13 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.NullSafeSubNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; import java.util.Set; @@ -60,14 +58,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - Label end = new Label(); - methodWriter.dup(); - methodWriter.ifNull(end); - guarded.write(classWriter, methodWriter, globals); - methodWriter.mark(end); + NullSafeSubNode write() { + return new NullSafeSubNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(guarded.write()); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java index d4260677f832d..ece825579014b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java @@ -19,13 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.NullSafeSubNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; import java.util.Set; @@ -58,12 +56,6 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } } - - @Override - int accessElementCount() { - return guarded.accessElementCount(); - } - @Override boolean isDefOptimized() { return guarded.isDefOptimized(); @@ -75,27 +67,13 @@ void updateActual(Class actual) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - Label end = new Label(); - methodWriter.dup(); - methodWriter.ifNull(end); - guarded.write(classWriter, methodWriter, globals); - methodWriter.mark(end); - } - - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalArgumentException("Can't write to null safe field")); - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalArgumentException("Can't write to null safe field")); - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new IllegalArgumentException("Can't write to null safe field")); + NullSafeSubNode write() { + return new NullSafeSubNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setChildNode(guarded.write()); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java index 7388aca1a8d47..4c686b3be4186 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java @@ -19,13 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.DotSubShortcutNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -77,19 +76,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.invokeMethodCall(getter); - - if (!getter.returnType.equals(getter.javaMethod.getReturnType())) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - int accessElementCount() { - return 1; + DotSubShortcutNode write() { + return new DotSubShortcutNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(actual) + ) + .setLocation(location) + .setGetter(getter) + .setSetter(setter); } @Override @@ -102,31 +97,6 @@ void updateActual(Class actual) { throw new IllegalArgumentException("Illegal tree structure."); } - @Override - void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // Do nothing. - } - - @Override - void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.invokeMethodCall(getter); - - if (getter.returnType != getter.javaMethod.getReturnType()) { - methodWriter.checkCast(MethodWriter.getType(getter.returnType)); - } - } - - @Override - void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeDebugInfo(location); - - methodWriter.invokeMethodCall(setter); - - methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); - } - @Override public String toString() { return singleLineToString(prefix, value); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java index a270bcc615d7f..8c2a9929c872a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.BlockNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; @@ -82,12 +80,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + BlockNode write() { + BlockNode blockNode = new BlockNode() + .setLocation(location) + .setAllEscape(allEscape) + .setStatementCount(statementCount); + for (AStatement statement : statements) { - statement.continu = continu; - statement.brake = brake; - statement.write(classWriter, methodWriter, globals); + blockNode.addStatementNode(statement.write()); } + + return blockNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java index 5794e833ec9cf..334a6b81c8619 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.BreakNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -55,8 +53,9 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.goTo(brake); + BreakNode write() { + return new BreakNode() + .setLocation(location); } @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 ad5382ad9f888..44898664bcad0 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,15 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.CatchNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -91,26 +88,11 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label jump = new Label(); - - methodWriter.mark(jump); - methodWriter.visitVarInsn( - MethodWriter.getType(declaration.variable.clazz).getOpcode(Opcodes.ISTORE), declaration.variable.getSlot()); - - if (block != null) { - block.continu = continu; - block.brake = brake; - block.write(classWriter, methodWriter, globals); - } - - methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declaration.variable.clazz).getInternalName()); - - if (exception != null && (block == null || !block.allEscape)) { - methodWriter.goTo(exception); - } + CatchNode write() { + return new CatchNode() + .setDeclarationNode(declaration.write()) + .setBlockNode(block.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java index e3dda3cd58f31..aeeaee363e5d3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java @@ -19,60 +19,27 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.CompilerSettings; -import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptClassInfo; -import org.elasticsearch.painless.symbol.ScriptRoot; -import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.ir.ClassNode; +import org.elasticsearch.painless.ir.StatementNode; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.symbol.FunctionTable; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; +import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.util.Printer; -import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.BitSet; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import static java.util.Collections.emptyList; -import static org.elasticsearch.painless.WriterConstants.BASE_INTERFACE_TYPE; -import static org.elasticsearch.painless.WriterConstants.BITSET_TYPE; -import static org.elasticsearch.painless.WriterConstants.BOOTSTRAP_METHOD_ERROR_TYPE; -import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; -import static org.elasticsearch.painless.WriterConstants.COLLECTIONS_TYPE; -import static org.elasticsearch.painless.WriterConstants.CONVERT_TO_SCRIPT_EXCEPTION_METHOD; -import static org.elasticsearch.painless.WriterConstants.DEFINITION_TYPE; -import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_DELEGATE_METHOD; -import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_DELEGATE_TYPE; -import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_METHOD; -import static org.elasticsearch.painless.WriterConstants.EMPTY_MAP_METHOD; -import static org.elasticsearch.painless.WriterConstants.EXCEPTION_TYPE; -import static org.elasticsearch.painless.WriterConstants.FUNCTION_TABLE_TYPE; -import static org.elasticsearch.painless.WriterConstants.GET_NAME_METHOD; -import static org.elasticsearch.painless.WriterConstants.GET_SOURCE_METHOD; -import static org.elasticsearch.painless.WriterConstants.GET_STATEMENTS_METHOD; -import static org.elasticsearch.painless.WriterConstants.OUT_OF_MEMORY_ERROR_TYPE; -import static org.elasticsearch.painless.WriterConstants.PAINLESS_ERROR_TYPE; -import static org.elasticsearch.painless.WriterConstants.PAINLESS_EXPLAIN_ERROR_GET_HEADERS_METHOD; -import static org.elasticsearch.painless.WriterConstants.PAINLESS_EXPLAIN_ERROR_TYPE; -import static org.elasticsearch.painless.WriterConstants.STACK_OVERFLOW_ERROR_TYPE; -import static org.elasticsearch.painless.WriterConstants.STRING_TYPE; /** * The root of all Painless trees. Contains a series of statements. @@ -89,11 +56,11 @@ public final class SClass extends AStatement { private CompilerSettings settings; - private ScriptRoot table; + private ScriptRoot scriptRoot; private Locals mainMethod; private final Set extractedVariables; private final List getMethods; - private byte[] bytes; + private final String sourceText; public SClass(ScriptClassInfo scriptClassInfo, String name, String sourceText, Printer debugStream, Location location, List functions, List statements) { @@ -103,6 +70,7 @@ public SClass(ScriptClassInfo scriptClassInfo, String name, String sourceText, P this.debugStream = debugStream; this.functions.addAll(Objects.requireNonNull(functions)); this.statements = Collections.unmodifiableList(statements); + this.sourceText = Objects.requireNonNull(sourceText); this.globals = new Globals(new BitSet(sourceText.length())); this.extractedVariables = new HashSet<>(); @@ -132,23 +100,23 @@ public void extractVariables(Set variables) { public ScriptRoot analyze(PainlessLookup painlessLookup, CompilerSettings settings) { this.settings = settings; - table = new ScriptRoot(painlessLookup, settings, scriptClassInfo, this); + scriptRoot = new ScriptRoot(painlessLookup, settings, scriptClassInfo, this); for (SFunction function : functions) { function.generateSignature(painlessLookup); String key = FunctionTable.buildLocalFunctionKey(function.name, function.parameters.size()); - if (table.getFunctionTable().getFunction(key) != null) { + if (scriptRoot.getFunctionTable().getFunction(key) != null) { throw createError(new IllegalArgumentException("Illegal duplicate functions [" + key + "].")); } - table.getFunctionTable().addFunction(function.name, function.returnType, function.typeParameters, false); + scriptRoot.getFunctionTable().addFunction(function.name, function.returnType, function.typeParameters, false); } Locals locals = Locals.newProgramScope(); - analyze(table, locals); - return table; + analyze(scriptRoot, locals); + return scriptRoot; } @Override @@ -198,246 +166,39 @@ void analyze(ScriptRoot scriptRoot, Locals program) { } } - public Map write() { - // Create the ClassWriter. - - int classFrames = org.objectweb.asm.ClassWriter.COMPUTE_FRAMES | org.objectweb.asm.ClassWriter.COMPUTE_MAXS; - int classAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL; - String interfaceBase = BASE_INTERFACE_TYPE.getInternalName(); - String className = CLASS_TYPE.getInternalName(); - String[] classInterfaces = new String[] { interfaceBase }; - - ClassWriter classWriter = new ClassWriter(settings, globals.getStatements(), debugStream, - scriptClassInfo.getBaseClass(), classFrames, classAccess, className, classInterfaces); - ClassVisitor classVisitor = classWriter.getClassVisitor(); - classVisitor.visitSource(Location.computeSourceName(name), null); - - // Write the a method to bootstrap def calls - MethodWriter bootstrapDef = classWriter.newMethodWriter(Opcodes.ACC_STATIC | Opcodes.ACC_VARARGS, DEF_BOOTSTRAP_METHOD); - bootstrapDef.visitCode(); - bootstrapDef.getStatic(CLASS_TYPE, "$DEFINITION", DEFINITION_TYPE); - bootstrapDef.getStatic(CLASS_TYPE, "$FUNCTIONS", FUNCTION_TABLE_TYPE); - bootstrapDef.loadArgs(); - bootstrapDef.invokeStatic(DEF_BOOTSTRAP_DELEGATE_TYPE, DEF_BOOTSTRAP_DELEGATE_METHOD); - bootstrapDef.returnValue(); - bootstrapDef.endMethod(); - - // Write static variables for name, source and statements used for writing exception messages - classVisitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$NAME", STRING_TYPE.getDescriptor(), null, null).visitEnd(); - classVisitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$SOURCE", STRING_TYPE.getDescriptor(), null, null).visitEnd(); - classVisitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$STATEMENTS", BITSET_TYPE.getDescriptor(), null, null).visitEnd(); - - // Write the static variables used by the method to bootstrap def calls - classVisitor.visitField( - Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$DEFINITION", DEFINITION_TYPE.getDescriptor(), null, null).visitEnd(); - classVisitor.visitField( - Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$FUNCTIONS", FUNCTION_TABLE_TYPE.getDescriptor(), null, null).visitEnd(); - - org.objectweb.asm.commons.Method init; - - if (scriptClassInfo.getBaseClass().getConstructors().length == 0) { - init = new org.objectweb.asm.commons.Method("", MethodType.methodType(void.class).toMethodDescriptorString()); - } else { - init = new org.objectweb.asm.commons.Method("", MethodType.methodType(void.class, - scriptClassInfo.getBaseClass().getConstructors()[0].getParameterTypes()).toMethodDescriptorString()); - } - - // Write the constructor: - MethodWriter constructor = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, init); - constructor.visitCode(); - constructor.loadThis(); - constructor.loadArgs(); - constructor.invokeConstructor(Type.getType(scriptClassInfo.getBaseClass()), init); - constructor.returnValue(); - constructor.endMethod(); - - // Write a method to get static variable source - MethodWriter nameMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, GET_NAME_METHOD); - nameMethod.visitCode(); - nameMethod.getStatic(CLASS_TYPE, "$NAME", STRING_TYPE); - nameMethod.returnValue(); - nameMethod.endMethod(); - - // Write a method to get static variable source - MethodWriter sourceMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, GET_SOURCE_METHOD); - sourceMethod.visitCode(); - sourceMethod.getStatic(CLASS_TYPE, "$SOURCE", STRING_TYPE); - sourceMethod.returnValue(); - sourceMethod.endMethod(); - - // Write a method to get static variable statements - MethodWriter statementsMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, GET_STATEMENTS_METHOD); - statementsMethod.visitCode(); - statementsMethod.getStatic(CLASS_TYPE, "$STATEMENTS", BITSET_TYPE); - statementsMethod.returnValue(); - statementsMethod.endMethod(); - - // Write the method defined in the interface: - MethodWriter executeMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, scriptClassInfo.getExecuteMethod()); - executeMethod.visitCode(); - write(classWriter, executeMethod, globals); - executeMethod.endMethod(); - - // Write all functions: - for (SFunction function : functions) { - function.write(classWriter, globals); - } - - // Write all fields: - for (SField field : fields) { - field.write(classWriter); - } - - // Write the constants - if (false == globals.getConstantInitializers().isEmpty()) { - Collection inits = globals.getConstantInitializers().values(); - - // Initialize the constants in a static initializerNode - final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC, - WriterConstants.CLINIT, classVisitor, globals.getStatements(), settings); - clinit.visitCode(); - for (Constant constant : inits) { - constant.initializer.accept(clinit); - clinit.putStatic(CLASS_TYPE, constant.name, constant.type); - } - clinit.returnValue(); - clinit.endMethod(); - } - - // Write any needsVarName methods for used variables - for (org.objectweb.asm.commons.Method needsMethod : scriptClassInfo.getNeedsMethods()) { - String name = needsMethod.getName(); - name = name.substring(5); - name = Character.toLowerCase(name.charAt(0)) + name.substring(1); - MethodWriter ifaceMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, needsMethod); - ifaceMethod.visitCode(); - ifaceMethod.push(extractedVariables.contains(name)); - ifaceMethod.returnValue(); - ifaceMethod.endMethod(); - } - - // End writing the class and store the generated bytes. - - classVisitor.visitEnd(); - bytes = classWriter.getClassBytes(); + @Override + public StatementNode write() { + throw new UnsupportedOperationException(); + } - Map statics = new HashMap<>(); - statics.put("$FUNCTIONS", table.getFunctionTable()); + public ClassNode writeClass() { + ClassNode classNode = new ClassNode() + .setLocation(location) + .setScriptClassInfo(scriptClassInfo) + .setScriptRoot(scriptRoot) + .setDebugStream(debugStream) + .setName(name) + .setSourceText(sourceText) + .setMainMethod(mainMethod) + .setMethodEscape(methodEscape) + .addGetMethods(getMethods); for (SField field : fields) { - if (field.getInstance() != null) { - statics.put(field.getName(), field.getInstance()); - } - } - - return statics; - } - - @Override - void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - // We wrap the whole method in a few try/catches to handle and/or convert other exceptions to ScriptException - Label startTry = new Label(); - Label endTry = new Label(); - Label startExplainCatch = new Label(); - Label startOtherCatch = new Label(); - Label endCatch = new Label(); - methodWriter.mark(startTry); - - if (settings.getMaxLoopCounter() > 0) { - // if there is infinite loop protection, we do this once: - // int #loop = settings.getMaxLoopCounter() - - Variable loop = mainMethod.getVariable(null, Locals.LOOP); - - methodWriter.push(settings.getMaxLoopCounter()); - methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); + classNode.addFieldNode(field.writeField()); } - for (org.objectweb.asm.commons.Method method : getMethods) { - String name = method.getName().substring(3); - name = Character.toLowerCase(name.charAt(0)) + name.substring(1); - Variable variable = mainMethod.getVariable(null, name); - - methodWriter.loadThis(); - methodWriter.invokeVirtual(Type.getType(scriptClassInfo.getBaseClass()), method); - methodWriter.visitVarInsn(method.getReturnType().getOpcode(Opcodes.ISTORE), variable.getSlot()); + for (SFunction function : functions) { + classNode.addFunctionNode(function.writeFunction()); } for (AStatement statement : statements) { - statement.write(classWriter, methodWriter, globals); - } - if (!methodEscape) { - switch (scriptClassInfo.getExecuteMethod().getReturnType().getSort()) { - case org.objectweb.asm.Type.VOID: - break; - case org.objectweb.asm.Type.BOOLEAN: - methodWriter.push(false); - break; - case org.objectweb.asm.Type.BYTE: - methodWriter.push(0); - break; - case org.objectweb.asm.Type.SHORT: - methodWriter.push(0); - break; - case org.objectweb.asm.Type.INT: - methodWriter.push(0); - break; - case org.objectweb.asm.Type.LONG: - methodWriter.push(0L); - break; - case org.objectweb.asm.Type.FLOAT: - methodWriter.push(0f); - break; - case org.objectweb.asm.Type.DOUBLE: - methodWriter.push(0d); - break; - default: - methodWriter.visitInsn(Opcodes.ACONST_NULL); - } - methodWriter.returnValue(); + classNode.addStatementNode(statement.write()); } - methodWriter.mark(endTry); - methodWriter.goTo(endCatch); - // This looks like: - // } catch (PainlessExplainError e) { - // throw this.convertToScriptException(e, e.getHeaders($DEFINITION)) - // } - methodWriter.visitTryCatchBlock(startTry, endTry, startExplainCatch, PAINLESS_EXPLAIN_ERROR_TYPE.getInternalName()); - methodWriter.mark(startExplainCatch); - methodWriter.loadThis(); - methodWriter.swap(); - methodWriter.dup(); - methodWriter.getStatic(CLASS_TYPE, "$DEFINITION", DEFINITION_TYPE); - methodWriter.invokeVirtual(PAINLESS_EXPLAIN_ERROR_TYPE, PAINLESS_EXPLAIN_ERROR_GET_HEADERS_METHOD); - methodWriter.invokeInterface(BASE_INTERFACE_TYPE, CONVERT_TO_SCRIPT_EXCEPTION_METHOD); - methodWriter.throwException(); - // This looks like: - // } catch (PainlessError | BootstrapMethodError | OutOfMemoryError | StackOverflowError | Exception e) { - // throw this.convertToScriptException(e, e.getHeaders()) - // } - // We *think* it is ok to catch OutOfMemoryError and StackOverflowError because Painless is stateless - methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, PAINLESS_ERROR_TYPE.getInternalName()); - methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, BOOTSTRAP_METHOD_ERROR_TYPE.getInternalName()); - methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, OUT_OF_MEMORY_ERROR_TYPE.getInternalName()); - methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, STACK_OVERFLOW_ERROR_TYPE.getInternalName()); - methodWriter.visitTryCatchBlock(startTry, endTry, startOtherCatch, EXCEPTION_TYPE.getInternalName()); - methodWriter.mark(startOtherCatch); - methodWriter.loadThis(); - methodWriter.swap(); - methodWriter.invokeStatic(COLLECTIONS_TYPE, EMPTY_MAP_METHOD); - methodWriter.invokeInterface(BASE_INTERFACE_TYPE, CONVERT_TO_SCRIPT_EXCEPTION_METHOD); - methodWriter.throwException(); - methodWriter.mark(endCatch); + return classNode; } - public BitSet getStatements() { - return globals.getStatements(); - } - public byte[] getBytes() { - return bytes; - } @Override public String toString() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java index 91d73b30f1d54..fa490658ee36a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ContinueNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -58,8 +56,9 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.goTo(continu); + ContinueNode write() { + return new ContinueNode() + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java index 14d91ad1b984c..cd22b37b04855 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.DeclarationBlockNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; @@ -62,10 +60,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - for (AStatement declaration : declarations) { - declaration.write(classWriter, methodWriter, globals); + DeclarationBlockNode write() { + DeclarationBlockNode declarationBlockNode = new DeclarationBlockNode() + .setLocation(location); + + for (SDeclaration declaration : declarations) { + declarationBlockNode.addDeclarationNode(declaration.write()); } + + return declarationBlockNode; } @Override 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 da4b7d19c3031..1909c36f5a34e 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 @@ -19,14 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.DeclarationNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -73,29 +70,11 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - if (expression == null) { - Class sort = variable.clazz; - - if (sort == void.class || sort == boolean.class || sort == byte.class || - sort == short.class || sort == char.class || sort == int.class) { - methodWriter.push(0); - } else if (sort == long.class) { - methodWriter.push(0L); - } else if (sort == float.class) { - methodWriter.push(0F); - } else if (sort == double.class) { - methodWriter.push(0D); - } else { - methodWriter.visitInsn(Opcodes.ACONST_NULL); - } - } else { - expression.write(classWriter, methodWriter, globals); - } - - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + DeclarationNode write() { + return new DeclarationNode() + .setExpressionNode(expression.write()) + .setLocation(location) + .setVariable(variable); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java index 0cb52f57c0249..73c0c5d4a0b67 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java @@ -19,14 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.DoWhileLoopNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -98,32 +94,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label start = new Label(); - Label begin = new Label(); - Label end = new Label(); - - methodWriter.mark(start); - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - - methodWriter.mark(begin); - - if (!continuous) { - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, end); - } - - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, block.statementCount), location); - } - - methodWriter.goTo(start); - methodWriter.mark(end); + DoWhileLoopNode write() { + return new DoWhileLoopNode() + .setConditionNode(condition.write()) + .setBlockNode(block.write()) + .setLocation(location) + .setLoopCounter(loopCounter) + .setContinuous(continuous); } @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 3850aa8987756..b85b4220efb27 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 @@ -19,15 +19,14 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ConditionNode; +import org.elasticsearch.painless.ir.ForEachLoopNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -111,8 +110,10 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - sub.write(classWriter, methodWriter, globals); + ForEachLoopNode write() { + return new ForEachLoopNode() + .setConditionNode((ConditionNode)sub.write()) + .setLocation(location); } @Override 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 49bfb9e808e03..e421024f1df84 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,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.StatementExpressionNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -72,15 +70,11 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - expression.write(classWriter, methodWriter, globals); - - if (methodEscape) { - methodWriter.returnValue(); - } else { - methodWriter.writePop(MethodWriter.getType(expression.expected).getSize()); - } + StatementExpressionNode write() { + return new StatementExpressionNode() + .setExpressionNode(expression.write()) + .setLocation(location) + .setMethodEscape(methodEscape); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java index 2bb3b41a2b9da..b9fdde4f15d93 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java @@ -19,13 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.FieldNode; +import org.elasticsearch.painless.ir.StatementNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Type; import java.util.Set; @@ -75,13 +74,20 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - throw createError(new UnsupportedOperationException("unexpected node")); + public StatementNode write() { + throw new UnsupportedOperationException(); } - void write(ClassWriter classWriter) { - classWriter.getClassVisitor().visitField( - ClassWriter.buildAccess(modifiers, true), name, Type.getType(type).getDescriptor(), null, null).visitEnd(); + FieldNode writeField() { + return new FieldNode() + .setTypeNode(new TypeNode() + .setLocation(location) + .setType(type) + ) + .setLocation(location) + .setModifiers(modifiers) + .setName(name) + .setInstance(instance); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java index 54c34a3cd43b4..23a70a69fb5e3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java @@ -19,14 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ForLoopNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Arrays; import java.util.Set; @@ -155,64 +151,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label start = new Label(); - Label begin = afterthought == null ? start : new Label(); - Label end = new Label(); - - if (initializer instanceof SDeclBlock) { - initializer.write(classWriter, methodWriter, globals); - } else if (initializer instanceof AExpression) { - AExpression initializer = (AExpression)this.initializer; - - initializer.write(classWriter, methodWriter, globals); - methodWriter.writePop(MethodWriter.getType(initializer.expected).getSize()); - } - - methodWriter.mark(start); - - if (condition != null && !continuous) { - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, end); - } - - boolean allEscape = false; - - if (block != null) { - allEscape = block.allEscape; - - int statementCount = Math.max(1, block.statementCount); - - if (afterthought != null) { - ++statementCount; - } - - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); - } - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - } else { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); - } - } - - if (afterthought != null) { - methodWriter.mark(begin); - afterthought.write(classWriter, methodWriter, globals); - methodWriter.writePop(MethodWriter.getType(afterthought.expected).getSize()); - } - - if (afterthought != null || !allEscape) { - methodWriter.goTo(start); - } - - methodWriter.mark(end); + ForLoopNode write() { + return new ForLoopNode() + .setInitialzerNode(initializer.write()) + .setConditionNode(condition.write()) + .setAfterthoughtNode(afterthought.write()) + .setBlockNode(block.write()) + .setLocation(location) + .setLoopCounter(loopCounter) + .setContinuous(continuous); } @Override 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 5fa430a7f29f1..a3168994a1004 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 @@ -19,17 +19,15 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Parameter; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.FunctionNode; +import org.elasticsearch.painless.ir.StatementNode; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Opcodes; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.lang.invoke.MethodType; import java.util.ArrayList; @@ -141,36 +139,22 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } } - /** Writes the function to given ClassVisitor. */ - void write(ClassWriter classWriter, Globals globals) { - int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; - if (synthetic) { - access |= Opcodes.ACC_SYNTHETIC; - } - final MethodWriter methodWriter = classWriter.newMethodWriter(access, method); - methodWriter.visitCode(); - write(classWriter, methodWriter, globals); - methodWriter.endMethod(); - } - @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - if (maxLoopCounter > 0) { - // if there is infinite loop protection, we do this once: - // int #loop = settings.getMaxLoopCounter() - methodWriter.push(maxLoopCounter); - methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); - } - - block.write(classWriter, methodWriter, globals); + public StatementNode write() { + throw new UnsupportedOperationException(); + } - if (!methodEscape) { - if (returnType == void.class) { - methodWriter.returnValue(); - } else { - throw createError(new IllegalStateException("Illegal tree structure.")); - } - } + FunctionNode writeFunction() { + return new FunctionNode() + .setBlockNode(block.write()) + .setLocation(location) + .setName(name) + .setReturnType(returnType) + .addTypeParameters(typeParameters) + .setSynthetic(synthetic) + .setMethodEscape(methodEscape) + .setLoopCounter(loopCounter) + .setMaxLoopCounter(maxLoopCounter); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java index 5098daad11ce7..ea4f4ae29ac95 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java @@ -19,14 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.IfNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -81,19 +77,11 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label fals = new Label(); - - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - ifblock.continu = continu; - ifblock.brake = brake; - ifblock.write(classWriter, methodWriter, globals); - - methodWriter.mark(fals); + IfNode write() { + return new IfNode() + .setConditionNode(condition.write()) + .setBlockNode(ifblock.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java index 1ab347d074c1e..3fbd297e32967 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java @@ -19,14 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.IfElseNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Arrays; import java.util.Objects; @@ -107,30 +103,12 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label fals = new Label(); - Label end = new Label(); - - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, fals); - - ifblock.continu = continu; - ifblock.brake = brake; - ifblock.write(classWriter, methodWriter, globals); - - if (!ifblock.allEscape) { - methodWriter.goTo(end); - } - - methodWriter.mark(fals); - - elseblock.continu = continu; - elseblock.brake = brake; - elseblock.write(classWriter, methodWriter, globals); - - methodWriter.mark(end); + IfElseNode write() { + return new IfElseNode() + .setConditionNode(condition.write()) + .setBlockNode(ifblock.write()) + .setElseBlockNode(elseblock.write()) + .setLocation(location); } @Override 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 60aa2fad60a5f..3f96dfb9ffeb7 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 @@ -19,13 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ReturnNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -72,14 +70,10 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - if (expression != null) { - expression.write(classWriter, methodWriter, globals); - } - - methodWriter.returnValue(); + ReturnNode write() { + return new ReturnNode() + .setExpressionNode(expression.write()) + .setLocation(location); } @Override 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 8424628e7e34f..91a3868080854 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 @@ -20,17 +20,14 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ForEachSubArrayNode; +import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; import java.util.Set; @@ -72,41 +69,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - expression.write(classWriter, methodWriter, globals); - methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ISTORE), array.getSlot()); - methodWriter.push(-1); - methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ISTORE), index.getSlot()); - - Label begin = new Label(); - Label end = new Label(); - - methodWriter.mark(begin); - - methodWriter.visitIincInsn(index.getSlot(), 1); - methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); - methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); - methodWriter.arrayLength(); - methodWriter.ifICmp(MethodWriter.GE, end); - - methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); - methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); - methodWriter.arrayLoad(MethodWriter.getType(indexed)); - methodWriter.writeCast(cast); - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); - - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); - } - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - - methodWriter.goTo(begin); - methodWriter.mark(end); + ForEachSubArrayNode write() { + return new ForEachSubArrayNode() + .setConditionNode(expression.write()) + .setBlockNode(block.write()) + .setIndexedTypeNode(new TypeNode() + .setLocation(location) + .setType(indexed) + ) + .setLocation(location) + .setVariable(variable) + .setCast(cast) + .setArray(array) + .setIndex(index) + .setLoopCounter(loopCounter) + .setContinuous(false); } @Override 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 1ad1b01ccfc4d..d6e2d7231947b 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 @@ -20,28 +20,20 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; -import org.elasticsearch.painless.symbol.ScriptRoot; +import org.elasticsearch.painless.ir.ForEachSubIterableNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; +import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Iterator; import java.util.Objects; import java.util.Set; -import static org.elasticsearch.painless.WriterConstants.ITERATOR_HASNEXT; -import static org.elasticsearch.painless.WriterConstants.ITERATOR_NEXT; -import static org.elasticsearch.painless.WriterConstants.ITERATOR_TYPE; import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName; /** @@ -91,45 +83,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - expression.write(classWriter, methodWriter, globals); - - if (method == null) { - org.objectweb.asm.Type methodType = org.objectweb.asm.Type - .getMethodType(org.objectweb.asm.Type.getType(Iterator.class), org.objectweb.asm.Type.getType(Object.class)); - methodWriter.invokeDefCall("iterator", methodType, DefBootstrap.ITERATOR); - } else { - methodWriter.invokeMethodCall(method); - } - - methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ISTORE), iterator.getSlot()); - - Label begin = new Label(); - Label end = new Label(); - - methodWriter.mark(begin); - - methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); - methodWriter.invokeInterface(ITERATOR_TYPE, ITERATOR_HASNEXT); - methodWriter.ifZCmp(MethodWriter.EQ, end); - - methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); - methodWriter.invokeInterface(ITERATOR_TYPE, ITERATOR_NEXT); - methodWriter.writeCast(cast); - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); - - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); - } - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - - methodWriter.goTo(begin); - methodWriter.mark(end); + ForEachSubIterableNode write() { + return new ForEachSubIterableNode() + .setConditionNode(expression.write()) + .setBlockNode(block.write()) + .setLocation(location) + .setVariable(variable) + .setCast(cast) + .setIterator(iterator) + .setMethod(method) + .setLoopCounter(loopCounter) + .setContinuous(false); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java index bb25793095a88..85a90bf07bb5c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java @@ -19,11 +19,9 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.ThrowNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -60,10 +58,10 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - expression.write(classWriter, methodWriter, globals); - methodWriter.throwException(); + ThrowNode write() { + return new ThrowNode() + .setExpressionNode(expression.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java index 5a026e1c74c0b..37b1f0f34daf6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java @@ -19,13 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.TryNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; import java.util.Collections; import java.util.List; @@ -98,35 +95,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label begin = new Label(); - Label end = new Label(); - Label exception = new Label(); - - methodWriter.mark(begin); - - block.continu = continu; - block.brake = brake; - block.write(classWriter, methodWriter, globals); - - if (!block.allEscape) { - methodWriter.goTo(exception); - } - - methodWriter.mark(end); + TryNode write() { + TryNode tryNode = new TryNode() + .setBlockNode(block.write()) + .setLocation(location); for (SCatch catc : catches) { - catc.begin = begin; - catc.end = end; - catc.exception = catches.size() > 1 ? exception : null; - catc.write(classWriter, methodWriter, globals); + tryNode.addCatchNode(catc.write()); } - if (!block.allEscape || catches.size() > 1) { - methodWriter.mark(exception); - } + return tryNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java index 991b1f08a4699..00182d3954b62 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java @@ -19,14 +19,10 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.ClassWriter; -import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.ir.WhileNode; import org.elasticsearch.painless.symbol.ScriptRoot; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import java.util.Objects; import java.util.Set; @@ -102,38 +98,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } @Override - void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.writeStatementOffset(location); - - Label begin = new Label(); - Label end = new Label(); - - methodWriter.mark(begin); - - if (!continuous) { - condition.write(classWriter, methodWriter, globals); - methodWriter.ifZCmp(Opcodes.IFEQ, end); - } - - if (block != null) { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, block.statementCount), location); - } - - block.continu = begin; - block.brake = end; - block.write(classWriter, methodWriter, globals); - } else { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); - } - } - - if (block == null || !block.allEscape) { - methodWriter.goTo(begin); - } - - methodWriter.mark(end); + WhileNode write() { + return new WhileNode() + .setConditionNode(condition.write()) + .setBlockNode(block.write()) + .setLocation(location) + .setLoopCounter(loopCounter) + .setContinuous(continuous); } @Override From 058c416ac501ba6ec386cdeab5d998413ae46ca4 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 24 Dec 2019 17:24:03 -0800 Subject: [PATCH 18/24] fix bugs/tests --- .../painless/ir/AssignmentNode.java | 25 +++++++++-- .../painless/ir/BinaryMathNode.java | 27 ++++++++++-- .../painless/ir/CallSubDefNode.java | 6 +-- .../painless/ir/ComparisonNode.java | 43 ++++++++++--------- .../painless/ir/FunctionNode.java | 9 ++-- .../elasticsearch/painless/ir/LambdaNode.java | 3 +- .../painless/ir/MapInitializationNode.java | 2 +- .../painless/ir/UnaryMathNode.java | 10 ++--- .../painless/node/EAssignment.java | 4 ++ .../elasticsearch/painless/node/EBinary.java | 4 ++ .../elasticsearch/painless/node/EUnary.java | 3 +- .../painless/node/PSubNullSafeCallInvoke.java | 3 +- .../painless/node/PSubNullSafeField.java | 3 +- .../elasticsearch/painless/node/SCatch.java | 2 +- .../elasticsearch/painless/node/SClass.java | 3 +- .../painless/node/SDeclaration.java | 2 +- .../org/elasticsearch/painless/node/SFor.java | 8 ++-- .../painless/node/SFunction.java | 5 +-- .../elasticsearch/painless/node/SReturn.java | 2 +- .../elasticsearch/painless/node/SWhile.java | 2 +- 20 files changed, 108 insertions(+), 58 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 473b4f3ef6645..bb045bd6eff2d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -33,6 +33,25 @@ public class AssignmentNode extends BinaryNode { /* ---- begin tree structure ---- */ + protected TypeNode compoundTypeNode; + + public AssignmentNode setCompoundTypeNode(TypeNode compoundTypeNode) { + this.compoundTypeNode = compoundTypeNode; + return this; + } + + public TypeNode getCompoundTypeNode() { + return compoundTypeNode; + } + + public Class getCompoundType() { + return compoundTypeNode.getType(); + } + + public String getCompoundCanonicalTypeName() { + return compoundTypeNode.getCanonicalTypeName(); + } + @Override public AssignmentNode setLeftNode(ExpressionNode leftNode) { super.setLeftNode(leftNode); @@ -200,11 +219,11 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals // XXX: fix these types, but first we need def compound assignment tests. // its tricky here as there are possibly explicit casts, too. // write the operation instruction for compound assignment - if (getType() == def.class) { + if (getCompoundType() == def.class) { methodWriter.writeDynamicBinaryInstruction( - location, getType(), def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); + location, getCompoundType(), def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); } else { - methodWriter.writeBinaryInstruction(location, getType(), operation); + methodWriter.writeBinaryInstruction(location, getCompoundType(), operation); } methodWriter.writeCast(back); // if necessary cast the promotion type value back to the lhs's type diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index 6b962be861ae1..d9e30dc97a8f8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -35,6 +35,25 @@ public class BinaryMathNode extends ShiftNode { /* ---- begin tree structure ---- */ + protected TypeNode binaryTypeNode; + + public BinaryMathNode setBinaryTypeNode(TypeNode binaryTypeNode) { + this.binaryTypeNode = binaryTypeNode; + return this; + } + + public TypeNode getBinaryTypeNode() { + return binaryTypeNode; + } + + public Class getBinaryType() { + return binaryTypeNode.getType(); + } + + public String getBinaryCanonicalTypeName() { + return binaryTypeNode.getCanonicalTypeName(); + } + @Override public BinaryMathNode setShiftTypeNode(TypeNode shiftTypeNode) { super.setShiftTypeNode(shiftTypeNode); @@ -108,20 +127,20 @@ public BinaryMathNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - if (getType() == String.class && operation == Operation.ADD) { + if (getBinaryType() == String.class && operation == Operation.ADD) { if (!cat) { methodWriter.writeNewStrings(); } leftNode.write(classWriter, methodWriter, globals); - if ((leftNode instanceof BinaryMathNode) == false || ((BinaryMathNode)leftNode).cat == false) { + if (!(leftNode instanceof BinaryMathNode) || !((BinaryMathNode)leftNode).cat) { methodWriter.writeAppendStrings(leftNode.getType()); } rightNode.write(classWriter, methodWriter, globals); - if ((rightNode instanceof BinaryMathNode) == false || ((BinaryMathNode)rightNode).cat == false) { + if (!(rightNode instanceof BinaryMathNode) || !((BinaryMathNode)rightNode).cat) { methodWriter.writeAppendStrings(rightNode.getType()); } @@ -145,7 +164,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals leftNode.write(classWriter, methodWriter, globals); rightNode.write(classWriter, methodWriter, globals); - if (getType() == def.class || (getShiftTypeNode() != null && getShiftType() == def.class)) { + if (getBinaryType() == def.class || (getShiftType() != null && getShiftType() == def.class)) { // def calls adopt the wanted return value. if there was a narrowing cast, // we need to flag that so that its done at runtime. int flags = 0; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java index 59fde24f34748..95e21030e2b90 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java @@ -80,8 +80,8 @@ public CallSubDefNode setTypeNode(TypeNode typeNode) { protected String name; protected String recipe; - protected List pointers; - protected List> typeParameters; + protected List pointers = new ArrayList<>(); + protected List> typeParameters = new ArrayList<>(); public CallSubDefNode setName(String name) { this.name = name; @@ -208,7 +208,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals // create method type from return value and arguments Type[] asmParameterTypes = new Type[typeParameters.size()]; for (int index = 0; index < asmParameterTypes.length; ++index) { - asmParameterTypes[index] = Type.getType(typeParameters.get(index)); + asmParameterTypes[index] = MethodWriter.getType(typeParameters.get(index)); } Type methodType = Type.getMethodType(MethodWriter.getType(getType()), asmParameterTypes); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index cbff1b9c088eb..b3c9460240b15 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -120,32 +120,33 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals boolean writejump = true; - Class comparisonType = getComparisonType(); - Type asmComparisonType = MethodWriter.getType(comparisonType); - - if (comparisonType == void.class || comparisonType == byte.class || comparisonType == short.class || comparisonType == char.class) { - throw new IllegalStateException("unexpected type [" + getComparisonCanonicalTypeName() + "] for comparison"); - } else if (comparisonType == boolean.class) { - if (eq) methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); + Type type = MethodWriter.getType(getComparisonType()); + + if (getComparisonType() == void.class || getComparisonType() == byte.class + || getComparisonType() == short.class || getComparisonType() == char.class) { + throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + + "for type [" + getCanonicalTypeName() + "]"); + } else if (getComparisonType() == boolean.class) { + if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + "for type [" + getCanonicalTypeName() + "]"); } - } else if (comparisonType == int.class || comparisonType == long.class - || comparisonType == float.class || comparisonType == double.class) { - if (eq) methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); - else if (ne) methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); - else if (lt) methodWriter.ifCmp(asmComparisonType, MethodWriter.LT, jump); - else if (lte) methodWriter.ifCmp(asmComparisonType, MethodWriter.LE, jump); - else if (gt) methodWriter.ifCmp(asmComparisonType, MethodWriter.GT, jump); - else if (gte) methodWriter.ifCmp(asmComparisonType, MethodWriter.GE, jump); + } else if (getComparisonType() == int.class || getComparisonType() == long.class + || getComparisonType() == float.class || getComparisonType() == double.class) { + if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); + else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); + else if (lt) methodWriter.ifCmp(type, MethodWriter.LT, jump); + else if (lte) methodWriter.ifCmp(type, MethodWriter.LE, jump); + else if (gt) methodWriter.ifCmp(type, MethodWriter.GT, jump); + else if (gte) methodWriter.ifCmp(type, MethodWriter.GE, jump); else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + "for type [" + getCanonicalTypeName() + "]"); } - } else if (comparisonType == def.class) { + } else if (getComparisonType() == def.class) { Type booleanType = Type.getType(boolean.class); Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(leftNode.getType()), MethodWriter.getType(rightNode.getType())); @@ -157,7 +158,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); writejump = false; } else { - methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); + methodWriter.ifCmp(type, MethodWriter.EQ, jump); } } else if (ne) { if (rightNode instanceof NullNode) { @@ -166,7 +167,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { - methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); + methodWriter.ifCmp(type, MethodWriter.NE, jump); } } else if (lt) { methodWriter.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0); @@ -192,7 +193,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); writejump = false; } else { - methodWriter.ifCmp(asmComparisonType, MethodWriter.EQ, jump); + methodWriter.ifCmp(type, MethodWriter.EQ, jump); } } else if (ne) { if (rightNode instanceof NullNode) { @@ -201,7 +202,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { - methodWriter.ifCmp(asmComparisonType, MethodWriter.NE, jump); + methodWriter.ifCmp(type, MethodWriter.NE, jump); } } else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java index 342a493770f5c..98cadcc94d69d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -28,6 +28,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; +import java.util.ArrayList; import java.util.List; public class FunctionNode extends IRNode { @@ -49,7 +50,7 @@ public BlockNode getBlockNode() { protected String name; Class returnType; - List> typeParameters; + List> typeParameters = new ArrayList<>(); protected boolean isSynthetic; protected boolean doesMethodEscape; protected Variable loopCounter; @@ -116,7 +117,7 @@ public FunctionNode clearTypeParameters() { } public FunctionNode setSynthetic(boolean isSythetic) { - this.name = name; + this.isSynthetic = isSythetic; return this; } @@ -171,11 +172,11 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals access |= Opcodes.ACC_SYNTHETIC; } - Type asmReturnType = Type.getType(returnType); + Type asmReturnType = MethodWriter.getType(returnType); Type[] asmParameterTypes = new Type[typeParameters.size()]; for (int index = 0; index < asmParameterTypes.length; ++index) { - asmParameterTypes[index] = Type.getType(typeParameters.get(index)); + asmParameterTypes[index] = MethodWriter.getType(typeParameters.get(index)); } Method method = new Method(name, asmReturnType, asmParameterTypes); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index 0b8ad80485aab..951e6b25dab2b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -27,6 +27,7 @@ import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -42,7 +43,7 @@ public LambdaNode setTypeNode(TypeNode typeNode) { /* ---- end tree structure, begin node data ---- */ - protected List captures; + protected List captures = new ArrayList<>(); protected FunctionRef funcRef; public LambdaNode addCapture(Variable capture) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java index 621afa8cd5a9d..d6c367bd6e574 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -55,7 +55,7 @@ public ExpressionNode getKeyNode(int index) { } public ExpressionNode getValueNode(int index) { - return keyNodes.get(index); + return valueNodes.get(index); } public ExpressionNode[] getArgumentNode(int index) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index 971420a245abd..93f2636262129 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -141,13 +141,13 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl Type childType = MethodWriter.getType(childNode.getType()); if (operation == Operation.BWNOT) { - if (getType() == def.class) { + if (getUnaryType() == def.class) { org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); methodWriter.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); } else { - if (getType() == int.class) { + if (getUnaryType() == int.class) { methodWriter.push(-1); - } else if (getType() == long.class) { + } else if (getUnaryType() == long.class) { methodWriter.push(-1L); } else { throw new IllegalStateException("unexpected unary math operation [" + operation + "] " + @@ -157,14 +157,14 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.math(MethodWriter.XOR, actualType); } } else if (operation == Operation.SUB) { - if (getType() == def.class) { + if (getUnaryType() == def.class) { org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); methodWriter.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); } else { methodWriter.math(MethodWriter.NEG, actualType); } } else if (operation == Operation.ADD) { - if (getType() == def.class) { + if (getUnaryType() == def.class) { org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType); methodWriter.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index c494a846e936e..bef2a52b8b1a1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -247,6 +247,10 @@ AssignmentNode write() { ) .setLeftNode(lhs.write()) .setRightNode(rhs.write()) + .setCompoundTypeNode(new TypeNode() + .setLocation(location) + .setType(promote) + ) .setLocation(location) .setPre(pre) .setPost(post) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index 1902d4889546a..44f88983fb2e6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -629,6 +629,10 @@ BinaryMathNode write() { .setLocation(location) .setType(shiftDistance) ) + .setBinaryTypeNode(new TypeNode() + .setLocation(location) + .setType(promote) + ) .setLocation(location) .setOperation(operation) .setCat(cat) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index dabb3af74eaf2..943ad35ecc5d6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -196,7 +196,8 @@ UnaryNode write() { .setType(promote) ) .setLocation(location) - .setOperation(operation); + .setOperation(operation) + .setOriginallExplicit(originallyExplicit); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java index 5ed3871ec5e1d..c3dfcc515bdad 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java @@ -64,7 +64,8 @@ NullSafeSubNode write() { .setLocation(location) .setType(actual) ) - .setChildNode(guarded.write()); + .setChildNode(guarded.write()) + .setLocation(location); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java index ece825579014b..d89989d1b48c6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java @@ -73,7 +73,8 @@ NullSafeSubNode write() { .setLocation(location) .setType(actual) ) - .setChildNode(guarded.write()); + .setChildNode(guarded.write()) + .setLocation(location); } @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 44898664bcad0..7186cd9127ec2 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 @@ -91,7 +91,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { CatchNode write() { return new CatchNode() .setDeclarationNode(declaration.write()) - .setBlockNode(block.write()) + .setBlockNode(block == null ? null : block.write()) .setLocation(location); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java index aeeaee363e5d3..37903260d62ad 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java @@ -181,7 +181,8 @@ public ClassNode writeClass() { .setSourceText(sourceText) .setMainMethod(mainMethod) .setMethodEscape(methodEscape) - .addGetMethods(getMethods); + .addGetMethods(getMethods) + .addExtractedVariables(extractedVariables); for (SField field : fields) { classNode.addFieldNode(field.writeField()); 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 1909c36f5a34e..5ea72e4a97c8b 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 @@ -72,7 +72,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DeclarationNode write() { return new DeclarationNode() - .setExpressionNode(expression.write()) + .setExpressionNode(expression == null ? null : expression.write()) .setLocation(location) .setVariable(variable); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java index 23a70a69fb5e3..a8c3514257578 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java @@ -153,10 +153,10 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ForLoopNode write() { return new ForLoopNode() - .setInitialzerNode(initializer.write()) - .setConditionNode(condition.write()) - .setAfterthoughtNode(afterthought.write()) - .setBlockNode(block.write()) + .setInitialzerNode(initializer == null ? null : initializer.write()) + .setConditionNode(condition == null ? null : condition.write()) + .setAfterthoughtNode(afterthought == null ? null : afterthought.write()) + .setBlockNode(block == null ? null : block.write()) .setLocation(location) .setLoopCounter(loopCounter) .setContinuous(continuous); 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 a3168994a1004..0ed88fc3c302e 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 @@ -21,7 +21,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Parameter; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.FunctionNode; import org.elasticsearch.painless.ir.StatementNode; @@ -60,8 +59,6 @@ public final class SFunction extends AStatement { org.objectweb.asm.commons.Method method; List parameters = new ArrayList<>(); - private Variable loop = null; - public SFunction(Location location, String rtnType, String name, List paramTypes, List paramNames, SBlock block, boolean synthetic) { @@ -135,7 +132,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } if (maxLoopCounter > 0) { - loop = locals.getVariable(null, Locals.LOOP); + loopCounter = locals.getVariable(null, Locals.LOOP); } } 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 3f96dfb9ffeb7..079f8ff566447 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 @@ -72,7 +72,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ReturnNode write() { return new ReturnNode() - .setExpressionNode(expression.write()) + .setExpressionNode(expression == null ? null : expression.write()) .setLocation(location); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java index 00182d3954b62..b697ebfbeed91 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java @@ -101,7 +101,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { WhileNode write() { return new WhileNode() .setConditionNode(condition.write()) - .setBlockNode(block.write()) + .setBlockNode(block == null ? null : block.write()) .setLocation(location) .setLoopCounter(loopCounter) .setContinuous(continuous); From e4fcce22db3dc2b05199978846c4eb0bd03d0e2c Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 21 Jan 2020 13:03:41 -0800 Subject: [PATCH 19/24] remove bad refactor of initializer to initializerNode --- .../src/main/java/org/elasticsearch/painless/Constant.java | 2 +- .../src/main/java/org/elasticsearch/painless/Globals.java | 4 ++-- .../java/org/elasticsearch/painless/antlr/PainlessParser.java | 2 +- .../main/java/org/elasticsearch/painless/ir/ClassNode.java | 2 +- .../main/java/org/elasticsearch/painless/node/EListInit.java | 2 +- .../main/java/org/elasticsearch/painless/node/EMapInit.java | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java index e4874a8a69baf..d42c267fc3fef 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Constant.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; /** - * A constant initializerNode to be added to the class file. + * A constant initializer to be added to the class file. */ public class Constant { public final Location location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java index 075e1181d2e90..31cefbcf0c21f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Globals.java @@ -35,10 +35,10 @@ public Globals(BitSet statements) { this.statements = statements; } - /** Adds a new constant initializerNode to be written */ + /** Adds a new constant initializer to be written */ public void addConstantInitializer(Constant constant) { if (constantInitializers.put(constant.name, constant) != null) { - throw new IllegalStateException("constant initializerNode: " + constant.name + " already exists"); + throw new IllegalStateException("constant initializer: " + constant.name + " already exists"); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java index d3bb437ac9883..0e3c831b98c56 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java @@ -52,7 +52,7 @@ class PainlessParser extends Parser { RULE_lamtype = 31, RULE_funcref = 32; public static final String[] ruleNames = { "source", "function", "parameters", "statement", "rstatement", "dstatement", - "trailer", "block", "empty", "initializerNode", "afterthoughtNode", "declaration", + "trailer", "block", "empty", "initializer", "afterthought", "declaration", "decltype", "declvar", "trap", "expression", "unary", "chain", "primary", "postfix", "postdot", "callinvoke", "fieldaccess", "braceaccess", "arrayinitializer", "listinitializer", "mapinitializer", "maptoken", "arguments", "argument", diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index 9411666ee9adc..e8ab25dfbf321 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -470,7 +470,7 @@ public Map write() { if (false == globals.getConstantInitializers().isEmpty()) { Collection inits = globals.getConstantInitializers().values(); - // Initialize the constants in a static initializerNode + // Initialize the constants in a static initializer final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC, WriterConstants.CLINIT, classVisitor, globals.getStatements(), scriptRoot.getCompilerSettings()); clinit.visitCode(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index 2016e76c2d3e3..833ceb79931ba 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -59,7 +59,7 @@ void extractVariables(Set variables) { @Override void analyze(ScriptRoot scriptRoot, Locals locals) { if (!read) { - throw createError(new IllegalArgumentException("Must read from list initializerNode.")); + throw createError(new IllegalArgumentException("Must read from list initializer.")); } actual = ArrayList.class; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index 9ea26d8c06351..025cd132b9f0f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -65,7 +65,7 @@ void extractVariables(Set variables) { @Override void analyze(ScriptRoot scriptRoot, Locals locals) { if (!read) { - throw createError(new IllegalArgumentException("Must read from map initializerNode.")); + throw createError(new IllegalArgumentException("Must read from map initializer.")); } actual = HashMap.class; From 0222ff546ce5105fdf3fc03d364ab6e8c9b8f39a Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 22 Jan 2020 14:53:00 -0800 Subject: [PATCH 20/24] remove pseudo builder setters from ir nodes --- .../painless/ir/ArgumentsNode.java | 59 +---- .../painless/ir/AssignmentNode.java | 151 +++++------- .../painless/ir/BinaryMathNode.java | 109 ++++----- .../elasticsearch/painless/ir/BinaryNode.java | 28 +-- .../elasticsearch/painless/ir/BlockNode.java | 56 +---- .../painless/ir/BooleanNode.java | 44 +--- .../elasticsearch/painless/ir/BraceNode.java | 47 +--- .../painless/ir/BraceSubDefNode.java | 37 +-- .../painless/ir/BraceSubNode.java | 31 +-- .../elasticsearch/painless/ir/BreakNode.java | 11 - .../elasticsearch/painless/ir/CallNode.java | 37 +-- .../painless/ir/CallSubDefNode.java | 144 +----------- .../painless/ir/CallSubNode.java | 67 +----- .../painless/ir/CapturingFuncRefNode.java | 41 +--- .../elasticsearch/painless/ir/CastNode.java | 30 +-- .../elasticsearch/painless/ir/CatchNode.java | 21 +- .../elasticsearch/painless/ir/ClassNode.java | 221 ++---------------- .../painless/ir/ComparisonNode.java | 105 +++------ .../painless/ir/ConditionNode.java | 22 +- .../painless/ir/ConditionalNode.java | 38 +-- .../painless/ir/ConstantNode.java | 22 +- .../painless/ir/ContinueNode.java | 11 - .../painless/ir/DeclarationBlockNode.java | 50 +--- .../painless/ir/DeclarationNode.java | 19 +- .../painless/ir/DoWhileLoopNode.java | 52 +---- .../elasticsearch/painless/ir/DotNode.java | 47 +--- .../painless/ir/DotSubArrayLengthNode.java | 19 -- .../painless/ir/DotSubDefNode.java | 33 +-- .../elasticsearch/painless/ir/DotSubNode.java | 20 +- .../painless/ir/DotSubShortcutNode.java | 28 +-- .../elasticsearch/painless/ir/ElvisNode.java | 35 +-- .../painless/ir/ExpressionNode.java | 31 +-- .../elasticsearch/painless/ir/FieldNode.java | 55 ++--- .../painless/ir/ForEachLoopNode.java | 16 +- .../painless/ir/ForEachSubArrayNode.java | 96 +++----- .../painless/ir/ForEachSubIterableNode.java | 71 ++---- .../painless/ir/ForLoopNode.java | 75 ++---- .../painless/ir/FuncRefNode.java | 22 +- .../painless/ir/FunctionNode.java | 80 ++----- .../org/elasticsearch/painless/ir/IRNode.java | 3 +- .../elasticsearch/painless/ir/IfElseNode.java | 38 +-- .../org/elasticsearch/painless/ir/IfNode.java | 33 +-- .../painless/ir/InstanceofNode.java | 68 +++--- .../elasticsearch/painless/ir/LambdaNode.java | 61 +---- .../painless/ir/ListInitializationNode.java | 69 +----- .../painless/ir/ListSubShortcutNode.java | 35 +-- .../elasticsearch/painless/ir/LoopNode.java | 33 +-- .../painless/ir/MapInitializationNode.java | 57 +---- .../painless/ir/MapSubShortcutNode.java | 37 +-- .../painless/ir/NewArrayFuncRefNode.java | 22 +- .../painless/ir/NewArrayNode.java | 78 +------ .../painless/ir/NewObjectNode.java | 69 +----- .../elasticsearch/painless/ir/NullNode.java | 19 -- .../painless/ir/NullSafeSubNode.java | 27 +-- .../elasticsearch/painless/ir/PrefixNode.java | 64 ----- .../elasticsearch/painless/ir/RegexNode.java | 32 +-- .../elasticsearch/painless/ir/ReturnNode.java | 16 +- .../elasticsearch/painless/ir/ShiftNode.java | 78 ------- .../painless/ir/StatementExpressionNode.java | 19 +- .../painless/ir/StatementNode.java | 11 - .../elasticsearch/painless/ir/StaticNode.java | 19 -- .../elasticsearch/painless/ir/ThrowNode.java | 16 +- .../elasticsearch/painless/ir/TryNode.java | 57 +---- .../elasticsearch/painless/ir/TypeNode.java | 55 ----- .../painless/ir/UnaryMathNode.java | 77 ++---- .../elasticsearch/painless/ir/UnaryNode.java | 23 +- .../painless/ir/UnboundCallNode.java | 95 ++------ .../painless/ir/VariableNode.java | 22 +- .../elasticsearch/painless/ir/WhileNode.java | 60 +---- 69 files changed, 588 insertions(+), 2786 deletions(-) delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java delete mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java index b8921813f9a0c..7caf98cc8313a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java @@ -19,75 +19,24 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Location; - import java.util.ArrayList; -import java.util.Collection; import java.util.List; public abstract class ArgumentsNode extends ExpressionNode { /* ---- begin tree structure ---- */ - protected List argumentNodes = new ArrayList<>(); + private final List argumentNodes = new ArrayList<>(); - public ArgumentsNode addArgumentNode(ExpressionNode argumentNode) { + public void addArgumentNode(ExpressionNode argumentNode) { argumentNodes.add(argumentNode); - return this; - } - - public ArgumentsNode addArgumentNodes(Collection argumentNodes) { - this.argumentNodes.addAll(argumentNodes); - return this; - } - - public ArgumentsNode setArgumentNode(int index, ExpressionNode argumentNode) { - argumentNodes.set(index, argumentNode); - return this; - } - - public ExpressionNode getArgumentNode(int index) { - return argumentNodes.get(index); - } - - public ArgumentsNode removeArgumentNode(ExpressionNode argumentNode) { - argumentNodes.remove(argumentNode); - return this; - } - - public ArgumentsNode removeArgumentNode(int index) { - argumentNodes.remove(index); - return this; - } - - public int getArgumentsSize() { - return argumentNodes.size(); } - public List getArgumentsNodes() { + public List getArgumentNodes() { return argumentNodes; } - public ArgumentsNode clearArgumentNodes() { - argumentNodes.clear(); - return this; - } - - @Override - public ArgumentsNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public ArgumentsNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure */ public ArgumentsNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index bb045bd6eff2d..3957fdb7b3c53 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -23,132 +23,93 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; public class AssignmentNode extends BinaryNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - protected TypeNode compoundTypeNode; + private boolean pre; + private boolean post; + private Operation operation; + private boolean read; + private boolean cat; + private Class compoundType; + private PainlessCast there; + private PainlessCast back; - public AssignmentNode setCompoundTypeNode(TypeNode compoundTypeNode) { - this.compoundTypeNode = compoundTypeNode; - return this; - } - - public TypeNode getCompoundTypeNode() { - return compoundTypeNode; - } - - public Class getCompoundType() { - return compoundTypeNode.getType(); - } - - public String getCompoundCanonicalTypeName() { - return compoundTypeNode.getCanonicalTypeName(); - } - - @Override - public AssignmentNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; - } - - @Override - public AssignmentNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; - } - - @Override - public AssignmentNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected boolean pre; - protected boolean post; - protected Operation operation; - protected boolean read; - protected boolean cat; - protected PainlessCast there; - protected PainlessCast back; - - public AssignmentNode setPre(boolean pre) { + public void setPre(boolean pre) { this.pre = pre; - return this; } public boolean getPre() { return pre; } - public AssignmentNode setPost(boolean post) { + public void setPost(boolean post) { this.post = post; - return this; } public boolean getPost() { return post; } - public AssignmentNode setOperation(Operation operation) { + public void setOperation(Operation operation) { this.operation = operation; - return this; } public Operation getOperation() { return operation; } - public AssignmentNode setRead(boolean read) { + public void setRead(boolean read) { this.read = read; - return this; } public boolean getRead() { return read; } - public AssignmentNode setCat(boolean cat) { + public void setCat(boolean cat) { this.cat = cat; - return this; } public boolean getCat() { return cat; } - public AssignmentNode setThere(PainlessCast there) { + public void setCompoundType(Class compoundType) { + this.compoundType = compoundType; + } + + public Class getCompoundType() { + return compoundType; + } + + public String getCompoundCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(compoundType); + } + + public void setThere(PainlessCast there) { this.there = there; - return this; } public PainlessCast getThere() { return there; } - public AssignmentNode setBack(PainlessCast back) { + public void setBack(PainlessCast back) { this.back = back; - return this; } public PainlessCast getBack() { return back; } - @Override - public AssignmentNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public AssignmentNode() { @@ -170,23 +131,23 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals catElementStackSize = methodWriter.writeNewStrings(); } - leftNode.setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation + getLeftNode().setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation if (cat) { // Handle the case where we are doing a compound assignment // representing a String concatenation. - methodWriter.writeDup(leftNode.accessElementCount(), catElementStackSize); // dup the top element and insert it - // before concat helper on stack - leftNode.load(classWriter, methodWriter, globals); // read the current lhs's value - methodWriter.writeAppendStrings(leftNode.getType()); // append the lhs's value using the StringBuilder + methodWriter.writeDup(getLeftNode().accessElementCount(), catElementStackSize); // dup the top element and insert it + // before concat helper on stack + getLeftNode().load(classWriter, methodWriter, globals); // read the current lhs's value + methodWriter.writeAppendStrings(getLeftNode().getExpressionType()); // append the lhs's value using the StringBuilder - rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs + getRightNode().write(classWriter, methodWriter, globals); // write the bytecode for the rhs - if (rightNode instanceof BinaryMathNode == false || ((BinaryMathNode)rightNode).cat == false) { // check to see if the rhs - // has already done a concatenation - methodWriter.writeAppendStrings(rightNode.getType()); // append the rhs's value since - // it's hasn't already + // check to see if the rhs has already done a concatenation + if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) { + // append the rhs's value since it's hasn't already + methodWriter.writeAppendStrings(getRightNode().getExpressionType()); } methodWriter.writeToStrings(); // put the value for string concat onto the stack @@ -194,59 +155,63 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals if (read) { // if this lhs is also read from dup the value onto the stack - methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + methodWriter.writeDup(MethodWriter.getType( + getLeftNode().getExpressionType()).getSize(), getLeftNode().accessElementCount()); } // store the lhs's value from the stack in its respective variable/field/array - leftNode.store(classWriter, methodWriter, globals); + getLeftNode().store(classWriter, methodWriter, globals); } else if (operation != null) { // Handle the case where we are doing a compound assignment that // does not represent a String concatenation. - methodWriter.writeDup(leftNode.accessElementCount(), 0); // if necessary, dup the previous lhs's value - // to be both loaded from and stored to - leftNode.load(classWriter, methodWriter, globals); // load the current lhs's value + methodWriter.writeDup(getLeftNode().accessElementCount(), 0); // if necessary, dup the previous lhs's value + // to be both loaded from and stored to + getLeftNode().load(classWriter, methodWriter, globals); // load the current lhs's value if (read && post) { // dup the value if the lhs is also read from and is a post increment - methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + methodWriter.writeDup(MethodWriter.getType( + getLeftNode().getExpressionType()).getSize(), getLeftNode().accessElementCount()); } methodWriter.writeCast(there); // if necessary cast the current lhs's value // to the promotion type between the lhs and rhs types - rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs + getRightNode().write(classWriter, methodWriter, globals); // write the bytecode for the rhs // XXX: fix these types, but first we need def compound assignment tests. // its tricky here as there are possibly explicit casts, too. // write the operation instruction for compound assignment - if (getCompoundType() == def.class) { + if (compoundType == def.class) { methodWriter.writeDynamicBinaryInstruction( - location, getCompoundType(), def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); + location, compoundType, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT); } else { - methodWriter.writeBinaryInstruction(location, getCompoundType(), operation); + methodWriter.writeBinaryInstruction(location, compoundType, operation); } methodWriter.writeCast(back); // if necessary cast the promotion type value back to the lhs's type if (read && !post) { // dup the value if the lhs is also read from and is not a post increment - methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + methodWriter.writeDup(MethodWriter.getType( + getLeftNode().getExpressionType()).getSize(), getLeftNode().accessElementCount()); } // store the lhs's value from the stack in its respective variable/field/array - leftNode.store(classWriter, methodWriter, globals); + getLeftNode().store(classWriter, methodWriter, globals); } else { // Handle the case for a simple write. - rightNode.write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs + getRightNode().write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs if (read) { // dup the value if the lhs is also read from - methodWriter.writeDup(MethodWriter.getType(leftNode.getType()).getSize(), leftNode.accessElementCount()); + methodWriter.writeDup(MethodWriter.getType( + getLeftNode().getExpressionType()).getSize(), getLeftNode().accessElementCount()); } // store the lhs's value from the stack in its respective variable/field/array - leftNode.store(classWriter, methodWriter, globals); + getLeftNode().store(classWriter, methodWriter, globals); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index d9e30dc97a8f8..5c73352a1a394 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -26,85 +26,64 @@ import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class BinaryMathNode extends ShiftNode { +public class BinaryMathNode extends BinaryNode { - /* ---- begin tree structure ---- */ - - protected TypeNode binaryTypeNode; - - public BinaryMathNode setBinaryTypeNode(TypeNode binaryTypeNode) { - this.binaryTypeNode = binaryTypeNode; - return this; - } + /* ---- begin node data ---- */ - public TypeNode getBinaryTypeNode() { - return binaryTypeNode; - } + private Operation operation; + private Class binaryType; + private Class shiftType; + private boolean cat; + private boolean originallyExplicit; // record whether there was originally an explicit cast - public Class getBinaryType() { - return binaryTypeNode.getType(); + public void setOperation(Operation operation) { + this.operation = operation; } - public String getBinaryCanonicalTypeName() { - return binaryTypeNode.getCanonicalTypeName(); + public Operation getOperation() { + return operation; } - @Override - public BinaryMathNode setShiftTypeNode(TypeNode shiftTypeNode) { - super.setShiftTypeNode(shiftTypeNode); - return this; + public void setBinaryType(Class binaryType) { + this.binaryType = binaryType; } - @Override - public BinaryMathNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; + public Class getBinaryType() { + return binaryType; } - @Override - public BinaryMathNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; + public String getBinaryCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(binaryType); } - @Override - public BinaryMathNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; + public void setShiftType(Class shiftType) { + this.shiftType = shiftType; } - /* ---- begin node data ---- */ - - protected Operation operation; - protected boolean cat; - protected boolean originallyExplicit; // record whether there was originally an explicit cast - - public BinaryMathNode setOperation(Operation operation) { - this.operation = operation; - return this; + public Class getShiftType() { + return shiftType; } - public Operation getOperation() { - return operation; + public String getShiftCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(shiftType); } - public BinaryMathNode setCat(boolean cat) { + public void setCat(boolean cat) { this.cat = cat; - return this; } public boolean getCat() { return cat; } - public BinaryMathNode setOriginallExplicit(boolean originallyExplicit) { + public void setOriginallExplicit(boolean originallyExplicit) { this.originallyExplicit = originallyExplicit; - return this; } public boolean getOriginallyExplicit() { @@ -112,9 +91,8 @@ public boolean getOriginallyExplicit() { } @Override - public BinaryMathNode setLocation(Location location) { + public void setLocation(Location location) { super.setLocation(location); - return this; } /* ---- end node data ---- */ @@ -128,28 +106,28 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeDebugInfo(location); if (getBinaryType() == String.class && operation == Operation.ADD) { - if (!cat) { + if (cat == false) { methodWriter.writeNewStrings(); } - leftNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); - if (!(leftNode instanceof BinaryMathNode) || !((BinaryMathNode)leftNode).cat) { - methodWriter.writeAppendStrings(leftNode.getType()); + if (getLeftNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getLeftNode()).getCat() == false) { + methodWriter.writeAppendStrings(getLeftNode().getExpressionType()); } - rightNode.write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); - if (!(rightNode instanceof BinaryMathNode) || !((BinaryMathNode)rightNode).cat) { - methodWriter.writeAppendStrings(rightNode.getType()); + if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) { + methodWriter.writeAppendStrings(getRightNode().getExpressionType()); } - if (!cat) { + if (cat == false) { methodWriter.writeToStrings(); } } else if (operation == Operation.FIND || operation == Operation.MATCH) { - rightNode.write(classWriter, methodWriter, globals); - leftNode.write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER); if (operation == Operation.FIND) { @@ -158,22 +136,23 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Matcher.class), WriterConstants.MATCHER_MATCHES); } else { throw new IllegalStateException("unexpected binary math operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } } else { - leftNode.write(classWriter, methodWriter, globals); - rightNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); - if (getBinaryType() == def.class || (getShiftType() != null && getShiftType() == def.class)) { + if (binaryType == def.class || (shiftType != null && shiftType == def.class)) { // def calls adopt the wanted return value. if there was a narrowing cast, // we need to flag that so that its done at runtime. int flags = 0; if (originallyExplicit) { flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; } - methodWriter.writeDynamicBinaryInstruction(location, getType(), leftNode.getType(), rightNode.getType(), operation, flags); + methodWriter.writeDynamicBinaryInstruction(location, + getExpressionType(), getLeftNode().getExpressionType(), getRightNode().getExpressionType(), operation, flags); } else { - methodWriter.writeBinaryInstruction(location, getType(), operation); + methodWriter.writeBinaryInstruction(location, getExpressionType(), operation); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java index 85096d13e0768..0858afb55bc83 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java @@ -19,48 +19,30 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Location; - public abstract class BinaryNode extends ExpressionNode { /* ---- begin tree structure ---- */ - protected ExpressionNode leftNode; - protected ExpressionNode rightNode; + private ExpressionNode leftNode; + private ExpressionNode rightNode; - public BinaryNode setLeftNode(ExpressionNode leftNode) { + public void setLeftNode(ExpressionNode leftNode) { this.leftNode = leftNode; - return this; } public ExpressionNode getLeftNode() { return leftNode; } - public BinaryNode setRightNode(ExpressionNode rightNode) { + public void setRightNode(ExpressionNode rightNode) { this.rightNode = rightNode; - return this; } public ExpressionNode getRightNode() { return rightNode; } - @Override - public BinaryNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public BinaryNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public BinaryNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java index 4ce94b803c2f9..f702f53850d5d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java @@ -21,90 +21,46 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; public class BlockNode extends StatementNode { /* ---- begin tree structure ---- */ - protected List statementNodes = new ArrayList<>(); + private final List statementNodes = new ArrayList<>(); - public BlockNode addStatementNode(StatementNode statementNode) { + public void addStatementNode(StatementNode statementNode) { statementNodes.add(statementNode); - return this; - } - - public BlockNode addStatementNodes(Collection statementNodes) { - this.statementNodes.addAll(statementNodes); - return this; - } - - public BlockNode setStatementNode(int index, StatementNode statementNode) { - statementNodes.set(index, statementNode); - return this; - } - - public StatementNode getStatementNode(int index) { - return statementNodes.get(index); - } - - public BlockNode removeStatementNode(StatementNode statementNode) { - statementNodes.remove(statementNode); - return this; - } - - public BlockNode removeStatementNode(int index) { - statementNodes.remove(index); - return this; - } - - public int getStatementsSize() { - return statementNodes.size(); } public List getStatementsNodes() { return statementNodes; } - public BlockNode clearStatementNodes() { - statementNodes.clear(); - return this; - } - /* ---- end tree structure, begin node data ---- */ - protected boolean doAllEscape; - protected int statementCount; + private boolean doAllEscape; + private int statementCount; - public BlockNode setAllEscape(boolean doAllEscape) { + public void setAllEscape(boolean doAllEscape) { this.doAllEscape = doAllEscape; - return this; } public boolean doAllEscape() { return doAllEscape; } - public BlockNode setStatementCount(int statementCount) { + public void setStatementCount(int statementCount) { this.statementCount = statementCount; - return this; } public int getStatementCount() { return statementCount; } - @Override - public BlockNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public BlockNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index a67c7a52ed788..412823d20b5d3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.objectweb.asm.Label; @@ -29,45 +28,18 @@ public class BooleanNode extends BinaryNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public BooleanNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; - } + private Operation operation; - @Override - public BooleanNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; - } - - @Override - public BooleanNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected Operation operation; - - public BooleanNode setOperation(Operation operation) { + public void setOperation(Operation operation) { this.operation = operation; - return this; } public Operation getOperation() { return operation; } - @Override - public BooleanNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public BooleanNode() { @@ -82,9 +54,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label fals = new Label(); Label end = new Label(); - leftNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - rightNode.write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.push(true); @@ -97,9 +69,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label fals = new Label(); Label end = new Label(); - leftNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFNE, tru); - rightNode.write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.mark(tru); @@ -110,7 +82,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.mark(end); } else { throw new IllegalStateException("unexpected boolean operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java index f6898a5dcb74a..5e4165718e5a5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java @@ -21,40 +21,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -public class BraceNode extends PrefixNode { - - /* ---- begin tree structure ---- */ - - @Override - public BraceNode setPrefixNode(ExpressionNode prefixNode) { - this.prefixNode = prefixNode; - return this; - } - - @Override - public BraceNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public BraceNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public BraceNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ +public class BraceNode extends BinaryNode { public BraceNode() { // do nothing @@ -62,28 +31,28 @@ public BraceNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefixNode.write(classWriter, methodWriter, globals); - childNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); } @Override protected int accessElementCount() { - return childNode.accessElementCount(); + return getRightNode().accessElementCount(); } @Override protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefixNode.write(classWriter, methodWriter, globals); - childNode.setup(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().setup(classWriter, methodWriter, globals); } @Override protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.load(classWriter, methodWriter, globals); + getRightNode().load(classWriter, methodWriter, globals); } @Override protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.store(classWriter, methodWriter, globals); + getRightNode().store(classWriter, methodWriter, globals); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java index 0995501cd9f3b..6eae4c31ae630 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java @@ -22,36 +22,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; public class BraceSubDefNode extends UnaryNode { - /* ---- begin tree structure ---- */ - - @Override - public BraceSubDefNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public BraceSubDefNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public BraceSubDefNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public BraceSubDefNode() { // do nothing } @@ -70,9 +45,9 @@ protected int accessElementCount() { @Override protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.dup(); - childNode.write(classWriter, methodWriter, globals); - Type methodType = Type.getMethodType( - MethodWriter.getType(childNode.getType()), Type.getType(Object.class), MethodWriter.getType(childNode.getType())); + getChildNode().write(classWriter, methodWriter, globals); + Type methodType = Type.getMethodType(MethodWriter.getType( + getChildNode().getExpressionType()), Type.getType(Object.class), MethodWriter.getType(getChildNode().getExpressionType())); methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); } @@ -80,8 +55,8 @@ protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - Type methodType = - Type.getMethodType(MethodWriter.getType(getType()), Type.getType(Object.class), MethodWriter.getType(childNode.getType())); + Type methodType = Type.getMethodType(MethodWriter.getType( + getExpressionType()), Type.getType(Object.class), MethodWriter.getType(getChildNode().getExpressionType())); methodWriter.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD); } @@ -90,7 +65,7 @@ protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType(Type.getType(void.class), Type.getType(Object.class), - MethodWriter.getType(childNode.getType()), MethodWriter.getType(getType())); + MethodWriter.getType(getChildNode().getExpressionType()), MethodWriter.getType(getExpressionType())); methodWriter.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java index 04852bc8b3d6f..1c9a2fec25635 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java @@ -21,37 +21,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class BraceSubNode extends UnaryNode { - /* ---- begin tree structure ---- */ - - @Override - public BraceSubNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public BraceSubNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public BraceSubNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public BraceSubNode() { // do nothing } @@ -69,7 +44,7 @@ protected int accessElementCount() { @Override protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); Label noFlip = new Label(); methodWriter.dup(); @@ -84,12 +59,12 @@ protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals @Override protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - methodWriter.arrayLoad(MethodWriter.getType(getType())); + methodWriter.arrayLoad(MethodWriter.getType(getExpressionType())); } @Override protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - methodWriter.arrayStore(MethodWriter.getType(getType())); + methodWriter.arrayStore(MethodWriter.getType(getExpressionType())); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java index 6239e23dbd24e..296e31f381f67 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java @@ -21,21 +21,10 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class BreakNode extends StatementNode { - /* ---- begin node data ---- */ - - @Override - public BreakNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public BreakNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java index 3f009e65ca367..2f79de8472c23 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java @@ -21,40 +21,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -public class CallNode extends PrefixNode { - - /* ---- begin tree structure ---- */ - - @Override - public CallNode setPrefixNode(ExpressionNode prefixNode) { - this.prefixNode = prefixNode; - return this; - } - - @Override - public CallNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public CallNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public CallNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ +public class CallNode extends BinaryNode { public CallNode() { // do nothing @@ -62,7 +31,7 @@ public CallNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefixNode.write(classWriter, methodWriter, globals); - childNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java index 95e21030e2b90..56e1ae400e8f9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java @@ -22,175 +22,53 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Type; import java.util.ArrayList; -import java.util.Collection; import java.util.List; public class CallSubDefNode extends ArgumentsNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public CallSubDefNode addArgumentNode(ExpressionNode argumentNode) { - super.addArgumentNode(argumentNode); - return this; - } - - @Override - public CallSubDefNode addArgumentNodes(Collection argumentNodes) { - super.addArgumentNodes(argumentNodes); - return this; - } - - @Override - public CallSubDefNode setArgumentNode(int index, ExpressionNode argumentNode) { - super.setArgumentNode(index, argumentNode); - return this; - } - - @Override - public CallSubDefNode removeArgumentNode(ExpressionNode argumentNode) { - super.removeArgumentNode(argumentNode); - return this; - } - - @Override - public CallSubDefNode removeArgumentNode(int index) { - super.removeArgumentNode(index); - return this; - } + private String name; + private String recipe; + private final List pointers = new ArrayList<>(); + private final List> typeParameters = new ArrayList<>(); - @Override - public CallSubDefNode clearArgumentNodes() { - super.clearArgumentNodes(); - return this; - } - - @Override - public CallSubDefNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected String name; - protected String recipe; - protected List pointers = new ArrayList<>(); - protected List> typeParameters = new ArrayList<>(); - - public CallSubDefNode setName(String name) { + public void setName(String name) { this.name = name; - return this; } public String getName() { return name; } - public CallSubDefNode setRecipe(String recipe) { + public void setRecipe(String recipe) { this.recipe = recipe; - return this; } public String getRecipe() { return recipe; } - public CallSubDefNode addPointer(String pointer) { + public void addPointer(String pointer) { pointers.add(pointer); - return this; - } - - public CallSubDefNode addPointers(Collection pointers) { - this.pointers.addAll(pointers); - return this; - } - - public CallSubDefNode setPointer(int index, String pointer) { - pointers.set(index, pointer); - return this; - } - - public String getPointer(int index) { - return pointers.get(index); - } - - public CallSubDefNode removePointer(String pointer) { - pointers.remove(pointer); - return this; - } - - public CallSubDefNode removePointer(int index) { - pointers.remove(index); - return this; - } - - public int getPointersSize() { - return pointers.size(); } public List getPointers() { return pointers; } - public CallSubDefNode clearPointers() { - pointers.clear(); - return this; - } - - public CallSubDefNode addTypeParameter(Class typeParameter) { + public void addTypeParameter(Class typeParameter) { typeParameters.add(typeParameter); - return this; - } - - public CallSubDefNode addTypeParameters(Collection> typeParameters) { - this.typeParameters.addAll(typeParameters); - return this; - } - - public CallSubDefNode setTypeParameter(int index, Class typeParameter) { - typeParameters.set(index, typeParameter); - return this; - } - - public Class getTypeParameter(int index) { - return typeParameters.get(index); - } - - public CallSubDefNode removeTypeParameter(Class typeParameter) { - typeParameters.remove(typeParameter); - return this; - } - - public CallSubDefNode removeTypeParameter(int index) { - typeParameters.remove(index); - return this; - } - - public int getTypeParametersSize() { - return typeParameters.size(); } public List> getTypeParameters() { return typeParameters; } - public CallSubDefNode clearTypeParameters() { - typeParameters.clear(); - return this; - } - - @Override - public CallSubDefNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public CallSubDefNode() { @@ -201,7 +79,7 @@ public CallSubDefNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - for (ExpressionNode argumentNode : argumentNodes) { + for (ExpressionNode argumentNode : getArgumentNodes()) { argumentNode.write(classWriter, methodWriter, globals); } @@ -210,7 +88,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals for (int index = 0; index < asmParameterTypes.length; ++index) { asmParameterTypes[index] = MethodWriter.getType(typeParameters.get(index)); } - Type methodType = Type.getMethodType(MethodWriter.getType(getType()), asmParameterTypes); + Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), asmParameterTypes); List args = new ArrayList<>(); args.add(recipe); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java index e87740296b1af..f16a09d1bb2e5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java @@ -21,87 +21,32 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; -import java.util.Collection; - public class CallSubNode extends ArgumentsNode { - /* ---- begin tree structure ---- */ - - @Override - public CallSubNode addArgumentNode(ExpressionNode argumentNode) { - super.addArgumentNode(argumentNode); - return this; - } - - @Override - public CallSubNode addArgumentNodes(Collection argumentNodes) { - super.addArgumentNodes(argumentNodes); - return this; - } - - @Override - public CallSubNode setArgumentNode(int index, ExpressionNode argumentNode) { - super.setArgumentNode(index, argumentNode); - return this; - } - - @Override - public CallSubNode removeArgumentNode(ExpressionNode argumentNode) { - super.removeArgumentNode(argumentNode); - return this; - } - - @Override - public CallSubNode removeArgumentNode(int index) { - super.removeArgumentNode(index); - return this; - } + /* ---- begin node data ---- */ - @Override - public CallSubNode clearArgumentNodes() { - super.clearArgumentNodes(); - return this; - } + private PainlessMethod method; + private Class box; - @Override - public CallSubNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected PainlessMethod method; - protected Class box; - - public CallSubNode setMethod(PainlessMethod method) { + public void setMethod(PainlessMethod method) { this.method = method; - return this; } public PainlessMethod getMethod() { return method; } - public CallSubNode setBox(Class box) { + public void setBox(Class box) { this.box = box; - return this; } public Class getBox() { return box; } - @Override - public CallSubNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public CallSubNode() { @@ -116,7 +61,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.box(MethodWriter.getType(box)); } - for (ExpressionNode argumentNode : argumentNodes) { + for (ExpressionNode argumentNode : getArgumentNodes()) { argumentNode.write(classWriter, methodWriter, globals); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index c62f127fb98c1..bb74312012e85 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -24,70 +24,51 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; public class CapturingFuncRefNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public CapturingFuncRefNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected String name; - protected Variable captured; - protected FunctionRef funcRef; - protected String pointer; + private String name; + private Variable captured; + private FunctionRef funcRef; + private String pointer; - public CapturingFuncRefNode setName(String name) { + public void setName(String name) { this.name = name; - return this; } public String getName() { return name; } - public CapturingFuncRefNode setCaptured(Variable captured) { + public void setCaptured(Variable captured) { this.captured = captured; - return this; } public Variable getCaptured() { return captured; } - public CapturingFuncRefNode setFuncRef(FunctionRef funcRef) { + public void setFuncRef(FunctionRef funcRef) { this.funcRef = funcRef; - return this; } public FunctionRef getFuncRef() { return funcRef; } - public CapturingFuncRefNode setPointer(String pointer) { + public void setPointer(String pointer) { this.pointer = pointer; - return this; } public String getPointer() { return pointer; } - @Override - public CapturingFuncRefNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public CapturingFuncRefNode() { @@ -104,8 +85,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } else if (funcRef == null) { // typed interface, dynamic implementation methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - Type methodType = Type.getMethodType(MethodWriter.getType(getType()), MethodWriter.getType(captured.clazz)); - methodWriter.invokeDefCall(name, methodType, DefBootstrap.REFERENCE, getCanonicalTypeName()); + Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), MethodWriter.getType(captured.clazz)); + methodWriter.invokeDefCall(name, methodType, DefBootstrap.REFERENCE, getExpressionCanonicalTypeName()); } else { // typed interface, typed implementation methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java index 92189be6c80d9..a47d02452d7a9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java @@ -21,47 +21,23 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; public class CastNode extends UnaryNode { - /* ---- begin tree structure ---- */ - - @Override - public CastNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public CastNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - /* ---- begin node data ---- */ - protected PainlessCast cast; + private PainlessCast cast; - public CastNode setCast(PainlessCast cast) { + public void setCast(PainlessCast cast) { this.cast = cast; - return this; } public PainlessCast getCast() { return cast; } - @Override - public CastNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public CastNode() { @@ -70,7 +46,7 @@ public CastNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); methodWriter.writeDebugInfo(location); methodWriter.writeCast(cast); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index b8fbda1a1d782..c8f85f92d6bd8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -30,36 +29,26 @@ public class CatchNode extends StatementNode { /* ---- begin tree structure ---- */ - protected DeclarationNode declarationNode; - protected BlockNode blockNode; + private DeclarationNode declarationNode; + private BlockNode blockNode; - public CatchNode setDeclarationNode(DeclarationNode declarationNode) { + public void setDeclarationNode(DeclarationNode declarationNode) { this.declarationNode = declarationNode; - return this; } public DeclarationNode getDeclarationNode() { return declarationNode; } - public CatchNode setBlockNode(BlockNode blockNode) { + public void setBlockNode(BlockNode blockNode) { this.blockNode = blockNode; - return this; } public BlockNode getBlockNode() { return blockNode; } - /* ---- end tree structure, begin node data ---- */ - - @Override - public CatchNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public CatchNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index e8ab25dfbf321..6e6d5376bcdb3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -72,291 +72,118 @@ public class ClassNode extends IRNode { /* ---- begin tree structure ---- */ - protected final List fieldNodes = new ArrayList<>(); - protected final List functionNodes = new ArrayList<>(); - protected final List statementNodes = new ArrayList<>(); + private final List fieldNodes = new ArrayList<>(); + private final List functionNodes = new ArrayList<>(); + private final List statementNodes = new ArrayList<>(); - public ClassNode addFieldNode(FieldNode fieldNode) { + public void addFieldNode(FieldNode fieldNode) { fieldNodes.add(fieldNode); - return this; - } - - public ClassNode addFieldNodes(Collection fieldNodes) { - this.fieldNodes.addAll(fieldNodes); - return this; - } - - public ClassNode setFieldNode(int index, FieldNode fieldNode) { - fieldNodes.set(index, fieldNode); - return this; - } - - public FieldNode getFieldNode(int index) { - return fieldNodes.get(index); - } - - public ClassNode removeFieldNode(FieldNode fieldNode) { - fieldNodes.remove(fieldNode); - return this; - } - - public ClassNode removeFieldNode(int index) { - fieldNodes.remove(index); - return this; - } - - public int getFieldsSize() { - return fieldNodes.size(); } public List getFieldsNodes() { return fieldNodes; } - - public ClassNode clearFieldNodes() { - fieldNodes.clear(); - return this; - } - public ClassNode addFunctionNode(FunctionNode functionNode) { + public void addFunctionNode(FunctionNode functionNode) { functionNodes.add(functionNode); - return this; - } - - public ClassNode addFunctionNode(Collection functionNodes) { - this.functionNodes.addAll(functionNodes); - return this; - } - - public ClassNode setFunctionNode(int index, FunctionNode functionNode) { - functionNodes.set(index, functionNode); - return this; - } - - public FunctionNode getFunctionNode(int index) { - return functionNodes.get(index); - } - - public ClassNode removeFunctionNode(FunctionNode functionNode) { - functionNodes.remove(functionNode); - return this; - } - - public ClassNode removeFunctionNode(int index) { - functionNodes.remove(index); - return this; - } - - public int getFunctionsSize() { - return functionNodes.size(); } public List getFunctionsNodes() { return functionNodes; } - public ClassNode clearFunctionNodes() { - functionNodes.clear(); - return this; - } - - public ClassNode addStatementNode(StatementNode statementNode) { + public void addStatementNode(StatementNode statementNode) { statementNodes.add(statementNode); - return this; - } - - public ClassNode addStatementNodes(Collection statementNodes) { - this.statementNodes.addAll(statementNodes); - return this; - } - - public ClassNode setStatementNode(int index, StatementNode statementNode) { - statementNodes.set(index, statementNode); - return this; - } - - public StatementNode getStatementNode(int index) { - return statementNodes.get(index); - } - - public ClassNode removeStatementNode(StatementNode statementNode) { - statementNodes.remove(statementNode); - return this; - } - - public ClassNode removeStatementNode(int index) { - statementNodes.remove(index); - return this; - } - - public int getStatementsSize() { - return statementNodes.size(); } public List getStatementsNodes() { return statementNodes; } - - public ClassNode clearStatementNodes() { - statementNodes.clear(); - return this; - } /* ---- end tree structure, begin node data ---- */ - protected ScriptClassInfo scriptClassInfo; - protected String name; - protected String sourceText; - protected Printer debugStream; - protected ScriptRoot scriptRoot; - protected Locals mainMethod; - protected boolean doesMethodEscape; - protected final Set extractedVariables = new HashSet<>(); - protected final List getMethods = new ArrayList<>(); - - public ClassNode setScriptClassInfo(ScriptClassInfo scriptClassInfo) { + private ScriptClassInfo scriptClassInfo; + private String name; + private String sourceText; + private Printer debugStream; + private ScriptRoot scriptRoot; + private Locals mainMethod; + private boolean doesMethodEscape; + private final Set extractedVariables = new HashSet<>(); + private final List getMethods = new ArrayList<>(); + + public void setScriptClassInfo(ScriptClassInfo scriptClassInfo) { this.scriptClassInfo = scriptClassInfo; - return this; } public ScriptClassInfo getScriptClassInfo() { return scriptClassInfo; } - public ClassNode setName(String name) { + public void setName(String name) { this.name = name; - return this; } public String getName() { return name; } - public ClassNode setSourceText(String sourceText) { + public void setSourceText(String sourceText) { this.sourceText = sourceText; - return this; } public String getSourceText() { return sourceText; } - public ClassNode setDebugStream(Printer debugStream) { + public void setDebugStream(Printer debugStream) { this.debugStream = debugStream; - return this; } public Printer getDebugStream() { return debugStream; } - public ClassNode setScriptRoot(ScriptRoot scriptRoot) { + public void setScriptRoot(ScriptRoot scriptRoot) { this.scriptRoot = scriptRoot; - return this; } public ScriptRoot getScriptRoot() { return scriptRoot; } - public ClassNode setMainMethod(Locals mainMethod) { + public void setMainMethod(Locals mainMethod) { this.mainMethod = mainMethod; - return this; } public Locals getMainMethod() { return mainMethod; } - public ClassNode setMethodEscape(boolean doesMethodEscape) { + public void setMethodEscape(boolean doesMethodEscape) { this.doesMethodEscape = doesMethodEscape; - return this; } public boolean doesMethodEscape() { return doesMethodEscape; } - public ClassNode addExtractedVariable(String extractedVariable) { + public void addExtractedVariable(String extractedVariable) { extractedVariables.add(extractedVariable); - return this; - } - - public ClassNode addExtractedVariables(Collection extractedVariables) { - this.extractedVariables.addAll(extractedVariables); - return this; } public boolean containsExtractedVariable(String extractedVariable) { return extractedVariables.contains(extractedVariable); } - public ClassNode removeExtractedVariable(String extractedVariable) { - extractedVariables.remove(extractedVariable); - return this; - } - - public int getExtractedVariablesSize() { - return extractedVariables.size(); - } - public Set getExtractedVariables() { return extractedVariables; } - public ClassNode clearExtractedVariables() { - extractedVariables.clear(); - return this; - } - - public ClassNode addGetMethod(org.objectweb.asm.commons.Method getMethod) { - getMethods.add(getMethod); - return this; - } - - public ClassNode addGetMethods(Collection getMethods) { - this.getMethods.addAll(getMethods); - return this; - } - - public ClassNode setGetMethod(int index, org.objectweb.asm.commons.Method getMethod) { - getMethods.set(index, getMethod); - return this; - } - - public org.objectweb.asm.commons.Method getGetMethod(int index) { - return getMethods.get(index); - } - - public ClassNode removeGetMethod(org.objectweb.asm.commons.Method getMethod) { - getMethods.remove(getMethod); - return this; - } - - public ClassNode removeGetMethod(int index) { - getMethods.remove(index); - return this; - } - - public int getGetMethodsSize() { - return getMethods.size(); - } - public List getGetMethods() { return getMethods; } - public ClassNode clearGetMethods() { - getMethods.clear(); - return this; - } - - @Override - public ClassNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ protected Globals globals; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index b3c9460240b15..adffe597fb3d1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -22,9 +22,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Type; @@ -34,62 +34,29 @@ public class ComparisonNode extends BinaryNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - protected TypeNode comparisonTypeNode; + private Operation operation; + private Class comparisonType; - public ComparisonNode setComparisonTypeNode(TypeNode comparisonTypeNode) { - this.comparisonTypeNode = comparisonTypeNode; - return this; - } - - public TypeNode getComparisonTypeNode() { - return comparisonTypeNode; - } - - public Class getComparisonType() { - return comparisonTypeNode.getType(); - } - - public String getComparisonCanonicalTypeName() { - return comparisonTypeNode.getCanonicalTypeName(); - } - - @Override - public ComparisonNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; - } - - @Override - public ComparisonNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; + public void setOperation(Operation operation) { + this.operation = operation; } - @Override - public ComparisonNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; + public Operation getOperation() { + return operation; } - /* ---- end tree structure, begin node data ---- */ - - protected Operation operation; - - public ComparisonNode setOperation(Operation operation) { - this.operation = operation; - return this; + public void setComparisonType(Class comparisonType) { + this.comparisonType = comparisonType; } - public Operation getOperation() { - return operation; + public Class getComparisonType() { + return comparisonType; } - @Override - public ComparisonNode setLocation(Location location) { - super.setLocation(location); - return this; + public String getComparisonCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(comparisonType); } /* ---- end node data ---- */ @@ -102,10 +69,10 @@ public ComparisonNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - leftNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); - if (rightNode instanceof NullNode == false) { - rightNode.write(classWriter, methodWriter, globals); + if (getRightNode() instanceof NullNode == false) { + getRightNode().write(classWriter, methodWriter, globals); } Label jump = new Label(); @@ -120,21 +87,21 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals boolean writejump = true; - Type type = MethodWriter.getType(getComparisonType()); + Type type = MethodWriter.getType(comparisonType); - if (getComparisonType() == void.class || getComparisonType() == byte.class - || getComparisonType() == short.class || getComparisonType() == char.class) { + if (comparisonType == void.class || comparisonType == byte.class + || comparisonType == short.class || comparisonType == char.class) { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); - } else if (getComparisonType() == boolean.class) { + "for type [" + getExpressionCanonicalTypeName() + "]"); + } else if (comparisonType == boolean.class) { if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } - } else if (getComparisonType() == int.class || getComparisonType() == long.class - || getComparisonType() == float.class || getComparisonType() == double.class) { + } else if (comparisonType == int.class || comparisonType == long.class + || comparisonType == float.class || comparisonType == double.class) { if (eq) methodWriter.ifCmp(type, MethodWriter.EQ, jump); else if (ne) methodWriter.ifCmp(type, MethodWriter.NE, jump); else if (lt) methodWriter.ifCmp(type, MethodWriter.LT, jump); @@ -143,27 +110,27 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals else if (gte) methodWriter.ifCmp(type, MethodWriter.GE, jump); else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } - } else if (getComparisonType() == def.class) { + } else if (comparisonType == def.class) { Type booleanType = Type.getType(boolean.class); Type descriptor = Type.getMethodType(booleanType, - MethodWriter.getType(leftNode.getType()), MethodWriter.getType(rightNode.getType())); + MethodWriter.getType(getLeftNode().getExpressionType()), MethodWriter.getType(getRightNode().getExpressionType())); if (eq) { - if (rightNode instanceof NullNode) { + if (getRightNode() instanceof NullNode) { methodWriter.ifNull(jump); - } else if (leftNode instanceof NullNode == false && operation == Operation.EQ) { + } else if (getLeftNode() instanceof NullNode == false && operation == Operation.EQ) { methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); writejump = false; } else { methodWriter.ifCmp(type, MethodWriter.EQ, jump); } } else if (ne) { - if (rightNode instanceof NullNode) { + if (getRightNode() instanceof NullNode) { methodWriter.ifNonNull(jump); - } else if (leftNode instanceof NullNode == false && operation == Operation.NE) { + } else if (getLeftNode() instanceof NullNode == false && operation == Operation.NE) { methodWriter.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); methodWriter.ifZCmp(MethodWriter.EQ, jump); } else { @@ -183,11 +150,11 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals writejump = false; } else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } } else { if (eq) { - if (rightNode instanceof NullNode) { + if (getRightNode() instanceof NullNode) { methodWriter.ifNull(jump); } else if (operation == Operation.EQ) { methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); @@ -196,7 +163,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.ifCmp(type, MethodWriter.EQ, jump); } } else if (ne) { - if (rightNode instanceof NullNode) { + if (getRightNode() instanceof NullNode) { methodWriter.ifNonNull(jump); } else if (operation == Operation.NE) { methodWriter.invokeStatic(OBJECTS_TYPE, EQUALS); @@ -206,7 +173,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } } else { throw new IllegalStateException("unexpected comparison operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java index b5df4e89e1259..0f28a8e3ec78c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java @@ -19,42 +19,30 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Location; - public abstract class ConditionNode extends StatementNode { /* ---- begin tree structure ---- */ - protected ExpressionNode conditionNode; - protected BlockNode blockNode; + private ExpressionNode conditionNode; + private BlockNode blockNode; - public ConditionNode setConditionNode(ExpressionNode conditionNode) { + public void setConditionNode(ExpressionNode conditionNode) { this.conditionNode = conditionNode; - return this; } public ExpressionNode getConditionNode() { return conditionNode; } - public ConditionNode setBlockNode(BlockNode blockNode) { + public void setBlockNode(BlockNode blockNode) { this.blockNode = blockNode; - return this; } public BlockNode getBlockNode() { return blockNode; } - /* ---- end tree structure, begin node data ---- */ - - @Override - public ConditionNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public ConditionNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java index 961ad32f3cd69..4e2998ebb3158 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -30,44 +29,17 @@ public class ConditionalNode extends BinaryNode { /* ---- begin tree structure ---- */ - protected ExpressionNode conditionNode; + private ExpressionNode conditionNode; - public ConditionalNode setConditionNode(ExpressionNode conditionNode) { + public void setConditionNode(ExpressionNode conditionNode) { this.conditionNode = conditionNode; - return this; } public ExpressionNode getConditionNode() { return conditionNode; } - @Override - public ConditionalNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; - } - - @Override - public ConditionalNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; - } - - @Override - public ConditionalNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public ConditionalNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public ConditionalNode() { // do nothing @@ -83,10 +55,10 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals conditionNode.write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - leftNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); methodWriter.goTo(end); methodWriter.mark(fals); - rightNode.write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); methodWriter.mark(end); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java index 296eab6cbe074..100680d0c0c82 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -21,38 +21,22 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ConstantNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public ConstantNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected Object constant; + private Object constant; - public ConstantNode setConstant(Object constant) { + public void setConstant(Object constant) { this.constant = constant; - return this; } public Object getConstant() { return constant; } - @Override - public ConstantNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public ConstantNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java index 24e39e3fc9000..fd182caf3bf81 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java @@ -21,21 +21,10 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ContinueNode extends StatementNode { - /* ---- begin node data ---- */ - - @Override - public ContinueNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public ContinueNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java index 3e8d2201864be..06af3b15e0ccb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java @@ -21,70 +21,26 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; public final class DeclarationBlockNode extends StatementNode { /* ---- begin tree structure ---- */ - protected List declarationNodes = new ArrayList<>(); + private final List declarationNodes = new ArrayList<>(); - public DeclarationBlockNode addDeclarationNode(DeclarationNode declarationNode) { + public void addDeclarationNode(DeclarationNode declarationNode) { declarationNodes.add(declarationNode); - return this; - } - - public DeclarationBlockNode addDeclarationNodes(Collection declarationNodes) { - this.declarationNodes.addAll(declarationNodes); - return this; - } - - public DeclarationBlockNode setDeclarationNode(int index, DeclarationNode declarationNode) { - declarationNodes.set(index, declarationNode); - return this; - } - - public DeclarationNode getDeclarationNode(int index) { - return declarationNodes.get(index); - } - - public DeclarationBlockNode removeDeclarationNode(DeclarationNode declarationNode) { - declarationNodes.remove(declarationNode); - return this; - } - - public DeclarationBlockNode removeDeclarationNode(int index) { - declarationNodes.remove(index); - return this; - } - - public int getDeclarationsSize() { - return declarationNodes.size(); } public List getDeclarationsNodes() { return declarationNodes; } - public DeclarationBlockNode clearDeclarationNodes() { - declarationNodes.clear(); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public DeclarationBlockNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public DeclarationBlockNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index 34fed3882317a..2898224f397ed 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; @@ -30,11 +29,10 @@ public class DeclarationNode extends StatementNode { /* ---- begin tree structure ---- */ - protected ExpressionNode expressionNode; + private ExpressionNode expressionNode; - public DeclarationNode setExpressionNode(ExpressionNode childNode) { - this.expressionNode = childNode; - return this; + public void setExpressionNode(ExpressionNode expressionNode) { + this.expressionNode = expressionNode; } public ExpressionNode getExpressionNode() { @@ -43,23 +41,16 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure, begin node data ---- */ - protected Variable variable; + private Variable variable; - public DeclarationNode setVariable(Variable variable) { + public void setVariable(Variable variable) { this.variable = variable; - return this; } public Variable getVariable() { return variable; } - @Override - public DeclarationNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public DeclarationNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java index 21ea0651986a3..96d3c3850d9d6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java @@ -21,50 +21,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class DoWhileLoopNode extends LoopNode { - /* ---- begin tree structure ---- */ - - @Override - public DoWhileLoopNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public DoWhileLoopNode setBlockNode(BlockNode blockNode) { - super.setBlockNode(blockNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public DoWhileLoopNode setContinuous(boolean isContinuous) { - super.setContinuous(isContinuous); - return this; - } - - @Override - public DoWhileLoopNode setLoopCounter(Locals.Variable loopCounter) { - super.setLoopCounter(loopCounter); - return this; - } - - @Override - public DoWhileLoopNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public DoWhileLoopNode() { // do nothing } @@ -79,19 +41,19 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.mark(start); - blockNode.continueLabel = begin; - blockNode.breakLabel = end; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = begin; + getBlockNode().breakLabel = end; + getBlockNode().write(classWriter, methodWriter, globals); methodWriter.mark(begin); - if (!isContinuous) { - conditionNode.write(classWriter, methodWriter, globals); + if (isContinuous() == false) { + getConditionNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, end); } - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, blockNode.getStatementCount()), location); + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), Math.max(1, getBlockNode().getStatementCount()), location); } methodWriter.goTo(start); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java index e21658d7412ce..5334415927945 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java @@ -21,40 +21,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -public class DotNode extends PrefixNode { - - /* ---- begin tree structure ---- */ - - @Override - public DotNode setPrefixNode(ExpressionNode prefixNode) { - this.prefixNode = prefixNode; - return this; - } - - @Override - public DotNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public DotNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public DotNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ +public class DotNode extends BinaryNode { public DotNode() { // do nothing @@ -62,28 +31,28 @@ public DotNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefixNode.write(classWriter, methodWriter, globals); - childNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); } @Override protected int accessElementCount() { - return childNode.accessElementCount(); + return getRightNode().accessElementCount(); } @Override protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - prefixNode.write(classWriter, methodWriter, globals); - childNode.setup(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().setup(classWriter, methodWriter, globals); } @Override protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.load(classWriter, methodWriter, globals); + getRightNode().load(classWriter, methodWriter, globals); } @Override protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.store(classWriter, methodWriter, globals); + getRightNode().store(classWriter, methodWriter, globals); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java index eddc60695c3b3..5fc43114279a3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java @@ -21,29 +21,10 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class DotSubArrayLengthNode extends ExpressionNode { - /* ---- begin tree structure ---- */ - - @Override - public DotSubArrayLengthNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public DotSubArrayLengthNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public DotSubArrayLengthNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java index 75387fff23c90..ae41e50c767ec 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java @@ -22,38 +22,23 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.objectweb.asm.Type; public class DotSubDefNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public DotSubDefNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected String value; + private String value; - public DotSubDefNode setValue(String value) { + public void setValue(String value) { this.value = value; - return this; } public String getValue() { return value; } - @Override - public DotSubDefNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public DotSubDefNode() { @@ -64,8 +49,7 @@ public DotSubDefNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - org.objectweb.asm.Type methodType = - org.objectweb.asm.Type.getMethodType(MethodWriter.getType(getType()), org.objectweb.asm.Type.getType(Object.class)); + Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), Type.getType(Object.class)); methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); } @@ -83,8 +67,7 @@ protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - org.objectweb.asm.Type methodType = - org.objectweb.asm.Type.getMethodType(MethodWriter.getType(getType()), org.objectweb.asm.Type.getType(Object.class)); + Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), Type.getType(Object.class)); methodWriter.invokeDefCall(value, methodType, DefBootstrap.LOAD); } @@ -92,8 +75,8 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType( - org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(getType())); + Type methodType = Type.getMethodType( + Type.getType(void.class), Type.getType(Object.class), MethodWriter.getType(getExpressionType())); methodWriter.invokeDefCall(value, methodType, DefBootstrap.STORE); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java index 6072f3ae0626b..e0d81a0f9cfd0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java @@ -21,40 +21,24 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessField; import org.objectweb.asm.Type; public class DotSubNode extends ExpressionNode { - /* ---- begin tree structure ---- */ - - @Override - public DotSubNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - /* ---- begin node data ---- */ - protected PainlessField field; + private PainlessField field; - public DotSubNode setField(PainlessField field) { + public void setField(PainlessField field) { this.field = field; - return this; } public PainlessField getField() { return field; } - @Override - public DotSubNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public DotSubNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java index 55d16258b3335..1cd0738d5d4f0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java @@ -21,50 +21,32 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; public class DotSubShortcutNode extends ExpressionNode { - /* begin tree structure */ + /* ---- begin node data ---- */ - @Override - public DotSubShortcutNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected PainlessMethod setter; - protected PainlessMethod getter; + private PainlessMethod setter; + private PainlessMethod getter; - public DotSubShortcutNode setSetter(PainlessMethod setter) { + public void setSetter(PainlessMethod setter) { this.setter = setter; - return this; } public PainlessMethod getSetter() { return setter; } - public DotSubShortcutNode setGetter(PainlessMethod getter) { + public void setGetter(PainlessMethod getter) { this.getter = getter; - return this; } public PainlessMethod getGetter() { return getter; } - - @Override - public DotSubShortcutNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public DotSubShortcutNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java index aea59edb03313..dccbc1ed55601 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java @@ -21,42 +21,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; public class ElvisNode extends BinaryNode { - /* ---- begin tree structure ---- */ - - @Override - public ElvisNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; - } - - @Override - public ElvisNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; - } - - @Override - public ElvisNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public ElvisNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public ElvisNode() { // do nothing } @@ -67,11 +36,11 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label end = new Label(); - leftNode.write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals); methodWriter.dup(); methodWriter.ifNonNull(end); methodWriter.pop(); - rightNode.write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals); methodWriter.mark(end); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java index 55bce8eda4356..c385f28e0eab4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java @@ -19,37 +19,24 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; public abstract class ExpressionNode extends IRNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - protected TypeNode typeNode; + private Class expressionType; - public ExpressionNode setTypeNode(TypeNode typeNode) { - this.typeNode = typeNode; - return this; + public void setExpressionType(Class expressionType) { + this.expressionType = expressionType; } - public TypeNode getTypeNode() { - return typeNode; + public Class getExpressionType() { + return expressionType; } - public Class getType() { - return typeNode.getType(); - } - - public String getCanonicalTypeName() { - return typeNode.getCanonicalTypeName(); - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public ExpressionNode setLocation(Location location) { - super.setLocation(location); - return this; + public String getExpressionCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(expressionType); } /* ---- end node data ---- */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java index b66d539b6133e..26253e6fc5ed5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -21,72 +21,55 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Type; public class FieldNode extends IRNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - protected TypeNode typeNode; + private int modifiers; + private Class fieldType; + private String name; + private Object instance; - public FieldNode setTypeNode(TypeNode typeNode) { - this.typeNode = typeNode; - return this; + public void setModifiers(int modifiers) { + this.modifiers = modifiers; } - public TypeNode getTypeNode() { - return typeNode; + public int getModifiers(int modifiers) { + return modifiers; } - public Class getType() { - return typeNode.getType(); + public void setFieldType(Class fieldType) { + this.fieldType = fieldType; } - public String getCanonicalTypeName() { - return typeNode.getCanonicalTypeName(); + public Class getFieldType() { + return fieldType; } - /* ---- end tree structure, begin node data ---- */ - - protected int modifiers; - protected String name; - protected Object instance; - - public FieldNode setModifiers(int modifiers) { - this.modifiers = modifiers; - return this; + public String getFieldCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(fieldType); } - public int getModifiers(int modifiers) { - return modifiers; - } - - public FieldNode setName(String name) { + public void setName(String name) { this.name = name; - return this; } public String getName() { return name; } - public FieldNode setInstance(Object instance) { + public void setInstance(Object instance) { this.instance = instance; - return this; } public Object getInstance() { return instance; } - @Override - public FieldNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public FieldNode() { @@ -96,6 +79,6 @@ public FieldNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { classWriter.getClassVisitor().visitField( - ClassWriter.buildAccess(modifiers, true), name, Type.getType(getType()).getDescriptor(), null, null).visitEnd(); + ClassWriter.buildAccess(modifiers, true), name, Type.getType(fieldType).getDescriptor(), null, null).visitEnd(); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java index 6ee0500d6e9fd..2ead35b0f08a1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java @@ -21,33 +21,23 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ForEachLoopNode extends StatementNode { /* ---- begin tree structure ---- */ - protected ConditionNode conditionNode; + private ConditionNode conditionNode; - public ForEachLoopNode setConditionNode(ConditionNode conditionNode) { + public void setConditionNode(ConditionNode conditionNode) { this.conditionNode = conditionNode; - return this; } public ConditionNode getConditionNode() { return conditionNode; } - /* ---- end tree structure, being node data ---- */ - - @Override - public ForEachLoopNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public ForEachLoopNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java index dfeeb64ba53f8..27855606e4bbf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java @@ -22,108 +22,66 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class ForEachSubArrayNode extends LoopNode { - /* ---- being tree structure ---- */ - - protected TypeNode indexedTypeNode; - - public ForEachSubArrayNode setIndexedTypeNode(TypeNode indexedTypeNode) { - this.indexedTypeNode = indexedTypeNode; - return this; - } - - public TypeNode getIndexedTypeNode() { - return indexedTypeNode; - } - - public Class getIndexedType() { - return indexedTypeNode.getType(); - } - - public String getIndexedCanonicalTypeName() { - return indexedTypeNode.getCanonicalTypeName(); - } - - @Override - public ForEachSubArrayNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public ForEachSubArrayNode setBlockNode(BlockNode blockNode) { - super.setBlockNode(blockNode); - return this; - } - /* ---- begin node data ---- */ - protected Variable variable; - protected PainlessCast cast; - protected Variable array; - protected Variable index; + private Variable variable; + private PainlessCast cast; + private Variable array; + private Variable index; + private Class indexedType; - public ForEachSubArrayNode setVariable(Variable variable) { + public void setVariable(Variable variable) { this.variable = variable; - return this; } public Variable getVariable() { - return this.variable; + return variable; } - public ForEachSubArrayNode setCast(PainlessCast cast) { + public void setCast(PainlessCast cast) { this.cast = cast; - return this; } public PainlessCast getCast() { return cast; } - public ForEachSubArrayNode setArray(Variable array) { + public void setArray(Variable array) { this.array = array; - return this; } public Variable getArray() { - return this.array; + return array; } - public ForEachSubArrayNode setIndex(Variable index) { + public void setIndex(Variable index) { this.index = index; - return this; } public Variable getIndex() { - return this.index; + return index; } - - @Override - public ForEachSubArrayNode setContinuous(boolean isContinuous) { - super.setContinuous(isContinuous); - return this; + + public void setIndexedType(Class indexedType) { + this.indexedType = indexedType; } - @Override - public ForEachSubArrayNode setLoopCounter(Variable loopCounter) { - super.setLoopCounter(loopCounter); - return this; + public Class getIndexedType() { + return indexedType; } - @Override - public ForEachSubArrayNode setLocation(Location location) { - super.setLocation(location); - return this; + public String getIndexedCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(indexedType); } - + /* ---- end node data ---- */ public ForEachSubArrayNode() { @@ -134,7 +92,7 @@ public ForEachSubArrayNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); - conditionNode.write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals); methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ISTORE), array.getSlot()); methodWriter.push(-1); methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ISTORE), index.getSlot()); @@ -156,13 +114,13 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeCast(cast); methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), blockNode.getStatementCount(), location); + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), getBlockNode().getStatementCount(), location); } - blockNode.continueLabel = begin; - blockNode.breakLabel = end; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = begin; + getBlockNode().breakLabel = end; + getBlockNode().write(classWriter, methodWriter, globals); methodWriter.goTo(begin); methodWriter.mark(end); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java index ec97ff6be5d6d..3c9cc0a411c32 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -41,81 +40,45 @@ */ public class ForEachSubIterableNode extends LoopNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public ForEachSubIterableNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public ForEachSubIterableNode setBlockNode(BlockNode blockNode) { - super.setBlockNode(blockNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ + private Variable variable; + private PainlessCast cast; + private Variable iterator; + private PainlessMethod method; - protected Variable variable; - protected PainlessCast cast; - protected Variable iterator; - protected PainlessMethod method; - - public ForEachSubIterableNode setVariable(Variable variable) { + public void setVariable(Variable variable) { this.variable = variable; - return this; } public Variable getVariable() { - return this.variable; + return variable; } - public ForEachSubIterableNode setCast(PainlessCast cast) { + public void setCast(PainlessCast cast) { this.cast = cast; - return this; } public PainlessCast getCast() { return cast; } - public ForEachSubIterableNode setIterator(Variable iterator) { + public void setIterator(Variable iterator) { this.iterator = iterator; - return this; } public Variable getIterator() { - return this.iterator; + return iterator; } - public ForEachSubIterableNode setMethod(PainlessMethod method) { + public void setMethod(PainlessMethod method) { this.method = method; - return this; } public PainlessMethod getMethod() { return method; } - @Override - public ForEachSubIterableNode setContinuous(boolean isContinuous) { - super.setContinuous(isContinuous); - return this; - } - - @Override - public ForEachSubIterableNode setLoopCounter(Variable loopCounter) { - super.setLoopCounter(loopCounter); - return this; - } - - @Override - public ForEachSubIterableNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public ForEachSubIterableNode() { @@ -126,7 +89,7 @@ public ForEachSubIterableNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); - conditionNode.write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals); if (method == null) { org.objectweb.asm.Type methodType = org.objectweb.asm.Type @@ -152,13 +115,13 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeCast(cast); methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), blockNode.getStatementCount(), location); + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), getBlockNode().getStatementCount(), location); } - blockNode.continueLabel = begin; - blockNode.breakLabel = end; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = begin; + getBlockNode().breakLabel = end; + getBlockNode().write(classWriter, methodWriter, globals); methodWriter.goTo(begin); methodWriter.mark(end); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java index dd051f6ad52d6..145b8c3053ab7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java @@ -21,71 +21,34 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import static org.elasticsearch.painless.Locals.Variable; - public class ForLoopNode extends LoopNode { /* ---- begin tree structure ---- */ - protected IRNode initializerNode; - protected ExpressionNode afterthoughtNode; + private IRNode initializerNode; + private ExpressionNode afterthoughtNode; - public ForLoopNode setInitialzerNode(IRNode initializerNode) { + public void setInitialzerNode(IRNode initializerNode) { this.initializerNode = initializerNode; - return this; } public IRNode getInitializerNode() { return initializerNode; } - public ForLoopNode setAfterthoughtNode(ExpressionNode afterthoughtNode) { + public void setAfterthoughtNode(ExpressionNode afterthoughtNode) { this.afterthoughtNode = afterthoughtNode; - return this; } public ExpressionNode getAfterthoughtNode() { return afterthoughtNode; } - @Override - public ForLoopNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public ForLoopNode setBlockNode(BlockNode blockNode) { - super.setBlockNode(blockNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public ForLoopNode setContinuous(boolean isContinuous) { - super.setContinuous(isContinuous); - return this; - } - - @Override - public ForLoopNode setLoopCounter(Variable loopCounter) { - super.setLoopCounter(loopCounter); - return this; - } - - @Override - public ForLoopNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public ForLoopNode() { // do nothing @@ -104,44 +67,44 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } else if (initializerNode instanceof ExpressionNode) { ExpressionNode initializer = (ExpressionNode)this.initializerNode; initializer.write(classWriter, methodWriter, globals); - methodWriter.writePop(MethodWriter.getType(initializer.getType()).getSize()); + methodWriter.writePop(MethodWriter.getType(initializer.getExpressionType()).getSize()); } methodWriter.mark(start); - if (conditionNode != null && isContinuous == false) { - conditionNode.write(classWriter, methodWriter, globals); + if (getConditionNode() != null && isContinuous() == false) { + getConditionNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, end); } boolean allEscape = false; - if (blockNode != null) { - allEscape = blockNode.doAllEscape(); + if (getBlockNode() != null) { + allEscape = getBlockNode().doAllEscape(); - int statementCount = Math.max(1, blockNode.statementCount); + int statementCount = Math.max(1, getBlockNode().getStatementCount()); if (afterthoughtNode != null) { ++statementCount; } - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), statementCount, location); + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), statementCount, location); } - blockNode.continueLabel = begin; - blockNode.breakLabel = end; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = begin; + getBlockNode().breakLabel = end; + getBlockNode().write(classWriter, methodWriter, globals); } else { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), 1, location); } } if (afterthoughtNode != null) { methodWriter.mark(begin); afterthoughtNode.write(classWriter, methodWriter, globals); - methodWriter.writePop(MethodWriter.getType(afterthoughtNode.getType()).getSize()); + methodWriter.writePop(MethodWriter.getType(afterthoughtNode.getExpressionType()).getSize()); } if (afterthoughtNode != null || !allEscape) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java index 37e8bb83a7743..3e51d4e1f1299 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java @@ -22,38 +22,22 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class FuncRefNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public FuncRefNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected FunctionRef funcRef; + private FunctionRef funcRef; - public FuncRefNode setFuncRef(FunctionRef funcRef) { + public void setFuncRef(FunctionRef funcRef) { this.funcRef = funcRef; - return this; } public FunctionRef getFuncRef() { return funcRef; } - @Override - public FuncRefNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public FuncRefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java index 98cadcc94d69d..e84fa7cef860d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -35,11 +34,10 @@ public class FunctionNode extends IRNode { /* ---- begin tree structure ---- */ - protected BlockNode blockNode; + private BlockNode blockNode; - public FunctionNode setBlockNode(BlockNode blockNode) { + public void setBlockNode(BlockNode blockNode) { this.blockNode = blockNode; - return this; } public BlockNode getBlockNode() { @@ -48,116 +46,70 @@ public BlockNode getBlockNode() { /* ---- end tree structure, begin node data ---- */ - protected String name; - Class returnType; - List> typeParameters = new ArrayList<>(); - protected boolean isSynthetic; - protected boolean doesMethodEscape; - protected Variable loopCounter; - protected int maxLoopCounter; + private String name; + private Class returnType; + private final List> typeParameters = new ArrayList<>(); + private boolean isSynthetic; + private boolean doesMethodEscape; + private Variable loopCounter; + private int maxLoopCounter; - public FunctionNode setName(String name) { + public void setName(String name) { this.name = name; - return this; } public String getName() { return name; } - public FunctionNode setReturnType(Class returnType) { + public void setReturnType(Class returnType) { this.returnType = returnType; - return this; } public Class getReturnType() { return returnType; } - public FunctionNode addTypeParameter(Class typeParameter) { + public void addTypeParameter(Class typeParameter) { typeParameters.add(typeParameter); - return this; - } - - public FunctionNode addTypeParameters(List> typeParameters) { - this.typeParameters.addAll(typeParameters); - return this; - } - - public FunctionNode setTypeParameter(int index, Class typeParameter) { - typeParameters.set(index, typeParameter); - return this; - } - - public Class getTypeParameter(int index) { - return typeParameters.get(index); - } - - public FunctionNode removeTypeParameter(Class typeParameter) { - typeParameters.remove(typeParameter); - return this; - } - - public FunctionNode removeTypeParameter(int index) { - typeParameters.remove(index); - return this; - } - - public int getTypeParametersSize() { - return typeParameters.size(); } public List> getTypeParameters() { return typeParameters; } - public FunctionNode clearTypeParameters() { - typeParameters.clear(); - return this; - } - - public FunctionNode setSynthetic(boolean isSythetic) { + public void setSynthetic(boolean isSythetic) { this.isSynthetic = isSythetic; - return this; } public boolean isSynthetic() { return isSynthetic; } - public FunctionNode setMethodEscape(boolean doesMethodEscape) { + public void setMethodEscape(boolean doesMethodEscape) { this.doesMethodEscape = doesMethodEscape; - return this; } public boolean doesMethodEscape() { return doesMethodEscape; } - public FunctionNode setLoopCounter(Variable loopCounter) { + public void setLoopCounter(Variable loopCounter) { this.loopCounter = loopCounter; - return this; } public Variable getLoopCounter() { return loopCounter; } - public FunctionNode setMaxLoopCounter(int maxLoopCounter) { + public void setMaxLoopCounter(int maxLoopCounter) { this.maxLoopCounter = maxLoopCounter; - return this; } public int getMaxLoopCounter() { return maxLoopCounter; } - @Override - public FunctionNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public FunctionNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java index e98ffa5bf1c69..7c51328091276 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java @@ -30,9 +30,8 @@ public abstract class IRNode { protected Location location; - public IRNode setLocation(Location location) { + public void setLocation(Location location) { this.location = location; - return this; } public Location getLocation() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java index d3fc99e738057..4d8b39f9c477b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -30,38 +29,17 @@ public class IfElseNode extends ConditionNode { /* ---- begin tree structure ---- */ - protected BlockNode elseBlockNode; + private BlockNode elseBlockNode; - public IfElseNode setElseBlockNode(BlockNode elseBlockNode) { + public void setElseBlockNode(BlockNode elseBlockNode) { this.elseBlockNode = elseBlockNode; - return this; } public BlockNode getElseBlockNode() { return elseBlockNode; } - @Override - public IfElseNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public IfElseNode setBlockNode(BlockNode blockNode) { - this.blockNode = blockNode; - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public IfElseNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public IfElseNode() { // do nothing @@ -74,14 +52,14 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label fals = new Label(); Label end = new Label(); - conditionNode.write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - blockNode.continueLabel = continueLabel; - blockNode.breakLabel = breakLabel; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = continueLabel; + getBlockNode().breakLabel = breakLabel; + getBlockNode().write(classWriter, methodWriter, globals); - if (blockNode.doAllEscape() == false) { + if (getBlockNode().doAllEscape() == false) { methodWriter.goTo(end); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java index 8e1d5fc48f250..3316cccccaff5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java @@ -21,37 +21,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class IfNode extends ConditionNode { - /* ---- begin tree structure ---- */ - - @Override - public IfNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public IfNode setBlockNode(BlockNode blockNode) { - this.blockNode = blockNode; - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public IfNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public IfNode() { // do nothing } @@ -62,12 +37,12 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label fals = new Label(); - conditionNode.write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - blockNode.continueLabel = continueLabel; - blockNode.breakLabel = breakLabel; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = continueLabel; + getBlockNode().breakLabel = breakLabel; + getBlockNode().write(classWriter, methodWriter, globals); methodWriter.mark(fals); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java index 3ee6bfab688e9..d6053302d41ee 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -21,66 +21,50 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Type; public class InstanceofNode extends UnaryNode { + + /* ---- begin node data ---- */ - /* ---- begin tree structure ---- */ + private Class instanceType; + private Class resolvedType; + private boolean isPrimitiveResult; - protected TypeNode expressionTypeNode; - protected TypeNode resolvedTypeNode; - - public InstanceofNode setExpressionTypeNode(TypeNode expressionTypeNode) { - this.expressionTypeNode = expressionTypeNode; - return this; + public void setInstanceType(Class instanceType) { + this.instanceType = instanceType; } - - public TypeNode getExpressionTypeNode() { - return expressionTypeNode; + + public Class getInstanceType() { + return instanceType; } - - public InstanceofNode setResolvedTypeNode(TypeNode resolvedTypeNode) { - this.resolvedTypeNode = resolvedTypeNode; - return this; + + public String getInstanceCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(instanceType); } - public TypeNode getResolvedTypeNode() { - return resolvedTypeNode; + public void setResolvedType(Class resolvedType) { + this.resolvedType = resolvedType; } - @Override - public InstanceofNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; + public Class getResolvedType() { + return resolvedType; } - @Override - public InstanceofNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; + public String getResolvedCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(resolvedType); } - - /* ---- end tree structure, begin node data ---- */ - - protected boolean isPrimitiveResult; - - public InstanceofNode setPrimitiveResult(boolean isPrimitiveResult) { + + public void setPrimitiveResult(boolean isPrimitiveResult) { this.isPrimitiveResult = isPrimitiveResult; - return this; } public boolean isPrimitiveResult() { return isPrimitiveResult; } - @Override - public InstanceofNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public InstanceofNode() { @@ -89,17 +73,17 @@ public InstanceofNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); // primitive types if (isPrimitiveResult) { // discard child's result result - methodWriter.writePop(MethodWriter.getType(childNode.getType()).getSize()); + methodWriter.writePop(MethodWriter.getType(getExpressionType()).getSize()); // push our result: its' a primitive so it cannot be null - methodWriter.push(resolvedTypeNode.getType().isAssignableFrom(expressionTypeNode.getType())); + methodWriter.push(resolvedType.isAssignableFrom(instanceType)); } else { // ordinary instanceof - methodWriter.instanceOf(Type.getType(resolvedTypeNode.getType())); + methodWriter.instanceOf(Type.getType(resolvedType)); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index 951e6b25dab2b..04ac33f6dd1cb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -23,86 +23,35 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; import java.util.ArrayList; -import java.util.Collection; import java.util.List; public class LambdaNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public LambdaNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ + private final List captures = new ArrayList<>(); + private FunctionRef funcRef; - protected List captures = new ArrayList<>(); - protected FunctionRef funcRef; - - public LambdaNode addCapture(Variable capture) { + public void addCapture(Variable capture) { captures.add(capture); - return this; - } - - public LambdaNode addCaptures(Collection captures) { - this.captures.addAll(captures); - return this; - } - - public LambdaNode setCapture(int index, Variable capture) { - captures.set(index, capture); - return this; - } - - public Variable getCapture(int index) { - return captures.get(index); - } - - public LambdaNode removeCapture(Variable capture) { - captures.remove(capture); - return this; - } - - public LambdaNode removeCapture(int index) { - captures.remove(index); - return this; - } - - public int getCapturesSize() { - return captures.size(); } public List getCaptures() { return captures; } - public LambdaNode clearCaptures() { - captures.clear(); - return this; - } - - public LambdaNode setFuncRef(FunctionRef funcRef) { + public void setFuncRef(FunctionRef funcRef) { this.funcRef = funcRef; - return this; } public FunctionRef getFuncRef() { return funcRef; } - @Override - public LambdaNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public LambdaNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java index 684cdfc0a2143..971d1cd4f67de 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java @@ -21,90 +21,35 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import java.util.Collection; - public class ListInitializationNode extends ArgumentsNode { - /* ---- begin tree structure ---- */ - - @Override - public ListInitializationNode addArgumentNode(ExpressionNode argumentNode) { - super.addArgumentNode(argumentNode); - return this; - } - - @Override - public ListInitializationNode addArgumentNodes(Collection argumentNodes) { - super.addArgumentNodes(argumentNodes); - return this; - } - - @Override - public ListInitializationNode setArgumentNode(int index, ExpressionNode argumentNode) { - super.setArgumentNode(index, argumentNode); - return this; - } - - @Override - public ListInitializationNode removeArgumentNode(ExpressionNode argumentNode) { - super.removeArgumentNode(argumentNode); - return this; - } - - @Override - public ListInitializationNode removeArgumentNode(int index) { - super.removeArgumentNode(index); - return this; - } + /* ---- begin node data ---- */ - @Override - public ListInitializationNode clearArgumentNodes() { - super.clearArgumentNodes(); - return this; - } + private PainlessConstructor constructor; + private PainlessMethod method; - @Override - public ListInitializationNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected PainlessConstructor constructor; - protected PainlessMethod method; - - public ListInitializationNode setConstructor(PainlessConstructor constructor) { + public void setConstructor(PainlessConstructor constructor) { this.constructor = constructor; - return this; } public PainlessConstructor getConstructor() { return constructor; } - public ListInitializationNode setMethod(PainlessMethod method) { + public void setMethod(PainlessMethod method) { this.method = method; - return this; } public PainlessMethod getMethod() { return method; } - @Override - public ListInitializationNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public ListInitializationNode() { @@ -115,12 +60,12 @@ public ListInitializationNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - methodWriter.newInstance(MethodWriter.getType(getType())); + methodWriter.newInstance(MethodWriter.getType(getExpressionType())); methodWriter.dup(); methodWriter.invokeConstructor( Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); - for (ExpressionNode argument : argumentNodes) { + for (ExpressionNode argument : getArgumentNodes()) { methodWriter.dup(); argument.write(classWriter, methodWriter, globals); methodWriter.invokeMethodCall(method); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java index a60aa461af287..be3897c3382f4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -30,49 +29,27 @@ public class ListSubShortcutNode extends UnaryNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public ListSubShortcutNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public ListSubShortcutNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } + private PainlessMethod setter; + private PainlessMethod getter; - /* ---- end tree structure, begin node data ---- */ - - protected PainlessMethod setter; - protected PainlessMethod getter; - - public ListSubShortcutNode setSetter(PainlessMethod setter) { + public void setSetter(PainlessMethod setter) { this.setter = setter; - return this; } public PainlessMethod getSetter() { return setter; } - public ListSubShortcutNode setGetter(PainlessMethod getter) { + public void setGetter(PainlessMethod getter) { this.getter = getter; - return this; } public PainlessMethod getGetter() { return getter; } - @Override - public ListSubShortcutNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public ListSubShortcutNode() { @@ -92,7 +69,7 @@ protected int accessElementCount() { @Override protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); Label noFlip = new Label(); methodWriter.dup(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java index 9d42857ae3cb9..a4c7b6310b68d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java @@ -20,53 +20,30 @@ package org.elasticsearch.painless.ir; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; public abstract class LoopNode extends ConditionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public LoopNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public LoopNode setBlockNode(BlockNode blockNode) { - this.blockNode = blockNode; - return this; - } - - /* ---- end tree structure, begin node data ---- */ + private boolean isContinuous; + private Variable loopCounter; - protected boolean isContinuous; - protected Variable loopCounter; - - public LoopNode setContinuous(boolean isContinuous) { + public void setContinuous(boolean isContinuous) { this.isContinuous = isContinuous; - return this; } public boolean isContinuous() { return isContinuous; } - public LoopNode setLoopCounter(Variable loopCounter) { + public void setLoopCounter(Variable loopCounter) { this.loopCounter = loopCounter; - return this; } public Variable getLoopCounter() { return loopCounter; } - @Override - public LoopNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public LoopNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java index d6c367bd6e574..2e83a170e7432 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -35,19 +34,12 @@ public class MapInitializationNode extends ExpressionNode { /* ---- begin tree structure ---- */ - protected final List keyNodes = new ArrayList<>(); - protected final List valueNodes = new ArrayList<>(); + private final List keyNodes = new ArrayList<>(); + private final List valueNodes = new ArrayList<>(); - public MapInitializationNode addArgumentNode(ExpressionNode keyNode, ExpressionNode valueNode) { + public void addArgumentNode(ExpressionNode keyNode, ExpressionNode valueNode) { keyNodes.add(keyNode); valueNodes.add(valueNode); - return this; - } - - public MapInitializationNode setArgumentNode(int index, ExpressionNode keyNode, ExpressionNode valueNode) { - keyNodes.set(index, keyNode); - valueNodes.set(index, valueNode); - return this; } public ExpressionNode getKeyNode(int index) { @@ -58,19 +50,6 @@ public ExpressionNode getValueNode(int index) { return valueNodes.get(index); } - public ExpressionNode[] getArgumentNode(int index) { - return new ExpressionNode[] { - keyNodes.get(index), - valueNodes.get(index) - }; - } - - public MapInitializationNode removeArgumentNode(int index) { - keyNodes.remove(index); - valueNodes.remove(index); - return this; - } - public int getArgumentsSize() { return keyNodes.size(); } @@ -83,47 +62,27 @@ public List getValueNodes() { return valueNodes; } - public MapInitializationNode clearArgumentNodes() { - keyNodes.clear(); - valueNodes.clear(); - return this; - } - - @Override - public MapInitializationNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - /* ---- end tree structure, begin node data ---- */ - protected PainlessConstructor constructor; - protected PainlessMethod method; + private PainlessConstructor constructor; + private PainlessMethod method; - public MapInitializationNode setConstructor(PainlessConstructor constructor) { + public void setConstructor(PainlessConstructor constructor) { this.constructor = constructor; - return this; } public PainlessConstructor getConstructor() { return constructor; } - public MapInitializationNode setMethod(PainlessMethod method) { + public void setMethod(PainlessMethod method) { this.method = method; - return this; } public PainlessMethod getMethod() { return method; } - @Override - public MapInitializationNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public MapInitializationNode() { @@ -134,7 +93,7 @@ public MapInitializationNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - methodWriter.newInstance(MethodWriter.getType(getType())); + methodWriter.newInstance(MethodWriter.getType(getExpressionType())); methodWriter.dup(); methodWriter.invokeConstructor( Type.getType(constructor.javaConstructor.getDeclaringClass()), Method.getMethod(constructor.javaConstructor)); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java index 4fb2c2cb16d43..a4144699adb21 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -21,55 +21,32 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; public class MapSubShortcutNode extends UnaryNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public MapSubShortcutNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public MapSubShortcutNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } + private PainlessMethod setter; + private PainlessMethod getter; - /* ---- end tree structure, begin node data ---- */ - - protected PainlessMethod setter; - protected PainlessMethod getter; - - public MapSubShortcutNode setSetter(PainlessMethod setter) { + public void setSetter(PainlessMethod setter) { this.setter = setter; - return this; } public PainlessMethod getSetter() { return setter; } - public MapSubShortcutNode setGetter(PainlessMethod getter) { + public void setGetter(PainlessMethod getter) { this.getter = getter; - return this; } public PainlessMethod getGetter() { return getter; } - @Override - public MapSubShortcutNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public MapSubShortcutNode() { @@ -78,7 +55,7 @@ public MapSubShortcutNode() { @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -95,7 +72,7 @@ protected int accessElementCount() { @Override protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java index 4d522023525fa..0d6aef1bea44a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java @@ -22,38 +22,22 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class NewArrayFuncRefNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public NewArrayFuncRefNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected FunctionRef funcRef; + private FunctionRef funcRef; - public NewArrayFuncRefNode setFuncRef(FunctionRef funcRef) { + public void setFuncRef(FunctionRef funcRef) { this.funcRef = funcRef; - return this; } public FunctionRef getFuncRef() { return funcRef; } - @Override - public NewArrayFuncRefNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public NewArrayFuncRefNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java index 36ac3eea2735f..3959d7d1b707d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java @@ -21,76 +21,22 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import java.util.Collection; - public class NewArrayNode extends ArgumentsNode { - /* ---- begin tree structure ---- */ - - @Override - public NewArrayNode addArgumentNode(ExpressionNode argumentNode) { - super.addArgumentNode(argumentNode); - return this; - } - - @Override - public NewArrayNode addArgumentNodes(Collection argumentNodes) { - super.addArgumentNodes(argumentNodes); - return this; - } - - @Override - public NewArrayNode setArgumentNode(int index, ExpressionNode argumentNode) { - super.setArgumentNode(index, argumentNode); - return this; - } - - @Override - public NewArrayNode removeArgumentNode(ExpressionNode argumentNode) { - super.removeArgumentNode(argumentNode); - return this; - } - - @Override - public NewArrayNode removeArgumentNode(int index) { - super.removeArgumentNode(index); - return this; - } + /* ---- begin node data ---- */ - @Override - public NewArrayNode clearArgumentNodes() { - super.clearArgumentNodes(); - return this; - } + private boolean initialize; - @Override - public NewArrayNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected boolean initialize; - - public NewArrayNode setInitialize(boolean initialize) { + public void setInitialize(boolean initialize) { this.initialize = initialize; - return this; } public boolean getInitialize() { return initialize; } - @Override - public NewArrayNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public NewArrayNode() { @@ -102,26 +48,26 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeDebugInfo(location); if (initialize) { - methodWriter.push(argumentNodes.size()); - methodWriter.newArray(MethodWriter.getType(getType().getComponentType())); + methodWriter.push(getArgumentNodes().size()); + methodWriter.newArray(MethodWriter.getType(getExpressionType().getComponentType())); - for (int index = 0; index < argumentNodes.size(); ++index) { - ExpressionNode argumentNode = argumentNodes.get(index); + for (int index = 0; index < getArgumentNodes().size(); ++index) { + ExpressionNode argumentNode = getArgumentNodes().get(index); methodWriter.dup(); methodWriter.push(index); argumentNode.write(classWriter, methodWriter, globals); - methodWriter.arrayStore(MethodWriter.getType(getType().getComponentType())); + methodWriter.arrayStore(MethodWriter.getType(getExpressionType().getComponentType())); } } else { - for (ExpressionNode argumentNode : argumentNodes) { + for (ExpressionNode argumentNode : getArgumentNodes()) { argumentNode.write(classWriter, methodWriter, globals); } - if (argumentNodes.size() > 1) { - methodWriter.visitMultiANewArrayInsn(MethodWriter.getType(getType()).getDescriptor(), argumentNodes.size()); + if (getArgumentNodes().size() > 1) { + methodWriter.visitMultiANewArrayInsn(MethodWriter.getType(getExpressionType()).getDescriptor(), getArgumentNodes().size()); } else { - methodWriter.newArray(MethodWriter.getType(getType().getComponentType())); + methodWriter.newArray(MethodWriter.getType(getExpressionType().getComponentType())); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java index 03657989a8733..55c8f511be4d8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java @@ -21,89 +21,34 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import java.util.Collection; - public final class NewObjectNode extends ArgumentsNode { - /* ---- begin tree structure ---- */ - - @Override - public NewObjectNode addArgumentNode(ExpressionNode argumentNode) { - super.addArgumentNode(argumentNode); - return this; - } - - @Override - public NewObjectNode addArgumentNodes(Collection argumentNodes) { - super.addArgumentNodes(argumentNodes); - return this; - } - - @Override - public NewObjectNode setArgumentNode(int index, ExpressionNode argumentNode) { - super.setArgumentNode(index, argumentNode); - return this; - } - - @Override - public NewObjectNode removeArgumentNode(ExpressionNode argumentNode) { - super.removeArgumentNode(argumentNode); - return this; - } - - @Override - public NewObjectNode removeArgumentNode(int index) { - super.removeArgumentNode(index); - return this; - } + /* ---- begin node data ---- */ - @Override - public NewObjectNode clearArgumentNodes() { - super.clearArgumentNodes(); - return this; - } + private PainlessConstructor constructor; + private boolean read; - @Override - public NewObjectNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected PainlessConstructor constructor; - protected boolean read; - - public NewObjectNode setConstructor(PainlessConstructor constructor) { + public void setConstructor(PainlessConstructor constructor) { this.constructor = constructor; - return this; } public PainlessConstructor getConstructor() { return constructor; } - public NewObjectNode setRead(boolean read) { + public void setRead(boolean read) { this.read = read; - return this; } public boolean getRead() { return read; } - @Override - public NewObjectNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public NewObjectNode() { @@ -114,13 +59,13 @@ public NewObjectNode() { protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); - methodWriter.newInstance(MethodWriter.getType(getType())); + methodWriter.newInstance(MethodWriter.getType(getExpressionType())); if (read) { methodWriter.dup(); } - for (ExpressionNode argumentNode : argumentNodes) { + for (ExpressionNode argumentNode : getArgumentNodes()) { argumentNode.write(classWriter, methodWriter, globals); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java index 74577f00c5d92..59ee2b72cf8e0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java @@ -21,30 +21,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; public class NullNode extends ExpressionNode { - /* ---- begin tree structure ---- */ - - @Override - public NullNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public NullNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public NullNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java index 3164a0eb10589..10fdd90962a24 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java @@ -21,36 +21,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; public class NullSafeSubNode extends UnaryNode { - /* ---- begin tree structure ---- */ - - @Override - public NullSafeSubNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public NullSafeSubNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public NullSafeSubNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public NullSafeSubNode() { // do nothing } @@ -62,7 +37,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label end = new Label(); methodWriter.dup(); methodWriter.ifNull(end); - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); methodWriter.mark(end); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java deleted file mode 100644 index 88c62f6e4a040..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/PrefixNode.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.ir; - -import org.elasticsearch.painless.Location; - -public abstract class PrefixNode extends UnaryNode { - - /* ---- begin tree structure ---- */ - - protected ExpressionNode prefixNode; - - public PrefixNode setPrefixNode(ExpressionNode prefixNode) { - this.prefixNode = prefixNode; - return this; - } - - public ExpressionNode getPrefixNode() { - return prefixNode; - } - - @Override - public PrefixNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; - } - - @Override - public PrefixNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public PrefixNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - - public PrefixNode() { - // do nothing - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java index f6a1b786981a2..ea77612466eef 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; @@ -30,53 +29,36 @@ public class RegexNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public RegexNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected String pattern; - protected int flags; - protected Constant constant; + private String pattern; + private int flags; + private Constant constant; - public RegexNode setPattern(String pattern) { + public void setPattern(String pattern) { this.pattern = pattern; - return this; } public String getPattern() { return pattern; } - public RegexNode setFlags(int flags) { + public void setFlags(int flags) { this.flags = flags; - return this; } public int getFlags() { return flags; } - public RegexNode setConstant(Constant constant) { + public void setConstant(Constant constant) { this.constant = constant; - return this; } public Object getConstant() { return constant; } - @Override - public RegexNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public RegexNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java index e0427cef0055d..bb84e7e259c65 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java @@ -21,33 +21,23 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ReturnNode extends StatementNode { /* ---- begin tree structure ---- */ - protected ExpressionNode expressionNode; + private ExpressionNode expressionNode; - public ReturnNode setExpressionNode(ExpressionNode expressionNode) { + public void setExpressionNode(ExpressionNode expressionNode) { this.expressionNode = expressionNode; - return this; } public ExpressionNode getExpressionNode() { return expressionNode; } - /* ---- end tree structure, begin node data ---- */ - - @Override - public ReturnNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public ReturnNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java deleted file mode 100644 index 2f3971b043c08..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ShiftNode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.ir; - -import org.elasticsearch.painless.Location; - -public abstract class ShiftNode extends BinaryNode { - - /* ---- begin tree structure ---- */ - - protected TypeNode shiftTypeNode; - - public ShiftNode setShiftTypeNode(TypeNode shiftTypeNode) { - this.shiftTypeNode = shiftTypeNode; - return this; - } - - public TypeNode getShiftTypeNode() { - return shiftTypeNode; - } - - public Class getShiftType() { - return shiftTypeNode.getType(); - } - - public String getShiftCanonicalTypeName() { - return shiftTypeNode.getCanonicalTypeName(); - } - - @Override - public ShiftNode setLeftNode(ExpressionNode leftNode) { - super.setLeftNode(leftNode); - return this; - } - - @Override - public ShiftNode setRightNode(ExpressionNode rightNode) { - super.setRightNode(rightNode); - return this; - } - - @Override - public ShiftNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public ShiftNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - - public ShiftNode() { - // do nothing - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java index d1bd0e5eb62cc..7e427884562f8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java @@ -21,18 +21,16 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class StatementExpressionNode extends StatementNode { /* ---- begin tree structure ---- */ - protected ExpressionNode expressionNode; + private ExpressionNode expressionNode; - public StatementExpressionNode setExpressionNode(ExpressionNode expressionNode) { + public void setExpressionNode(ExpressionNode expressionNode) { this.expressionNode = expressionNode; - return this; } public ExpressionNode getExpressionNode() { @@ -41,23 +39,16 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure, begin node data ---- */ - protected boolean methodEscape; + private boolean methodEscape; - public StatementExpressionNode setMethodEscape(boolean methodEscape) { + public void setMethodEscape(boolean methodEscape) { this.methodEscape = methodEscape; - return this; } public boolean getMethodEscape() { return methodEscape; } - @Override - public StatementExpressionNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public StatementExpressionNode() { @@ -72,7 +63,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals if (methodEscape) { methodWriter.returnValue(); } else { - methodWriter.writePop(MethodWriter.getType(expressionNode.getType()).getSize()); + methodWriter.writePop(MethodWriter.getType(expressionNode.getExpressionType()).getSize()); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java index 4f4eae7a479e3..cda9353b7dd10 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java @@ -19,21 +19,10 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Location; import org.objectweb.asm.Label; public abstract class StatementNode extends IRNode { - /* ---- begin node data ---- */ - - @Override - public StatementNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - protected Label continueLabel = null; protected Label breakLabel = null; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java index 31a5dc1f90dc2..631406a11307e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java @@ -21,29 +21,10 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class StaticNode extends ExpressionNode { - /* ---- begin tree structure ---- */ - - @Override - public StaticNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public StaticNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public StaticNode() { // do nothing } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java index 9ddcc132f166f..b1f3b680fc72e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java @@ -21,33 +21,23 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; public class ThrowNode extends StatementNode { /* ---- begin tree structure ---- */ - protected ExpressionNode expressionNode; + private ExpressionNode expressionNode; - public ThrowNode setExpressionNode(ExpressionNode expressionNode) { + public void setExpressionNode(ExpressionNode expressionNode) { this.expressionNode = expressionNode; - return this; } public ExpressionNode getExpressionNode() { return expressionNode; } - /* ---- end tree structure, begin node data ---- */ - - @Override - public ThrowNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public ThrowNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java index 23aad69fc70f0..0ebe0f6b6137e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java @@ -21,81 +21,32 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import java.util.ArrayList; -import java.util.Collection; import java.util.List; public class TryNode extends StatementNode { /* ---- begin tree structure ---- */ - protected BlockNode blockNode; - protected List catchNodes = new ArrayList<>(); + private BlockNode blockNode; + private final List catchNodes = new ArrayList<>(); - public TryNode setBlockNode(BlockNode blockNode) { + public void setBlockNode(BlockNode blockNode) { this.blockNode = blockNode; - return this; } public BlockNode getBlockNode() { return blockNode; } - public TryNode addCatchNode(CatchNode catchNode) { - catchNodes.add(catchNode); - return this; - } - - public TryNode addCatchNodes(Collection catchNodes) { - this.catchNodes.addAll(catchNodes); - return this; - } - - public TryNode setCatchNode(int index, CatchNode catchNode) { - catchNodes.set(index, catchNode); - return this; - } - - public CatchNode getCatchNode(int index) { - return catchNodes.get(index); - } - - public TryNode removeCatchNode(CatchNode catchNode) { - catchNodes.remove(catchNode); - return this; - } - - public TryNode removeCatchNode(int index) { - catchNodes.remove(index); - return this; - } - - public int getCatchsSize() { - return catchNodes.size(); - } - public List getCatchsNodes() { return catchNodes; } - public TryNode clearCatchNodes() { - catchNodes.clear(); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public TryNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public TryNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java deleted file mode 100644 index c973449d10372..0000000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TypeNode.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless.ir; - -import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.lookup.PainlessLookupUtility; - -public class TypeNode extends IRNode { - - /* ---- begin node data ---- */ - - protected Class type; - - public TypeNode setType(Class type) { - this.type = type; - return this; - } - - public Class getType() { - return type; - } - - public String getCanonicalTypeName() { - return PainlessLookupUtility.typeToCanonicalTypeName(type); - } - - @Override - public TypeNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - - public TypeNode() { - // do nothing - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index 93f2636262129..c741471041b78 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -22,9 +22,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -32,78 +32,49 @@ public class UnaryMathNode extends UnaryNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - protected TypeNode unaryTypeNode; + private Operation operation; + private Class unaryType; + private boolean cat; + private boolean originallyExplicit; // record whether there was originally an explicit cast - public UnaryMathNode setUnaryTypeNode(TypeNode unaryTypeNode) { - this.unaryTypeNode = unaryTypeNode; - return this; - } - - public TypeNode getUnaryTypeNode() { - return unaryTypeNode; - } - - public Class getUnaryType() { - return unaryTypeNode.getType(); + public void setOperation(Operation operation) { + this.operation = operation; } - public String getUnaryCanonicalTypeName() { - return unaryTypeNode.getCanonicalTypeName(); - } - - @Override - public UnaryMathNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; + public Operation getOperation() { + return operation; } - @Override - public UnaryMathNode setChildNode(ExpressionNode childNode) { - super.setChildNode(childNode); - return this; + public void setUnaryType(Class unaryType) { + this.unaryType = unaryType; } - /* ---- end tree structure, begin node data ---- */ - - protected Operation operation; - protected boolean cat; - protected boolean originallyExplicit; // record whether there was originally an explicit cast - - public UnaryMathNode setOperation(Operation operation) { - this.operation = operation; - return this; + public Class getUnaryType() { + return unaryType; } - public Operation getOperation() { - return operation; + public String getUnaryCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(unaryType); } - public UnaryMathNode setCat(boolean cat) { + public void setCat(boolean cat) { this.cat = cat; - return this; } public boolean getCat() { return cat; } - public UnaryMathNode setOriginallExplicit(boolean originallyExplicit) { + public void setOriginallExplicit(boolean originallyExplicit) { this.originallyExplicit = originallyExplicit; - return this; } public boolean getOriginallyExplicit() { return originallyExplicit; } - @Override - public UnaryMathNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public UnaryMathNode() { @@ -118,7 +89,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl Label fals = new Label(); Label end = new Label(); - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.push(false); @@ -127,7 +98,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.push(true); methodWriter.mark(end); } else { - childNode.write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals); // Def calls adopt the wanted return value. If there was a narrowing cast, // we need to flag that so that it's done at runtime. @@ -137,8 +108,8 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST; } - Type actualType = MethodWriter.getType(getType()); - Type childType = MethodWriter.getType(childNode.getType()); + Type actualType = MethodWriter.getType(getExpressionType()); + Type childType = MethodWriter.getType(getChildNode().getExpressionType()); if (operation == Operation.BWNOT) { if (getUnaryType() == def.class) { @@ -151,7 +122,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.push(-1L); } else { throw new IllegalStateException("unexpected unary math operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } methodWriter.math(MethodWriter.XOR, actualType); @@ -170,7 +141,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } } else { throw new IllegalStateException("unexpected unary math operation [" + operation + "] " + - "for type [" + getCanonicalTypeName() + "]"); + "for type [" + getExpressionCanonicalTypeName() + "]"); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java index 70df3ed6dd2b0..693e0d0fef8ce 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java @@ -19,38 +19,21 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Location; - public abstract class UnaryNode extends ExpressionNode { /* ---- begin tree structure ---- */ - protected ExpressionNode childNode; + private ExpressionNode childNode; - public UnaryNode setChildNode(ExpressionNode childNode) { + public void setChildNode(ExpressionNode childNode) { this.childNode = childNode; - return this; } public ExpressionNode getChildNode() { return childNode; } - @Override - public UnaryNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public UnaryNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ + /* ---- end tree structure ---- */ public UnaryNode() { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java index d2b19291f5fde..ec2af7e2497f8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessClassBinding; import org.elasticsearch.painless.lookup.PainlessInstanceBinding; @@ -31,125 +30,67 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import java.util.Collection; - import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; public class UnboundCallNode extends ArgumentsNode { - /* ---- begin tree structure ---- */ - - @Override - public UnboundCallNode addArgumentNode(ExpressionNode argumentNode) { - super.addArgumentNode(argumentNode); - return this; - } - - @Override - public UnboundCallNode addArgumentNodes(Collection argumentNodes) { - super.addArgumentNodes(argumentNodes); - return this; - } - - @Override - public UnboundCallNode setArgumentNode(int index, ExpressionNode argumentNode) { - super.setArgumentNode(index, argumentNode); - return this; - } - - @Override - public UnboundCallNode removeArgumentNode(ExpressionNode argumentNode) { - super.removeArgumentNode(argumentNode); - return this; - } - - @Override - public UnboundCallNode removeArgumentNode(int index) { - super.removeArgumentNode(index); - return this; - } + /* ---- begin node data ---- */ - @Override - public UnboundCallNode clearArgumentNodes() { - super.clearArgumentNodes(); - return this; - } + private LocalFunction localFunction; + private PainlessMethod importedMethod; + private PainlessClassBinding classBinding; + private int classBindingOffset; + private PainlessInstanceBinding instanceBinding; + private String bindingName; - @Override - public UnboundCallNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected LocalFunction localFunction; - protected PainlessMethod importedMethod; - protected PainlessClassBinding classBinding; - protected int classBindingOffset; - protected PainlessInstanceBinding instanceBinding; - protected String bindingName; - - public UnboundCallNode setLocalFunction(LocalFunction localFunction) { + public void setLocalFunction(LocalFunction localFunction) { this.localFunction = localFunction; - return this; } public LocalFunction getLocalFunction() { return localFunction; } - public UnboundCallNode setImportedMethod(PainlessMethod importedMethod) { + public void setImportedMethod(PainlessMethod importedMethod) { this.importedMethod = importedMethod; - return this; } public PainlessMethod getImportedMethod() { return importedMethod; } - public UnboundCallNode setClassBinding(PainlessClassBinding classBinding) { + public void setClassBinding(PainlessClassBinding classBinding) { this.classBinding = classBinding; - return this; } public PainlessClassBinding getClassBinding() { return classBinding; } - public UnboundCallNode setClassBindingOffset(int classBindingOffset) { + public void setClassBindingOffset(int classBindingOffset) { this.classBindingOffset = classBindingOffset; - return this; } public int getClassBindingOffset() { return classBindingOffset; } - public UnboundCallNode setInstanceBinding(PainlessInstanceBinding instanceBinding) { + public void setInstanceBinding(PainlessInstanceBinding instanceBinding) { this.instanceBinding = instanceBinding; - return this; } public PainlessInstanceBinding getInstanceBinding() { return instanceBinding; } - public UnboundCallNode setBindingName(String bindingName) { + public void setBindingName(String bindingName) { this.bindingName = bindingName; - return this; } public String getBindingName() { return bindingName; } - @Override - public UnboundCallNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public UnboundCallNode() { @@ -161,13 +102,13 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.writeDebugInfo(location); if (localFunction != null) { - for (ExpressionNode argumentNode : argumentNodes) { + for (ExpressionNode argumentNode : getArgumentNodes()) { argumentNode.write(classWriter, methodWriter, globals); } methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod()); } else if (importedMethod != null) { - for (ExpressionNode argumentNode : argumentNodes) { + for (ExpressionNode argumentNode : getArgumentNodes()) { argumentNode.write(classWriter, methodWriter, globals); } @@ -191,7 +132,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } for (int argument = 0; argument < javaConstructorParameterCount; ++argument) { - argumentNodes.get(argument).write(classWriter, methodWriter, globals); + getArgumentNodes().get(argument).write(classWriter, methodWriter, globals); } methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor)); @@ -202,7 +143,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.getField(CLASS_TYPE, bindingName, type); for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) { - argumentNodes.get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); + getArgumentNodes().get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); } methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod)); @@ -213,7 +154,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.getStatic(CLASS_TYPE, bindingName, type); for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) { - argumentNodes.get(argument).write(classWriter, methodWriter, globals); + getArgumentNodes().get(argument).write(classWriter, methodWriter, globals); } methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod)); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java index 5b15527f9205d..b702a0bedb6fc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java @@ -22,39 +22,23 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals.Variable; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Opcodes; public class VariableNode extends ExpressionNode { - /* ---- begin tree structure ---- */ + /* ---- begin node data ---- */ - @Override - public VariableNode setTypeNode(TypeNode typeNode) { - super.setTypeNode(typeNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - protected Variable variable; + private Variable variable; - public VariableNode setVariable(Variable variable) { + public void setVariable(Variable variable) { this.variable = variable; - return this; } public Variable getVariable() { return variable; } - @Override - public VariableNode setLocation(Location location) { - super.setLocation(location); - return this; - } - /* ---- end node data ---- */ public VariableNode() { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java index e229162fd09cc..649096176047d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java @@ -21,50 +21,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class WhileNode extends LoopNode { - /* ---- begin tree structure ---- */ - - @Override - public WhileNode setConditionNode(ExpressionNode conditionNode) { - super.setConditionNode(conditionNode); - return this; - } - - @Override - public WhileNode setBlockNode(BlockNode blockNode) { - super.setBlockNode(blockNode); - return this; - } - - /* ---- end tree structure, begin node data ---- */ - - @Override - public WhileNode setContinuous(boolean isContinuous) { - super.setContinuous(isContinuous); - return this; - } - - @Override - public WhileNode setLoopCounter(Locals.Variable loopCounter) { - super.setLoopCounter(loopCounter); - return this; - } - - @Override - public WhileNode setLocation(Location location) { - super.setLocation(location); - return this; - } - - /* ---- end node data ---- */ - public WhileNode() { // do nothing } @@ -78,26 +40,26 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.mark(begin); - if (isContinuous == false) { - conditionNode.write(classWriter, methodWriter, globals); + if (isContinuous() == false) { + getConditionNode().write(classWriter, methodWriter, globals); methodWriter.ifZCmp(Opcodes.IFEQ, end); } - if (blockNode != null) { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), Math.max(1, blockNode.getStatementCount()), location); + if (getBlockNode() != null) { + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), Math.max(1, getBlockNode().getStatementCount()), location); } - blockNode.continueLabel = begin; - blockNode.breakLabel = end; - blockNode.write(classWriter, methodWriter, globals); + getBlockNode().continueLabel = begin; + getBlockNode().breakLabel = end; + getBlockNode().write(classWriter, methodWriter, globals); } else { - if (loopCounter != null) { - methodWriter.writeLoopCounter(loopCounter.getSlot(), 1, location); + if (getLoopCounter() != null) { + methodWriter.writeLoopCounter(getLoopCounter().getSlot(), 1, location); } } - if (blockNode == null || blockNode.doAllEscape() == false) { + if (getBlockNode() == null || getBlockNode().doAllEscape() == false) { methodWriter.goTo(begin); } From fbe2745277016a3aa683fc6e60ed602970670f98 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 22 Jan 2020 16:30:17 -0800 Subject: [PATCH 21/24] modify user nodes to work with ir setters --- .../elasticsearch/painless/ir/TryNode.java | 4 ++ .../painless/node/DResolvedType.java | 10 ----- .../painless/node/EAssignment.java | 37 +++++++++---------- .../elasticsearch/painless/node/EBinary.java | 34 +++++++---------- .../elasticsearch/painless/node/EBool.java | 20 +++++----- .../painless/node/ECallLocal.java | 23 +++++------- .../painless/node/ECapturingFunctionRef.java | 22 +++++------ .../elasticsearch/painless/node/ECast.java | 18 ++++----- .../elasticsearch/painless/node/EComp.java | 25 ++++++------- .../painless/node/EConditional.java | 20 +++++----- .../painless/node/EConstant.java | 15 ++++---- .../elasticsearch/painless/node/EElvis.java | 18 ++++----- .../painless/node/EFunctionRef.java | 15 ++++---- .../painless/node/EInstanceof.java | 30 ++++++--------- .../elasticsearch/painless/node/ELambda.java | 17 ++++----- .../painless/node/EListInit.java | 15 +++----- .../elasticsearch/painless/node/EMapInit.java | 15 +++----- .../painless/node/ENewArray.java | 13 +++---- .../painless/node/ENewArrayFunctionRef.java | 15 ++++---- .../elasticsearch/painless/node/ENewObj.java | 15 +++----- .../elasticsearch/painless/node/ENull.java | 13 +++---- .../elasticsearch/painless/node/ERegex.java | 19 +++++----- .../elasticsearch/painless/node/EStatic.java | 13 +++---- .../elasticsearch/painless/node/EUnary.java | 25 ++++++------- .../painless/node/EVariable.java | 15 ++++---- .../elasticsearch/painless/node/PBrace.java | 18 ++++----- .../painless/node/PCallInvoke.java | 18 ++++----- .../elasticsearch/painless/node/PField.java | 18 ++++----- .../painless/node/PSubArrayLength.java | 13 +++---- .../painless/node/PSubBrace.java | 16 ++++---- .../painless/node/PSubCallInvoke.java | 15 +++----- .../painless/node/PSubDefArray.java | 16 ++++---- .../painless/node/PSubDefCall.java | 19 ++++------ .../painless/node/PSubDefField.java | 15 ++++---- .../painless/node/PSubField.java | 15 ++++---- .../painless/node/PSubListShortcut.java | 20 +++++----- .../painless/node/PSubMapShortcut.java | 20 +++++----- .../painless/node/PSubNullSafeCallInvoke.java | 16 ++++---- .../painless/node/PSubNullSafeField.java | 16 ++++---- .../painless/node/PSubShortcut.java | 17 ++++----- .../elasticsearch/painless/node/SBlock.java | 9 +++-- .../elasticsearch/painless/node/SBreak.java | 7 +++- .../elasticsearch/painless/node/SCatch.java | 12 ++++-- .../elasticsearch/painless/node/SClass.java | 23 ++++++------ .../painless/node/SContinue.java | 7 +++- .../painless/node/SDeclBlock.java | 5 ++- .../painless/node/SDeclaration.java | 12 ++++-- .../org/elasticsearch/painless/node/SDo.java | 16 +++++--- .../elasticsearch/painless/node/SEach.java | 10 +++-- .../painless/node/SExpression.java | 12 ++++-- .../elasticsearch/painless/node/SField.java | 19 +++++----- .../org/elasticsearch/painless/node/SFor.java | 20 ++++++---- .../painless/node/SFunction.java | 24 +++++++----- .../org/elasticsearch/painless/node/SIf.java | 12 ++++-- .../elasticsearch/painless/node/SIfElse.java | 14 ++++--- .../elasticsearch/painless/node/SReturn.java | 10 +++-- .../painless/node/SSubEachArray.java | 30 +++++++-------- .../painless/node/SSubEachIterable.java | 24 +++++++----- .../elasticsearch/painless/node/SThrow.java | 10 +++-- .../org/elasticsearch/painless/node/STry.java | 8 ++-- .../elasticsearch/painless/node/SWhile.java | 16 +++++--- .../painless/symbol/ScriptRoot.java | 1 - 62 files changed, 509 insertions(+), 510 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java index 0ebe0f6b6137e..1b2251db10ce8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java @@ -42,6 +42,10 @@ public BlockNode getBlockNode() { return blockNode; } + public void addCatchNode(CatchNode catchNode) { + catchNodes.add(catchNode); + } + public List getCatchsNodes() { return catchNodes; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java index f3e8a9c950f53..c1917944f260e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/DResolvedType.java @@ -20,7 +20,6 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupUtility; @@ -75,15 +74,6 @@ public Class getType() { return type; } - /** - * Writes ASM based on the data collected during the analysis phase. - */ - TypeNode write() { - return new TypeNode() - .setLocation(location) - .setType(type); - } - @Override public String toString() { return "(DResolvedType [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "])"; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index bef2a52b8b1a1..e00c8a0f5a075 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -25,7 +25,6 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.ir.AssignmentNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -240,25 +239,23 @@ private void analyzeSimple(ScriptRoot scriptRoot, Locals locals) { */ @Override AssignmentNode write() { - return new AssignmentNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLeftNode(lhs.write()) - .setRightNode(rhs.write()) - .setCompoundTypeNode(new TypeNode() - .setLocation(location) - .setType(promote) - ) - .setLocation(location) - .setPre(pre) - .setPost(post) - .setOperation(operation) - .setRead(read) - .setCat(cat) - .setThere(there) - .setBack(back); + AssignmentNode assignmentNode = new AssignmentNode(); + + assignmentNode.setLeftNode(lhs.write()); + assignmentNode.setRightNode(rhs.write()); + + assignmentNode.setLocation(location); + assignmentNode.setExpressionType(actual); + assignmentNode.setCompoundType(promote); + assignmentNode.setPre(pre); + assignmentNode.setPost(post); + assignmentNode.setOperation(operation); + assignmentNode.setRead(read); + assignmentNode.setCat(cat); + assignmentNode.setThere(there); + assignmentNode.setBack(back); + + return assignmentNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index 44f88983fb2e6..845dd86fd4036 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -24,7 +24,6 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.ir.BinaryMathNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -618,25 +617,20 @@ private void analyzeBWOr(ScriptRoot scriptRoot, Locals variables) { @Override BinaryMathNode write() { - return new BinaryMathNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLeftNode(left.write()) - .setRightNode(right.write()) - .setShiftTypeNode(new TypeNode() - .setLocation(location) - .setType(shiftDistance) - ) - .setBinaryTypeNode(new TypeNode() - .setLocation(location) - .setType(promote) - ) - .setLocation(location) - .setOperation(operation) - .setCat(cat) - .setOriginallExplicit(originallyExplicit); + BinaryMathNode binaryMathNode = new BinaryMathNode(); + + binaryMathNode.setLeftNode(left.write()); + binaryMathNode.setRightNode(right.write()); + + binaryMathNode.setLocation(location); + binaryMathNode.setExpressionType(actual); + binaryMathNode.setBinaryType(promote); + binaryMathNode.setShiftType(shiftDistance); + binaryMathNode.setOperation(operation); + binaryMathNode.setCat(cat); + binaryMathNode.setOriginallExplicit(originallyExplicit); + + return binaryMathNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java index eaf1cc193ce50..209f0a98b6d04 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.ir.BooleanNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -77,15 +76,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override BooleanNode write() { - return new BooleanNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLeftNode(left.write()) - .setRightNode(right.write()) - .setLocation(location) - .setOperation(operation); + BooleanNode booleanNode = new BooleanNode(); + + booleanNode.setLeftNode(left.write()); + booleanNode.setRightNode(right.write()); + + booleanNode.setLocation(location); + booleanNode.setExpressionType(actual); + booleanNode.setOperation(operation); + + return booleanNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java index adaaecac126bb..b57fada3a6eeb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java @@ -21,7 +21,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.ir.UnboundCallNode; import org.elasticsearch.painless.lookup.PainlessClassBinding; import org.elasticsearch.painless.lookup.PainlessInstanceBinding; @@ -159,23 +158,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override UnboundCallNode write() { - UnboundCallNode unboundCallNode = new UnboundCallNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setLocalFunction(localFunction) - .setImportedMethod(importedMethod) - .setClassBinding(classBinding) - .setClassBindingOffset(classBindingOffset) - .setBindingName(bindingName) - .setInstanceBinding(instanceBinding); + UnboundCallNode unboundCallNode = new UnboundCallNode(); for (AExpression argument : arguments) { unboundCallNode.addArgumentNode(argument.write()); } + unboundCallNode.setLocation(location); + unboundCallNode.setExpressionType(actual); + unboundCallNode.setLocalFunction(localFunction); + unboundCallNode.setImportedMethod(importedMethod); + unboundCallNode.setClassBinding(classBinding); + unboundCallNode.setClassBindingOffset(classBindingOffset); + unboundCallNode.setBindingName(bindingName); + unboundCallNode.setInstanceBinding(instanceBinding); + return unboundCallNode; } 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 007d0d07f700d..ed098df80fd31 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 @@ -24,7 +24,6 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.CapturingFuncRefNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -82,16 +81,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override CapturingFuncRefNode write() { - return new CapturingFuncRefNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setCaptured(captured) - .setName(call) - .setPointer(defPointer) - .setFuncRef(ref); + CapturingFuncRefNode capturingFuncRefNode = new CapturingFuncRefNode(); + + capturingFuncRefNode.setLocation(location); + capturingFuncRefNode.setExpressionType(actual); + capturingFuncRefNode.setCaptured(captured); + capturingFuncRefNode.setName(call); + capturingFuncRefNode.setPointer(defPointer); + capturingFuncRefNode.setFuncRef(ref);; + + return capturingFuncRefNode; + } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 5ee6e17e91269..fe413e6f4693c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.CastNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -57,14 +56,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override CastNode write() { - return new CastNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(child.write()) - .setLocation(location) - .setCast(cast); + CastNode castNode = new CastNode(); + + castNode.setChildNode(child.write()); + + castNode.setLocation(location); + castNode.setExpressionType(actual); + castNode.setCast(cast); + + return castNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 2f8f1739aebaa..8e264e2519496 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -24,7 +24,6 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.ir.ComparisonNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -424,19 +423,17 @@ private void analyzeLT(ScriptRoot scriptRoot, Locals variables) { @Override ComparisonNode write() { - return new ComparisonNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLeftNode(left.write()) - .setRightNode(right.write()) - .setComparisonTypeNode(new TypeNode() - .setLocation(location) - .setType(promotedType) - ) - .setLocation(location) - .setOperation(operation); + ComparisonNode comparisonNode = new ComparisonNode(); + + comparisonNode.setLeftNode(left.write()); + comparisonNode.setRightNode(right.write()); + + comparisonNode.setLocation(location); + comparisonNode.setExpressionType(actual); + comparisonNode.setComparisonType(promotedType); + comparisonNode.setOperation(operation); + + return comparisonNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java index 849cfa05e53f6..6136527e059b3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.ConditionalNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -88,15 +87,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ConditionalNode write() { - return new ConditionalNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLeftNode(left.write()) - .setRightNode(right.write()) - .setConditionNode(condition.write()) - .setLocation(location); + ConditionalNode conditionalNode = new ConditionalNode(); + + conditionalNode.setLeftNode(left.write()); + conditionalNode.setRightNode(right.write()); + conditionalNode.setConditionNode(condition.write()); + + conditionalNode.setLocation(location); + conditionalNode.setExpressionType(actual); + + return conditionalNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java index 4064a08232491..4773e7a1a2aa4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.ConstantNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -71,13 +70,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ConstantNode write() { - return new ConstantNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setConstant(constant); + ConstantNode constantNode = new ConstantNode(); + + constantNode.setLocation(location); + constantNode.setExpressionType(actual); + constantNode.setConstant(constant); + + return constantNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java index 56b347c590e36..2550e9aa67d4c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.ElvisNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -93,14 +92,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ElvisNode write() { - return new ElvisNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLeftNode(lhs.write()) - .setRightNode(rhs.write()) - .setLocation(location); + ElvisNode elvisNode = new ElvisNode(); + + elvisNode.setLeftNode(lhs.write()); + elvisNode.setRightNode(rhs.write()); + + elvisNode.setLocation(location); + elvisNode.setExpressionType(actual); + + return elvisNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index f4aae11cf5d21..9db390725bfe8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.FuncRefNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Collections; @@ -68,13 +67,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override FuncRefNode write() { - return new FuncRefNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setFuncRef(ref); + FuncRefNode funcRefNode = new FuncRefNode(); + + funcRefNode.setLocation(location); + funcRefNode.setExpressionType(actual); + funcRefNode.setFuncRef(ref); + + return funcRefNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java index a7f2357443c05..852df27249289 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.InstanceofNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -39,7 +38,7 @@ public final class EInstanceof extends AExpression { private final String type; private Class resolvedType; - private Class expressionType; + private Class instanceType; private boolean primitiveExpression; public EInstanceof(Location location, AExpression expression, String type) { @@ -74,7 +73,7 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { // record if the expression returns a primitive primitiveExpression = expression.actual.isPrimitive(); // map to wrapped type for primitive types - expressionType = expression.actual.isPrimitive() ? + instanceType = expression.actual.isPrimitive() ? PainlessLookupUtility.typeToBoxedType(expression.actual) : PainlessLookupUtility.typeToJavaType(clazz); actual = boolean.class; @@ -82,22 +81,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override InstanceofNode write() { - return new InstanceofNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(expression.write()) - .setExpressionTypeNode(new TypeNode() - .setLocation(location) - .setType(expressionType) - ) - .setResolvedTypeNode(new TypeNode() - .setLocation(location) - .setType(resolvedType) - ) - .setLocation(location) - .setPrimitiveResult(primitiveExpression); + InstanceofNode instanceofNode = new InstanceofNode(); + + instanceofNode.setLocation(location); + instanceofNode.setExpressionType(actual); + instanceofNode.setInstanceType(instanceType); + instanceofNode.setResolvedType(resolvedType); + instanceofNode.setPrimitiveResult(primitiveExpression); + + return instanceofNode; } @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 f4195f45c5aae..01341dee87a1c 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 @@ -24,7 +24,6 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.LambdaNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; @@ -187,14 +186,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override LambdaNode write() { - return new LambdaNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setFuncRef(ref) - .addCaptures(captures); + LambdaNode lambdaNode = new LambdaNode(); + + lambdaNode.setLocation(location); + lambdaNode.setExpressionType(actual); + lambdaNode.setFuncRef(ref); + lambdaNode.getCaptures().addAll(captures); + + return lambdaNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index 833ceb79931ba..3123a235f145c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.ListInitializationNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; @@ -89,19 +88,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ListInitializationNode write() { - ListInitializationNode listInitializationNode = new ListInitializationNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setConstructor(constructor) - .setMethod(method); + ListInitializationNode listInitializationNode = new ListInitializationNode(); for (AExpression value : values) { listInitializationNode.addArgumentNode(value.write()); } + listInitializationNode.setLocation(location); + listInitializationNode.setExpressionType(actual); + listInitializationNode.setConstructor(constructor); + listInitializationNode.setMethod(method); + return listInitializationNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index 025cd132b9f0f..f764756591e9d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.MapInitializationNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; @@ -108,19 +107,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override MapInitializationNode write() { - MapInitializationNode mapInitializationNode = new MapInitializationNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setConstructor(constructor) - .setMethod(method); + MapInitializationNode mapInitializationNode = new MapInitializationNode(); for (int index = 0; index < keys.size(); ++index) { mapInitializationNode.addArgumentNode(keys.get(index).write(), values.get(index).write()); } + mapInitializationNode.setLocation(location); + mapInitializationNode.setExpressionType(actual); + mapInitializationNode.setConstructor(constructor); + mapInitializationNode.setMethod(method); + return mapInitializationNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java index f4cd0481a0604..625662c68e46f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.NewArrayNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.List; @@ -79,18 +78,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override NewArrayNode write() { - NewArrayNode newArrayNode = new NewArrayNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setInitialize(initialize); + NewArrayNode newArrayNode = new NewArrayNode(); for (AExpression argument : arguments) { newArrayNode.addArgumentNode(argument.write()); } + newArrayNode.setLocation(location); + newArrayNode.setExpressionType(actual); + newArrayNode.setInitialize(initialize); + return newArrayNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java index 6391f9ea98aeb..12a62f008eb59 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArrayFunctionRef.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.NewArrayFuncRefNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Arrays; @@ -81,13 +80,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override NewArrayFuncRefNode write() { - return new NewArrayFuncRefNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setFuncRef(ref); + NewArrayFuncRefNode newArrayFuncRefNode = new NewArrayFuncRefNode(); + + newArrayFuncRefNode.setLocation(location); + newArrayFuncRefNode.setExpressionType(actual); + newArrayFuncRefNode.setFuncRef(ref); + + return newArrayFuncRefNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java index d514f3c1872a3..0853a5cc0d8e9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.NewObjectNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; @@ -98,19 +97,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override NewObjectNode write() { - NewObjectNode newObjectNode = new NewObjectNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setRead(read) - .setConstructor(constructor); + NewObjectNode newObjectNode = new NewObjectNode(); for (AExpression argument : arguments) { newObjectNode.addArgumentNode(argument.write()); } + newObjectNode.setLocation(location); + newObjectNode.setExpressionType(actual); + newObjectNode.setRead(read); + newObjectNode.setConstructor(constructor); + return newObjectNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java index 83412a27f6cfa..8d999fc6dc177 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.NullNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -64,12 +63,12 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override NullNode write() { - return new NullNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location); + NullNode nullNode = new NullNode(); + + nullNode.setLocation(location); + nullNode.setExpressionType(actual); + + return nullNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java index 697d0464e6e4e..8e5e7b7018003 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java @@ -25,7 +25,6 @@ import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.ir.RegexNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.lang.reflect.Modifier; @@ -89,15 +88,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override RegexNode write() { - return new RegexNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setFlags(flags) - .setPattern(pattern) - .setConstant(constant); + RegexNode regexNode = new RegexNode(); + regexNode.setLocation(location); + + regexNode.setExpressionType(actual); + regexNode.setFlags(flags); + regexNode.setPattern(pattern); + regexNode.setConstant(constant); + + return regexNode; } private void initializeConstant(MethodWriter writer) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java index 9ed44451e2abf..368376289dae3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.StaticNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -57,12 +56,12 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override StaticNode write() { - return new StaticNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location); + StaticNode staticNode = new StaticNode(); + + staticNode.setLocation(location); + staticNode.setExpressionType(actual); + + return staticNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index 943ad35ecc5d6..f5a8f4dc9615a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.ir.UnaryMathNode; import org.elasticsearch.painless.ir.UnaryNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; @@ -185,19 +184,17 @@ void analyzerSub(ScriptRoot scriptRoot, Locals variables) { @Override UnaryNode write() { - return new UnaryMathNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(child.write()) - .setUnaryTypeNode(new TypeNode() - .setLocation(location) - .setType(promote) - ) - .setLocation(location) - .setOperation(operation) - .setOriginallExplicit(originallyExplicit); + UnaryMathNode unaryMathNode = new UnaryMathNode(); + + unaryMathNode.setChildNode(child.write()); + + unaryMathNode.setLocation(location); + unaryMathNode.setExpressionType(actual); + unaryMathNode.setUnaryType(promote); + unaryMathNode.setOperation(operation); + unaryMathNode.setOriginallExplicit(originallyExplicit); + + return unaryMathNode; } @Override 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 38b8a72b27d3f..62661210a6242 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 @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.ir.VariableNode; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -62,13 +61,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override VariableNode write() { - return new VariableNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setVariable(variable); + VariableNode variableNode = new VariableNode(); + + variableNode.setLocation(location); + variableNode.setExpressionType(actual); + variableNode.setVariable(variable); + + return variableNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java index ecdb9b8eed1e5..996725bb85de2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.BraceNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -82,14 +81,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override BraceNode write() { - return new BraceNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(sub.write()) - .setPrefixNode(prefix.write()) - .setLocation(location); + BraceNode braceNode = new BraceNode(); + + braceNode.setLeftNode(prefix.write()); + braceNode.setRightNode(sub.write()); + + braceNode.setLocation(location); + braceNode.setExpressionType(actual); + + return braceNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java index cc3c3a34bde1e..6f58eebcd4863 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.CallNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation; @@ -98,14 +97,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override CallNode write() { - return new CallNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(sub.write()) - .setPrefixNode(prefix.write()) - .setLocation(location); + CallNode callNode = new CallNode(); + + callNode.setLeftNode(prefix.write()); + callNode.setRightNode(sub.write()); + + callNode.setLocation(location); + callNode.setExpressionType(actual); + + return callNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java index 3a687d0bad07c..e1b0b721f41a7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.DotNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; @@ -124,14 +123,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DotNode write() { - return new DotNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(sub.write()) - .setPrefixNode(prefix.write()) - .setLocation(location); + DotNode dotNode = new DotNode(); + + dotNode.setLeftNode(prefix.write()); + dotNode.setRightNode(sub.write()); + + dotNode.setLocation(location); + dotNode.setExpressionType(actual); + + return dotNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java index 9c6a3d2b9a2c9..77e4b06bb6b55 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.DotSubArrayLengthNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -63,12 +62,12 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DotSubArrayLengthNode write() { - return new DotSubArrayLengthNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location); + DotSubArrayLengthNode dotSubArrayLengthNode = new DotSubArrayLengthNode(); + + dotSubArrayLengthNode.setLocation(location); + dotSubArrayLengthNode.setExpressionType(actual); + + return dotSubArrayLengthNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java index 465f4e3fc306b..5d2815ff5b59c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.BraceSubNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Objects; @@ -58,13 +57,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { } BraceSubNode write() { - return new BraceSubNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(index.write()) - .setLocation(location); + BraceSubNode braceSubNode = new BraceSubNode(); + + braceSubNode.setChildNode(index.write()); + + braceSubNode.setLocation(location); + braceSubNode.setExpressionType(actual); + + return braceSubNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java index 5e3d118de50b5..21bd7f2c2d964 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.CallSubNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -69,19 +68,17 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override CallSubNode write() { - CallSubNode callSubNode = new CallSubNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setMethod(method) - .setBox(box); + CallSubNode callSubNode = new CallSubNode(); for (AExpression argument : arguments) { callSubNode.addArgumentNode(argument.write()); } + callSubNode.setLocation(location); + callSubNode.setExpressionType(actual); + callSubNode.setMethod(method); + callSubNode .setBox(box); + return callSubNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java index 1b22d9066616e..f0eb190733e2b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.BraceSubDefNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -59,13 +58,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override BraceSubDefNode write() { - return new BraceSubDefNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(index.write()) - .setLocation(location); + BraceSubDefNode braceSubDefNode = new BraceSubDefNode(); + + braceSubDefNode.setChildNode(index.write()); + + braceSubDefNode.setLocation(location); + braceSubDefNode.setExpressionType(actual); + + return braceSubDefNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index 4fb3570137b8b..07fb57a699e03 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.CallSubDefNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -92,21 +91,19 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override CallSubDefNode write() { - CallSubDefNode callSubDefNode = new CallSubDefNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setName(name) - .setRecipe(recipe.toString()) - .addPointers(pointers) - .addTypeParameters(parameterTypes); + CallSubDefNode callSubDefNode = new CallSubDefNode(); for (AExpression argument : arguments) { callSubDefNode.addArgumentNode(argument.write()); } + callSubDefNode.setLocation(location); + callSubDefNode.setExpressionType(actual); + callSubDefNode.setName(name); + callSubDefNode.setRecipe(recipe.toString()); + callSubDefNode.getPointers().addAll(pointers); + callSubDefNode.getTypeParameters().addAll(parameterTypes); + return callSubDefNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java index cc87eecae1fe4..f7f6c55f83b99 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.DotSubDefNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -56,13 +55,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DotSubDefNode write() { - return new DotSubDefNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setValue(value); + DotSubDefNode dotSubDefNode = new DotSubDefNode(); + + dotSubDefNode.setLocation(location); + dotSubDefNode.setExpressionType(actual); + dotSubDefNode.setValue(value); + + return dotSubDefNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java index f43400db520fa..02e379e8f0f73 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.DotSubNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -61,13 +60,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DotSubNode write() { - return new DotSubNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setField(field); + DotSubNode dotSubNode = new DotSubNode(); + + dotSubNode.setLocation(location); + dotSubNode.setExpressionType(actual); + dotSubNode.setField(field); + + return dotSubNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java index e0386c0a7c2b0..c4dcecdb113cc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.ListSubShortcutNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -87,15 +86,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ListSubShortcutNode write() { - return new ListSubShortcutNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(index.write()) - .setLocation(location) - .setGetter(getter) - .setSetter(setter); + ListSubShortcutNode listSubShortcutNode = new ListSubShortcutNode(); + + listSubShortcutNode.setChildNode(index.write()); + + listSubShortcutNode.setLocation(location); + listSubShortcutNode.setExpressionType(actual); + listSubShortcutNode.setGetter(getter); + listSubShortcutNode.setSetter(setter); + + return listSubShortcutNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java index 9d4930db2405c..016ca8f430bd5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.MapSubShortcutNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -86,15 +85,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override MapSubShortcutNode write() { - return new MapSubShortcutNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(index.write()) - .setLocation(location) - .setGetter(getter) - .setSetter(setter); + MapSubShortcutNode mapSubShortcutNode = new MapSubShortcutNode(); + + mapSubShortcutNode.setChildNode(index.write()); + + mapSubShortcutNode.setLocation(location); + mapSubShortcutNode.setExpressionType(actual); + mapSubShortcutNode.setGetter(getter); + mapSubShortcutNode.setSetter(setter); + + return mapSubShortcutNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java index c3dfcc515bdad..4d4da1b76ebe3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.NullSafeSubNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -59,13 +58,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override NullSafeSubNode write() { - return new NullSafeSubNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(guarded.write()) - .setLocation(location); + NullSafeSubNode nullSafeSubNode = new NullSafeSubNode(); + + nullSafeSubNode.setChildNode(guarded.write()); + + nullSafeSubNode.setLocation(location); + nullSafeSubNode.setExpressionType(actual); + + return nullSafeSubNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java index d89989d1b48c6..1922b9e56411f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.NullSafeSubNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -68,13 +67,14 @@ void updateActual(Class actual) { @Override NullSafeSubNode write() { - return new NullSafeSubNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setChildNode(guarded.write()) - .setLocation(location); + NullSafeSubNode nullSafeSubNode = new NullSafeSubNode(); + + nullSafeSubNode.setChildNode(guarded.write()); + + nullSafeSubNode.setLocation(location); + nullSafeSubNode.setExpressionType(actual); + + return nullSafeSubNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java index 4c686b3be4186..b8b53dcf53943 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java @@ -22,7 +22,6 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.DotSubShortcutNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -77,14 +76,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DotSubShortcutNode write() { - return new DotSubShortcutNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(actual) - ) - .setLocation(location) - .setGetter(getter) - .setSetter(setter); + DotSubShortcutNode dotSubShortcutNode = new DotSubShortcutNode(); + + dotSubShortcutNode.setLocation(location); + dotSubShortcutNode.setExpressionType(actual); + dotSubShortcutNode.setGetter(getter); + dotSubShortcutNode.setSetter(setter); + + return dotSubShortcutNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java index 8c2a9929c872a..89124ba760998 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java @@ -81,15 +81,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override BlockNode write() { - BlockNode blockNode = new BlockNode() - .setLocation(location) - .setAllEscape(allEscape) - .setStatementCount(statementCount); + BlockNode blockNode = new BlockNode(); for (AStatement statement : statements) { blockNode.addStatementNode(statement.write()); } + blockNode.setLocation(location); + blockNode.setAllEscape(allEscape); + blockNode.setStatementCount(statementCount); + return blockNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java index 334a6b81c8619..c778859614398 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java @@ -54,8 +54,11 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override BreakNode write() { - return new BreakNode() - .setLocation(location); + BreakNode breakNode = new BreakNode(); + + breakNode.setLocation(location); + + return breakNode; } @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 7186cd9127ec2..74ea41b3fc328 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 @@ -89,10 +89,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override CatchNode write() { - return new CatchNode() - .setDeclarationNode(declaration.write()) - .setBlockNode(block == null ? null : block.write()) - .setLocation(location); + CatchNode catchNode = new CatchNode(); + + catchNode.setDeclarationNode(declaration.write()); + catchNode.setBlockNode(block == null ? null : block.write()); + + catchNode.setLocation(location); + + return catchNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java index 37903260d62ad..f343f0d1b443d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java @@ -172,17 +172,7 @@ public StatementNode write() { } public ClassNode writeClass() { - ClassNode classNode = new ClassNode() - .setLocation(location) - .setScriptClassInfo(scriptClassInfo) - .setScriptRoot(scriptRoot) - .setDebugStream(debugStream) - .setName(name) - .setSourceText(sourceText) - .setMainMethod(mainMethod) - .setMethodEscape(methodEscape) - .addGetMethods(getMethods) - .addExtractedVariables(extractedVariables); + ClassNode classNode = new ClassNode(); for (SField field : fields) { classNode.addFieldNode(field.writeField()); @@ -196,6 +186,17 @@ public ClassNode writeClass() { classNode.addStatementNode(statement.write()); } + classNode.setLocation(location); + classNode.setScriptClassInfo(scriptClassInfo); + classNode.setScriptRoot(scriptRoot); + classNode.setDebugStream(debugStream); + classNode.setName(name); + classNode.setSourceText(sourceText); + classNode.setMainMethod(mainMethod); + classNode.setMethodEscape(methodEscape); + classNode.getGetMethods().addAll(getMethods); + classNode.getExtractedVariables().addAll(extractedVariables); + return classNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java index fa490658ee36a..f61494e60988f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java @@ -57,8 +57,11 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ContinueNode write() { - return new ContinueNode() - .setLocation(location); + ContinueNode continueNode = new ContinueNode(); + + continueNode.setLocation(location); + + return continueNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java index cd22b37b04855..48e265dc68341 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java @@ -61,13 +61,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DeclarationBlockNode write() { - DeclarationBlockNode declarationBlockNode = new DeclarationBlockNode() - .setLocation(location); + DeclarationBlockNode declarationBlockNode = new DeclarationBlockNode(); for (SDeclaration declaration : declarations) { declarationBlockNode.addDeclarationNode(declaration.write()); } + declarationBlockNode.setLocation(location); + return declarationBlockNode; } 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 5ea72e4a97c8b..877c1dbd04911 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 @@ -71,10 +71,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DeclarationNode write() { - return new DeclarationNode() - .setExpressionNode(expression == null ? null : expression.write()) - .setLocation(location) - .setVariable(variable); + DeclarationNode declarationNode = new DeclarationNode(); + + declarationNode.setExpressionNode(expression == null ? null : expression.write()); + + declarationNode.setLocation(location); + declarationNode.setVariable(variable); + + return declarationNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java index 73c0c5d4a0b67..41a9da5afbe75 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java @@ -95,12 +95,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override DoWhileLoopNode write() { - return new DoWhileLoopNode() - .setConditionNode(condition.write()) - .setBlockNode(block.write()) - .setLocation(location) - .setLoopCounter(loopCounter) - .setContinuous(continuous); + DoWhileLoopNode doWhileLoopNode = new DoWhileLoopNode(); + + doWhileLoopNode.setConditionNode(condition.write()); + doWhileLoopNode.setBlockNode(block.write()); + + doWhileLoopNode.setLocation(location); + doWhileLoopNode.setLoopCounter(loopCounter); + doWhileLoopNode.setContinuous(continuous); + + return doWhileLoopNode; } @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 b85b4220efb27..017b87733bdb6 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 @@ -111,9 +111,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ForEachLoopNode write() { - return new ForEachLoopNode() - .setConditionNode((ConditionNode)sub.write()) - .setLocation(location); + ForEachLoopNode forEachLoopNode = new ForEachLoopNode(); + + forEachLoopNode.setConditionNode((ConditionNode)sub.write()); + + forEachLoopNode.setLocation(location); + + return forEachLoopNode; } @Override 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 e421024f1df84..14e486d5d9b5d 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 @@ -71,10 +71,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override StatementExpressionNode write() { - return new StatementExpressionNode() - .setExpressionNode(expression.write()) - .setLocation(location) - .setMethodEscape(methodEscape); + StatementExpressionNode statementExpressionNode = new StatementExpressionNode(); + + statementExpressionNode.setExpressionNode(expression.write()); + + statementExpressionNode.setLocation(location); + statementExpressionNode.setMethodEscape(methodEscape); + + return statementExpressionNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java index b9fdde4f15d93..eb7490c5a3f55 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SField.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.FieldNode; import org.elasticsearch.painless.ir.StatementNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.symbol.ScriptRoot; import java.util.Set; @@ -79,15 +78,15 @@ public StatementNode write() { } FieldNode writeField() { - return new FieldNode() - .setTypeNode(new TypeNode() - .setLocation(location) - .setType(type) - ) - .setLocation(location) - .setModifiers(modifiers) - .setName(name) - .setInstance(instance); + FieldNode fieldNode = new FieldNode(); + + fieldNode.setLocation(location); + fieldNode.setModifiers(modifiers); + fieldNode.setName(name); + fieldNode.setFieldType(type); + fieldNode.setInstance(instance); + + return fieldNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java index a8c3514257578..8ed1f0b1481b7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java @@ -152,14 +152,18 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ForLoopNode write() { - return new ForLoopNode() - .setInitialzerNode(initializer == null ? null : initializer.write()) - .setConditionNode(condition == null ? null : condition.write()) - .setAfterthoughtNode(afterthought == null ? null : afterthought.write()) - .setBlockNode(block == null ? null : block.write()) - .setLocation(location) - .setLoopCounter(loopCounter) - .setContinuous(continuous); + ForLoopNode forLoopNode = new ForLoopNode(); + + forLoopNode.setInitialzerNode(initializer == null ? null : initializer.write()); + forLoopNode.setConditionNode(condition == null ? null : condition.write()); + forLoopNode.setAfterthoughtNode(afterthought == null ? null : afterthought.write()); + forLoopNode.setBlockNode(block == null ? null : block.write()); + + forLoopNode.setLocation(location); + forLoopNode.setLoopCounter(loopCounter); + forLoopNode.setContinuous(continuous); + + return forLoopNode; } @Override 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 0ed88fc3c302e..c1f135a344a8b 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 @@ -142,16 +142,20 @@ public StatementNode write() { } FunctionNode writeFunction() { - return new FunctionNode() - .setBlockNode(block.write()) - .setLocation(location) - .setName(name) - .setReturnType(returnType) - .addTypeParameters(typeParameters) - .setSynthetic(synthetic) - .setMethodEscape(methodEscape) - .setLoopCounter(loopCounter) - .setMaxLoopCounter(maxLoopCounter); + FunctionNode functionNode = new FunctionNode(); + + functionNode.setBlockNode(block.write()); + + functionNode.setLocation(location); + functionNode.setName(name); + functionNode.setReturnType(returnType); + functionNode.getTypeParameters().addAll(typeParameters); + functionNode.setSynthetic(synthetic); + functionNode.setMethodEscape(methodEscape); + functionNode.setLoopCounter(loopCounter); + functionNode.setMaxLoopCounter(maxLoopCounter); + + return functionNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java index ea4f4ae29ac95..446e575d446a2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java @@ -78,10 +78,14 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override IfNode write() { - return new IfNode() - .setConditionNode(condition.write()) - .setBlockNode(ifblock.write()) - .setLocation(location); + IfNode ifNode = new IfNode(); + + ifNode.setConditionNode(condition.write()); + ifNode.setBlockNode(ifblock.write()); + + ifNode.setLocation(location); + + return ifNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java index 3fbd297e32967..d571c377fdf91 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java @@ -104,11 +104,15 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override IfElseNode write() { - return new IfElseNode() - .setConditionNode(condition.write()) - .setBlockNode(ifblock.write()) - .setElseBlockNode(elseblock.write()) - .setLocation(location); + IfElseNode ifElseNode = new IfElseNode(); + + ifElseNode.setConditionNode(condition.write()); + ifElseNode.setBlockNode(ifblock.write()); + ifElseNode.setElseBlockNode(elseblock.write()); + + ifElseNode.setLocation(location); + + return ifElseNode; } @Override 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 079f8ff566447..e0f314d133174 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 @@ -71,9 +71,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ReturnNode write() { - return new ReturnNode() - .setExpressionNode(expression == null ? null : expression.write()) - .setLocation(location); + ReturnNode returnNode = new ReturnNode(); + + returnNode.setExpressionNode(expression == null ? null : expression.write()); + + returnNode.setLocation(location); + + return returnNode; } @Override 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 91a3868080854..33a33d8a1b702 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 @@ -24,7 +24,6 @@ import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ir.ForEachSubArrayNode; -import org.elasticsearch.painless.ir.TypeNode; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.symbol.ScriptRoot; @@ -70,20 +69,21 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ForEachSubArrayNode write() { - return new ForEachSubArrayNode() - .setConditionNode(expression.write()) - .setBlockNode(block.write()) - .setIndexedTypeNode(new TypeNode() - .setLocation(location) - .setType(indexed) - ) - .setLocation(location) - .setVariable(variable) - .setCast(cast) - .setArray(array) - .setIndex(index) - .setLoopCounter(loopCounter) - .setContinuous(false); + ForEachSubArrayNode forEachSubArrayNode = new ForEachSubArrayNode(); + + forEachSubArrayNode.setConditionNode(expression.write()); + forEachSubArrayNode.setBlockNode(block.write()); + + forEachSubArrayNode.setLocation(location); + forEachSubArrayNode.setVariable(variable); + forEachSubArrayNode.setCast(cast); + forEachSubArrayNode.setArray(array); + forEachSubArrayNode.setIndex(index); + forEachSubArrayNode.setIndexedType(indexed); + forEachSubArrayNode.setLoopCounter(loopCounter); + forEachSubArrayNode.setContinuous(false); + + return forEachSubArrayNode; } @Override 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 d6e2d7231947b..5ed45207361f9 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 @@ -84,16 +84,20 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ForEachSubIterableNode write() { - return new ForEachSubIterableNode() - .setConditionNode(expression.write()) - .setBlockNode(block.write()) - .setLocation(location) - .setVariable(variable) - .setCast(cast) - .setIterator(iterator) - .setMethod(method) - .setLoopCounter(loopCounter) - .setContinuous(false); + ForEachSubIterableNode forEachSubIterableNode = new ForEachSubIterableNode(); + + forEachSubIterableNode.setConditionNode(expression.write()); + forEachSubIterableNode.setBlockNode(block.write()); + + forEachSubIterableNode.setLocation(location); + forEachSubIterableNode.setVariable(variable); + forEachSubIterableNode.setCast(cast); + forEachSubIterableNode.setIterator(iterator); + forEachSubIterableNode.setMethod(method); + forEachSubIterableNode.setLoopCounter(loopCounter); + forEachSubIterableNode.setContinuous(false); + + return forEachSubIterableNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java index 85a90bf07bb5c..a2d645fb30779 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java @@ -59,9 +59,13 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override ThrowNode write() { - return new ThrowNode() - .setExpressionNode(expression.write()) - .setLocation(location); + ThrowNode throwNode = new ThrowNode(); + + throwNode.setExpressionNode(expression.write()); + + throwNode.setLocation(location); + + return throwNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java index 37b1f0f34daf6..51e8edccd262b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java @@ -96,14 +96,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override TryNode write() { - TryNode tryNode = new TryNode() - .setBlockNode(block.write()) - .setLocation(location); + TryNode tryNode = new TryNode(); for (SCatch catc : catches) { tryNode.addCatchNode(catc.write()); } + tryNode.setBlockNode(block.write()); + + tryNode.setLocation(location); + return tryNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java index b697ebfbeed91..18e4894bb29bd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java @@ -99,12 +99,16 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { @Override WhileNode write() { - return new WhileNode() - .setConditionNode(condition.write()) - .setBlockNode(block == null ? null : block.write()) - .setLocation(location) - .setLoopCounter(loopCounter) - .setContinuous(continuous); + WhileNode whileNode = new WhileNode(); + + whileNode.setConditionNode(condition.write()); + whileNode.setBlockNode(block == null ? null : block.write()); + + whileNode.setLocation(location); + whileNode.setLoopCounter(loopCounter); + whileNode.setContinuous(continuous); + + return whileNode; } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java index b59ea77e8c8a6..52173c5c2d58e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScriptRoot.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.ScriptClassInfo; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.node.SClass; -import org.elasticsearch.painless.symbol.FunctionTable; import java.util.Objects; From 8a0a65ce0645ff786cf882d605fe16ba99d93d56 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 22 Jan 2020 16:36:56 -0800 Subject: [PATCH 22/24] fix instanceof missing node --- .../main/java/org/elasticsearch/painless/node/EInstanceof.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java index 852df27249289..f2a49ca5b2d69 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java @@ -83,6 +83,8 @@ void analyze(ScriptRoot scriptRoot, Locals locals) { InstanceofNode write() { InstanceofNode instanceofNode = new InstanceofNode(); + instanceofNode.setChildNode(expression.write()); + instanceofNode.setLocation(location); instanceofNode.setExpressionType(actual); instanceofNode.setInstanceType(instanceType); From 1c03a51379c896b0f0c5897901f1635c2b43dc12 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 23 Jan 2020 12:22:39 -0800 Subject: [PATCH 23/24] remove all default constructors from ir nodes --- .../java/org/elasticsearch/painless/ir/ArgumentsNode.java | 3 --- .../java/org/elasticsearch/painless/ir/AssignmentNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/BinaryMathNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/BinaryNode.java | 3 --- .../main/java/org/elasticsearch/painless/ir/BlockNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/BooleanNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/BraceNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/BraceSubDefNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/BraceSubNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/BreakNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/CallNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/CallSubDefNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/CallSubNode.java | 4 ---- .../org/elasticsearch/painless/ir/CapturingFuncRefNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/CastNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/CatchNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ClassNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/ComparisonNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/ConditionNode.java | 3 --- .../java/org/elasticsearch/painless/ir/ConditionalNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ConstantNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ContinueNode.java | 4 ---- .../org/elasticsearch/painless/ir/DeclarationBlockNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/DeclarationNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/DoWhileLoopNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/DotNode.java | 4 ---- .../org/elasticsearch/painless/ir/DotSubArrayLengthNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/DotSubDefNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/DotSubNode.java | 4 ---- .../org/elasticsearch/painless/ir/DotSubShortcutNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ElvisNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/ExpressionNode.java | 3 --- .../main/java/org/elasticsearch/painless/ir/FieldNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/ForEachLoopNode.java | 4 ---- .../org/elasticsearch/painless/ir/ForEachSubArrayNode.java | 4 ---- .../org/elasticsearch/painless/ir/ForEachSubIterableNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ForLoopNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/FuncRefNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/FunctionNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/IRNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/IfElseNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/IfNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/InstanceofNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/LambdaNode.java | 4 ---- .../org/elasticsearch/painless/ir/ListInitializationNode.java | 4 ---- .../org/elasticsearch/painless/ir/ListSubShortcutNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/LoopNode.java | 3 --- .../org/elasticsearch/painless/ir/MapInitializationNode.java | 4 ---- .../org/elasticsearch/painless/ir/MapSubShortcutNode.java | 4 ---- .../org/elasticsearch/painless/ir/NewArrayFuncRefNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/NewArrayNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/NewObjectNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/NullNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/NullSafeSubNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/RegexNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ReturnNode.java | 4 ---- .../elasticsearch/painless/ir/StatementExpressionNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/StatementNode.java | 3 --- .../main/java/org/elasticsearch/painless/ir/StaticNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/ThrowNode.java | 4 ---- .../src/main/java/org/elasticsearch/painless/ir/TryNode.java | 4 ---- .../java/org/elasticsearch/painless/ir/UnaryMathNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/UnaryNode.java | 3 --- .../java/org/elasticsearch/painless/ir/UnboundCallNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/VariableNode.java | 4 ---- .../main/java/org/elasticsearch/painless/ir/WhileNode.java | 4 ---- 66 files changed, 257 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java index 7caf98cc8313a..40f6d901bb198 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ArgumentsNode.java @@ -38,7 +38,4 @@ public List getArgumentNodes() { /* ---- end tree structure */ - public ArgumentsNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 3957fdb7b3c53..41d12c3c76171 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -112,10 +112,6 @@ public PainlessCast getBack() { /* ---- end node data ---- */ - public AssignmentNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index 5c73352a1a394..2f45c3408e448 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -97,10 +97,6 @@ public void setLocation(Location location) { /* ---- end node data ---- */ - public BinaryMathNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java index 0858afb55bc83..3cdfcfd9839d3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryNode.java @@ -44,7 +44,4 @@ public ExpressionNode getRightNode() { /* ---- end tree structure ---- */ - public BinaryNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java index f702f53850d5d..fdc0c3e32530c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java @@ -63,10 +63,6 @@ public int getStatementCount() { /* ---- end node data ---- */ - public BlockNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { for (StatementNode statementNode : statementNodes) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index 412823d20b5d3..65057de255fe9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -42,10 +42,6 @@ public Operation getOperation() { /* ---- end node data ---- */ - public BooleanNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java index 5e4165718e5a5..4a3dea6778622 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java @@ -25,10 +25,6 @@ public class BraceNode extends BinaryNode { - public BraceNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { getLeftNode().write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java index 6eae4c31ae630..2be964e9967d2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java @@ -27,10 +27,6 @@ public class BraceSubDefNode extends UnaryNode { - public BraceSubDefNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { setup(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java index 1c9a2fec25635..3c8483b7e6099 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java @@ -27,10 +27,6 @@ public class BraceSubNode extends UnaryNode { - public BraceSubNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { setup(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java index 296e31f381f67..405bbb77305b6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java @@ -25,10 +25,6 @@ public class BreakNode extends StatementNode { - public BreakNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.goTo(breakLabel); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java index 2f79de8472c23..b24adc0c1915f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java @@ -25,10 +25,6 @@ public class CallNode extends BinaryNode { - public CallNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { getLeftNode().write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java index 56e1ae400e8f9..b6fd079767653 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java @@ -71,10 +71,6 @@ public List> getTypeParameters() { /* ---- end node data ---- */ - public CallSubDefNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java index f16a09d1bb2e5..6770640d9c857 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java @@ -49,10 +49,6 @@ public Class getBox() { /* ---- end node data ---- */ - public CallSubNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index bb74312012e85..d00cb17557440 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -71,10 +71,6 @@ public String getPointer() { /* ---- end node data ---- */ - public CapturingFuncRefNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java index a47d02452d7a9..75b1bd2c32be5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java @@ -40,10 +40,6 @@ public PainlessCast getCast() { /* ---- end node data ---- */ - public CastNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { getChildNode().write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index c8f85f92d6bd8..3bf0717757619 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -50,10 +50,6 @@ public BlockNode getBlockNode() { /* ---- end tree structure ---- */ - public CatchNode() { - // do nothing - } - Label begin = null; Label end = null; Label exception = null; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index 6e6d5376bcdb3..1959902afc977 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -189,10 +189,6 @@ public List getGetMethods() { protected Globals globals; protected byte[] bytes; - public ClassNode() { - // do nothing - } - public BitSet getStatements() { return globals.getStatements(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index adffe597fb3d1..75b6136fbe294 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -61,10 +61,6 @@ public String getComparisonCanonicalTypeName() { /* ---- end node data ---- */ - public ComparisonNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java index 0f28a8e3ec78c..8efeac594fe0e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionNode.java @@ -44,7 +44,4 @@ public BlockNode getBlockNode() { /* ---- end tree structure ---- */ - public ConditionNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java index 4e2998ebb3158..f903cc297e2ff 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java @@ -41,10 +41,6 @@ public ExpressionNode getConditionNode() { /* ---- end tree structure ---- */ - public ConditionalNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java index 100680d0c0c82..3728cc020d92f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -38,10 +38,6 @@ public Object getConstant() { } /* ---- end node data ---- */ - - public ConstantNode() { - // do nothing - } @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java index fd182caf3bf81..82eeeaec9015f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java @@ -25,10 +25,6 @@ public class ContinueNode extends StatementNode { - public ContinueNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.goTo(continueLabel); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java index 06af3b15e0ccb..1decb6cf91f4f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java @@ -42,10 +42,6 @@ public List getDeclarationsNodes() { /* ---- end tree structure ---- */ - public DeclarationBlockNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { for (DeclarationNode declarationNode : declarationNodes) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index 2898224f397ed..2339a74c5788a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -53,10 +53,6 @@ public Variable getVariable() { /* ---- end node data ---- */ - public DeclarationNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java index 96d3c3850d9d6..2fd104666ab70 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java @@ -27,10 +27,6 @@ public class DoWhileLoopNode extends LoopNode { - public DoWhileLoopNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java index 5334415927945..2ea11e5f4d906 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java @@ -25,10 +25,6 @@ public class DotNode extends BinaryNode { - public DotNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { getLeftNode().write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java index 5fc43114279a3..2f32a73d74b31 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java @@ -25,10 +25,6 @@ public class DotSubArrayLengthNode extends ExpressionNode { - public DotSubArrayLengthNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java index ae41e50c767ec..8be070de26e02 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java @@ -41,10 +41,6 @@ public String getValue() { /* ---- end node data ---- */ - public DotSubDefNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java index e0d81a0f9cfd0..5dc188419c286 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java @@ -40,10 +40,6 @@ public PainlessField getField() { } /* ---- end node data ---- */ - - public DotSubNode() { - // do nothing - } @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java index 1cd0738d5d4f0..412aef5b07d69 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java @@ -49,10 +49,6 @@ public PainlessMethod getGetter() { /* ---- end node data ---- */ - public DotSubShortcutNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java index dccbc1ed55601..43c5fbc725d73 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java @@ -26,10 +26,6 @@ public class ElvisNode extends BinaryNode { - public ElvisNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java index c385f28e0eab4..418b5afc39197 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ExpressionNode.java @@ -41,7 +41,4 @@ public String getExpressionCanonicalTypeName() { /* ---- end node data ---- */ - public ExpressionNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java index 26253e6fc5ed5..b9a70eaec27aa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -72,10 +72,6 @@ public Object getInstance() { /* ---- end node data ---- */ - public FieldNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { classWriter.getClassVisitor().visitField( diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java index 2ead35b0f08a1..76d5140a024b8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java @@ -39,10 +39,6 @@ public ConditionNode getConditionNode() { /* ---- end tree structure ---- */ - public ForEachLoopNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { conditionNode.write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java index 27855606e4bbf..9dcb01cb1094b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java @@ -84,10 +84,6 @@ public String getIndexedCanonicalTypeName() { /* ---- end node data ---- */ - public ForEachSubArrayNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java index 3c9cc0a411c32..c6c7fe63cbf18 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java @@ -81,10 +81,6 @@ public PainlessMethod getMethod() { /* ---- end node data ---- */ - public ForEachSubIterableNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java index 145b8c3053ab7..df800919f88dc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java @@ -50,10 +50,6 @@ public ExpressionNode getAfterthoughtNode() { /* ---- end tree structure ---- */ - public ForLoopNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java index 3e51d4e1f1299..8c249a3cba703 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java @@ -40,10 +40,6 @@ public FunctionRef getFuncRef() { /* ---- end node data ---- */ - public FuncRefNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { if (funcRef != null) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java index e84fa7cef860d..1262f767a86be 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -112,10 +112,6 @@ public int getMaxLoopCounter() { /* ---- end node data ---- */ - public FunctionNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java index 7c51328091276..7a955e17aff13 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java @@ -40,10 +40,6 @@ public Location getLocation() { /* end node data */ - public IRNode() { - // do nothing - } - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} protected int accessElementCount() {throw new UnsupportedOperationException();} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java index 4d8b39f9c477b..267dd5d737328 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java @@ -41,10 +41,6 @@ public BlockNode getElseBlockNode() { /* ---- end tree structure ---- */ - public IfElseNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java index 3316cccccaff5..d151a87f66c34 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java @@ -27,10 +27,6 @@ public class IfNode extends ConditionNode { - public IfNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java index d6053302d41ee..7dc8c3c8c50fd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -67,10 +67,6 @@ public boolean isPrimitiveResult() { /* ---- end node data ---- */ - public InstanceofNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { getChildNode().write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index 04ac33f6dd1cb..267df6c54e1f0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -54,10 +54,6 @@ public FunctionRef getFuncRef() { /* ---- end node data ---- */ - public LambdaNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java index 971d1cd4f67de..a0cefdc4bfed4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java @@ -52,10 +52,6 @@ public PainlessMethod getMethod() { /* ---- end node data ---- */ - public ListInitializationNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java index be3897c3382f4..f902fca25a9be 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java @@ -52,10 +52,6 @@ public PainlessMethod getGetter() { /* ---- end node data ---- */ - public ListSubShortcutNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { setup(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java index a4c7b6310b68d..dc3a546d7de05 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java @@ -46,7 +46,4 @@ public Variable getLoopCounter() { /* ---- end node data ---- */ - public LoopNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java index 2e83a170e7432..f3411f837c5d8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -85,10 +85,6 @@ public PainlessMethod getMethod() { /* ---- end node data ---- */ - public MapInitializationNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java index a4144699adb21..f151ca89b2fa0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -49,10 +49,6 @@ public PainlessMethod getGetter() { /* ---- end node data ---- */ - public MapSubShortcutNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { getChildNode().write(classWriter, methodWriter, globals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java index 0d6aef1bea44a..74cbe5c32ad41 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java @@ -40,10 +40,6 @@ public FunctionRef getFuncRef() { /* ---- end node data ---- */ - public NewArrayFuncRefNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { if (funcRef != null) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java index 3959d7d1b707d..d2f26efe4c0ca 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java @@ -39,10 +39,6 @@ public boolean getInitialize() { /* ---- end node data ---- */ - public NewArrayNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java index 55c8f511be4d8..f92bb753e0a63 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java @@ -51,10 +51,6 @@ public boolean getRead() { /* ---- end node data ---- */ - public NewObjectNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java index 59ee2b72cf8e0..91baae23ab28a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java @@ -26,10 +26,6 @@ public class NullNode extends ExpressionNode { - public NullNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.visitInsn(Opcodes.ACONST_NULL); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java index 10fdd90962a24..61585b13e926d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java @@ -26,10 +26,6 @@ public class NullSafeSubNode extends UnaryNode { - public NullSafeSubNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java index ea77612466eef..dc4f042332b83 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java @@ -61,10 +61,6 @@ public Object getConstant() { /* ---- end node data ---- */ - public RegexNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java index bb84e7e259c65..8752b6fd915c9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java @@ -39,10 +39,6 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure ---- */ - public ReturnNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java index 7e427884562f8..95c2195f62ae4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java @@ -51,10 +51,6 @@ public boolean getMethodEscape() { /* ---- end node data ---- */ - public StatementExpressionNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java index cda9353b7dd10..d2f7ec658320e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementNode.java @@ -26,7 +26,4 @@ public abstract class StatementNode extends IRNode { protected Label continueLabel = null; protected Label breakLabel = null; - public StatementNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java index 631406a11307e..f144f4e601d7b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java @@ -25,10 +25,6 @@ public class StaticNode extends ExpressionNode { - public StaticNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { // do nothing diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java index b1f3b680fc72e..dec6cec871b43 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java @@ -39,10 +39,6 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure ---- */ - public ThrowNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java index 1b2251db10ce8..7a89a6fadb600 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java @@ -52,10 +52,6 @@ public List getCatchsNodes() { /* ---- end tree structure ---- */ - public TryNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index c741471041b78..ea6d08579039c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -77,10 +77,6 @@ public boolean getOriginallyExplicit() { /* ---- end node data ---- */ - public UnaryMathNode() { - // do nothing - } - @Override public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java index 693e0d0fef8ce..1fca6e0e6a74a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryNode.java @@ -35,7 +35,4 @@ public ExpressionNode getChildNode() { /* ---- end tree structure ---- */ - public UnaryNode() { - // do nothing - } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java index ec2af7e2497f8..9c2323b27cb73 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -93,10 +93,6 @@ public String getBindingName() { /* ---- end node data ---- */ - public UnboundCallNode() { - // do nothing - } - @Override public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeDebugInfo(location); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java index b702a0bedb6fc..37af99a09c3a9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java @@ -41,10 +41,6 @@ public Variable getVariable() { /* ---- end node data ---- */ - public VariableNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java index 649096176047d..6f918e66f37fb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java @@ -27,10 +27,6 @@ public class WhileNode extends LoopNode { - public WhileNode() { - // do nothing - } - @Override protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { methodWriter.writeStatementOffset(location); From 56a366ad2beac268810914237d99b084ccad1d7d Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 23 Jan 2020 13:41:00 -0800 Subject: [PATCH 24/24] added some comments for cat --- .../main/java/org/elasticsearch/painless/ir/AssignmentNode.java | 2 +- .../main/java/org/elasticsearch/painless/ir/BinaryMathNode.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 41d12c3c76171..8841143e84d53 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -37,7 +37,7 @@ public class AssignmentNode extends BinaryNode { private boolean post; private Operation operation; private boolean read; - private boolean cat; + private boolean cat; // set to true for a compound assignment String concatenation private Class compoundType; private PainlessCast there; private PainlessCast back; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index 2f45c3408e448..cff2f89c3a676 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -39,7 +39,7 @@ public class BinaryMathNode extends BinaryNode { private Operation operation; private Class binaryType; private Class shiftType; - private boolean cat; + private boolean cat; // set to true for a String concatenation private boolean originallyExplicit; // record whether there was originally an explicit cast public void setOperation(Operation operation) {