From commits-return-10049-archive-asf-public=cust-asf.ponee.io@groovy.apache.org Sun Dec 1 10:41:40 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id 459EA18065B for ; Sun, 1 Dec 2019 11:41:40 +0100 (CET) Received: (qmail 25197 invoked by uid 500); 1 Dec 2019 10:41:39 -0000 Mailing-List: contact commits-help@groovy.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@groovy.apache.org Delivered-To: mailing list commits@groovy.apache.org Received: (qmail 25180 invoked by uid 99); 1 Dec 2019 10:41:39 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 01 Dec 2019 10:41:39 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 1804B8B68F; Sun, 1 Dec 2019 10:41:39 +0000 (UTC) Date: Sun, 01 Dec 2019 10:41:39 +0000 To: "commits@groovy.apache.org" Subject: [groovy] 01/20: organize members and other minor edits MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit From: sunlan@apache.org In-Reply-To: <157519689837.22317.13480026071125475937@gitbox.apache.org> References: <157519689837.22317.13480026071125475937@gitbox.apache.org> X-Git-Host: gitbox.apache.org X-Git-Repo: groovy X-Git-Refname: refs/heads/GROOVY_3_0_X X-Git-Reftype: branch X-Git-Rev: 90f44afb90ac5f5b03584bd5c9d738b87cfe416b X-Git-NotificationType: diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated Message-Id: <20191201104139.1804B8B68F@gitbox.apache.org> This is an automated email from the ASF dual-hosted git repository. sunlan pushed a commit to branch GROOVY_3_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git commit 90f44afb90ac5f5b03584bd5c9d738b87cfe416b Author: Eric Milles AuthorDate: Sat Nov 23 11:55:04 2019 -0600 organize members and other minor edits (cherry picked from commit b51fe06dd9aa5d41489106d7a3047dbda76bb68e) --- .../classgen/asm/OptimizingStatementWriter.java | 527 +++++++++++---------- 1 file changed, 273 insertions(+), 254 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java index fb07f94..5c4b50c 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java @@ -60,8 +60,10 @@ import org.codehaus.groovy.syntax.Types; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import java.util.Deque; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import static org.codehaus.groovy.ast.ClassHelper.BigDecimal_TYPE; import static org.codehaus.groovy.ast.ClassHelper.GROOVY_INTERCEPTABLE_TYPE; @@ -85,40 +87,8 @@ import static org.objectweb.asm.Opcodes.IFEQ; import static org.objectweb.asm.Opcodes.IFNE; import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; -/** - * A class to write out the optimized statements - */ public class OptimizingStatementWriter extends StatementWriter { - private static class FastPathData { - private Label pathStart = new Label(); - private Label afterPath = new Label(); - } - - public static class ClassNodeSkip{} - - public static class StatementMeta { - private boolean optimize=false; - protected MethodNode target; - protected ClassNode type; - protected VariableExpression declaredVariableExpression; - protected boolean[] involvedTypes = new boolean[typeMapKeyNames.length]; - public void chainInvolvedTypes(OptimizeFlagsCollector opt) { - for (int i=0; i olderEntries = new LinkedList(); + private final Deque previous = new LinkedList<>(); + public void push() { - olderEntries.addLast(current); + previous.addLast(current); current = new OptimizeFlagsEntry(); } - public void pop(boolean propagateFlags){ + + public void pop(final boolean propagateFlags) { OptimizeFlagsEntry old = current; - current = olderEntries.removeLast(); + current = previous.removeLast(); if (propagateFlags) { chainCanOptimize(old.canOptimize); chainShouldOptimize(old.shouldOptimize); - for (int i=0; i", call.getArguments(), false); } @Override - public void visitExpressionStatement(ExpressionStatement statement) { - if (statement.getNodeMetaData(StatementMeta.class)!=null) return; - opt.push(); - super.visitExpressionStatement(statement); - if (opt.shouldOptimize()) addMeta(statement,opt); - opt.pop(opt.shouldOptimize()); + public void visitDeclarationExpression(final DeclarationExpression expression) { + Expression right = expression.getRightExpression(); + right.visit(this); + + ClassNode leftType = typeChooser.resolveType(expression.getLeftExpression(), node); + Expression rightExpression = expression.getRightExpression(); + ClassNode rightType = optimizeDivWithIntOrLongTarget(rightExpression, leftType); + if (rightType == null) rightType = typeChooser.resolveType(expression.getRightExpression(), node); + if (isPrimitiveType(leftType) && isPrimitiveType(rightType)) { + // if right is a constant, then we optimize only if it makes a block complete, so we set a maybe + if (right instanceof ConstantExpression) { + opt.chainCanOptimize(true); + } else { + opt.chainShouldOptimize(true); + } + addMeta(expression).type = Optional.ofNullable(typeChooser.resolveType(expression, node)).orElse(leftType); + opt.chainInvolvedType(leftType); + opt.chainInvolvedType(rightType); + } } @Override - public void visitBlockStatement(BlockStatement block) { - opt.push(); - boolean optAll = true; - for (Statement statement : block.getStatements()) { - opt.push(); - statement.visit(this); - optAll = optAll && opt.canOptimize(); - opt.pop(true); + public void visitMethodCallExpression(final MethodCallExpression expression) { + if (expression.getNodeMetaData(StatementMeta.class) != null) return; + super.visitMethodCallExpression(expression); + + Expression objectExpression = expression.getObjectExpression(); + boolean setTarget = AsmClassGenerator.isThisExpression(objectExpression); + if (!setTarget) { + if (!(objectExpression instanceof ClassExpression)) return; + setTarget = objectExpression.equals(node); // XXX: comparing Expression and ClassNode } - if (block.isEmpty()) { - opt.chainCanOptimize(true); - opt.pop(true); - } else { - opt.chainShouldOptimize(optAll); - if (optAll) addMeta(block,opt); - opt.pop(optAll); + if (setTarget) { + setMethodTarget(expression, expression.getMethodAsString(), expression.getArguments(), true); } } @Override - public void visitIfElse(IfStatement statement) { - opt.push(); - super.visitIfElse(statement); - if (opt.shouldOptimize()) addMeta(statement,opt); - opt.pop(opt.shouldOptimize()); + public void visitPostfixExpression(final PostfixExpression expression) { + super.visitPostfixExpression(expression); + addTypeInformation(expression.getExpression(), expression); } - /*@Override - public void visitConstantExpression(ConstantExpression expression) { - super.visitConstantExpression(expression); - opt.chainShouldOptimize(true); - }*/ + @Override + public void visitPrefixExpression(final PrefixExpression expression) { + super.visitPrefixExpression(expression); + addTypeInformation(expression.getExpression(), expression); + } @Override - public void visitStaticMethodCallExpression(StaticMethodCallExpression expression) { - if (expression.getNodeMetaData(StatementMeta.class)!=null) return; + public void visitStaticMethodCallExpression(final StaticMethodCallExpression expression) { + if (expression.getNodeMetaData(StatementMeta.class) != null) return; super.visitStaticMethodCallExpression(expression); + setMethodTarget(expression, expression.getMethod(), expression.getArguments(), true); + } - setMethodTarget(expression,expression.getMethod(), expression.getArguments(), true); + @Override + public void visitUnaryMinusExpression(final UnaryMinusExpression expression) { + // TODO: implement int operations for this + super.visitUnaryMinusExpression(expression); + addMeta(expression).type = OBJECT_TYPE; } @Override - public void visitMethodCallExpression(MethodCallExpression expression) { - if (expression.getNodeMetaData(StatementMeta.class)!=null) return; - super.visitMethodCallExpression(expression); + public void visitUnaryPlusExpression(final UnaryPlusExpression expression) { + // TODO: implement int operations for this + super.visitUnaryPlusExpression(expression); + addMeta(expression).type = OBJECT_TYPE; + } - Expression object = expression.getObjectExpression(); - boolean setTarget = AsmClassGenerator.isThisExpression(object); - if (!setTarget) { - if (!(object instanceof ClassExpression)) return; - setTarget = object.equals(node); - } + // - if (!setTarget) return; - setMethodTarget(expression, expression.getMethodAsString(), expression.getArguments(), true); + private void addTypeInformation(final Expression expression, final Expression orig) { + ClassNode type = typeChooser.resolveType(expression, node); + if (isPrimitiveType(type)) { + addMeta(orig).type = type; + opt.chainShouldOptimize(true); + opt.chainInvolvedType(type); + } } - @Override - public void visitConstructorCallExpression(ConstructorCallExpression call) { - if (call.getNodeMetaData(StatementMeta.class)!=null) return; - super.visitConstructorCallExpression(call); + /** + * Optimizes "Z = X/Y" with Z being int or long style. + * + * @returns null if the optimization cannot be applied, otherwise it will return the new target type + */ + private ClassNode optimizeDivWithIntOrLongTarget(final Expression rhs, final ClassNode assignmentTartgetType) { + if (!(rhs instanceof BinaryExpression)) return null; + BinaryExpression binExp = (BinaryExpression) rhs; + int op = binExp.getOperation().getType(); + if (op != Types.DIVIDE && op != Types.DIVIDE_EQUAL) return null; - // we cannot a target for the constructor call, since we cannot easily - // check the meta class of the other class - // setMethodTarget(call, "", call.getArguments(), false); + ClassNode originalResultType = typeChooser.resolveType(binExp, node); + if (!originalResultType.equals(BigDecimal_TYPE) + || !(isLongCategory(assignmentTartgetType) + || isFloatingCategory(assignmentTartgetType))) { + return null; + } + + ClassNode leftType = typeChooser.resolveType(binExp.getLeftExpression(), node); + if (!isLongCategory(leftType)) return null; + ClassNode rightType = typeChooser.resolveType(binExp.getRightExpression(), node); + if (!isLongCategory(rightType)) return null; + + ClassNode target; + if (isIntCategory(leftType) && isIntCategory(rightType)) { + target = int_TYPE; + } else if (isLongCategory(leftType) && isLongCategory(rightType)) { + target = long_TYPE; + } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) { + target = double_TYPE; + } else { + return null; + } + addMeta(rhs).type = target; + opt.chainInvolvedType(target); + return target; } - private void setMethodTarget(Expression expression, String name, Expression callArgs, boolean isMethod) { - if (name==null) return; + private void setMethodTarget(final Expression expression, final String name, final Expression callArgs, final boolean isMethod) { + if (name == null) return; if (!optimizeMethodCall) return; if (AsmClassGenerator.containsSpreadExpression(callArgs)) return; + // find method call target Parameter[] paraTypes = null; if (callArgs instanceof ArgumentListExpression) { ArgumentListExpression args = (ArgumentListExpression) callArgs; int size = args.getExpressions().size(); paraTypes = new Parameter[size]; - int i=0; - for (Expression exp: args.getExpressions()) { + int i = 0; + for (Expression exp : args.getExpressions()) { ClassNode type = typeChooser.resolveType(exp, node); if (!validTypeForCall(type)) return; - paraTypes[i] = new Parameter(type,""); - i++; + paraTypes[i] = new Parameter(type, ""); + i += 1; } } else { ClassNode type = typeChooser.resolveType(callArgs, node); if (!validTypeForCall(type)) return; - paraTypes = new Parameter[]{new Parameter(type,"")}; + paraTypes = new Parameter[]{new Parameter(type, "")}; } MethodNode target; ClassNode type; if (isMethod) { target = node.getMethod(name, paraTypes); - if (target==null) return; + if (target == null) return; if (!target.getDeclaringClass().equals(node)) return; if (scope.isInStaticContext() && !target.isStatic()) return; type = target.getReturnType().redirect(); } else { type = expression.getType(); target = selectConstructor(type, paraTypes); - if (target==null) return; + if (target == null) return; } StatementMeta meta = addMeta(expression); @@ -910,37 +945,21 @@ public class OptimizingStatementWriter extends StatementWriter { opt.chainShouldOptimize(true); } - private static MethodNode selectConstructor(ClassNode node, Parameter[] paraTypes) { - List cl = node.getDeclaredConstructors(); - MethodNode res = null; - for (ConstructorNode cn : cl) { - if (ParameterUtils.parametersEqual(cn.getParameters(), paraTypes)) { - res = cn; + private static MethodNode selectConstructor(final ClassNode node, final Parameter[] parameters) { + List ctors = node.getDeclaredConstructors(); + MethodNode result = null; + for (ConstructorNode ctor : ctors) { + if (ParameterUtils.parametersEqual(ctor.getParameters(), parameters)) { + result = ctor; break; } } - if (res !=null && res.isPublic()) return res; - return null; + return (result != null && result.isPublic() ? result : null); } - private static boolean validTypeForCall(ClassNode type) { + private static boolean validTypeForCall(final ClassNode type) { // do call only for final classes and primitive types - if (isPrimitiveType(type)) return true; - return (type.getModifiers() & ACC_FINAL) > 0; - } - - @Override - public void visitClosureExpression(ClosureExpression expression) { - } - - @Override - public void visitForLoop(ForStatement statement) { - opt.push(); - super.visitForLoop(statement); - if (opt.shouldOptimize()) addMeta(statement,opt); - opt.pop(opt.shouldOptimize()); + return isPrimitiveType(type) || (type.getModifiers() & ACC_FINAL) > 0; } } - - }