Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify constant handling in Painless #52612

Merged
merged 8 commits into from
Feb 25, 2020
Merged

Conversation

jdconrad
Copy link
Contributor

This change makes constant handling simpler by doing the following:

  1. Removes the ir tree node RegexNode entirely in favor or using more generic nodes such as ConstantNode and MemberFieldLoadNode generated by the user tree node ERegex. This requires a clinit method added to the ClassNode, but allows for additional removals. This clinit method can also be used for potential optimization passes.
  2. Removes the Constant class as with the changes to regex nodes it's no longer necessary.
  3. Removes the Globals class from the ir tree write phase. With the previous removals, Globals is no longer necessary.

@jdconrad jdconrad added :Core/Infra/Scripting Scripting abstractions, Painless, and Mustache >refactoring v8.0.0 labels Feb 21, 2020
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (:Core/Infra/Scripting)

@@ -72,6 +72,7 @@ StatementExpressionNode write(ClassNode classNode) {

statementExpressionNode.setLocation(location);
statementExpressionNode.setMethodEscape(methodEscape);
statementExpressionNode.setNoop(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After speaking with you (@stu-elastic) and @rjernst I've decided to change this a bit. I've removed noop in favor of doPop which will pop extraneous values off the stack when necessary such as a method call with side effects, but an ignored return value somecall();.

I also removed the need for StatementExpressionNode to handle return values. Instead, SExpression will just directly translate to a ReturnNode if a return is required. This moves the responsibility to where is makes sense instead of having redundant returns in multiple nodes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I continued to iterate on this after more discussion with @rjernst . I removed the doPop and will instead use an expression's type to determine if a pop is required or not (popping the void type is the same as a noop in this case).

@Override
public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
public void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's now MemberFieldLoadNode and MemberFieldStoreNode where Store has the following new code:

        if (isStatic == false) {
            methodWriter.loadThis();
        }

        getChildNode().write(classWriter, methodWriter, scopeTable);

Why the new code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new code is to handle putting the value on the stack that will be written to the field. So store requires an expression to generate a value to store where as load does not.

callSubNode.setExpressionType(Pattern.class);
callSubNode.setBox(Pattern.class);
callSubNode.setMethod(new PainlessMethod(
Pattern.class.getMethod("compile", String.class, int.class),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this being written to clinit?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh perhaps in classNode.addFieldNode(fieldNode);?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

classNode.addFieldNode creates a declaration for a member field.

These lines actually add the regex constant generation and assignment to the clinit method:

BlockNode blockNode = classNode.getClinitNode().getBlockNode();
blockNode.addStatementNode(statementExpressionNode);


import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE;

public class MemberFieldStoreNode extends UnaryNode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal javadoc please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

if (clinitNode.getBlockNode().getStatementsNodes().isEmpty() == false) {
ReturnNode returnNode = new ReturnNode();
returnNode.setLocation(new Location("internal$clinit$return", 0));
clinitNode.getBlockNode().addStatementNode(returnNode);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add this when creating the clinit block, and have an inner block that we expose as the one that statements can be added to? This way we don't manipulate the IR tree when calling write.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to do no modifications of the ir tree from write. I just do the method writer for clinit and the return statement in the ClassNode. I'll consider better ways to do this, but for now this makes the most sense because it's the simplest change.

@jdconrad
Copy link
Contributor Author

@rjernst @stu-elastic Thanks for the initial rounds of review.

@jdconrad
Copy link
Contributor Author

@rjernst I think this is ready for another look. I believe I addressed all your comments and continued iterating on the best way to handle StatementExpressionNode - see Stu's initial comments on this for my follow ups.

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jdconrad
Copy link
Contributor Author

@rjernst Thanks for the second review.

@jdconrad jdconrad merged commit 37e3391 into elastic:master Feb 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/Scripting Scripting abstractions, Painless, and Mustache >refactoring v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants