From 1955973c3b99b144d7aae79ce7e360c069fd1f91 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 13 Nov 2023 10:37:30 +0100 Subject: [PATCH] JS: fix removal of unused functions in handwritten JS --- .../backend/javascript/ast/AstVisitor.java | 28 ++++++++++++------- .../templating/RemovablePartsFinder.java | 27 +++++++++++++----- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/javascript/ast/AstVisitor.java b/core/src/main/java/org/teavm/backend/javascript/ast/AstVisitor.java index b85958a05..5ad1f85a3 100644 --- a/core/src/main/java/org/teavm/backend/javascript/ast/AstVisitor.java +++ b/core/src/main/java/org/teavm/backend/javascript/ast/AstVisitor.java @@ -268,7 +268,7 @@ public class AstVisitor { public void visit(Scope node) { var scope = enterScope(node); visitChildren(node); - leaveScope(scope); + leaveScope(node, scope); } public void visit(LabeledStatement node) { @@ -294,7 +294,7 @@ public class AstVisitor { var scope = enterScope(node); visitProperty(node, DoLoop::getBody, DoLoop::setBody, EMPTY_DEFAULT); visitProperty(node, DoLoop::getCondition, DoLoop::setCondition, NULL_DEFAULT); - leaveScope(scope); + leaveScope(node, scope); } public void visit(ForInLoop node) { @@ -302,7 +302,7 @@ public class AstVisitor { visitProperty(node, ForInLoop::getIterator, ForInLoop::setIterator, NULL_DEFAULT); visitProperty(node, ForInLoop::getIteratedObject, ForInLoop::setIteratedObject, NULL_DEFAULT); visitProperty(node, ForInLoop::getBody, ForInLoop::setBody, EMPTY_DEFAULT); - leaveScope(scope); + leaveScope(node, scope); } public void visit(ForLoop node) { @@ -311,14 +311,14 @@ public class AstVisitor { visitProperty(node, ForLoop::getCondition, ForLoop::setCondition, EMPTY_EXPR_DEFAULT); visitProperty(node, ForLoop::getIncrement, ForLoop::setIncrement, EMPTY_EXPR_DEFAULT); visitProperty(node, ForLoop::getBody, ForLoop::setBody, EMPTY_DEFAULT); - leaveScope(scope); + leaveScope(node, scope); } public void visit(WhileLoop node) { var scope = enterScope(node); visitProperty(node, WhileLoop::getCondition, WhileLoop::setCondition, NULL_DEFAULT); visitProperty(node, WhileLoop::getBody, WhileLoop::setBody, EMPTY_DEFAULT); - leaveScope(scope); + leaveScope(node, scope); } public void visit(IfStatement node) { @@ -397,7 +397,7 @@ public class AstVisitor { } visitProperty(node, ArrayComprehension::getFilter, ArrayComprehension::setFilter); visitProperty(node, ArrayComprehension::getResult, ArrayComprehension::setResult); - leaveScope(scope); + leaveScope(node, scope); } public void visit(GeneratorExpression node) { @@ -409,7 +409,7 @@ public class AstVisitor { } visitProperty(node, GeneratorExpression::getFilter, GeneratorExpression::setFilter); visitProperty(node, GeneratorExpression::getResult, GeneratorExpression::setResult); - leaveScope(scope); + leaveScope(node, scope); } public void visit(NumberLiteral node) { @@ -452,14 +452,14 @@ public class AstVisitor { visitProperty(node, FunctionNode::getFunctionName, FunctionNode::setFunctionName); visitMany(node.getParams()); visitChildren(node.getBody()); - leaveScope(scope); + leaveScope(node, scope); } public void visit(LetNode node) { var scope = enterScope(node); visitProperty(node, LetNode::getVariables, LetNode::setVariables); visitProperty(node, LetNode::getBody, LetNode::setBody); - leaveScope(scope); + leaveScope(node, scope); } public void visit(ParenthesizedExpression node) { @@ -492,6 +492,7 @@ public class AstVisitor { private Map enterScope(Scope scope) { + onEnterScope(scope); if (scope.getSymbolTable() == null) { return Collections.emptyMap(); } @@ -503,7 +504,11 @@ public class AstVisitor { return map; } - private void leaveScope(Map backup) { + protected void onEnterScope(Scope scope) { + } + + private void leaveScope(Scope scope, Map backup) { + onLeaveScope(scope); for (var entry : backup.entrySet()) { if (entry.getValue() == null) { currentScopes.remove(entry.getKey()); @@ -513,6 +518,9 @@ public class AstVisitor { } } + protected void onLeaveScope(Scope scope) { + } + protected Scope scopeOfId(String id) { return currentScopes.get(id); } diff --git a/core/src/main/java/org/teavm/backend/javascript/templating/RemovablePartsFinder.java b/core/src/main/java/org/teavm/backend/javascript/templating/RemovablePartsFinder.java index 9b442f8ba..c6f06b4d7 100644 --- a/core/src/main/java/org/teavm/backend/javascript/templating/RemovablePartsFinder.java +++ b/core/src/main/java/org/teavm/backend/javascript/templating/RemovablePartsFinder.java @@ -34,7 +34,7 @@ import org.teavm.backend.javascript.ast.AstVisitor; public class RemovablePartsFinder extends AstVisitor { private Map> removableDeclarations = new HashMap<>(); - private Map removableDeclarationScopes = new HashMap<>(); + private Set removableDeclarationScopes = new HashSet<>(); private Map> dependencies = new HashMap<>(); private String insideDeclaration; private boolean topLevel = true; @@ -44,7 +44,6 @@ public class RemovablePartsFinder extends AstVisitor { if (topLevel) { if (node.getName() != null && !node.getName().isEmpty()) { removableDeclarations.computeIfAbsent(node.getName(), k -> new ArrayList<>()).add(node); - removableDeclarationScopes.put(node.getName(), scopeOfId(node.getName())); } topLevel = false; insideDeclaration = node.getName(); @@ -64,7 +63,6 @@ public class RemovablePartsFinder extends AstVisitor { if (name != null) { removableDeclarations.computeIfAbsent(name.getIdentifier(), k -> new ArrayList<>()) .add(initializer); - removableDeclarationScopes.put(name.getIdentifier(), scopeOfId(name.getIdentifier())); if (initializer.getInitializer() != null) { topLevel = false; insideDeclaration = name.getIdentifier(); @@ -86,7 +84,6 @@ public class RemovablePartsFinder extends AstVisitor { var name = extractName(assign.getLeft()); removableDeclarations.computeIfAbsent(name.getIdentifier(), k -> new ArrayList<>()) .add(node.getExpression()); - removableDeclarationScopes.put(name.getIdentifier(), scopeOfId(name.getIdentifier())); if (name != null) { topLevel = false; insideDeclaration = name.getIdentifier(); @@ -106,9 +103,11 @@ public class RemovablePartsFinder extends AstVisitor { @Override public void visit(Name node) { - if (scopeOfId(node.getIdentifier()) == removableDeclarationScopes.get(node.getIdentifier()) - && insideDeclaration != null) { - dependencies.computeIfAbsent(insideDeclaration, k -> new HashSet<>()).add(node.getIdentifier()); + if (insideDeclaration != null) { + var actualScope = scopeOfId(node.getIdentifier()); + if (actualScope == null || removableDeclarationScopes.contains(actualScope)) { + dependencies.computeIfAbsent(insideDeclaration, k -> new HashSet<>()).add(node.getIdentifier()); + } } } @@ -141,4 +140,18 @@ public class RemovablePartsFinder extends AstVisitor { } return nodes; } + + @Override + protected void onEnterScope(Scope scope) { + if (topLevel) { + removableDeclarationScopes.add(scope); + } + } + + @Override + protected void onLeaveScope(Scope scope) { + if (topLevel) { + removableDeclarationScopes.remove(scope); + } + } }