From 98490e92f6d41de9792ce1ac28d33c0f3c5319de Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 19 May 2022 11:14:15 +0300 Subject: [PATCH] JS: fix strict mode null pointer check with inlining --- .../teavm/backend/javascript/JavaScriptTarget.java | 8 +++++++- .../model/optimization/DefaultInliningStrategy.java | 9 ++++++--- .../optimization/UnusedVariableElimination.java | 12 ------------ .../model/optimization/VariableEscapeAnalyzer.java | 13 +++++++++++++ core/src/main/java/org/teavm/vm/TeaVM.java | 9 +++++++++ core/src/main/java/org/teavm/vm/TeaVMTarget.java | 3 +++ 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index 624739067..e57d0de6b 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -339,11 +339,17 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { } } + @Override + public void beforeInlining(Program program, MethodReader method) { + if (strict) { + nullCheckInsertion.transformProgram(program, method.getReference()); + } + } + @Override public void beforeOptimizations(Program program, MethodReader method) { if (strict) { boundCheckInsertion.transformProgram(program, method.getReference()); - nullCheckInsertion.transformProgram(program, method.getReference()); } } diff --git a/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java b/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java index 6106a4abb..b93924f60 100644 --- a/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java +++ b/core/src/main/java/org/teavm/model/optimization/DefaultInliningStrategy.java @@ -31,6 +31,7 @@ public class DefaultInliningStrategy implements InliningStrategy { private final int depthThreshold; private final int totalComplexityThreshold; private final boolean onceUsedOnly; + private int getComplexityDepth; public DefaultInliningStrategy(int complexityThreshold, int depthThreshold, int totalComplexityThreshold, boolean onceUsedOnly) { @@ -52,7 +53,7 @@ public class DefaultInliningStrategy implements InliningStrategy { return new InliningStepImpl(complexityHolder); } - private static Complexity getComplexity(ProgramReader program, InliningContext context) { + private Complexity getComplexity(ProgramReader program, InliningContext context) { int complexity = 0; ComplexityCounter counter = new ComplexityCounter(context); for (int i = 0; i < program.basicBlockCount(); ++i) { @@ -101,7 +102,7 @@ public class DefaultInliningStrategy implements InliningStrategy { int complexity; } - static class ComplexityCounter extends AbstractInstructionReader { + class ComplexityCounter extends AbstractInstructionReader { InliningContext context; int complexity; boolean callsToUsedOnceMethods; @@ -132,10 +133,12 @@ public class DefaultInliningStrategy implements InliningStrategy { } private boolean isTrivialCall(ProgramReader program) { - if (program == null) { + if (program == null || getComplexityDepth > 10) { return false; } + getComplexityDepth++; Complexity complexity = getComplexity(program, context); + getComplexityDepth--; return complexity.score <= 1 && !complexity.callsToUsedOnceMethods; } diff --git a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java index b6dee5abd..35dac629a 100644 --- a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java @@ -27,7 +27,6 @@ import org.teavm.model.instructions.AbstractInstructionVisitor; import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.BinaryInstruction; -import org.teavm.model.instructions.BoundCheckInstruction; import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastIntegerInstruction; import org.teavm.model.instructions.CastNumberInstruction; @@ -45,7 +44,6 @@ import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.IsInstanceInstruction; import org.teavm.model.instructions.LongConstantInstruction; import org.teavm.model.instructions.NegateInstruction; -import org.teavm.model.instructions.NullCheckInstruction; import org.teavm.model.instructions.NullConstantInstruction; import org.teavm.model.instructions.StringConstantInstruction; import org.teavm.model.instructions.UnwrapArrayInstruction; @@ -256,15 +254,5 @@ public class UnusedVariableElimination implements MethodOptimization { public void visit(IsInstanceInstruction insn) { requestUsage(insn.getReceiver()); } - - @Override - public void visit(NullCheckInstruction insn) { - requestUsage(insn.getReceiver()); - } - - @Override - public void visit(BoundCheckInstruction insn) { - requestUsage(insn.getReceiver()); - } } } diff --git a/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java b/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java index 8da1fcf91..928628f4e 100644 --- a/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java +++ b/core/src/main/java/org/teavm/model/optimization/VariableEscapeAnalyzer.java @@ -119,6 +119,19 @@ public final class VariableEscapeAnalyzer { if (insn.getArray() != null) { escaping[insn.getArray().getIndex()] = true; } + if (insn.getReceiver() != null) { + escaping[insn.getReceiver().getIndex()] = true; + } + } + + @Override + public void visit(NullCheckInstruction insn) { + if (insn.getValue() != null) { + escaping[insn.getValue().getIndex()] = true; + } + if (insn.getReceiver() != null) { + escaping[insn.getReceiver().getIndex()] = true; + } } } } diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index fef5d87de..c84a09336 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -467,6 +467,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository { target.setController(targetController); + for (String className : classSet.getClassNames()) { + ClassHolder cls = classSet.get(className); + for (MethodHolder method : cls.getMethods()) { + if (method.getProgram() != null) { + target.beforeInlining(method.getProgram(), method); + } + } + } inline(classSet); if (wasCancelled()) { return null; @@ -979,6 +987,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { missingItemsProcessor.processMethod(method.getReference(), program); linker.link(method, program); clinitInsertion.apply(method, program); + target.beforeInlining(program, method); program = optimizeMethodCacheMiss(method, program); Program finalProgram = program; programCache.store(method.getReference(), finalProgram, diff --git a/core/src/main/java/org/teavm/vm/TeaVMTarget.java b/core/src/main/java/org/teavm/vm/TeaVMTarget.java index 2ba7cc46c..2271cbb53 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMTarget.java +++ b/core/src/main/java/org/teavm/vm/TeaVMTarget.java @@ -40,6 +40,9 @@ public interface TeaVMTarget { void contributeDependencies(DependencyAnalyzer dependencyAnalyzer); + default void beforeInlining(Program program, MethodReader method) { + } + default void analyzeBeforeOptimizations(ListableClassReaderSource classSource) { }