From 621efcd976db6f860f576df8d927900523d165a0 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Wed, 10 Sep 2014 13:08:58 +0200 Subject: [PATCH] 8034954: Optimistic iteration in for-in and for-each Reviewed-by: hannesw, lagergren --- .../internal/codegen/CodeGenerator.java | 15 ++++++++--- .../nashorn/internal/codegen/Compiler.java | 15 +++++++++++ .../codegen/LocalVariableTypesCalculator.java | 25 +++++++++++++------ .../internal/codegen/TypeEvaluator.java | 13 ++++++++++ 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java index cfdb64bd1db..97b26212a46 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -1622,9 +1622,18 @@ final class CodeGenerator extends NodeOperatorVisitor{ final Expression init = forNode.getInit(); if(forNode.isForIn()) { - forNode.getModify().accept(this); - enterTestFirstLoop(forNode, null, init); + final JoinPredecessorExpression iterable = forNode.getModify(); + iterable.accept(this); + enterTestFirstLoop(forNode, null, init, + // If we're iterating over property names, and we can discern from the runtime environment + // of the compilation that the object being iterated over must use strings for property + // names (e.g., it is a native JS object or array), then we'll not bother trying to treat + // the property names optimistically. + !forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression())); } else { if(init != null) { init.accept(this); } - enterTestFirstLoop(forNode, forNode.getModify(), null); + enterTestFirstLoop(forNode, forNode.getModify(), null, false); } return false; } @@ -792,7 +798,8 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return false; } - private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify, final Expression iteratorValues) { + private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify, + final Expression iteratorValues, final boolean iteratorValuesAreObject) { final JoinPredecessorExpression test = loopNode.getTest(); if(isAlwaysFalse(test)) { test.accept(this); @@ -814,8 +821,12 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ jumpToLabel(test, breakLabel); } if(iteratorValues instanceof IdentNode) { - // Receives iterator values; they're currently all objects (JDK-8034954). - onAssignment((IdentNode)iteratorValues, LvarType.OBJECT); + final IdentNode ident = (IdentNode)iteratorValues; + // Receives iterator values; the optimistic type of the iterator values is tracked on the + // identifier, but we override optimism if it's known that the object being iterated over will + // never have primitive property names. + onAssignment(ident, iteratorValuesAreObject ? LvarType.OBJECT : + toLvarType(compiler.getOptimisticType(ident))); } final Block body = loopNode.getBody(); body.accept(this); @@ -955,7 +966,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ if(whileNode.isDoWhile()) { enterDoWhileLoop(whileNode); } else { - enterTestFirstLoop(whileNode, null, null); + enterTestFirstLoop(whileNode, null, null, false); } return false; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java index ea58d0a9d17..11a23ecd3a1 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java @@ -55,6 +55,19 @@ final class TypeEvaluator { this.runtimeScope = runtimeScope; } + /** + * Returns true if the expression can be safely evaluated, and its value is an object known to always use + * String as the type of its property names retrieved through + * {@link ScriptRuntime#toPropertyIterator(Object)}. It is used to avoid optimistic assumptions about its + * property name types. + * @param expr the expression to test + * @return true if the expression can be safely evaluated, and its value is an object known to always use + * String as the type of its property iterators. + */ + boolean hasStringPropertyIterator(final Expression expr) { + return evaluateSafely(expr) instanceof ScriptObject; + } + Type getOptimisticType(final Optimistic node) { assert compiler.useOptimisticTypes();