aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlana <none@none>2013-06-03 23:24:36 -0700
committerlana <none@none>2013-06-03 23:24:36 -0700
commit4cfe9dbcf3012777d6d2d4fb98d58828ce208b32 (patch)
tree359f9c42b935e470e2b4fe094076266033ad1efd
parenta625eb3c1836a6d65e7256f5a9fc03babb30700e (diff)
parentc8946732936082e4f6dbd7517625397b8954f461 (diff)
downloadnashorn-jdk8-b93.tar.gz
-rw-r--r--.hgignore1
-rw-r--r--docs/JavaScriptingProgrammersGuide.html240
-rw-r--r--docs/source/javaarray.js4
-rw-r--r--make/build-benchmark.xml104
-rw-r--r--make/build.xml6
-rw-r--r--make/code_coverage.xml26
-rw-r--r--make/project.properties7
-rw-r--r--src/jdk/nashorn/api/scripting/JSObject.java (renamed from src/netscape/javascript/JSObject.java)18
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptObjectMirror.java1
-rw-r--r--src/jdk/nashorn/api/scripting/resources/engine.js2
-rw-r--r--src/jdk/nashorn/internal/codegen/Attr.java116
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java480
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java235
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilationPhase.java107
-rw-r--r--src/jdk/nashorn/internal/codegen/Compiler.java7
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilerConstants.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/FinalizeTypes.java38
-rw-r--r--src/jdk/nashorn/internal/codegen/FoldConstants.java19
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java81
-rw-r--r--src/jdk/nashorn/internal/codegen/MethodEmitter.java9
-rw-r--r--src/jdk/nashorn/internal/codegen/RangeAnalyzer.java476
-rw-r--r--src/jdk/nashorn/internal/codegen/SharedScopeCall.java5
-rw-r--r--src/jdk/nashorn/internal/codegen/Splitter.java25
-rw-r--r--src/jdk/nashorn/internal/codegen/WeighNodes.java6
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Range.java705
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Type.java12
-rw-r--r--src/jdk/nashorn/internal/ir/AccessNode.java3
-rw-r--r--src/jdk/nashorn/internal/ir/BinaryNode.java19
-rw-r--r--src/jdk/nashorn/internal/ir/Block.java2
-rw-r--r--src/jdk/nashorn/internal/ir/BreakNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/CallNode.java3
-rw-r--r--src/jdk/nashorn/internal/ir/CaseNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/CatchNode.java32
-rw-r--r--src/jdk/nashorn/internal/ir/ContinueNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/EmptyNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/ExecuteNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/ForNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/FunctionNode.java42
-rw-r--r--src/jdk/nashorn/internal/ir/IdentNode.java3
-rw-r--r--src/jdk/nashorn/internal/ir/IfNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/IndexNode.java22
-rw-r--r--src/jdk/nashorn/internal/ir/LabelNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java20
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContextNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/LiteralNode.java7
-rw-r--r--src/jdk/nashorn/internal/ir/Node.java13
-rw-r--r--src/jdk/nashorn/internal/ir/ObjectNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/PropertyNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/ReturnNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/RuntimeNode.java3
-rw-r--r--src/jdk/nashorn/internal/ir/SplitNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/SwitchNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/Symbol.java33
-rw-r--r--src/jdk/nashorn/internal/ir/TernaryNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/ThrowNode.java26
-rw-r--r--src/jdk/nashorn/internal/ir/TryNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/UnaryNode.java3
-rw-r--r--src/jdk/nashorn/internal/ir/VarNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/WhileNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/WithNode.java2
-rw-r--r--src/jdk/nashorn/internal/ir/debug/JSONWriter.java9
-rw-r--r--src/jdk/nashorn/internal/ir/debug/PrintVisitor.java4
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java12
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java17
-rw-r--r--src/jdk/nashorn/internal/objects/ArrayBufferView.java5
-rw-r--r--src/jdk/nashorn/internal/objects/DateParser.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArguments.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java43
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDate.java2
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFloat32Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFloat64Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt16Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt32Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt8Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJava.java62
-rw-r--r--src/jdk/nashorn/internal/objects/NativeMath.java10
-rw-r--r--src/jdk/nashorn/internal/objects/NativeString.java20
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint16Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint32Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint8Array.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java9
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java4
-rw-r--r--src/jdk/nashorn/internal/parser/TokenType.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/AccessorProperty.java116
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunction.java32
-rw-r--r--src/jdk/nashorn/internal/runtime/DebugLogger.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/FindProperty.java19
-rw-r--r--src/jdk/nashorn/internal/runtime/GlobalFunctions.java5
-rw-r--r--src/jdk/nashorn/internal/runtime/JSONFunctions.java25
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java17
-rw-r--r--src/jdk/nashorn/internal/runtime/ListAdapter.java337
-rw-r--r--src/jdk/nashorn/internal/runtime/Logging.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/NativeJavaPackage.java37
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java24
-rw-r--r--src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java234
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptEnvironment.java21
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunctionData.java14
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java124
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptRuntime.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptingFunctions.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/SetMethodCreator.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/UserAccessorProperty.java76
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/InvokeByName.java14
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java32
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/options/Option.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/options/OptionTemplate.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/options/Options.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java (renamed from src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java)4
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java837
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java408
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java109
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java267
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java8
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java7
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java263
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java237
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java74
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Config.java17
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java14
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java376
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java18
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java97
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java27
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java195
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java139
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Region.java19
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java104
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java69
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java40
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/CTypeNode.java50
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/CallNode.java86
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java38
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java44
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java65
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java49
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchGreedyBacktrack.java7
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchRailsRegs.java31
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchSeveralRegexps.java17
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java235
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/constants/Reduce.java61
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java157
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/encoding/ObjPtr.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/encoding/PosixBracket.java77
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/encoding/Ptr.java35
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java29
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Messages.properties1
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Options.properties15
-rw-r--r--test/script/basic/JDK-8008554.js2
-rw-r--r--test/script/basic/JDK-8010804.js86
-rw-r--r--test/script/basic/JDK-8010804.js.EXPECTED42
-rw-r--r--test/script/basic/JDK-8011023.js34
-rw-r--r--test/script/basic/JDK-8011023.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8011718.js46
-rw-r--r--test/script/basic/JDK-8011718.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8012083.js70
-rw-r--r--test/script/basic/JDK-8012083.js.EXPECTED19
-rw-r--r--test/script/basic/JDK-8012305.js39
-rw-r--r--test/script/basic/JDK-8012305.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8013919.js39
-rw-r--r--test/script/basic/JDK-8013919.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8014426.js49
-rw-r--r--test/script/basic/JDK-8014426.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8014647.js40
-rw-r--r--test/script/basic/JDK-8014647.js.EXPECTED5
-rw-r--r--test/script/basic/JDK-8014735.js43
-rw-r--r--test/script/basic/JDK-8014735.js.EXPECTED9
-rw-r--r--test/script/basic/JDK-8014953.js45
-rw-r--r--test/script/basic/JDK-8014953.js.EXPECTED6
-rw-r--r--test/script/basic/JDK-8015267.js109
-rw-r--r--test/script/basic/JDK-8015267.js.EXPECTED40
-rw-r--r--test/script/basic/JDK-8015348.js35
-rw-r--r--test/script/basic/JDK-8015348.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8015349.js43
-rw-r--r--test/script/basic/JDK-8015349.js.EXPECTED9
-rw-r--r--test/script/basic/JDK-8015352.js46
-rw-r--r--test/script/basic/JDK-8015354.js46
-rw-r--r--test/script/basic/NASHORN-377.js4
-rw-r--r--test/script/basic/NASHORN-556.js24
-rw-r--r--test/script/basic/allgettersetters.js3
-rw-r--r--test/script/basic/compile-octane.js.EXPECTED52
-rw-r--r--test/script/basic/javaarrayconversion.js16
-rw-r--r--test/script/basic/ranges_disabled.js32
-rw-r--r--test/script/basic/ranges_disabled.js.EXPECTED4
-rw-r--r--test/script/basic/ranges_enabled.js33
-rw-r--r--test/script/basic/ranges_enabled.js.EXPECTED4
-rw-r--r--test/script/basic/ranges_payload.js74
-rw-r--r--test/script/basic/run-octane.js216
-rw-r--r--test/script/currently-failing/logcoverage.js3
-rw-r--r--test/script/trusted/NASHORN-638.js3
-rw-r--r--test/script/trusted/NASHORN-653.js3
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java1
-rw-r--r--test/src/jdk/nashorn/internal/runtime/regexp/JdkRegExpTest.java61
-rw-r--r--test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java (renamed from src/jdk/nashorn/internal/runtime/options/ValueOption.java)47
206 files changed, 5185 insertions, 5164 deletions
diff --git a/.hgignore b/.hgignore
index 56e01bae..6d68c1d4 100644
--- a/.hgignore
+++ b/.hgignore
@@ -24,3 +24,4 @@ jcov2/*
.idea/*
test/lib/testng.jar
test/script/external/*
+.project
diff --git a/docs/JavaScriptingProgrammersGuide.html b/docs/JavaScriptingProgrammersGuide.html
index 811b29c9..a9803f7f 100644
--- a/docs/JavaScriptingProgrammersGuide.html
+++ b/docs/JavaScriptingProgrammersGuide.html
@@ -71,9 +71,20 @@ Classes</a></span></li>
Arrays</a></span></li>
<li><span><a href="#jsimplement">Implementing Java
Interfaces</a></span></li>
-<li><span><a href="#jsextend">Extending Java classes
+<li><span><a href="#jsextendabstract">Extending Abstract Java Classes
+</a></span></li>
+<li><span><a href="#jsextendconcrete">Extending Concrete Java Classes
+</a></span></li>
+<li><span><a href="#jsimplementmultiple">Implementing Multiple Java Interfaces
+</a></span></li>
+<li><span><a href="#classBoundImplementations">Class-Bound Implementations
</a></span></li>
<li><span><a href="#jsoverload">Overload Resolution</a></span></li>
+<li><span><a href="#dataTypeMapping">Mapping of Data Types Between Java
+and JavaScript</a></span></li>
+
+
+
</ul>
</li>
<li><span><a href="#engineimpl">Implementing Your Own Script
@@ -466,10 +477,10 @@ language rather than JavaScript.</p>
</code>
</pre>
-Note that the name of the type is always a string for a fully qualified name. You can use any of these types to create new instances, e.g.:
+Note that the name of the type is always a string for a fully qualified name. You can use any of these expressions to create new instances, e.g.:
<pre><code>
- var anArrayList = new Java.type("java.util.ArrayList")
+ var anArrayList = new (Java.type("java.util.ArrayList"))
</code></pre>
or
@@ -496,6 +507,37 @@ However, once you retrieved the outer class, you can access the inner class as a
<p>
You can access both static and non-static inner classes. If you want to create an instance of a non-static inner class, remember to pass an instance of its outer class as the first argument to the constructor.
</p>
+<p>
+In addition to creating new instances, the type objects returned from <code>Java.type</code> calls can also be used to access the
+static fields and methods of the classes:
+<pre><code>
+ var File = Java.type("java.io.File")
+ File.createTempFile("nashorn", ".tmp")
+</code></pre>
+<p>
+Methods with names of the form <code>isXxx()</code>, <code>getXxx()</code>, and <code>setXxx()</code> can also be used as properties, for both instances and statics.
+</p>
+<p>
+A type object returned from <code>Java.type</code> is distinct from a <code>java.lang.Class</code> object. You can obtain one from the other using properties <code>class</code> and <code>static</code> on them.
+<pre><code>
+ var ArrayList = Java.type("java.util.ArrayList")
+ var a = new ArrayList
+
+ // All of the following print true:
+ print("Type acts as target of instanceof: " + (a instanceof ArrayList))
+ print("Class doesn't act as target of instanceof: " + !(a instanceof a.getClass()))
+ print("Type is not same as instance's getClass(): " + (a.getClass() !== ArrayList))
+ print("Type's `class` property is same as instance getClass(): " + (a.getClass() === ArrayList.class))
+ print("Type is same as instance getClass()'s `static` property: " + (a.getClass().static === ArrayList))
+</code></pre>
+<p>
+You can think of the type object as similar to the class names as used in Java source code: you use them as the
+arguments to the <code>new</code> and <code>instanceof</code> operators and as the namespace for the static fields
+and methods, but they are different than the runtime <code>Class</code> objects returned by <code>getClass()</code> calls.
+Syntactically and semantically, this separation produces code that is most similar to Java code, where a distinction
+between compile-time class expressions and runtime class objects also exists. (Also, Java can't have the equivalent of <code>static</code>
+property on a <code>Class</code> object since compile-time class expressions are never reified as objects).
+</p>
<hr>
<a name="jsimport" id="jsimport"></a>
<h3>Importing Java Packages, Classes</h3>
@@ -558,10 +600,7 @@ with (SwingGui) {
<a name="jsarrays" id="jsarrays"></a>
<h3>Creating, Converting and Using Java Arrays</h3>
<p>
-Array element access or length access is
-the same as in Java. Also, a script array can be used when a Java
-method expects a Java array (auto conversion). So in most cases we
-don't have to create Java arrays explicitly.</p>
+Array element access or length access is the same as in Java.</p>
<pre><code>
// <a href="source/javaarray.js">javaarray.js</a>
@@ -577,27 +616,31 @@ print(a[0]);
</pre>
<p>
It is also possible to convert between JavaScript and Java arrays.
-Given a JavaScript array and a Java type, <code>Java.toJavaArray</code> returns a Java array with the same initial contents, and with the specified component type.
+Given a JavaScript array and a Java type, <code>Java.to</code> returns a Java array with the same initial contents, and with the specified array type.
</p>
<pre><code>
var anArray = [1, "13", false]
- var javaIntArray = Java.toJavaArray(anArray, "int")
+ var javaIntArray = Java.to(anArray, "int[]")
print(javaIntArray[0]) // prints 1
print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
</code></pre>
<p>
-Given a Java array or Collection, <code>Java.toJavaScriptArray</code> returns a JavaScript array with a shallow copy of its contents. Note that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will want to use this method.i
+You can use either a string or a type object returned from <code>Java.type()</code> to specify the type of the array.
+You can also omit the array type, in which case a <code>Object[]</code> will be created.
+</p>
+<p>
+Given a Java array or Collection, <code>Java.from</code> returns a JavaScript array with a shallow copy of its contents. Note that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will want to use this method.
</p>
<pre><code>
var File = Java.type("java.io.File");
var listCurDir = new File(".").listFiles();
-var jsList = Java.toJavaScriptArray(listCurDir);
+var jsList = Java.from(listCurDir);
print(jsList);
</code></pre>
<hr>
<a name="jsimplement" id="jsimplement"></a>
-<h3>Implementing Java Interfaces</h3>
+<h3>Implementing Java interfaces</h3>
<p>A Java interface can be implemented in JavaScript by using a
Java anonymous class-like syntax:</p>
<pre><code>
@@ -631,8 +674,8 @@ th.join();
</code>
</pre>
<hr>
-<a name="jsextend" id="jsextend"></a>
-<h3>Extending Java classes</h3>
+<a name="jsextendabstract" id="jsextendabstract"></a>
+<h3>Extending Abstract Java Classes</h3>
<p>
If a Java class is abstract, you can instantiate an anonymous subclass of it using an argument list that is applicable to any of its public or protected constructors, but inserting a JavaScript object with functions properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the JavaScript function will provide implementation for all overloads. E.g.:
</p>
@@ -671,6 +714,9 @@ The use of functions can be taken even further; if you are invoking a Java metho
Here, <code>Timer.schedule()</code> expects a <code>TimerTask</code> as its argument, so Nashorn creates an instance of a TimerTask subclass and uses the passed function to implement its only abstract method, run(). In this usage though, you can't use non-default constructors; the type must be either an interface, or must have a protected or public no-arg constructor.
+<hr>
+<a name="jsextendconcrete" id="jsextendconcrete"></a>
+<h3>Extending Concrete Java Classes</h3>
<p>
To extend a concrete Java class, you have to use <code>Java.extend</code> function.
<code>Java.extend</code> returns a type object for a subclass of the specified Java class (or implementation of the specified interface) that acts as a script-to-Java adapter for it.
@@ -695,26 +741,178 @@ var printAddInvokedArrayList = new ArrayListExtender() {
printSizeInvokedArrayList.size();
printAddInvokedArrayList.add(33, 33);
</code></pre>
+<p>
+The reason you must use <code>Java.extend()</code> with concrete classes is that with concrete classes, there can be a
+syntactic ambiguity if you just invoke their constructor. Consider this example:
+</p>
+<pre><code>
+var t = new java.lang.Thread({ run: function() { print("Hello!") } })
+</code></pre>
+<p>
+If we allowed subclassing of concrete classes with constructor syntax, Nashorn couldn't tell if you're creating a new
+<code>Thread</code> and passing it a <code>Runnable</code> at this point, or you are subclassing <code>Thread</code> and
+passing it a new implementation for its own <code>run()</code> method.
+</p>
+<hr>
+<a name="jsimplementmultiple" id="jsimplementmultiple"></a>
+<h3>Implementing Multiple Interfaces</h3>
+<p>
+<code>Java.extend</code> can in fact take a list of multiple types. At most one of the types can be a class, and the rest must
+be interfaces (the class doesn't have to be the first in the list). You will get back an object that extends the class and
+implements all the interfaces. (Obviously, if you only specify interfaces and no class, the object will extend <code>java.lang.Object</code>).
+<hr>
+<a name="classBoundImplementations" id="classBoundImplementations"></a>
+<h3>Class-Bound Implementations</h3>
+<p>
+The methods shown so far for extending Java classes and implementing interfaces &ndash; passing an implementation JavaScript object
+or function to a constructor, or using <code>Java.extend</code> with <code>new</code> &ndash; all produce classes that take an
+extra JavaScript object parameter in their constructors that specifies the implementation. The implementation is therefore always bound
+to the actual instance being created with <code>new</code>, and not to the whole class. This has some advantages, for example in the
+memory footprint of the runtime, as Nashorn can just create a single "universal adapter" for every combination of types being implemented.
+In reality, the below code shows that different instantiations of, say, <code>Runnable</code> have the same class regardless of them having
+different JavaScript implementation objects:
+</p>
+<pre><code>
+var Runnable = java.lang.Runnable;
+var r1 = new Runnable(function() { print("I'm runnable 1!") })
+var r2 = new Runnable(function() { print("I'm runnable 2!") })
+r1.run()
+r2.run()
+print("We share the same class: " + (r1.class === r2.class))
+</code></pre>
+<p>
+prints:
+</p>
+<pre><code>
+I'm runnable 1!
+I'm runnable 2!
+We share the same class: true
+</code></pre>
+<p>
+Sometimes, however, you'll want to extend a Java class or implement an interface with implementation bound to the class, not to
+its instances. Such a need arises, for example, when you need to pass the class for instantiation to an external API; prime example
+of this is the JavaFX framework where you need to pass an Application class to the FX API and let it instantiate it.
+</p>
+<p>
+Fortunately, there's a solution for that: <code>Java.extend()</code> &ndash; aside from being able to take any number of type parameters
+denoting a class to extend and interfaces to implement &ndash; can also take one last argument that has to be a JavaScript object
+that serves as the implementation for the methods. In this case, <code>Java.extend()</code> will create a class that has the same
+constructors as the original class had, as they don't need to take an an extra implementation object parameter. The example below
+shows how you can create class-bound implementations, and shows that in this case, the implementation classes for different invocations
+are indeed different:
+</p>
+<pre><code>
+var RunnableImpl1 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") })
+var RunnableImpl2 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 2!") })
+var r1 = new RunnableImpl1()
+var r2 = new RunnableImpl2()
+r1.run()
+r2.run()
+print("We share the same class: " + (r1.class === r2.class))
+</code></pre>
+<p>
+prints:
+</p>
+<pre><code>
+I'm runnable 1!
+I'm runnable 2!
+We share the same class: false
+</code></pre>
+<p>
+As you can see, the major difference here is that we moved the implementation object into the invocation of <code>Java.extend</code>
+from the constructor invocations &ndash; indeed the constructor invocations now don't even need to take an extra parameter! Since
+the implementations are bound to a class, the two classes obviously can't be the same, and we indeed see that the two runnables no
+longer share the same class &ndash; every invocation of <code>Java.extend()</code> with a class-specific implementation object triggers
+the creation of a new Java adapter class.
+</p>
+<p>
+Finally, the adapter classes with class-bound implementations can <i>still</i> take an additional constructor parameter to further
+override the behavior on a per-instance basis. Thus, you can even combine the two approaches: you can provide part of the implementation
+in a class-based JavaScript implementation object passed to <code>Java.extend</code>, and part in another object passed to the constructor.
+Whatever functions are provided by the constructor-passed object will override the functions in the class-bound object.
+</p>
+<pre><code>
+var RunnableImpl = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") })
+var r1 = new RunnableImpl()
+var r2 = new RunnableImpl(function() { print("I'm runnable 2!") })
+r1.run()
+r2.run()
+print("We share the same class: " + (r1.class === r2.class))
+</code></pre>
+<p>
+prints:
+</p>
+<pre><code>
+I'm runnable 1!
+I'm runnable 2!
+We share the same class: true
+</code></pre>
<hr>
<a name="jsoverload" id="jsoverload"></a>
<h3>Overload Resolution</h3>
<p>Java methods can be overloaded by argument types. In Java,
overload resolution occurs at compile time (performed by javac).
-When calling Java methods from a script, the script
-interpreter/compiler needs to select the appropriate method. With
-the JavaScript engine, you do not need to do anything special - the
-correct Java method overload variant is selected based on the
-argument types. But, sometimes you may want (or have) to explicitly
-select a particular overload variant.</p>
+When calling Java methods from Nashorn, the appropriate method will be
+selected based on the argument types at invocation time. You do not need
+to do anything special &ndash; the correct Java method overload variant
+is selected based automatically. You still have the option of explicitly
+specifying a particular overload variant. Reasons for this include
+either running into a genuine ambiguity with actual argument types, or
+rarely reasons of performance &ndash; if you specify the actual overload
+then the engine doesn't have to perform resolution during invocation.
+Individual overloads of a Java methods are exposed as special properties
+with the name of the method followed with its signature in parentheses.
+You can invoke them like this:</p>
<pre><code>
// <a href="source/overload.js">overload.js</a>
var out = java.lang.System.out;
// select a particular print function
-out["println(java.lang.Object)"]("hello");
+out["println(Object)"]("hello");
</code>
</pre>
+<p>
+Note that you normally don't even have to use qualified class names in
+the signatures as long as the unqualified name of the type is sufficient
+for uniquely identifying the signature. In practice this means that only
+in the extremely unlikely case that two overloads only differ in
+parameter types that have identical unqualified names but come from
+different packages would you need to use the fully qualified name of the
+class.
+</p>
+<hr>
+<a name="dataTypeMapping" id="dataTypeMapping"></a>
+<h3>Mapping of Data Types Between Java and JavaScript</h3>
+<p>
+We have previously shown some of the data type mappings between Java and JavaScript.
+We saw that arrays need to be explicitly converted. We have also shown that JavaScript functions
+are automatically converted to SAM types when passed as parameters to Java methods. Most other
+conversions work as you would expect.
+</p>
+<p>
+Every JavaScript object is also a <code>java.util.Map</code> so APIs receiving maps will receive them directly.
+</p>
+<p>
+When numbers are passed to a Java API, they will be converted to the expected target numeric type, either boxed or
+primitive, but if the target type is less specific, say <code>Number</code> or <code>Object</code>, you can only
+count on them being a <code>Number</code>, and have to test specifically for whether it's a boxed <code>Double</code>,
+<code>Integer</code>, <code>Long</code>, etc. &ndash; it can be any of these due to internal optimizations. Also, you
+can pass any JavaScript value to a Java API expecting either a boxed or primitive number; the JavaScript specification's
+<code>ToNumber</code> conversion algorithm will be applied to the value.
+</p>
+<p>
+In a similar vein, if a Java method expects a <code>String</code> or a <code>Boolean</code>, the values will be
+converted using all conversions allowed by the JavaScript specification's <code>ToString</code> and <code>ToBoolean</code>
+conversions.
+</p>
+<p>
+Finally, a word of caution about strings. Due to internal performance optimizations of string operations, JavaScript strings are
+not always necessarily of type <code>java.lang.String</code>, but they will always be of type <code>java.lang.CharSequence</code>.
+If you pass them to a Java method that expects a <code>java.lang.String</code> parameter, then you will naturally receive a Java
+String, but if the signature of your method is more generic, i.e. it receives a <code>java.lang.Object</code> parameter, you can
+end up with an object of private engine implementation class that implements <code>CharSequence</code> but is not a Java String.
+</p>
<hr>
<a name="engineimpl" id="engineimpl"></a>
<h2>Implementing Your Own Script Engine</h2>
diff --git a/docs/source/javaarray.js b/docs/source/javaarray.js
index a02aa3ca..d0de9124 100644
--- a/docs/source/javaarray.js
+++ b/docs/source/javaarray.js
@@ -40,7 +40,7 @@ print(a[0]);
// convert a script array to Java array
var anArray = [1, "13", false];
-var javaIntArray = Java.toJavaArray(anArray, "int");
+var javaIntArray = Java.to(anArray, "int[]");
print(javaIntArray[0]);// prints 1
print(javaIntArray[1]); // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
print(javaIntArray[2]);// prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
@@ -48,5 +48,5 @@ print(javaIntArray[2]);// prints 0, as boolean false was converted to number 0 a
// convert a Java array to a JavaScript array
var File = Java.type("java.io.File");
var listCurDir = new File(".").listFiles();
-var jsList = Java.toJavaScriptArray(listCurDir);
+var jsList = Java.from(listCurDir);
print(jsList);
diff --git a/make/build-benchmark.xml b/make/build-benchmark.xml
index d28de93d..f1ce180a 100644
--- a/make/build-benchmark.xml
+++ b/make/build-benchmark.xml
@@ -24,258 +24,270 @@
<project name="nashorn-benchmarks" default="all" basedir="..">
<target name="octane-init" depends="jar">
- <fileset id="octane-set"
- dir="${octane-test-sys-prop.test.js.roots}"
- excludes="${octane-test-sys-prop.test.js.exclude.list}">
- <include name="*.js"/>
- </fileset>
- <pathconvert pathsep=" " property="octane-tests" refid="octane-set"/>
+ <property name="octane-tests" value="box2d code-load crypto deltablue earley-boyer gbemu navier-stokes pdfjs raytrace regexp richards splay"/>
+ </target>
+
+ <!-- ignore benchmarks where rhino crashes -->
+ <target name="octane-init-rhino" depends="jar">
+ <property name="octane-tests" value="box2d code-load crypto deltablue earley-boyer gbemu navier-stokes raytrace regexp richards splay"/>
</target>
<!-- box2d -->
<target name="octane-box2d" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/box2d.js"/>
+ <param name="octane-tests" value="box2d"/>
</antcall>
</target>
<target name="octane-box2d-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/box2d.js"/>
+ <param name="octane-tests" value="box2d"/>
</antcall>
</target>
<target name="octane-box2d-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/box2d.js"/>
+ <param name="octane-tests" value="box2d"/>
</antcall>
</target>
+
<!-- code-load -->
<target name="octane-code-load" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/code-load.js"/>
+ <param name="octane-tests" value="code-load"/>
</antcall>
</target>
<target name="octane-code-load-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/code-load.js"/>
+ <param name="octane-tests" value="code-load"/>
</antcall>
</target>
<target name="octane-code-load-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/code-load.js"/>
+ <param name="octane-tests" value="code-load"/>
</antcall>
</target>
+
<!-- crypto -->
<target name="octane-crypto" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/crypto.js"/>
+ <param name="octane-tests" value="crypto"/>
</antcall>
</target>
<target name="octane-crypto-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/crypto.js"/>
+ <param name="octane-tests" value="crypto"/>
</antcall>
</target>
<target name="octane-crypto-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/crypto.js"/>
+ <param name="octane-tests" value="crypto"/>
</antcall>
</target>
+
<!-- deltablue -->
<target name="octane-deltablue" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/deltablue.js"/>
+ <param name="octane-tests" value="deltablue"/>
</antcall>
</target>
<target name="octane-deltablue-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/deltablue.js"/>
+ <param name="octane-tests" value="deltablue"/>
</antcall>
</target>
<target name="octane-deltablue-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/deltablue.js"/>
+ <param name="octane-tests" value="deltablue"/>
</antcall>
</target>
+
<!-- earley-boyer -->
<target name="octane-earley-boyer" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/earley-boyer.js"/>
+ <param name="octane-tests" value="earley-boyer"/>
</antcall>
</target>
<target name="octane-earley-boyer-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/earley-boyer.js"/>
+ <param name="octane-tests" value="earley-boyer"/>
</antcall>
</target>
<target name="octane-earley-boyer-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/earley-boyer.js"/>
+ <param name="octane-tests" value="earley-boyer"/>
</antcall>
</target>
+
<!-- gbemu -->
<target name="octane-gbemu" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/gbemu.js"/>
+ <param name="octane-tests" value="gbemu"/>
</antcall>
</target>
<target name="octane-gbemu-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/gbemu.js"/>
+ <param name="octane-tests" value="gbemu"/>
</antcall>
</target>
<target name="octane-gbemu-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/gbemu.js"/>
+ <param name="octane-tests" value="gbemu"/>
</antcall>
</target>
+
<!-- mandreel -->
<target name="octane-mandreel" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/mandreel.js"/>
+ <param name="octane-tests" value="mandreel"/>
</antcall>
</target>
<target name="octane-mandreel-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/mandreel.js"/>
+ <param name="octane-tests" value="mandreel"/>
</antcall>
</target>
<target name="octane-mandreel-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/mandreel.js"/>
+ <param name="octane-tests" value="mandreel"/>
</antcall>
</target>
+
<!-- navier-stokes -->
<target name="octane-navier-stokes" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/navier-stokes.js"/>
+ <param name="octane-tests" value="navier-stokes"/>
</antcall>
</target>
<target name="octane-navier-stokes-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/navier-stokes.js"/>
+ <param name="octane-tests" value="navier-stokes"/>
</antcall>
</target>
<target name="octane-navier-stokes-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/navier-stokes.js"/>
+ <param name="octane-tests" value="navier-stokes"/>
</antcall>
</target>
+
<!-- pdfjs -->
<target name="octane-pdfjs" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/pdfjs.js"/>
+ <param name="octane-tests" value="pdfjs"/>
</antcall>
</target>
<target name="octane-pdfjs-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/pdfjs.js"/>
+ <param name="octane-tests" value="pdfjs"/>
</antcall>
</target>
<target name="octane-pdfjs-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/pdfjs.js"/>
+ <param name="octane-tests" value="pdfjs"/>
</antcall>
</target>
+
<!-- raytrace -->
<target name="octane-raytrace" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/raytrace.js"/>
+ <param name="octane-tests" value="raytrace"/>
</antcall>
</target>
<target name="octane-raytrace-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/raytrace.js"/>
+ <param name="octane-tests" value="raytrace"/>
</antcall>
</target>
<target name="octane-raytrace-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/raytrace.js"/>
+ <param name="octane-tests" value="raytrace"/>
</antcall>
</target>
+
<!-- regexp -->
<target name="octane-regexp" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/regexp.js"/>
+ <param name="octane-tests" value="regexp"/>
</antcall>
</target>
<target name="octane-regexp-octane-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/regexp.js"/>
+ <param name="octane-tests" value="regexp"/>
</antcall>
</target>
<target name="octane-regexp-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/regexp.js"/>
+ <param name="octane-tests" value="regexp"/>
</antcall>
</target>
+
<!-- richards -->
<target name="octane-richards" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/richards.js"/>
+ <param name="octane-tests" value="richards"/>
</antcall>
</target>
<target name="octane-richards-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/richards.js"/>
+ <param name="octane-tests" value="richards"/>
</antcall>
</target>
<target name="octane-richards-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/richards.js"/>
+ <param name="octane-tests" value="richards"/>
</antcall>
</target>
+
<!-- splay -->
<target name="octane-splay" depends="jar">
<antcall target="run-octane">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/splay.js"/>
+ <param name="octane-tests" value="splay"/>
</antcall>
</target>
<target name="octane-splay-v8" depends="jar">
<antcall target="run-octane-v8">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/splay.js"/>
+ <param name="octane-tests" value="splay"/>
</antcall>
</target>
<target name="octane-splay-rhino" depends="jar">
<antcall target="run-octane-rhino">
- <param name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/splay.js"/>
+ <param name="octane-tests" value="splay"/>
</antcall>
</target>
@@ -307,7 +319,7 @@
</target>
<!-- run octane benchmarks using Rhino as runtime -->
- <target name="octane-rhino" depends="octane-init">
+ <target name="octane-rhino" depends="octane-init-rhino">
<antcall target="run-octane-rhino"/>
</target>
diff --git a/make/build.xml b/make/build.xml
index d884b2fe..7c05e789 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -212,7 +212,9 @@
target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
- includeantruntime="false"/>
+ includeantruntime="false">
+ <compilerarg line="-extdirs &quot;&quot;"/>
+ </javac>
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
@@ -305,6 +307,8 @@
<include name="**/codegen/*Test.class"/>
<include name="**/parser/*Test.class"/>
<include name="**/runtime/*Test.class"/>
+ <include name="**/runtime/regexp/*Test.class"/>
+ <include name="**/runtime/regexp/joni/*Test.class"/>
<include name="**/framework/*Test.class"/>
</fileset>
diff --git a/make/code_coverage.xml b/make/code_coverage.xml
index 33980bdf..3e2860f8 100644
--- a/make/code_coverage.xml
+++ b/make/code_coverage.xml
@@ -139,6 +139,32 @@
<arg value="${cc.merged.xml}"/>
<arg value="-exclude"/>
<arg value="com\.oracle\.nashorn\.runtime\.ScriptRuntime*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.javaadapters*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.objects\.annotations*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.scripts*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.lookup\.MethodHandleFactory*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.test\.framework*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.test\.models*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.ir\.debug*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.runtime\.regexp\.joni\.bench*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.runtime\.DebugLogger*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.runtime\.Timing*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.runtime\.Logging*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.runtime\.Debug*"/>
+ <arg value="-exclude"/>
+ <arg value="jdk\.nashorn\.internal\.objects\.NativeDebug*"/>
<arg line="${cc.all.xmls}"/>
<classpath>
<pathelement location="${jcov.jar}"/>
diff --git a/make/project.properties b/make/project.properties
index 2d66dfef..2e3839b6 100644
--- a/make/project.properties
+++ b/make/project.properties
@@ -87,6 +87,7 @@ testng.verbose=2
testng.listeners=\
org.testng.reporters.SuiteHTMLReporter, \
+ org.testng.reporters.TestHTMLReporter, \
org.testng.reporters.jq.Main, \
org.testng.reporters.FailedReporter, \
org.testng.reporters.XMLReporter \
@@ -214,9 +215,13 @@ test.src.dir=test/src
run.test.xmx=3G
run.test.xms=2G
+run.test.user.language=tr
+run.test.user.country=TR
+
# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
# add '-Dtest.js.outofprocess' to run each test in a new sub-process
-run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
+run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country}
+
#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
diff --git a/src/netscape/javascript/JSObject.java b/src/jdk/nashorn/api/scripting/JSObject.java
index 23054c63..583e8f7a 100644
--- a/src/netscape/javascript/JSObject.java
+++ b/src/jdk/nashorn/api/scripting/JSObject.java
@@ -23,26 +23,12 @@
* questions.
*/
-package netscape.javascript;
-
-import java.applet.Applet;
+package jdk.nashorn.api.scripting;
/**
- * Stub for JSObject to get compilation going.
+ * netscape.javascript.JSObject-like interface for nashorn script objects.
*/
public abstract class JSObject {
-
- /**
- * Get the window for an {@link Applet}. Not supported
- * by Nashorn
- *
- * @param a applet
- * @return the window instance
- */
- public static JSObject getWindow(final Applet a) {
- throw new UnsupportedOperationException("getWindow");
- }
-
/**
* Call a JavaScript method
*
diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
index 266ce87f..e53903d3 100644
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
+++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
@@ -42,7 +42,6 @@ import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import netscape.javascript.JSObject;
/**
* Mirror object that wraps a given ScriptObject instance. User can
diff --git a/src/jdk/nashorn/api/scripting/resources/engine.js b/src/jdk/nashorn/api/scripting/resources/engine.js
index e9560728..62d6735e 100644
--- a/src/jdk/nashorn/api/scripting/resources/engine.js
+++ b/src/jdk/nashorn/api/scripting/resources/engine.js
@@ -88,7 +88,7 @@ Object.defineProperty(this, "sprintf", {
}
}
- array = Java.toJavaArray(array);
+ array = Java.to(array);
return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array);
}
});
diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java
index 4e47892f..cf3e6946 100644
--- a/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/src/jdk/nashorn/internal/codegen/Attr.java
@@ -84,8 +84,8 @@ import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
@@ -111,7 +111,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
* computed.
*/
-final class Attr extends NodeOperatorVisitor {
+final class Attr extends NodeOperatorVisitor<LexicalContext> {
/**
* Local definitions in current block (to discriminate from function
@@ -138,6 +138,7 @@ final class Attr extends NodeOperatorVisitor {
* Constructor.
*/
Attr(final TemporarySymbols temporarySymbols) {
+ super(new LexicalContext());
this.temporarySymbols = temporarySymbols;
this.localDefs = new ArrayDeque<>();
this.localUses = new ArrayDeque<>();
@@ -202,7 +203,7 @@ final class Attr extends NodeOperatorVisitor {
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
// This visitor will assign symbol to all declared variables, except function declarations (which are taken care
// in a separate step above) and "var" declarations in for loop initializers.
- body.accept(new NodeOperatorVisitor() {
+ body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterFunctionNode(final FunctionNode nestedFn) {
return false;
@@ -218,7 +219,7 @@ final class Attr extends NodeOperatorVisitor {
if (varNode.isFunctionDeclaration()) {
newType(symbol, FunctionNode.FUNCTION_TYPE);
}
- return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol));
+ return varNode.setName((IdentNode)ident.setSymbol(lc, symbol));
}
return varNode;
}
@@ -227,8 +228,8 @@ final class Attr extends NodeOperatorVisitor {
private void enterFunctionBody() {
- final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
- final Block body = getLexicalContext().getCurrentBlock();
+ final FunctionNode functionNode = lc.getCurrentFunction();
+ final Block body = lc.getCurrentBlock();
initFunctionWideVariables(functionNode, body);
@@ -256,7 +257,7 @@ final class Attr extends NodeOperatorVisitor {
//the symbols in the block should really be stateless
block.clearSymbols();
- if (getLexicalContext().isFunctionBody()) {
+ if (lc.isFunctionBody()) {
enterFunctionBody();
}
pushLocalsBlock();
@@ -283,7 +284,7 @@ final class Attr extends NodeOperatorVisitor {
@Override
public boolean enterCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
- final Block block = getLexicalContext().getCurrentBlock();
+ final Block block = lc.getCurrentBlock();
start(catchNode);
@@ -298,10 +299,10 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
- final Block block = getLexicalContext().getCurrentBlock();
+ final Block block = lc.getCurrentBlock();
final Symbol symbol = findSymbol(block, exception.getName());
assert symbol != null;
- return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol)));
+ return end(catchNode.setException((IdentNode)exception.setSymbol(lc, symbol)));
}
/**
@@ -320,7 +321,7 @@ final class Attr extends NodeOperatorVisitor {
flags |= IS_SCOPE;
}
- final FunctionNode function = getLexicalContext().getFunction(block);
+ final FunctionNode function = lc.getFunction(block);
if (symbol != null) {
// Symbol was already defined. Check if it needs to be redefined.
if ((flags & KINDMASK) == IS_PARAM) {
@@ -353,12 +354,12 @@ final class Attr extends NodeOperatorVisitor {
if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
symbolBlock = block; //internal vars are always defined in the block closest to them
} else {
- symbolBlock = getLexicalContext().getFunctionBody(function);
+ symbolBlock = lc.getFunctionBody(function);
}
// Create and add to appropriate block.
symbol = new Symbol(name, flags);
- symbolBlock.putSymbol(getLexicalContext(), symbol);
+ symbolBlock.putSymbol(lc, symbol);
if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
symbol.setNeedsSlot(true);
@@ -381,7 +382,7 @@ final class Attr extends NodeOperatorVisitor {
//an outermost function in our lexical context that is not a program (runScript)
//is possible - it is a function being compiled lazily
if (functionNode.isDeclared()) {
- final Iterator<Block> blocks = getLexicalContext().getBlocks();
+ final Iterator<Block> blocks = lc.getBlocks();
if (blocks.hasNext()) {
defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR);
}
@@ -397,13 +398,11 @@ final class Attr extends NodeOperatorVisitor {
public Node leaveFunctionNode(final FunctionNode functionNode) {
FunctionNode newFunctionNode = functionNode;
- final LexicalContext lc = getLexicalContext();
-
final Block body = newFunctionNode.getBody();
//look for this function in the parent block
if (functionNode.isDeclared()) {
- final Iterator<Block> blocks = getLexicalContext().getBlocks();
+ final Iterator<Block> blocks = lc.getBlocks();
if (blocks.hasNext()) {
newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName()));
}
@@ -411,7 +410,7 @@ final class Attr extends NodeOperatorVisitor {
final boolean anonymous = functionNode.isAnonymous();
final String name = anonymous ? null : functionNode.getIdent().getName();
if (anonymous || body.getExistingSymbol(name) != null) {
- newFunctionNode = (FunctionNode)ensureSymbol(lc, FunctionNode.FUNCTION_TYPE, newFunctionNode);
+ newFunctionNode = (FunctionNode)ensureSymbol(FunctionNode.FUNCTION_TYPE, newFunctionNode);
} else {
assert name != null;
final Symbol self = body.getExistingSymbol(name);
@@ -490,8 +489,6 @@ final class Attr extends NodeOperatorVisitor {
start(identNode);
- final LexicalContext lc = getLexicalContext();
-
if (identNode.isPropertyName()) {
// assign a pseudo symbol to property name
final Symbol pseudoSymbol = pseudoSymbol(name);
@@ -549,7 +546,7 @@ final class Attr extends NodeOperatorVisitor {
*/
private void maybeForceScope(final Symbol symbol) {
if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
- Symbol.setSymbolIsScope(getLexicalContext(), symbol);
+ Symbol.setSymbolIsScope(lc, symbol);
}
}
@@ -558,7 +555,7 @@ final class Attr extends NodeOperatorVisitor {
return false;
}
boolean previousWasBlock = false;
- for(final Iterator<LexicalContextNode> it = getLexicalContext().getAllNodes(); it.hasNext();) {
+ for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
final LexicalContextNode node = it.next();
if(node instanceof FunctionNode) {
// We reached the function boundary without seeing a definition for the symbol - it needs to be in
@@ -594,10 +591,8 @@ final class Attr extends NodeOperatorVisitor {
}
if (symbol.isScope()) {
- final LexicalContext lc = getLexicalContext();
-
Block scopeBlock = null;
- for (final Iterator<LexicalContextNode> contextNodeIter = getLexicalContext().getAllNodes(); contextNodeIter.hasNext(); ) {
+ for (final Iterator<LexicalContextNode> contextNodeIter = lc.getAllNodes(); contextNodeIter.hasNext(); ) {
final LexicalContextNode node = contextNodeIter.next();
if (node instanceof Block) {
if (((Block)node).getExistingSymbol(name) != null) {
@@ -610,7 +605,7 @@ final class Attr extends NodeOperatorVisitor {
}
if (scopeBlock != null) {
- assert getLexicalContext().contains(scopeBlock);
+ assert lc.contains(scopeBlock);
lc.setFlag(scopeBlock, Block.NEEDS_SCOPE);
}
}
@@ -622,8 +617,8 @@ final class Attr extends NodeOperatorVisitor {
* @see #needsParentScope()
*/
private void setUsesGlobalSymbol() {
- for (final Iterator<FunctionNode> fns = getLexicalContext().getFunctions(); fns.hasNext();) {
- getLexicalContext().setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE);
+ for (final Iterator<FunctionNode> fns = lc.getFunctions(); fns.hasNext();) {
+ lc.setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE);
}
}
@@ -635,7 +630,7 @@ final class Attr extends NodeOperatorVisitor {
private Symbol findSymbol(final Block block, final String name) {
// Search up block chain to locate symbol.
- for (final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) {
+ for (final Iterator<Block> blocks = lc.getBlocks(block); blocks.hasNext();) {
// Find name.
final Symbol symbol = blocks.next().getExistingSymbol(name);
// If found then we are good.
@@ -656,11 +651,11 @@ final class Attr extends NodeOperatorVisitor {
public Node leaveLiteralNode(final LiteralNode literalNode) {
assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
- final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType());
+ final Symbol symbol = new Symbol(lc.getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType());
if (literalNode instanceof ArrayLiteralNode) {
((ArrayLiteralNode)literalNode).analyze();
}
- return end(literalNode.setSymbol(getLexicalContext(), symbol));
+ return end(literalNode.setSymbol(lc, symbol));
}
@Override
@@ -676,7 +671,7 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leavePropertyNode(final PropertyNode propertyNode) {
// assign a pseudo symbol to property name, see NASHORN-710
- return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
+ return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
}
@Override
@@ -734,11 +729,11 @@ final class Attr extends NodeOperatorVisitor {
type = Type.OBJECT;
}
- switchNode.setTag(newInternal(getLexicalContext().getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type));
+ switchNode.setTag(newInternal(lc.getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type));
end(switchNode);
- return switchNode.setCases(getLexicalContext(), newCases);
+ return switchNode.setCases(lc, newCases);
}
@Override
@@ -761,7 +756,7 @@ final class Attr extends NodeOperatorVisitor {
final IdentNode ident = varNode.getName();
final String name = ident.getName();
- final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR);
+ final Symbol symbol = defineSymbol(lc.getCurrentBlock(), name, IS_VAR);
assert symbol != null;
// NASHORN-467 - use before definition of vars - conservative
@@ -781,7 +776,6 @@ final class Attr extends NodeOperatorVisitor {
final IdentNode ident = newVarNode.getName();
final String name = ident.getName();
- final LexicalContext lc = getLexicalContext();
final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
if (init == null) {
@@ -834,7 +828,7 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveDELETE(final UnaryNode unaryNode) {
- final FunctionNode currentFunctionNode = getLexicalContext().getCurrentFunction();
+ final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
final Node rhs = unaryNode.rhs();
final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this);
@@ -894,10 +888,10 @@ final class Attr extends NodeOperatorVisitor {
* @return true if the symbol denoted by the specified name in the current lexical context defined in the program level.
*/
private boolean isProgramLevelSymbol(final String name) {
- for(final Iterator<Block> it = getLexicalContext().getBlocks(); it.hasNext();) {
+ for(final Iterator<Block> it = lc.getBlocks(); it.hasNext();) {
final Block next = it.next();
if(next.getExistingSymbol(name) != null) {
- return next == getLexicalContext().getFunctionBody(getLexicalContext().getOutermostFunction());
+ return next == lc.getFunctionBody(lc.getOutermostFunction());
}
}
throw new AssertionError("Couldn't find symbol " + name + " in the context");
@@ -914,14 +908,14 @@ final class Attr extends NodeOperatorVisitor {
}
private IdentNode compilerConstant(CompilerConstants cc) {
- final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+ final FunctionNode functionNode = lc.getCurrentFunction();
return (IdentNode)
new IdentNode(
functionNode.getToken(),
functionNode.getFinish(),
cc.symbolName()).
setSymbol(
- getLexicalContext(),
+ lc,
functionNode.compilerConstant(cc));
}
@@ -999,7 +993,7 @@ final class Attr extends NodeOperatorVisitor {
final Node lhs = binaryNode.lhs();
if (lhs instanceof IdentNode) {
- final Block block = getLexicalContext().getCurrentBlock();
+ final Block block = lc.getCurrentBlock();
final IdentNode ident = (IdentNode)lhs;
final String name = ident.getName();
@@ -1043,7 +1037,7 @@ final class Attr extends NodeOperatorVisitor {
}
private boolean isLocal(FunctionNode function, Symbol symbol) {
- final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol);
+ final FunctionNode definingFn = lc.getDefiningFunction(symbol);
// Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local
return definingFn == null || definingFn == function;
}
@@ -1329,7 +1323,7 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveForNode(final ForNode forNode) {
if (forNode.isForIn()) {
- forNode.setIterator(newInternal(getLexicalContext().getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73
+ forNode.setIterator(newInternal(lc.getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73
/*
* Iterators return objects, so we need to widen the scope of the
* init variable if it, for example, has been assigned double type
@@ -1407,7 +1401,7 @@ final class Attr extends NodeOperatorVisitor {
final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName());
assert paramSymbol != null;
assert paramSymbol.isParam();
- newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol));
+ newParams.add((IdentNode)param.setSymbol(lc, paramSymbol));
assert paramSymbol != null;
Type type = functionNode.getHints().getParameterType(pos);
@@ -1439,10 +1433,10 @@ final class Attr extends NodeOperatorVisitor {
FunctionNode newFunctionNode = functionNode;
if (nparams == 0 || (specialize * 2) < nparams) {
- newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext());
+ newFunctionNode = newFunctionNode.clearSnapshot(lc);
}
- return newFunctionNode.setParameters(getLexicalContext(), newParams);
+ return newFunctionNode.setParameters(lc, newParams);
}
/**
@@ -1506,7 +1500,7 @@ final class Attr extends NodeOperatorVisitor {
}
private Symbol exceptionSymbol() {
- return newInternal(getLexicalContext().getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class));
+ return newInternal(lc.getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class));
}
/**
@@ -1520,8 +1514,8 @@ final class Attr extends NodeOperatorVisitor {
* @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
*/
private Node ensureAssignmentSlots(final Node assignmentDest) {
- final LexicalContext attrLexicalContext = getLexicalContext();
- return assignmentDest.accept(new NodeVisitor() {
+ final LexicalContext attrLexicalContext = lc;
+ return assignmentDest.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveIndexNode(final IndexNode indexNode) {
assert indexNode.getSymbol().isTemp();
@@ -1565,7 +1559,7 @@ final class Attr extends NodeOperatorVisitor {
FunctionNode currentFunctionNode = functionNode;
do {
changed.clear();
- final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor() {
+ final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
private Node widen(final Node node, final Type to) {
if (node instanceof LiteralNode) {
@@ -1579,7 +1573,7 @@ final class Attr extends NodeOperatorVisitor {
symbol = temporarySymbols.getTypedTemporarySymbol(to);
}
newType(symbol, to);
- final Node newNode = node.setSymbol(getLexicalContext(), symbol);
+ final Node newNode = node.setSymbol(lc, symbol);
changed.add(newNode);
return newNode;
}
@@ -1622,7 +1616,7 @@ final class Attr extends NodeOperatorVisitor {
return newBinaryNode;
}
});
- getLexicalContext().replace(currentFunctionNode, newFunctionNode);
+ lc.replace(currentFunctionNode, newFunctionNode);
currentFunctionNode = newFunctionNode;
} while (!changed.isEmpty());
return currentFunctionNode;
@@ -1643,12 +1637,12 @@ final class Attr extends NodeOperatorVisitor {
}
private Node ensureSymbol(final Type type, final Node node) {
- LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type);
- return ensureSymbol(getLexicalContext(), type, node);
+ LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type);
+ return temporarySymbols.ensureSymbol(lc, type, node);
}
private Symbol newInternal(final String name, final Type type) {
- final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL);
+ final Symbol iter = defineSymbol(lc.getCurrentBlock(), name, IS_VAR | IS_INTERNAL);
iter.setType(type); // NASHORN-73
return iter;
}
@@ -1705,10 +1699,6 @@ final class Attr extends NodeOperatorVisitor {
localUses.peek().add(name);
}
- private Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
- return temporarySymbols.ensureSymbol(lc, type, node);
- }
-
/**
* Pessimistically promote all symbols in current function node to Object types
* This is done when the function contains unevaluated black boxes such as
@@ -1717,7 +1707,7 @@ final class Attr extends NodeOperatorVisitor {
* @param body body for the function node we are leaving
*/
private static void objectifySymbols(final Block body) {
- body.accept(new NodeVisitor() {
+ body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
private void toObject(final Block block) {
for (final Symbol symbol : block.getSymbols()) {
if (!symbol.isTemp()) {
@@ -1761,7 +1751,7 @@ final class Attr extends NodeOperatorVisitor {
append("] ").
append(printNode ? node.toString() : "").
append(" in '").
- append(getLexicalContext().getCurrentFunction().getName()).
+ append(lc.getCurrentFunction().getName()).
append("'");
LOG.info(sb);
LOG.indent();
@@ -1787,7 +1777,7 @@ final class Attr extends NodeOperatorVisitor {
append("] ").
append(printNode ? node.toString() : "").
append(" in '").
- append(getLexicalContext().getCurrentFunction().getName());
+ append(lc.getCurrentFunction().getName());
if (node.getSymbol() == null) {
sb.append(" <NO SYMBOL>");
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 1fae1294..21b61cd8 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -52,16 +52,13 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
import java.io.PrintWriter;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Deque;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
+import java.util.Locale;
import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
@@ -83,11 +80,11 @@ import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
@@ -150,7 +147,7 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
* The CodeGenerator visits nodes only once, tags them as resolved and emits
* bytecode for them.
*/
-final class CodeGenerator extends NodeOperatorVisitor {
+final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> {
/** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */
private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global";
@@ -168,23 +165,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** How many regexp fields have been emitted */
private int regexFieldCount;
- /** Map of shared scope call sites */
- private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
-
- /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */
- private final Deque<CompileUnit> compileUnits = new ArrayDeque<>();
-
- /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */
- private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>();
-
- /** The discard stack - whenever we enter a discard node we keep track of its return value status -
- * i.e. should we keep it or throw it away */
- private final Deque<Node> discard = new ArrayDeque<>();
+ /** Line number for last statement. If we encounter a new line number, line number bytecode information
+ * needs to be generated */
+ private int lastLineNumber = -1;
- // A stack tracking the next free local variable slot in the blocks. There's one entry for every block
- // currently on the lexical context stack.
- private int[] nextFreeSlots = new int[16];
- private int nextFreeSlotsSize = 0;
+ /** When should we stop caching regexp expressions in fields to limit bytecode size? */
+ private static final int MAX_REGEX_FIELDS = 2 * 1024;
/** Current method emitter */
private MethodEmitter method;
@@ -192,20 +178,16 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** Current compile unit */
private CompileUnit unit;
- private int lastLineNumber = -1;
-
- /** When should we stop caching regexp expressions in fields to limit bytecode size? */
- private static final int MAX_REGEX_FIELDS = 2 * 1024;
-
private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug");
+
/**
* Constructor.
*
* @param compiler
*/
CodeGenerator(final Compiler compiler) {
- super(new DynamicScopeTrackingLexicalContext());
+ super(new CodeGeneratorLexicalContext());
this.compiler = compiler;
this.callSiteFlags = compiler.getEnv()._callsite_flags;
}
@@ -217,37 +199,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @return the correct flags for a call site in the current function
*/
int getCallSiteFlags() {
- return getLexicalContext().getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags;
- }
-
- private void pushMethodEmitter(final MethodEmitter newMethod) {
- methodEmitters.push(newMethod);
- this.method = newMethod;
- }
-
- private void popMethodEmitter(final MethodEmitter oldMethod) {
- assert methodEmitters.peek() == oldMethod;
- methodEmitters.pop();
- if (!methodEmitters.isEmpty()) {
- this.method = methodEmitters.peek();
- } else {
- this.method = null;
- }
- }
-
- private void push(final CompileUnit newUnit) {
- compileUnits.push(newUnit);
- this.unit = newUnit;
- }
-
- private void pop(final CompileUnit oldUnit) {
- assert compileUnits.peek() == oldUnit;
- compileUnits.pop();
- if (!compileUnits.isEmpty()) {
- this.unit = compileUnits.peek();
- } else {
- this.unit = null;
- }
+ return lc.getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags;
}
/**
@@ -265,7 +217,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
final String name = symbol.getName();
- final Source source = getLexicalContext().getCurrentFunction().getSource();
+ final Source source = lc.getCurrentFunction().getSource();
if (CompilerConstants.__FILE__.name().equals(name)) {
return method.load(source.getName());
@@ -291,88 +243,43 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
/**
- * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new
- * variables introduced into them at run time - a with block or a function directly containing an eval call.
- */
- private static class DynamicScopeTrackingLexicalContext extends LexicalContext {
- int dynamicScopeCount = 0;
-
- @Override
- public <T extends LexicalContextNode> T push(T node) {
- if(isDynamicScopeBoundary(node)) {
- ++dynamicScopeCount;
- }
- return super.push(node);
- }
-
- @Override
- public <T extends LexicalContextNode> T pop(T node) {
- final T popped = super.pop(node);
- if(isDynamicScopeBoundary(popped)) {
- --dynamicScopeCount;
- }
- return popped;
- }
-
- private boolean isDynamicScopeBoundary(LexicalContextNode node) {
- if(node instanceof Block) {
- // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture
- // processing of WithNode.expression too, but it should be unaffected.
- return !isEmpty() && peek() instanceof WithNode;
- } else if(node instanceof FunctionNode) {
- // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
- // variable into the function's scope), and it isn't strict (as evals in strict functions get an
- // isolated scope).
- return isFunctionDynamicScope((FunctionNode)node);
- }
- return false;
- }
- }
-
- boolean inDynamicScope() {
- return ((DynamicScopeTrackingLexicalContext)getLexicalContext()).dynamicScopeCount > 0;
- }
-
- static boolean isFunctionDynamicScope(FunctionNode fn) {
- return fn.hasEval() && !fn.isStrict();
- }
-
- /**
* Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
*
* @param function function to check for fast scope
* @return true if fast scope
*/
private boolean isFastScope(final Symbol symbol) {
- if(!symbol.isScope()) {
+ if (!symbol.isScope()) {
return false;
}
- final LexicalContext lc = getLexicalContext();
- if(!inDynamicScope()) {
+
+ if (!lc.inDynamicScope()) {
// If there's no with or eval in context, and the symbol is marked as scoped, it is fast scoped. Such a
// symbol must either be global, or its defining block must need scope.
assert symbol.isGlobal() || lc.getDefiningBlock(symbol).needsScope() : symbol.getName();
return true;
}
- if(symbol.isGlobal()) {
+
+ if (symbol.isGlobal()) {
// Shortcut: if there's a with or eval in context, globals can't be fast scoped
return false;
}
+
// Otherwise, check if there's a dynamic scope between use of the symbol and its definition
final String name = symbol.getName();
boolean previousWasBlock = false;
for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
final LexicalContextNode node = it.next();
- if(node instanceof Block) {
+ if (node instanceof Block) {
// If this block defines the symbol, then we can fast scope the symbol.
final Block block = (Block)node;
- if(block.getExistingSymbol(name) == symbol) {
+ if (block.getExistingSymbol(name) == symbol) {
assert block.needsScope();
return true;
}
previousWasBlock = true;
} else {
- if((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && isFunctionDynamicScope((FunctionNode)node))) {
+ if ((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node))) {
// If we hit a scope that can have symbols introduced into it at run time before finding the defining
// block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block
// before - its block. Otherwise, we are currently processing the WithNode's expression, and that's
@@ -387,16 +294,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
- method.load(isFastScope(symbol) ? getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol) : -1);
- final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE);
- scopeCall.generateInvoke(method);
- return method;
+ method.load(isFastScope(symbol) ? getScopeProtoDepth(lc.getCurrentBlock(), symbol) : -1);
+ final SharedScopeCall scopeCall = lc.getScopeGet(unit, valueType, symbol, flags | CALLSITE_FAST_SCOPE);
+ return scopeCall.generateInvoke(method);
}
private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) {
loadFastScopeProto(symbol, false);
- method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod);
- return method;
+ return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod);
}
private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) {
@@ -408,7 +313,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) {
int depth = 0;
final String name = symbol.getName();
- for(final Iterator<Block> blocks = getLexicalContext().getBlocks(startingBlock); blocks.hasNext();) {
+ for(final Iterator<Block> blocks = lc.getBlocks(startingBlock); blocks.hasNext();) {
final Block currentBlock = blocks.next();
if (currentBlock.getExistingSymbol(name) == symbol) {
return depth;
@@ -421,7 +326,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void loadFastScopeProto(final Symbol symbol, final boolean swap) {
- final int depth = getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol);
+ final int depth = getScopeProtoDepth(lc.getCurrentBlock(), symbol);
assert depth != -1;
if (depth > 0) {
if (swap) {
@@ -464,7 +369,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
*/
final CodeGenerator codegen = this;
- node.accept(new NodeVisitor() {
+ node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterIdentNode(final IdentNode identNode) {
loadIdent(identNode);
@@ -538,7 +443,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined();
if (symbol.hasSlot() && !isInternal) {
- assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getLexicalContext().getCurrentFunction();
+ assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + lc.getCurrentFunction();
if (symbol.getSymbolType().isNumber()) {
numbers.add(symbol);
} else if (symbol.getSymbolType().isObject()) {
@@ -595,7 +500,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
if (block.needsScope() && !block.isTerminal()) {
popBlockScope(block);
}
- --nextFreeSlotsSize;
return block;
}
@@ -624,11 +528,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterBreakNode(final BreakNode breakNode) {
lineNumber(breakNode);
- final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel());
- for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) {
+ final BreakableNode breakFrom = lc.getBreakable(breakNode.getLabel());
+ for (int i = 0; i < lc.getScopeNestingLevelTo(breakFrom); i++) {
closeWith();
}
- method.splitAwareGoto(getLexicalContext(), breakFrom.getBreakLabel());
+ method.splitAwareGoto(lc, breakFrom.getBreakLabel());
return false;
}
@@ -672,11 +576,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
final List<Node> args = callNode.getArgs();
final Node function = callNode.getFunction();
- final Block currentBlock = getLexicalContext().getCurrentBlock();
+ final Block currentBlock = lc.getCurrentBlock();
+ final CodeGeneratorLexicalContext codegenLexicalContext = lc;
- function.accept(new NodeVisitor() {
+ function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- private void sharedScopeCall(final IdentNode identNode, final int flags) {
+ private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) {
final Symbol symbol = identNode.getSymbol();
int scopeCallFlags = flags;
method.loadCompilerConstant(SCOPE);
@@ -688,8 +593,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
loadArgs(args);
final Type[] paramTypes = method.getTypesFromStack(args.size());
- final SharedScopeCall scopeCall = getScopeCall(symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags);
- scopeCall.generateInvoke(method);
+ final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags);
+ return scopeCall.generateInvoke(method);
}
private void scopeCall(final IdentNode node, final int flags) {
@@ -756,7 +661,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
evalCall(node, flags);
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
|| (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
- || CodeGenerator.this.inDynamicScope()) {
+ || CodeGenerator.this.lc.inDynamicScope()) {
scopeCall(node, flags);
} else {
sharedScopeCall(node, flags);
@@ -845,11 +750,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterContinueNode(final ContinueNode continueNode) {
lineNumber(continueNode);
- final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel());
- for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) {
+ final LoopNode continueTo = lc.getContinueTo(continueNode.getLabel());
+ for (int i = 0; i < lc.getScopeNestingLevelTo(continueTo); i++) {
closeWith();
}
- method.splitAwareGoto(getLexicalContext(), continueTo.getContinueLabel());
+ method.splitAwareGoto(lc, continueTo.getContinueLabel());
return false;
}
@@ -875,90 +780,89 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterForNode(final ForNode forNode) {
lineNumber(forNode);
+ if (forNode.isForIn()) {
+ enterForIn(forNode);
+ } else {
+ enterFor(forNode);
+ }
+
+ return false;
+ }
+
+ private void enterFor(final ForNode forNode) {
+ final Node init = forNode.getInit();
final Node test = forNode.getTest();
final Block body = forNode.getBody();
final Node modify = forNode.getModify();
- final Label breakLabel = forNode.getBreakLabel();
- final Label continueLabel = forNode.getContinueLabel();
- final Label loopLabel = new Label("loop");
-
- Node init = forNode.getInit();
+ if (init != null) {
+ init.accept(this);
+ }
- if (forNode.isForIn()) {
- final Symbol iter = forNode.getIterator();
+ final Label loopLabel = new Label("loop");
+ final Label testLabel = new Label("test");
- // We have to evaluate the optional initializer expression
- // of the iterator variable of the for-in statement.
- if (init instanceof VarNode) {
- init.accept(this);
- init = ((VarNode)init).getName();
- }
+ method._goto(testLabel);
+ method.label(loopLabel);
+ body.accept(this);
+ method.label(forNode.getContinueLabel());
+ if (!body.isTerminal() && modify != null) {
load(modify);
- assert modify.getType().isObject();
- method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR);
- method.store(iter);
- method._goto(continueLabel);
- method.label(loopLabel);
-
- new Store<Node>(init) {
- @Override
- protected void storeNonDiscard() {
- return;
- }
- @Override
- protected void evaluate() {
- method.load(iter);
- method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class));
- }
- }.store();
-
- body.accept(this);
+ }
- method.label(continueLabel);
- method.load(iter);
- method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class));
- method.ifne(loopLabel);
- method.label(breakLabel);
+ method.label(testLabel);
+ if (test != null) {
+ new BranchOptimizer(this, method).execute(test, loopLabel, true);
} else {
- if (init != null) {
- init.accept(this);
- }
+ method._goto(loopLabel);
+ }
- final Label testLabel = new Label("test");
+ method.label(forNode.getBreakLabel());
+ }
- method._goto(testLabel);
- method.label(loopLabel);
- body.accept(this);
- method.label(continueLabel);
+ private void enterForIn(final ForNode forNode) {
+ final Block body = forNode.getBody();
+ final Node modify = forNode.getModify();
- if (!body.isTerminal() && modify != null) {
- load(modify);
- }
+ final Symbol iter = forNode.getIterator();
+ final Label loopLabel = new Label("loop");
- method.label(testLabel);
- if (test != null) {
- new BranchOptimizer(this, method).execute(test, loopLabel, true);
- } else {
- method._goto(loopLabel);
- }
+ Node init = forNode.getInit();
- method.label(breakLabel);
+ // We have to evaluate the optional initializer expression
+ // of the iterator variable of the for-in statement.
+ if (init instanceof VarNode) {
+ init.accept(this);
+ init = ((VarNode)init).getName();
}
- return false;
- }
+ load(modify);
+ assert modify.getType().isObject();
+ method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR);
+ method.store(iter);
+ method._goto(forNode.getContinueLabel());
+ method.label(loopLabel);
- private static int assignSlots(final Block block, final int firstSlot) {
- int nextSlot = firstSlot;
- for (final Symbol symbol : block.getSymbols()) {
- if (symbol.hasSlot()) {
- symbol.setSlot(nextSlot);
- nextSlot += symbol.slotCount();
+ new Store<Node>(init) {
+ @Override
+ protected void storeNonDiscard() {
+ return;
}
- }
- return nextSlot;
+ @Override
+ protected void evaluate() {
+ method.load(iter);
+ method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class));
+ }
+ }.store();
+
+ body.accept(this);
+
+ method.label(forNode.getContinueLabel());
+ method.load(iter);
+ method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class));
+ method.ifne(loopLabel);
+ method.label(forNode.getBreakLabel());
}
/**
@@ -967,24 +871,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @param block block with local vars.
*/
private void initLocals(final Block block) {
- final boolean isFunctionBody = getLexicalContext().isFunctionBody();
+ lc.nextFreeSlot(block);
- final int nextFreeSlot;
- if (isFunctionBody) {
- // On entry to function, start with slot 0
- nextFreeSlot = 0;
- } else {
- // Otherwise, continue from previous block's first free slot
- nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1];
- }
- if(nextFreeSlotsSize == nextFreeSlots.length) {
- final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2];
- System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize);
- nextFreeSlots = newNextFreeSlots;
- }
- nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot);
+ final boolean isFunctionBody = lc.isFunctionBody();
- final FunctionNode function = getLexicalContext().getCurrentFunction();
+ final FunctionNode function = lc.getCurrentFunction();
if (isFunctionBody) {
/* Fix the predefined slots so they have numbers >= 0, like varargs. */
if (function.needsParentScope()) {
@@ -1023,7 +914,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
if (symbol.isVar()) {
- if(varsInScope || symbol.isScope()) {
+ if (varsInScope || symbol.isScope()) {
nameList.add(symbol.getName());
newSymbols.add(symbol);
values.add(null);
@@ -1062,7 +953,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
protected void loadScope(MethodEmitter m) {
- if(function.needsParentScope()) {
+ if (function.needsParentScope()) {
m.loadCompilerConstant(SCOPE);
} else {
m.loadNull();
@@ -1096,7 +987,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
private void initArguments(final FunctionNode function) {
method.loadCompilerConstant(VARARGS);
- if(function.needsCallee()) {
+ if (function.needsCallee()) {
method.loadCompilerConstant(CALLEE);
} else {
// If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the
@@ -1126,10 +1017,10 @@ final class CodeGenerator extends NodeOperatorVisitor {
LOG.info("=== BEGIN ", functionNode.getName());
assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode);
- push(functionNode.getCompileUnit());
- assert !compileUnits.isEmpty();
+ unit = lc.pushCompileUnit(functionNode.getCompileUnit());
+ assert lc.hasCompileUnits();
- pushMethodEmitter(unit.getClassEmitter().method(functionNode));
+ method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
// Mark end for variable tables.
method.begin();
@@ -1140,11 +1031,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
public Node leaveFunctionNode(final FunctionNode functionNode) {
try {
method.end(); // wrap up this method
- pop(functionNode.getCompileUnit());
- popMethodEmitter(method);
+ unit = lc.popCompileUnit(functionNode.getCompileUnit());
+ method = lc.popMethodEmitter(method);
LOG.info("=== END ", functionNode.getName());
- final FunctionNode newFunctionNode = functionNode.setState(getLexicalContext(), CompilationState.EMITTED);
+ final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
newFunctionObject(newFunctionNode, functionNode);
return newFunctionNode;
@@ -1238,16 +1129,16 @@ final class CodeGenerator extends NodeOperatorVisitor {
final MethodEmitter savedMethod = method;
for (final ArrayUnit arrayUnit : units) {
- push(arrayUnit.getCompileUnit());
+ unit = lc.pushCompileUnit(arrayUnit.getCompileUnit());
final String className = unit.getUnitClassName();
- final String name = getLexicalContext().getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName());
+ final String name = lc.getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName());
final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type);
final MethodEmitter me = unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature);
- pushMethodEmitter(me);
+ method = lc.pushMethodEmitter(me);
- method.setFunctionNode(getLexicalContext().getCurrentFunction());
+ method.setFunctionNode(lc.getCurrentFunction());
method.begin();
fixScopeSlot();
@@ -1260,7 +1151,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
method._return();
method.end();
- popMethodEmitter(me);
+ method = lc.popMethodEmitter(me);
assert method == savedMethod;
method.loadCompilerConstant(THIS);
@@ -1271,7 +1162,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.swap();
method.invokestatic(className, name, signature);
- pop(unit);
+ unit = lc.popCompileUnit(unit);
}
return method;
@@ -1407,7 +1298,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
return loadRegexToken(regexToken);
}
// emit field
- final String regexName = getLexicalContext().getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName());
+ final String regexName = lc.getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName());
final ClassEmitter classEmitter = unit.getClassEmitter();
classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class);
@@ -1545,7 +1436,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.registerReturn();
- final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
+ final Type returnType = lc.getCurrentFunction().getReturnType();
final Node expression = returnNode.getExpression();
if (expression != null) {
@@ -1756,7 +1647,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
- final FunctionNode fn = getLexicalContext().getCurrentFunction();
+ final FunctionNode fn = lc.getCurrentFunction();
final String className = splitCompileUnit.getUnitClassName();
final String name = splitNode.getName();
@@ -1767,7 +1658,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class};
final MethodEmitter caller = method;
- push(splitCompileUnit);
+ unit = lc.pushCompileUnit(splitCompileUnit);
final Call splitCall = staticCallNoLookup(
className,
@@ -1781,8 +1672,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
rtype,
ptypes);
- pushMethodEmitter(splitEmitter);
-
+ method = lc.pushMethodEmitter(splitEmitter);
method.setFunctionNode(fn);
if (fn.needsCallee()) {
@@ -1809,7 +1699,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void fixScopeSlot() {
- if (getLexicalContext().getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) {
+ if (lc.getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) {
// TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method)
method.load(Type.typeFor(ScriptObject.class), SCOPE.slot());
method.storeCompilerConstant(SCOPE);
@@ -1826,15 +1716,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
// Wrap up this method.
method.loadCompilerConstant(RETURN);
- method._return(getLexicalContext().getCurrentFunction().getReturnType());
+ method._return(lc.getCurrentFunction().getReturnType());
method.end();
- pop(splitNode.getCompileUnit());
- popMethodEmitter(method);
+ unit = lc.popCompileUnit(splitNode.getCompileUnit());
+ method = lc.popMethodEmitter(method);
} catch (final Throwable t) {
Context.printStackTrace(t);
- final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getLexicalContext().getCurrentFunction().getSource().getName());
+ final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + lc.getCurrentFunction().getSource().getName());
e.initCause(t);
throw e;
}
@@ -1862,7 +1752,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
//has to be zero
caller.label(new Label("split_return"));
method.loadCompilerConstant(RETURN);
- caller._return(getLexicalContext().getCurrentFunction().getReturnType());
+ caller._return(lc.getCurrentFunction().getReturnType());
caller.label(breakLabel);
} else {
assert !targets.isEmpty();
@@ -1879,14 +1769,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
caller.label(labels[i - low]);
if (i == 0) {
caller.loadCompilerConstant(RETURN);
- caller._return(getLexicalContext().getCurrentFunction().getReturnType());
+ caller._return(lc.getCurrentFunction().getReturnType());
} else {
// Clear split state.
caller.loadCompilerConstant(SCOPE);
caller.checkcast(Scope.class);
caller.load(-1);
caller.invoke(Scope.SET_SPLIT_STATE);
- caller.splitAwareGoto(getLexicalContext(), targets.get(i - 1));
+ caller.splitAwareGoto(lc, targets.get(i - 1));
}
}
caller.label(breakLabel);
@@ -2028,9 +1918,16 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterThrowNode(final ThrowNode throwNode) {
lineNumber(throwNode);
+ if (throwNode.isSyntheticRethrow()) {
+ //do not wrap whatever this is in an ecma exception, just rethrow it
+ load(throwNode.getExpression());
+ method.athrow();
+ return false;
+ }
+
method._new(ECMAException.class).dup();
- final Source source = getLexicalContext().getCurrentFunction().getSource();
+ final Source source = lc.getCurrentFunction().getSource();
final Node expression = throwNode.getExpression();
final int position = throwNode.position();
@@ -2081,7 +1978,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
//TODO this is very ugly - try not to call enter/leave methods directly
//better to use the implicit lexical context scoping given by the visitor's
//accept method.
- getLexicalContext().push(catchBlock);
+ lc.push(catchBlock);
enterBlock(catchBlock);
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
@@ -2094,15 +1991,19 @@ final class CodeGenerator extends NodeOperatorVisitor {
protected void storeNonDiscard() {
return;
}
+
@Override
protected void evaluate() {
+ if (catchNode.isSyntheticRethrow()) {
+ method.load(symbol);
+ return;
+ }
/*
* If caught object is an instance of ECMAException, then
* bind obj.thrown to the script catch var. Or else bind the
* caught object itself to the script catch var.
*/
final Label notEcmaException = new Label("no_ecma_exception");
-
method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException);
method.checkcast(ECMAException.class); //TODO is this necessary?
method.getField(ECMAException.THROWN);
@@ -2137,7 +2038,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
leaveBlock(catchBlock);
- getLexicalContext().pop(catchBlock);
+ lc.pop(catchBlock);
}
method.label(skip);
@@ -2234,7 +2135,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final boolean hasScope = method.hasScope();
final Label tryLabel;
- if(hasScope) {
+ if (hasScope) {
tryLabel = new Label("with_try");
method.label(tryLabel);
method.loadCompilerConstant(SCOPE);
@@ -2245,7 +2146,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
load(expression);
assert expression.getType().isObject() : "with expression needs to be object: " + expression;
- if(hasScope) {
+ if (hasScope) {
// Construct a WithObject if we have a scope
method.invoke(ScriptRuntime.OPEN_WITH);
method.storeCompilerConstant(SCOPE);
@@ -2285,7 +2186,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterADD(final UnaryNode unaryNode) {
load(unaryNode.rhs());
- assert unaryNode.rhs().getType().isNumber();
+ assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol();
method.store(unaryNode.getSymbol());
return false;
@@ -2320,7 +2221,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
method.convert(Type.OBJECT);
} else if (value instanceof Boolean) {
- method.getField(staticField(Boolean.class, value.toString().toUpperCase(), Boolean.class));
+ method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class));
} else {
load(rhs);
method.convert(unaryNode.getType());
@@ -2387,13 +2288,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterDISCARD(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
- discard.push(rhs);
+ lc.pushDiscard(rhs);
load(rhs);
- if (discard.peek() == rhs) {
+ if (lc.getCurrentDiscard() == rhs) {
assert !rhs.isAssignment();
method.pop();
- discard.pop();
+ lc.popDiscard();
}
return false;
@@ -2445,7 +2346,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
load(lhs);
load(rhs);
- method.add();
+ method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack?
method.store(symbol);
return null;
}
@@ -2989,53 +2890,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
* Generate all shared scope calls generated during codegen.
*/
protected void generateScopeCalls() {
- for (final SharedScopeCall scopeAccess : scopeCalls.values()) {
+ for (final SharedScopeCall scopeAccess : lc.getScopeCalls()) {
scopeAccess.generateScopeCall();
}
}
/**
- * Get a shared static method representing a dynamic scope callsite.
- *
- * @param symbol the symbol
- * @param valueType the value type of the symbol
- * @param returnType the return type
- * @param paramTypes the parameter types
- * @param flags the callsite flags
- * @return an object representing a shared scope call
- */
- private SharedScopeCall getScopeCall(final Symbol symbol, final Type valueType, final Type returnType,
- final Type[] paramTypes, final int flags) {
-
- final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags);
- if (scopeCalls.containsKey(scopeCall)) {
- return scopeCalls.get(scopeCall);
- }
- scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall"));
- scopeCalls.put(scopeCall, scopeCall);
- return scopeCall;
- }
-
- /**
- * Get a shared static method representing a dynamic scope get access.
- *
- * @param type the type of the variable
- * @param symbol the symbol
- * @param flags the callsite flags
- * @return an object representing a shared scope call
- */
- private SharedScopeCall getScopeGet(final Type type, final Symbol symbol, final int flags) {
-
- final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags);
- if (scopeCalls.containsKey(scopeCall)) {
- return scopeCalls.get(scopeCall);
- }
- scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall"));
- scopeCalls.put(scopeCall, scopeCall);
- return scopeCall;
- }
-
- /**
* Debug code used to print symbols
*
* @param block the block we are in
@@ -3129,14 +2989,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
private void prologue() {
final Symbol targetSymbol = target.getSymbol();
- final Symbol scopeSymbol = getLexicalContext().getCurrentFunction().compilerConstant(SCOPE);
+ final Symbol scopeSymbol = lc.getCurrentFunction().compilerConstant(SCOPE);
/**
* This loads the parts of the target, e.g base and index. they are kept
* on the stack throughout the store and used at the end to execute it
*/
- target.accept(new NodeVisitor() {
+ target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterIdentNode(final IdentNode node) {
if (targetSymbol.isScope()) {
@@ -3203,22 +3063,21 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @return the quick symbol
*/
private Symbol quickSymbol(final Type type, final String prefix) {
- final String name = getLexicalContext().getCurrentFunction().uniqueName(prefix);
+ final String name = lc.getCurrentFunction().uniqueName(prefix);
final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL);
symbol.setType(type);
- final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1];
- nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount();
- symbol.setSlot(quickSlot);
+
+ symbol.setSlot(lc.quickSlot(symbol));
return symbol;
}
// store the result that "lives on" after the op, e.g. "i" in i++ postfix.
protected void storeNonDiscard() {
- if (discard.peek() == assignNode) {
+ if (lc.getCurrentDiscard() == assignNode) {
assert assignNode.isAssignment();
- discard.pop();
+ lc.popDiscard();
return;
}
@@ -3246,7 +3105,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
*/
method.convert(target.getType());
- target.accept(new NodeVisitor() {
+ target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
protected boolean enterDefault(Node node) {
throw new AssertionError("Unexpected node " + node + " in store epilogue");
@@ -3308,7 +3167,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void newFunctionObject(final FunctionNode functionNode, final FunctionNode originalFunctionNode) {
- final LexicalContext lc = getLexicalContext();
assert lc.peek() == functionNode;
// We don't emit a ScriptFunction on stack for:
// 1. the outermost compiled function (as there's no code being generated in its outer context that'd need it
diff --git a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
new file mode 100644
index 00000000..d27bdd95
--- /dev/null
+++ b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LexicalContextNode;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.WithNode;
+
+/**
+ * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new
+ * variables introduced into them at run time - a with block or a function directly containing an eval call.
+ * Furthermore, this class keeps track of current discard state, which the current method emitter being used is,
+ * the current compile unit, and local variable indexes
+ */
+final class CodeGeneratorLexicalContext extends LexicalContext {
+ private int dynamicScopeCount;
+
+ /** Map of shared scope call sites */
+ private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
+
+ /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */
+ private final Deque<CompileUnit> compileUnits = new ArrayDeque<>();
+
+ /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */
+ private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>();
+
+ /** The discard stack - whenever we enter a discard node we keep track of its return value status -
+ * i.e. should we keep it or throw it away */
+ private final Deque<Node> discard = new ArrayDeque<>();
+
+ /** A stack tracking the next free local variable slot in the blocks. There's one entry for every block
+ * currently on the lexical context stack. */
+ private int[] nextFreeSlots = new int[16];
+
+ /** size of next free slot vector */
+ private int nextFreeSlotsSize;
+
+ @Override
+ public <T extends LexicalContextNode> T push(final T node) {
+ if (isDynamicScopeBoundary(node)) {
+ ++dynamicScopeCount;
+ }
+ return super.push(node);
+ }
+
+ @Override
+ public <T extends LexicalContextNode> T pop(final T node) {
+ final T popped = super.pop(node);
+ if (isDynamicScopeBoundary(popped)) {
+ --dynamicScopeCount;
+ }
+ if (node instanceof Block) {
+ --nextFreeSlotsSize;
+ }
+ return popped;
+ }
+
+ private boolean isDynamicScopeBoundary(final LexicalContextNode node) {
+ if (node instanceof Block) {
+ // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture
+ // processing of WithNode.expression too, but it should be unaffected.
+ return !isEmpty() && peek() instanceof WithNode;
+ } else if (node instanceof FunctionNode) {
+ // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
+ // variable into the function's scope), and it isn't strict (as evals in strict functions get an
+ // isolated scope).
+ return isFunctionDynamicScope((FunctionNode)node);
+ }
+ return false;
+ }
+
+ boolean inDynamicScope() {
+ return dynamicScopeCount > 0;
+ }
+
+ static boolean isFunctionDynamicScope(FunctionNode fn) {
+ return fn.hasEval() && !fn.isStrict();
+ }
+
+ MethodEmitter pushMethodEmitter(final MethodEmitter newMethod) {
+ methodEmitters.push(newMethod);
+ return newMethod;
+ }
+
+ MethodEmitter popMethodEmitter(final MethodEmitter oldMethod) {
+ assert methodEmitters.peek() == oldMethod;
+ methodEmitters.pop();
+ return methodEmitters.isEmpty() ? null : methodEmitters.peek();
+ }
+
+ CompileUnit pushCompileUnit(final CompileUnit newUnit) {
+ compileUnits.push(newUnit);
+ return newUnit;
+ }
+
+ CompileUnit popCompileUnit(final CompileUnit oldUnit) {
+ assert compileUnits.peek() == oldUnit;
+ compileUnits.pop();
+ return compileUnits.isEmpty() ? null : compileUnits.peek();
+ }
+
+ boolean hasCompileUnits() {
+ return !compileUnits.isEmpty();
+ }
+
+ Collection<SharedScopeCall> getScopeCalls() {
+ return Collections.unmodifiableCollection(scopeCalls.values());
+ }
+
+ /**
+ * Get a shared static method representing a dynamic scope callsite.
+ *
+ * @param unit current compile unit
+ * @param symbol the symbol
+ * @param valueType the value type of the symbol
+ * @param returnType the return type
+ * @param paramTypes the parameter types
+ * @param flags the callsite flags
+ * @return an object representing a shared scope call
+ */
+ SharedScopeCall getScopeCall(final CompileUnit unit, final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) {
+ final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags);
+ if (scopeCalls.containsKey(scopeCall)) {
+ return scopeCalls.get(scopeCall);
+ }
+ scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName("scopeCall"));
+ scopeCalls.put(scopeCall, scopeCall);
+ return scopeCall;
+ }
+
+ /**
+ * Get a shared static method representing a dynamic scope get access.
+ *
+ * @param unit current compile unit
+ * @param type the type of the variable
+ * @param symbol the symbol
+ * @param flags the callsite flags
+ * @return an object representing a shared scope call
+ */
+ SharedScopeCall getScopeGet(final CompileUnit unit, final Type type, final Symbol symbol, final int flags) {
+ final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags);
+ if (scopeCalls.containsKey(scopeCall)) {
+ return scopeCalls.get(scopeCall);
+ }
+ scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName("scopeCall"));
+ scopeCalls.put(scopeCall, scopeCall);
+ return scopeCall;
+ }
+
+
+ void nextFreeSlot(final Block block) {
+ final boolean isFunctionBody = isFunctionBody();
+
+ final int nextFreeSlot;
+ if (isFunctionBody) {
+ // On entry to function, start with slot 0
+ nextFreeSlot = 0;
+ } else {
+ // Otherwise, continue from previous block's first free slot
+ nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1];
+ }
+ if (nextFreeSlotsSize == nextFreeSlots.length) {
+ final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2];
+ System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize);
+ nextFreeSlots = newNextFreeSlots;
+ }
+ nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot);
+ }
+
+ private static int assignSlots(final Block block, final int firstSlot) {
+ int nextSlot = firstSlot;
+ for (final Symbol symbol : block.getSymbols()) {
+ if (symbol.hasSlot()) {
+ symbol.setSlot(nextSlot);
+ nextSlot += symbol.slotCount();
+ }
+ }
+ return nextSlot;
+ }
+
+ void pushDiscard(final Node node) {
+ discard.push(node);
+ }
+
+ Node popDiscard() {
+ return discard.pop();
+ }
+
+ Node getCurrentDiscard() {
+ return discard.peek();
+ }
+
+ int quickSlot(final Symbol symbol) {
+ final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1];
+ nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount();
+ return quickSlot;
+ }
+
+}
+
diff --git a/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
index bfc71cc2..9f263067 100644
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
@@ -11,20 +11,27 @@ import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
import java.util.EnumSet;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
+
+import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.ReturnNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.ECMAErrors;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -66,7 +73,7 @@ enum CompilationPhase {
FunctionNode newFunctionNode = outermostFunctionNode;
- newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() {
+ newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
// self references are done with invokestatic and thus cannot
// have trampolines - never lazy
@Override
@@ -99,10 +106,9 @@ enum CompilationPhase {
lazy.remove(node);
}
- newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeOperatorVisitor() {
+ newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
- final LexicalContext lc = getLexicalContext();
if (lazy.contains(functionNode)) {
Compiler.LOG.fine(
"Marking ",
@@ -174,7 +180,7 @@ enum CompilationPhase {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final TemporarySymbols ts = compiler.getTemporarySymbols();
final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts));
- if(compiler.getEnv()._print_mem_usage) {
+ if (compiler.getEnv()._print_mem_usage) {
Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
}
return newFunctionNode;
@@ -186,12 +192,11 @@ enum CompilationPhase {
* @param functionNode node where to start iterating
*/
private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) {
- return (FunctionNode)functionNode.accept(new NodeVisitor() {
+ return (FunctionNode)functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveFunctionNode(final FunctionNode node) {
- final LexicalContext lc = getLexicalContext();
if (node.isLazy()) {
- FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT);
+ FunctionNode newNode = node.setReturnType(lc, Type.OBJECT);
return ts.ensureSymbol(lc, Type.OBJECT, newNode);
}
//node may have a reference here that needs to be nulled if it was referred to by
@@ -208,6 +213,89 @@ enum CompilationPhase {
},
/*
+ * Range analysis
+ * Conservatively prove that certain variables can be narrower than
+ * the most generic number type
+ */
+ RANGE_ANALYSIS_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) {
+ @Override
+ FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
+ if (!compiler.getEnv()._range_analysis) {
+ return fn;
+ }
+
+ FunctionNode newFunctionNode = (FunctionNode)fn.accept(new RangeAnalyzer());
+ final List<ReturnNode> returns = new ArrayList<>();
+
+ newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ private final Deque<ArrayList<ReturnNode>> returnStack = new ArrayDeque<>();
+
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ returnStack.push(new ArrayList<ReturnNode>());
+ return true;
+ }
+
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ Type returnType = Type.UNKNOWN;
+ for (final ReturnNode ret : returnStack.pop()) {
+ if (ret.getExpression() == null) {
+ returnType = Type.OBJECT;
+ break;
+ }
+ returnType = Type.widest(returnType, ret.getExpression().getType());
+ }
+ return functionNode.setReturnType(lc, returnType);
+ }
+
+ @Override
+ public Node leaveReturnNode(final ReturnNode returnNode) {
+ final ReturnNode result = (ReturnNode)leaveDefault(returnNode);
+ returns.add(result);
+ return result;
+ }
+
+ @Override
+ public Node leaveDefault(final Node node) {
+ final Symbol symbol = node.getSymbol();
+ if (symbol != null) {
+ final Range range = symbol.getRange();
+ final Type symbolType = symbol.getSymbolType();
+ if (!symbolType.isNumeric()) {
+ return node;
+ }
+ final Type rangeType = range.getType();
+ if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
+ RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
+ return node.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
+ }
+ }
+ return node;
+ }
+ });
+
+ Type returnType = Type.UNKNOWN;
+ for (final ReturnNode node : returns) {
+ if (node.getExpression() != null) {
+ returnType = Type.widest(returnType, node.getExpression().getType());
+ } else {
+ returnType = Type.OBJECT;
+ break;
+ }
+ }
+
+ return newFunctionNode.setReturnType(null, returnType);
+ }
+
+ @Override
+ public String toString() {
+ return "[Range Analysis]";
+ }
+ },
+
+
+ /*
* Splitter Split the AST into several compile units based on a size
* heuristic Splitter needs attributed AST for weight calculations (e.g. is
* a + b a ScriptRuntime.ADD with call overhead or a dadd with much less).
@@ -218,7 +306,6 @@ enum CompilationPhase {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
-// assert fn.isProgram() ;
final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java
index 81a76186..faf7a3c5 100644
--- a/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -99,7 +99,7 @@ public final class Compiler {
private boolean strict;
- private CodeInstaller<ScriptEnvironment> installer;
+ private final CodeInstaller<ScriptEnvironment> installer;
private final TemporarySymbols temporarySymbols = new TemporarySymbols();
@@ -219,6 +219,7 @@ public final class Compiler {
CompilationPhase.CONSTANT_FOLDING_PHASE,
CompilationPhase.LOWERING_PHASE,
CompilationPhase.ATTRIBUTION_PHASE,
+ CompilationPhase.RANGE_ANALYSIS_PHASE,
CompilationPhase.SPLITTING_PHASE,
CompilationPhase.TYPE_FINALIZATION_PHASE,
CompilationPhase.BYTECODE_GENERATION_PHASE);
@@ -384,6 +385,8 @@ public final class Compiler {
if (info) {
final StringBuilder sb = new StringBuilder();
sb.append("Compile job for '").
+ append(newFunctionNode.getSource()).
+ append(':').
append(newFunctionNode.getName()).
append("' finished");
@@ -487,7 +490,7 @@ public final class Compiler {
}
if (sb != null) {
- LOG.info(sb);
+ LOG.fine(sb);
}
return rootClass;
diff --git a/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/src/jdk/nashorn/internal/codegen/CompilerConstants.java
index 6912534d..d9c68ad8 100644
--- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java
+++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java
@@ -262,7 +262,7 @@ public enum CompilerConstants {
* @return the internal descriptor for this type
*/
public static String typeDescriptor(final Class<?> clazz) {
- return Type.getDescriptor(clazz);
+ return Type.typeFor(clazz).getDescriptor();
}
/**
diff --git a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
index e94dab7c..f9d64322 100644
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
+++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
@@ -31,6 +31,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.Assignment;
@@ -84,13 +85,14 @@ import jdk.nashorn.internal.runtime.JSType;
* and frame optimizations
*/
-final class FinalizeTypes extends NodeOperatorVisitor {
+final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
private static final DebugLogger LOG = new DebugLogger("finalize");
private final TemporarySymbols temporarySymbols;
FinalizeTypes(final TemporarySymbols temporarySymbols) {
+ super(new LexicalContext());
this.temporarySymbols = temporarySymbols;
}
@@ -233,7 +235,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private boolean symbolIsInteger(Node node) {
final Symbol symbol = node.getSymbol();
- assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource();
+ assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource();
return true;
}
@@ -382,12 +384,10 @@ final class FinalizeTypes extends NodeOperatorVisitor {
final Node test = forNode.getTest();
final Node modify = forNode.getModify();
- final LexicalContext lc = getLexicalContext();
-
if (forNode.isForIn()) {
return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
}
- assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getLexicalContext().getCurrentFunction();
+ assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction();
return forNode.
setInit(lc, init == null ? null : discard(init)).
@@ -419,7 +419,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
- return functionNode.setState(getLexicalContext(), CompilationState.FINALIZED);
+ return functionNode.setState(lc, CompilationState.FINALIZED);
}
@Override
@@ -450,7 +450,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
if (expr != null) {
- return returnNode.setExpression(convert(expr, getLexicalContext().getCurrentFunction().getReturnType()));
+ return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType()));
}
return returnNode;
}
@@ -482,8 +482,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
return switchNode.
- setExpression(getLexicalContext(), convert(expression, Type.OBJECT)).
- setCases(getLexicalContext(), newCases);
+ setExpression(lc, convert(expression, Type.OBJECT)).
+ setCases(lc, newCases);
}
@Override
@@ -519,14 +519,14 @@ final class FinalizeTypes extends NodeOperatorVisitor {
public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
if (test != null) {
- return whileNode.setTest(getLexicalContext(), convert(test, Type.BOOLEAN));
+ return whileNode.setTest(lc, convert(test, Type.BOOLEAN));
}
return whileNode;
}
@Override
public Node leaveWithNode(final WithNode withNode) {
- return withNode.setExpression(getLexicalContext(), convert(withNode.getExpression(), Type.OBJECT));
+ return withNode.setExpression(lc, convert(withNode.getExpression(), Type.OBJECT));
}
private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
@@ -550,7 +550,6 @@ final class FinalizeTypes extends NodeOperatorVisitor {
return; // nothing to do
}
- final LexicalContext lc = getLexicalContext();
final FunctionNode functionNode = lc.getFunction(block);
final boolean allVarsInScope = functionNode.allVarsInScope();
final boolean isVarArg = functionNode.isVarArg();
@@ -652,7 +651,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private static void setCanBePrimitive(final Node node, final Type to) {
final HashSet<Node> exclude = new HashSet<>();
- node.accept(new NodeVisitor() {
+ node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
private void setCanBePrimitive(final Symbol symbol) {
LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol));
symbol.setCanBePrimitive(to);
@@ -762,7 +761,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
LOG.info("Type override for lhs in '", node, "' => ", to);
- return ((TypeOverride<T>)node).setType(temporarySymbols, getLexicalContext(), to);
+ return ((TypeOverride<T>)node).setType(temporarySymbols, lc, to);
}
/**
@@ -785,8 +784,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private Node convert(final Node node, final Type to) {
assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
assert node != null : "node is null";
- assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction();
- assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction();
+ assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction();
+ assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + lc.getCurrentFunction();
final Type from = node.getType();
@@ -800,7 +799,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
Node resultNode = node;
- if (node instanceof LiteralNode && !to.isObject()) {
+ if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) {
final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval();
if (newNode != null) {
resultNode = newNode;
@@ -817,7 +816,6 @@ final class FinalizeTypes extends NodeOperatorVisitor {
assert !node.isTerminal();
- final LexicalContext lc = getLexicalContext();
//This is the only place in this file that can create new temporaries
//FinalizeTypes may not introduce ANY node that is not a conversion.
return temporarySymbols.ensureSymbol(lc, to, resultNode);
@@ -854,7 +852,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
LOG.info("Type override for temporary in '", node, "' => ", to);
}
- return node.setSymbol(getLexicalContext(), symbol);
+ return node.setSymbol(lc, symbol);
}
/**
@@ -907,7 +905,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
if (literalNode != null) {
//inherit literal symbol for attr.
- literalNode = (LiteralNode<?>)literalNode.setSymbol(getLexicalContext(), parent.getSymbol());
+ literalNode = (LiteralNode<?>)literalNode.setSymbol(lc, parent.getSymbol());
}
return literalNode;
diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java
index 686c9836..2331cf75 100644
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -33,7 +33,9 @@ import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IfNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
@@ -45,11 +47,12 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
* Simple constant folding pass, executed before IR is starting to be lowered.
*/
-final class FoldConstants extends NodeVisitor {
+final class FoldConstants extends NodeVisitor<LexicalContext> {
private static final DebugLogger LOG = new DebugLogger("fold");
FoldConstants() {
+ super(new LexicalContext());
}
@Override
@@ -79,7 +82,7 @@ final class FoldConstants extends NodeVisitor {
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
- return functionNode.setState(getLexicalContext(), CompilationState.CONSTANT_FOLDED);
+ return functionNode.setState(lc, CompilationState.CONSTANT_FOLDED);
}
@Override
@@ -141,6 +144,10 @@ final class FoldConstants extends NodeVisitor {
return null;
}
+ if (rhsNode instanceof ArrayLiteralNode) {
+ return null;
+ }
+
final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
final boolean rhsInteger = rhs.getType().isInteger();
@@ -212,6 +219,10 @@ final class FoldConstants extends NodeVisitor {
final LiteralNode<?> lhs = (LiteralNode<?>)parent.lhs();
final LiteralNode<?> rhs = (LiteralNode<?>)parent.rhs();
+ if (lhs instanceof ArrayLiteralNode || rhs instanceof ArrayLiteralNode) {
+ return null;
+ }
+
final Type widest = Type.widest(lhs.getType(), rhs.getType());
boolean isInteger = widest.isInteger();
@@ -279,9 +290,9 @@ final class FoldConstants extends NodeVisitor {
isLong &= value != 0.0 && JSType.isRepresentableAsLong(value);
if (isInteger) {
- return LiteralNode.newInstance(token, finish, JSType.toInt32(value));
+ return LiteralNode.newInstance(token, finish, (int)value);
} else if (isLong) {
- return LiteralNode.newInstance(token, finish, JSType.toLong(value));
+ return LiteralNode.newInstance(token, finish, (long)value);
}
return LiteralNode.newInstance(token, finish, value);
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index 23e91b63..2747560a 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -80,7 +80,7 @@ import jdk.nashorn.internal.runtime.Source;
* finalized.
*/
-final class Lower extends NodeOperatorVisitor {
+final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
private static final DebugLogger LOG = new DebugLogger("lower");
@@ -105,7 +105,7 @@ final class Lower extends NodeOperatorVisitor {
terminated = true;
}
} else {
- statement.accept(new NodeVisitor() {
+ statement.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterVarNode(final VarNode varNode) {
newStatements.add(varNode.setInit(null));
@@ -121,7 +121,6 @@ final class Lower extends NodeOperatorVisitor {
@Override
public boolean enterBlock(final Block block) {
- final LexicalContext lc = getLexicalContext();
final FunctionNode function = lc.getCurrentFunction();
if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
@@ -134,12 +133,10 @@ final class Lower extends NodeOperatorVisitor {
//now we have committed the entire statement list to the block, but we need to truncate
//whatever is after the last terminal. block append won't append past it
- final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext();
-
Statement last = lc.getLastStatement();
if (lc.isFunctionBody()) {
- final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+ final FunctionNode currentFunction = lc.getCurrentFunction();
final boolean isProgram = currentFunction.isProgram();
final ReturnNode returnNode = new ReturnNode(
last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
@@ -191,7 +188,7 @@ final class Lower extends NodeOperatorVisitor {
final Node expr = executeNode.getExpression();
ExecuteNode node = executeNode;
- final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+ final FunctionNode currentFunction = lc.getCurrentFunction();
if (currentFunction.isProgram()) {
if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
@@ -216,7 +213,7 @@ final class Lower extends NodeOperatorVisitor {
final Node test = forNode.getTest();
if (!forNode.isForIn() && conservativeAlwaysTrue(test)) {
- newForNode = forNode.setTest(getLexicalContext(), null);
+ newForNode = forNode.setTest(lc, null);
}
return addStatement(checkEscape(newForNode));
@@ -230,7 +227,7 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
LOG.info("END FunctionNode: ", functionNode.getName());
- return functionNode.setState(getLexicalContext(), CompilationState.LOWERED);
+ return functionNode.setState(lc, CompilationState.LOWERED);
}
@Override
@@ -261,19 +258,25 @@ final class Lower extends NodeOperatorVisitor {
return throwNode;
}
- private static Node ensureUniqueLabelsIn(final Node node) {
- return node.accept(new NodeVisitor() {
- @Override
- public Node leaveDefault(final Node labelledNode) {
- return labelledNode.ensureUniqueLabels(getLexicalContext());
- }
+ private static Node ensureUniqueNamesIn(final LexicalContext lc, final Node node) {
+ return node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ final String name = functionNode.getName();
+ return functionNode.setName(lc, lc.getCurrentFunction().uniqueName(name));
+ }
+
+ @Override
+ public Node leaveDefault(final Node labelledNode) {
+ return labelledNode.ensureUniqueLabels(lc);
+ }
});
}
- private static List<Statement> copyFinally(final Block finallyBody) {
+ private static List<Statement> copyFinally(final LexicalContext lc, final Block finallyBody) {
final List<Statement> newStatements = new ArrayList<>();
for (final Statement statement : finallyBody.getStatements()) {
- newStatements.add((Statement)ensureUniqueLabelsIn(statement));
+ newStatements.add((Statement)ensureUniqueNamesIn(lc, statement));
if (statement.hasTerminalFlags()) {
return newStatements;
}
@@ -286,12 +289,12 @@ final class Lower extends NodeOperatorVisitor {
final long token = tryNode.getToken();
final int finish = tryNode.getFinish();
- final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
+ final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all"));
- final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))).
- setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal
+ final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
+ setIsTerminal(lc, true); //ends with throw, so terminal
- final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody);
+ final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW);
final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
//catchallblock -> catchallnode (catchnode) -> exception -> throw
@@ -300,7 +303,7 @@ final class Lower extends NodeOperatorVisitor {
}
private IdentNode compilerConstant(final CompilerConstants cc) {
- final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+ final FunctionNode functionNode = lc.getCurrentFunction();
return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
}
@@ -316,11 +319,10 @@ final class Lower extends NodeOperatorVisitor {
* @return new try node after splicing finally code (same if nop)
*/
private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
- final int finish = tryNode.getFinish();
-
assert tryNode.getFinallyBody() == null;
+ final int finish = tryNode.getFinish();
- final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor() {
+ final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
final List<Node> insideTry = new ArrayList<>();
@Override
@@ -338,7 +340,7 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveThrowNode(final ThrowNode throwNode) {
if (rethrows.contains(throwNode)) {
- final List<Statement> newStatements = copyFinally(finallyBody);
+ final List<Statement> newStatements = copyFinally(lc, finallyBody);
if (!isTerminal(newStatements)) {
newStatements.add(throwNode);
}
@@ -349,12 +351,12 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveBreakNode(final BreakNode breakNode) {
- return copy(breakNode, Lower.this.getLexicalContext().getBreakable(breakNode.getLabel()));
+ return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel()));
}
@Override
public Node leaveContinueNode(final ContinueNode continueNode) {
- return copy(continueNode, Lower.this.getLexicalContext().getContinueTo(continueNode.getLabel()));
+ return copy(continueNode, Lower.this.lc.getContinueTo(continueNode.getLabel()));
}
@Override
@@ -372,17 +374,17 @@ final class Lower extends NodeOperatorVisitor {
resultNode = null;
}
- newStatements.addAll(copyFinally(finallyBody));
+ newStatements.addAll(copyFinally(lc, finallyBody));
if (!isTerminal(newStatements)) {
newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
}
- return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
+ return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements));
}
private Node copy(final Statement endpoint, final Node targetNode) {
if (!insideTry.contains(targetNode)) {
- final List<Statement> newStatements = copyFinally(finallyBody);
+ final List<Statement> newStatements = copyFinally(lc, finallyBody);
if (!isTerminal(newStatements)) {
newStatements.add(endpoint);
}
@@ -436,7 +438,7 @@ final class Lower extends NodeOperatorVisitor {
final Block catchAll = catchAllBlock(tryNode);
final List<ThrowNode> rethrows = new ArrayList<>();
- catchAll.accept(new NodeVisitor() {
+ catchAll.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterThrowNode(final ThrowNode throwNode) {
rethrows.add(throwNode);
@@ -464,7 +466,7 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
- if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
+ if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) {
new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
}
return varNode;
@@ -478,7 +480,7 @@ final class Lower extends NodeOperatorVisitor {
if (conservativeAlwaysTrue(test)) {
//turn it into a for node without a test.
final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
- getLexicalContext().replace(whileNode, forNode);
+ lc.replace(whileNode, forNode);
return forNode;
}
@@ -513,7 +515,7 @@ final class Lower extends NodeOperatorVisitor {
* @return eval location
*/
private String evalLocation(final IdentNode node) {
- final Source source = getLexicalContext().getCurrentFunction().getSource();
+ final Source source = lc.getCurrentFunction().getSource();
return new StringBuilder().
append(source.getName()).
append('#').
@@ -545,10 +547,10 @@ final class Lower extends NodeOperatorVisitor {
// 'eval' call with at least one argument
if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
- final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+ final FunctionNode currentFunction = lc.getCurrentFunction();
return callNode.setEvalArgs(
new CallNode.EvalArgs(
- ensureUniqueLabelsIn(args.get(0)).accept(this),
+ ensureUniqueNamesIn(lc, args.get(0)).accept(this),
compilerConstant(THIS),
evalLocation(callee),
currentFunction.isStrict()));
@@ -574,7 +576,7 @@ final class Lower extends NodeOperatorVisitor {
private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) {
final List<Node> escapes = new ArrayList<>();
- loopBody.accept(new NodeVisitor() {
+ loopBody.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveBreakNode(final BreakNode node) {
escapes.add(node);
@@ -595,7 +597,6 @@ final class Lower extends NodeOperatorVisitor {
}
private LoopNode checkEscape(final LoopNode loopNode) {
- final LexicalContext lc = getLexicalContext();
final boolean escapes = controlFlowEscapes(lc, loopNode.getBody());
if (escapes) {
return loopNode.
@@ -607,7 +608,7 @@ final class Lower extends NodeOperatorVisitor {
private Node addStatement(final Statement statement) {
- ((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
+ lc.appendStatement(statement);
return statement;
}
diff --git a/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
index c156c865..4e07c477 100644
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
@@ -2081,7 +2081,9 @@ public class MethodEmitter implements Emitter {
* @param args debug information to print
*/
private void debug(final Object... args) {
- debug(30, args);
+ if (DEBUG) {
+ debug(30, args);
+ }
}
/**
@@ -2091,7 +2093,9 @@ public class MethodEmitter implements Emitter {
* @param args debug information to print
*/
private void debug_label(final Object... args) {
- debug(26, args);
+ if (DEBUG) {
+ debug(22, args);
+ }
}
private void debug(final int padConstant, final Object... args) {
@@ -2164,7 +2168,6 @@ public class MethodEmitter implements Emitter {
new Throwable().printStackTrace(LOG.getOutputStream());
}
}
-
}
}
diff --git a/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java b/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
new file mode 100644
index 00000000..ab61d374
--- /dev/null
+++ b/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import jdk.nashorn.internal.codegen.types.Range;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Assignment;
+import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.ForNode;
+import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
+import jdk.nashorn.internal.ir.LoopNode;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.RuntimeNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.UnaryNode;
+import jdk.nashorn.internal.ir.VarNode;
+import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.TokenType;
+import jdk.nashorn.internal.runtime.DebugLogger;
+
+/**
+ * Range analysis and narrowing of type where it can be proven
+ * that there is no spillover, e.g.
+ *
+ * function func(c) {
+ * var v = c & 0xfff;
+ * var w = c & 0xeee;
+ * var x = v * w;
+ * return x;
+ * }
+ *
+ * Proves that the multiplication never exceeds 24 bits and can thus be an int
+ */
+final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
+ static final DebugLogger LOG = new DebugLogger("ranges");
+
+ private static final Range.Functionality RANGE = new Range.Functionality(LOG);
+
+ private final Map<LoopNode, Symbol> loopCounters = new HashMap<>();
+
+ RangeAnalyzer() {
+ super(new LexicalContext());
+ }
+
+ @Override
+ public boolean enterForNode(final ForNode forNode) {
+ //conservatively attempt to identify the loop counter. Null means that it wasn't
+ //properly identified and that no optimizations can be made with it - its range is
+ //simply unknown in that case, if it is assigned in the loop
+ final Symbol counter = findLoopCounter(forNode);
+ LOG.fine("Entering forNode " + forNode + " counter = " + counter);
+ if (counter != null && !assignedInLoop(forNode, counter)) {
+ loopCounters.put(forNode, counter);
+ }
+ return true;
+ }
+
+ //destination visited
+ private Symbol setRange(final Node dest, final Range range) {
+ if (range.isUnknown()) {
+ return null;
+ }
+
+ final Symbol symbol = dest.getSymbol();
+ assert symbol != null : dest + " " + dest.getClass() + " has no symbol";
+ assert symbol.getRange() != null : symbol + " has no range";
+ final Range symRange = RANGE.join(symbol.getRange(), range);
+
+ //anything assigned in the loop, not being the safe loop counter(s) invalidates its entire range
+ if (lc.inLoop() && !isLoopCounter(lc.getCurrentLoop(), symbol)) {
+ symbol.setRange(Range.createGenericRange());
+ return symbol;
+ }
+
+ if (!symRange.equals(symbol.getRange())) {
+ LOG.fine("Modify range for " + dest + " " + symbol + " from " + symbol.getRange() + " to " + symRange + " (in node = " + dest + ")" );
+ symbol.setRange(symRange);
+ }
+
+ return null;
+ }
+
+ @Override
+ public Node leaveADD(final BinaryNode node) {
+ setRange(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveSUB(final BinaryNode node) {
+ setRange(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveMUL(final BinaryNode node) {
+ setRange(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveDIV(final BinaryNode node) {
+ setRange(node, RANGE.div(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveMOD(final BinaryNode node) {
+ setRange(node, RANGE.mod(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveBIT_AND(final BinaryNode node) {
+ setRange(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveBIT_OR(final BinaryNode node) {
+ setRange(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveBIT_XOR(final BinaryNode node) {
+ setRange(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveSAR(final BinaryNode node) {
+ setRange(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveSHL(final BinaryNode node) {
+ setRange(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveSHR(final BinaryNode node) {
+ setRange(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ private Node leaveCmp(final BinaryNode node) {
+ setRange(node, Range.createTypeRange(Type.BOOLEAN));
+ return node;
+ }
+
+ @Override
+ public Node leaveEQ(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveEQ_STRICT(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveNE(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveNE_STRICT(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveLT(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveLE(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveGT(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveGE(final BinaryNode node) {
+ return leaveCmp(node);
+ }
+
+ @Override
+ public Node leaveASSIGN(final BinaryNode node) {
+ Range range = node.rhs().getSymbol().getRange();
+ if (range.isUnknown()) {
+ range = Range.createGenericRange();
+ }
+
+ setRange(node.lhs(), range);
+ setRange(node, range);
+
+ return node;
+ }
+
+ private Node leaveSelfModifyingAssign(final BinaryNode node, final Range range) {
+ setRange(node.lhs(), range);
+ setRange(node, range);
+ return node;
+ }
+
+ private Node leaveSelfModifyingAssign(final UnaryNode node, final Range range) {
+ setRange(node.rhs(), range);
+ setRange(node, range);
+ return node;
+ }
+
+ @Override
+ public Node leaveASSIGN_ADD(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_SUB(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_MUL(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_DIV(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER));
+ }
+
+ @Override
+ public Node leaveASSIGN_MOD(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER));
+ }
+
+ @Override
+ public Node leaveASSIGN_BIT_AND(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_BIT_OR(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_BIT_XOR(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_SAR(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_SHR(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveASSIGN_SHL(final BinaryNode node) {
+ return leaveSelfModifyingAssign(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+ }
+
+ @Override
+ public Node leaveDECINC(final UnaryNode node) {
+ switch (node.tokenType()) {
+ case DECPREFIX:
+ case DECPOSTFIX:
+ return leaveSelfModifyingAssign(node, RANGE.sub(node.rhs().getSymbol().getRange(), Range.createRange(1)));
+ case INCPREFIX:
+ case INCPOSTFIX:
+ return leaveSelfModifyingAssign(node, RANGE.add(node.rhs().getSymbol().getRange(), Range.createRange(1)));
+ default:
+ assert false;
+ return node;
+ }
+ }
+
+ @Override
+ public Node leaveADD(final UnaryNode node) {
+ Range range = node.rhs().getSymbol().getRange();
+ if (!range.getType().isNumeric()) {
+ range = Range.createTypeRange(Type.NUMBER);
+ }
+ setRange(node, range);
+ return node;
+ }
+
+ @Override
+ public Node leaveBIT_NOT(final UnaryNode node) {
+ setRange(node, Range.createTypeRange(Type.INT));
+ return node;
+ }
+
+ @Override
+ public Node leaveNOT(final UnaryNode node) {
+ setRange(node, Range.createTypeRange(Type.BOOLEAN));
+ return node;
+ }
+
+ @Override
+ public Node leaveSUB(final UnaryNode node) {
+ setRange(node, RANGE.neg(node.rhs().getSymbol().getRange()));
+ return node;
+ }
+
+ @Override
+ public Node leaveVarNode(final VarNode node) {
+ if (node.isAssignment()) {
+ Range range = node.getInit().getSymbol().getRange();
+ range = range.isUnknown() ? Range.createGenericRange() : range;
+
+ setRange(node.getName(), range);
+ setRange(node, range);
+ }
+
+ return node;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean enterLiteralNode(final LiteralNode node) {
+ // ignore array literals
+ return !(node instanceof ArrayLiteralNode);
+ }
+
+ @Override
+ public Node leaveLiteralNode(@SuppressWarnings("rawtypes") final LiteralNode node) {
+ if (node.getType().isInteger()) {
+ setRange(node, Range.createRange(node.getInt32()));
+ } else if (node.getType().isNumber()) {
+ setRange(node, Range.createRange(node.getNumber()));
+ } else if (node.getType().isLong()) {
+ setRange(node, Range.createRange(node.getLong()));
+ } else if (node.getType().isBoolean()) {
+ setRange(node, Range.createTypeRange(Type.BOOLEAN));
+ } else {
+ setRange(node, Range.createGenericRange());
+ }
+ return node;
+ }
+
+ @Override
+ public boolean enterRuntimeNode(final RuntimeNode node) {
+ // a runtime node that cannot be specialized is no point entering
+ return node.getRequest().canSpecialize();
+ }
+
+ /**
+ * Check whether a symbol is unsafely assigned in a loop - i.e. repeteadly assigned and
+ * not being identified as the loop counter. That means we don't really know anything
+ * about its range.
+ * @param loopNode loop node
+ * @param symbol symbol
+ * @return true if assigned in loop
+ */
+ // TODO - this currently checks for nodes only - needs to be augmented for while nodes
+ // assignment analysis is also very conservative
+ private static boolean assignedInLoop(final LoopNode loopNode, final Symbol symbol) {
+ final HashSet<Node> skip = new HashSet<>();
+ final HashSet<Node> assignmentsInLoop = new HashSet<>();
+
+ loopNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ private boolean assigns(final Node node, final Symbol s) {
+ return node.isAssignment() && ((Assignment<?>)node).getAssignmentDest().getSymbol() == s;
+ }
+
+ @Override
+ public boolean enterForNode(final ForNode forNode) {
+ if (forNode.getInit() != null) {
+ skip.add(forNode.getInit());
+ }
+ if (forNode.getModify() != null) {
+ skip.add(forNode.getModify());
+ }
+ return true;
+ }
+
+ @Override
+ public Node leaveDefault(final Node node) {
+ //if this is an assignment to symbol
+ if (!skip.contains(node) && assigns(node, symbol)) {
+ assignmentsInLoop.add(node);
+ }
+ return node;
+ }
+ });
+
+ return !assignmentsInLoop.isEmpty();
+ }
+
+ /**
+ * Check for a loop counter. This is currently quite conservative, in that it only handles
+ * x <= counter and x < counter.
+ *
+ * @param node loop node to check
+ * @return
+ */
+ private static Symbol findLoopCounter(final LoopNode node) {
+ final Node test = node.getTest();
+
+ if (test != null && test.isComparison()) {
+ final BinaryNode binaryNode = (BinaryNode)test;
+ final Node lhs = binaryNode.lhs();
+ final Node rhs = binaryNode.rhs();
+
+ //detect ident cmp int_literal
+ if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode<?>)rhs).getType().isInteger()) {
+ final Symbol symbol = lhs.getSymbol();
+ final int margin = ((LiteralNode<?>)rhs).getInt32();
+ final TokenType op = test.tokenType();
+
+ switch (op) {
+ case LT:
+ case LE:
+ symbol.setRange(RANGE.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin)));
+ return symbol;
+ case GT:
+ case GE:
+ //setRange(lhs, Range.createRange(op == TokenType.GT ? margin + 1 : margin));
+ //return symbol;
+ default:
+ break;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isLoopCounter(final LoopNode loopNode, final Symbol symbol) {
+ //this only works if loop nodes aren't replaced by other ones during this transform, but they are not
+ return loopCounters.get(loopNode) == symbol;
+ }
+}
diff --git a/src/jdk/nashorn/internal/codegen/SharedScopeCall.java b/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
index 588e2f48..c7dfb40a 100644
--- a/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
+++ b/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
@@ -116,9 +116,10 @@ class SharedScopeCall {
/**
* Generate the invoke instruction for this shared scope call.
* @param method the method emitter
+ * @return the method emitter
*/
- public void generateInvoke(final MethodEmitter method) {
- method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature());
+ public MethodEmitter generateInvoke(final MethodEmitter method) {
+ return method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature());
}
/**
diff --git a/src/jdk/nashorn/internal/codegen/Splitter.java b/src/jdk/nashorn/internal/codegen/Splitter.java
index f18f686e..e724ce26 100644
--- a/src/jdk/nashorn/internal/codegen/Splitter.java
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java
@@ -49,12 +49,12 @@ import jdk.nashorn.internal.runtime.options.Options;
/**
* Split the IR into smaller compile units.
*/
-final class Splitter extends NodeVisitor {
+final class Splitter extends NodeVisitor<LexicalContext> {
/** Current compiler. */
private final Compiler compiler;
/** IR to be broken down. */
- private FunctionNode outermost;
+ private final FunctionNode outermost;
/** Compile unit for the main script. */
private final CompileUnit outermostCompileUnit;
@@ -75,6 +75,7 @@ final class Splitter extends NodeVisitor {
* @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit
*/
public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
+ super(new LexicalContext());
this.compiler = compiler;
this.outermost = functionNode;
this.outermostCompileUnit = outermostCompileUnit;
@@ -93,8 +94,6 @@ final class Splitter extends NodeVisitor {
LOG.finest("Initiating split of '", functionNode.getName(), "'");
- final LexicalContext lc = getLexicalContext();
-
long weight = WeighNodes.weigh(functionNode);
final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost;
@@ -127,7 +126,7 @@ final class Splitter extends NodeVisitor {
final Block body = functionNode.getBody();
final List<FunctionNode> dc = directChildren(functionNode);
- final Block newBody = (Block)body.accept(new NodeVisitor() {
+ final Block newBody = (Block)body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterFunctionNode(final FunctionNode nestedFunction) {
return dc.contains(nestedFunction);
@@ -136,7 +135,7 @@ final class Splitter extends NodeVisitor {
@Override
public Node leaveFunctionNode(final FunctionNode nestedFunction) {
FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
- getLexicalContext().replace(nestedFunction, split);
+ lc.replace(nestedFunction, split);
return split;
}
});
@@ -149,13 +148,13 @@ final class Splitter extends NodeVisitor {
private static List<FunctionNode> directChildren(final FunctionNode functionNode) {
final List<FunctionNode> dc = new ArrayList<>();
- functionNode.accept(new NodeVisitor() {
+ functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterFunctionNode(final FunctionNode child) {
if (child == functionNode) {
return true;
}
- if (getLexicalContext().getParentFunction(child) == functionNode) {
+ if (lc.getParentFunction(child) == functionNode) {
dc.add(child);
}
return false;
@@ -181,7 +180,7 @@ final class Splitter extends NodeVisitor {
* @return new weight for the resulting block.
*/
private Block splitBlock(final Block block, final FunctionNode function) {
- getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
+ lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_SPLIT);
final List<Statement> splits = new ArrayList<>();
List<Statement> statements = new ArrayList<>();
@@ -210,7 +209,7 @@ final class Splitter extends NodeVisitor {
splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
}
- return block.setStatements(getLexicalContext(), splits);
+ return block.setStatements(lc, splits);
}
/**
@@ -258,7 +257,7 @@ final class Splitter extends NodeVisitor {
// been split already, so weigh again before splitting.
long weight = WeighNodes.weigh(block, weightCache);
if (weight >= SPLIT_THRESHOLD) {
- newBlock = splitBlock(block, getLexicalContext().getFunction(block));
+ newBlock = splitBlock(block, lc.getFunction(block));
weight = WeighNodes.weigh(newBlock, weightCache);
}
weightCache.put(newBlock, weight);
@@ -274,9 +273,9 @@ final class Splitter extends NodeVisitor {
return literal;
}
- final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+ final FunctionNode functionNode = lc.getCurrentFunction();
- getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT);
+ lc.setFlag(functionNode, FunctionNode.IS_SPLIT);
if (literal instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
diff --git a/src/jdk/nashorn/internal/codegen/WeighNodes.java b/src/jdk/nashorn/internal/codegen/WeighNodes.java
index 002cc902..1adef12b 100644
--- a/src/jdk/nashorn/internal/codegen/WeighNodes.java
+++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.codegen;
import java.util.List;
import java.util.Map;
+
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@@ -41,6 +42,7 @@ import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
@@ -63,7 +65,7 @@ import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
* Computes the "byte code" weight of an AST segment. This is used
* for Splitting too large class files
*/
-final class WeighNodes extends NodeOperatorVisitor {
+final class WeighNodes extends NodeOperatorVisitor<LexicalContext> {
/*
* Weight constants.
*/
@@ -100,7 +102,7 @@ final class WeighNodes extends NodeOperatorVisitor {
* @param weightCache cache of already calculated block weights
*/
private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) {
- super();
+ super(new LexicalContext());
this.topFunction = topFunction;
this.weightCache = weightCache;
}
diff --git a/src/jdk/nashorn/internal/codegen/types/Range.java b/src/jdk/nashorn/internal/codegen/types/Range.java
new file mode 100644
index 00000000..2845d902
--- /dev/null
+++ b/src/jdk/nashorn/internal/codegen/types/Range.java
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen.types;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.JSType;
+
+/**
+ * Represents the value range of a symbol.
+ */
+public abstract class Range {
+
+ private static final Range GENERIC_RANGE = new Range() {
+ @Override
+ public Type getType() {
+ return Type.OBJECT;
+ }
+ };
+
+ private static final Range NUMBER_RANGE = new Range() {
+ @Override
+ public Type getType() {
+ return Type.NUMBER;
+ }
+ };
+
+ private static final Range UNKNOWN_RANGE = new Range() {
+ @Override
+ public Type getType() {
+ return Type.UNKNOWN;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return true;
+ }
+ };
+
+ private static class IntegerRange extends Range {
+ private final long min;
+ private final long max;
+ private final Type type;
+
+ private IntegerRange(final long min, final long max) {
+ assert min <= max;
+ this.min = min;
+ this.max = max;
+ this.type = typeFromRange(min, max);
+ }
+
+ private static Type typeFromRange(final long from, final long to) {
+ if (from >= Integer.MIN_VALUE && to <= Integer.MAX_VALUE) {
+ return Type.INT;
+ }
+ return Type.LONG;
+ }
+
+ @Override
+ public Type getType() {
+ return type;
+ }
+
+ public long getMin() {
+ return min;
+ }
+
+ public long getMax() {
+ return max;
+ }
+
+ @Override
+ public boolean isIntegerConst() {
+ return getMin() == getMax();
+ }
+
+ private long getBitMask() {
+ if (min == max) {
+ return min;
+ }
+
+ if (min < 0) {
+ return ~0L;
+ }
+
+ long mask = 1;
+ while (mask < max) {
+ mask = (mask << 1) | 1;
+ }
+ return mask;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj instanceof IntegerRange) {
+ final IntegerRange other = (IntegerRange)obj;
+ return this.type == other.type && this.min == other.min && this.max == other.max;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(min) ^ Long.hashCode(max);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "[" + min +", " + max + "]";
+ }
+ }
+
+ /**
+ * Get narrowest type for this range
+ * @return type
+ */
+ public abstract Type getType();
+
+ /**
+ * Is this range unknown
+ * @return true if unknown
+ */
+ public boolean isUnknown() {
+ return false;
+ }
+
+ /**
+ * Check if an integer is enough to span this range
+ * @return true if integer is enough
+ */
+ public boolean isIntegerType() {
+ return this instanceof IntegerRange;
+ }
+
+ /**
+ * Check if an integer is enough to span this range
+ * @return true if integer is enough
+ */
+ public boolean isIntegerConst() {
+ return false;
+ }
+
+ /**
+ * Create an unknown range - this is most likely a singleton object
+ * and it represents "we have no known range information"
+ * @return the range
+ */
+ public static Range createUnknownRange() {
+ return UNKNOWN_RANGE;
+ }
+
+ /**
+ * Create a constant range: [value, value]
+ * @param value value
+ * @return the range
+ */
+ public static Range createRange(final int value) {
+ return createIntegerRange(value, value);
+ }
+
+ /**
+ * Create a constant range: [value, value]
+ * @param value value
+ * @return the range
+ */
+ public static Range createRange(final long value) {
+ return createIntegerRange(value, value);
+ }
+
+ /**
+ * Create a constant range: [value, value]
+ * @param value value
+ * @return the range
+ */
+ public static Range createRange(final double value) {
+ if (isRepresentableAsLong(value)) {
+ return createIntegerRange((long) value, (long) value);
+ }
+ return createNumberRange();
+ }
+
+ /**
+ * Create a constant range: [value, value]
+ * @param value value
+ * @return the range
+ */
+ public static Range createRange(final Object value) {
+ if (value instanceof Integer) {
+ return createRange((int)value);
+ } else if (value instanceof Long) {
+ return createRange((long)value);
+ } else if (value instanceof Double) {
+ return createRange((double)value);
+ }
+
+ return createGenericRange();
+ }
+
+ /**
+ * Create a generic range - object symbol that carries no range
+ * information
+ * @return the range
+ */
+ public static Range createGenericRange() {
+ return GENERIC_RANGE;
+ }
+
+ /**
+ * Create a number range - number symbol that carries no range
+ * information
+ * @return the range
+ */
+ public static Range createNumberRange() {
+ return NUMBER_RANGE;
+ }
+
+ /**
+ * Create an integer range [min, max]
+ * @param min minimum value, inclusive
+ * @param max maximum value, inclusive
+ * @return the range
+ */
+ public static IntegerRange createIntegerRange(final long min, final long max) {
+ return new IntegerRange(min, max);
+ }
+
+ /**
+ * Create an integer range of maximum type width for the given type
+ * @param type the type
+ * @return the range
+ */
+ public static IntegerRange createIntegerRange(final Type type) {
+ assert type.isNumeric() && !type.isNumber();
+ final long min;
+ final long max;
+ if (type.isInteger()) {
+ min = Integer.MIN_VALUE;
+ max = Integer.MAX_VALUE;
+ } else if (type.isLong()) {
+ min = Long.MIN_VALUE;
+ max = Long.MAX_VALUE;
+ } else {
+ throw new AssertionError(); //type incompatible with integer range
+ }
+ return new IntegerRange(min, max);
+ }
+
+ /**
+ * Create an range of maximum type width for the given type
+ * @param type the type
+ * @return the range
+ */
+ public static Range createTypeRange(final Type type) {
+ if (type.isNumber()) {
+ return createNumberRange();
+ } else if (type.isNumeric()) {
+ return createIntegerRange(type);
+ } else {
+ return createGenericRange();
+ }
+ }
+
+ // check that add doesn't overflow
+ private static boolean checkAdd(final long a, final long b) {
+ final long result = a + b;
+ return ((a ^ result) & (b ^ result)) >= 0;
+ }
+
+ // check that sub doesn't overflow
+ private static boolean checkSub(final long a, final long b) {
+ final long result = a - b;
+ return ((a ^ result) & (b ^ result)) >= 0;
+ }
+
+ private static boolean checkMul(final long a, final long b) {
+ // TODO correct overflow check
+ return a >= Integer.MIN_VALUE && a <= Integer.MAX_VALUE && b >= Integer.MIN_VALUE && b <= Integer.MAX_VALUE;
+ }
+
+ /**
+ * The range functionality class responsible for merging ranges and drawing
+ * range conclusions from operations executed
+ */
+ public static class Functionality {
+ /** logger */
+ protected final DebugLogger log;
+
+ /**
+ * Constructor
+ * @param log logger
+ */
+ public Functionality(final DebugLogger log) {
+ this.log = log;
+ }
+
+ /**
+ * Join two ranges
+ * @param a first range
+ * @param b second range
+ * @return the joined range
+ */
+ public Range join(final Range a, final Range b) {
+ if (a.equals(b)) {
+ return a;
+ }
+
+ Type joinedType = a.getType();
+ if (a.getType() != b.getType()) {
+ if (a.isUnknown()) {
+ return b;
+ }
+ if (b.isUnknown()) {
+ return a;
+ }
+
+ joinedType = Type.widest(a.getType(), b.getType());
+ }
+
+ if (joinedType.isInteger() || joinedType.isLong()) {
+ return createIntegerRange(
+ Math.min(((IntegerRange) a).getMin(), ((IntegerRange) b).getMin()),
+ Math.max(((IntegerRange) a).getMax(), ((IntegerRange) b).getMax()));
+ }
+
+ return createTypeRange(joinedType);
+ }
+
+ /**
+ * Add operation
+ * @param a range of first symbol to be added
+ * @param b range of second symbol to be added
+ * @return resulting range representing the value range after add
+ */
+ public Range add(final Range a, final Range b) {
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final IntegerRange lhs = (IntegerRange)a;
+ final IntegerRange rhs = (IntegerRange)b;
+ if (checkAdd(lhs.getMin(), rhs.getMin()) && checkAdd(lhs.getMax(), rhs.getMax())) {
+ return createIntegerRange(lhs.getMin() + rhs.getMin(), lhs.getMax() + rhs.getMax());
+ }
+ }
+
+ if (a.getType().isNumeric() && b.getType().isNumeric()) {
+ return createNumberRange();
+ }
+
+ return createGenericRange();
+ }
+
+ /**
+ * Sub operation
+ * @param a range of first symbol to be subtracted
+ * @param b range of second symbol to be subtracted
+ * @return resulting range representing the value range after subtraction
+ */
+ public Range sub(final Range a, final Range b) {
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final IntegerRange lhs = (IntegerRange)a;
+ final IntegerRange rhs = (IntegerRange)b;
+ if (checkSub(lhs.getMin(), rhs.getMax()) && checkSub(lhs.getMax(), rhs.getMin())) {
+ return createIntegerRange(lhs.getMin() - rhs.getMax(), lhs.getMax() - rhs.getMin());
+ }
+ }
+
+ if (a.getType().isNumeric() && b.getType().isNumeric()) {
+ return createNumberRange();
+ }
+
+ return createGenericRange();
+ }
+
+ /**
+ * Mul operation
+ * @param a range of first symbol to be multiplied
+ * @param b range of second symbol to be multiplied
+ * @return resulting range representing the value range after multiplication
+ */
+ public Range mul(final Range a, final Range b) {
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final IntegerRange lhs = (IntegerRange)a;
+ final IntegerRange rhs = (IntegerRange)b;
+
+ //ensure that nothing ever overflows or underflows
+ if (checkMul(lhs.getMin(), rhs.getMin()) &&
+ checkMul(lhs.getMax(), rhs.getMax()) &&
+ checkMul(lhs.getMin(), rhs.getMax()) &&
+ checkMul(lhs.getMax(), rhs.getMin())) {
+
+ final List<Long> results =
+ Arrays.asList(
+ lhs.getMin() * rhs.getMin(),
+ lhs.getMin() * rhs.getMax(),
+ lhs.getMax() * rhs.getMin(),
+ lhs.getMax() * rhs.getMax());
+ return createIntegerRange(Collections.min(results), Collections.max(results));
+ }
+ }
+
+ if (a.getType().isNumeric() && b.getType().isNumeric()) {
+ return createNumberRange();
+ }
+
+ return createGenericRange();
+ }
+
+ /**
+ * Neg operation
+ * @param a range of value symbol to be negated
+ * @return resulting range representing the value range after neg
+ */
+ public Range neg(final Range a) {
+ if (a.isIntegerType()) {
+ final IntegerRange rhs = (IntegerRange)a;
+ if (rhs.getMin() != Long.MIN_VALUE && rhs.getMax() != Long.MIN_VALUE) {
+ return createIntegerRange(-rhs.getMax(), -rhs.getMin());
+ }
+ }
+
+ if (a.getType().isNumeric()) {
+ return createNumberRange();
+ }
+
+ return createGenericRange();
+ }
+
+ /**
+ * Bitwise and operation
+ * @param a range of first symbol to be and:ed
+ * @param b range of second symbol to be and:ed
+ * @return resulting range representing the value range after and
+ */
+ public Range and(final Range a, final Range b) {
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final int resultMask = (int) (((IntegerRange)a).getBitMask() & ((IntegerRange)b).getBitMask());
+ if (resultMask >= 0) {
+ return createIntegerRange(0, resultMask);
+ }
+ } else if (a.isUnknown() && b.isIntegerType()) {
+ final long operandMask = ((IntegerRange)b).getBitMask();
+ if (operandMask >= 0) {
+ return createIntegerRange(0, operandMask);
+ }
+ } else if (a.isIntegerType() && b.isUnknown()) {
+ final long operandMask = ((IntegerRange)a).getBitMask();
+ if (operandMask >= 0) {
+ return createIntegerRange(0, operandMask);
+ }
+ }
+
+ return createTypeRange(Type.INT);
+ }
+
+ /**
+ * Bitwise or operation
+ * @param a range of first symbol to be or:ed
+ * @param b range of second symbol to be or:ed
+ * @return resulting range representing the value range after or
+ */
+ public Range or(final Range a, final Range b) {
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask());
+ if (resultMask >= 0) {
+ return createIntegerRange(0, resultMask);
+ }
+ }
+
+ return createTypeRange(Type.INT);
+ }
+
+ /**
+ * Bitwise xor operation
+ * @param a range of first symbol to be xor:ed
+ * @param b range of second symbol to be xor:ed
+ * @return resulting range representing the value range after and
+ */
+ public Range xor(final Range a, final Range b) {
+ if (a.isIntegerConst() && b.isIntegerConst()) {
+ return createRange(((IntegerRange)a).getMin() ^ ((IntegerRange)b).getMin());
+ }
+
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask());
+ if (resultMask >= 0) {
+ return createIntegerRange(0, createIntegerRange(0, resultMask).getBitMask());
+ }
+ }
+ return createTypeRange(Type.INT);
+ }
+
+ /**
+ * Bitwise shl operation
+ * @param a range of first symbol to be shl:ed
+ * @param b range of second symbol to be shl:ed
+ * @return resulting range representing the value range after shl
+ */
+ public Range shl(final Range a, final Range b) {
+ if (b.isIntegerType() && b.isIntegerConst()) {
+ final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
+ final int shift = (int)((IntegerRange) b).getMin() & 0x1f;
+ final int min = (int)left.getMin() << shift;
+ final int max = (int)left.getMax() << shift;
+ if (min >> shift == left.getMin() && max >> shift == left.getMax()) {
+ return createIntegerRange(min, max);
+ }
+ }
+
+ return createTypeRange(Type.INT);
+ }
+
+ /**
+ * Bitwise shr operation
+ * @param a range of first symbol to be shr:ed
+ * @param b range of second symbol to be shr:ed
+ * @return resulting range representing the value range after shr
+ */
+ public Range shr(final Range a, final Range b) {
+ if (b.isIntegerType() && b.isIntegerConst()) {
+ final long shift = ((IntegerRange) b).getMin() & 0x1f;
+ final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
+ if (left.getMin() >= 0) {
+ long min = left.getMin() >>> shift;
+ long max = left.getMax() >>> shift;
+ return createIntegerRange(min, max);
+ } else if (shift >= 1) {
+ return createIntegerRange(0, JSType.MAX_UINT >>> shift);
+ }
+ }
+
+ return createTypeRange(Type.INT);
+ }
+
+ /**
+ * Bitwise sar operation
+ * @param a range of first symbol to be sar:ed
+ * @param b range of second symbol to be sar:ed
+ * @return resulting range representing the value range after sar
+ */
+ public Range sar(final Range a, final Range b) {
+ if (b.isIntegerType() && b.isIntegerConst()) {
+ final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
+ final long shift = ((IntegerRange) b).getMin() & 0x1f;
+ final long min = left.getMin() >> shift;
+ final long max = left.getMax() >> shift;
+ return createIntegerRange(min, max);
+ }
+
+ return createTypeRange(Type.INT);
+ }
+
+ /**
+ * Modulo operation
+ * @param a range of first symbol to the mod operation
+ * @param b range of second symbol to be mod operation
+ * @return resulting range representing the value range after mod
+ */
+ public Range mod(final Range a, final Range b) {
+ if (a.isIntegerType() && b.isIntegerType()) {
+ final IntegerRange rhs = (IntegerRange) b;
+ if (rhs.getMin() > 0 || rhs.getMax() < 0) { // divisor range must not include 0
+ final long absmax = Math.max(Math.abs(rhs.getMin()), Math.abs(rhs.getMax())) - 1;
+ return createIntegerRange(rhs.getMin() > 0 ? 0 : -absmax, rhs.getMax() < 0 ? 0 : +absmax);
+ }
+ }
+ return createTypeRange(Type.NUMBER);
+ }
+
+ /**
+ * Division operation
+ * @param a range of first symbol to the division
+ * @param b range of second symbol to be division
+ * @return resulting range representing the value range after division
+ */
+ public Range div(final Range a, final Range b) {
+ // TODO
+ return createTypeRange(Type.NUMBER);
+ }
+ }
+
+ /**
+ * Simple trace functionality that will log range creation
+ */
+ public static class TraceFunctionality extends Functionality {
+ TraceFunctionality(final DebugLogger log) {
+ super(log);
+ }
+
+ private Range trace(final Range result, final String operation, final Range... operands) {
+ log.fine("range::" + operation + Arrays.toString(operands) + " => " + result);
+ return result;
+ }
+
+ @Override
+ public Range join(final Range a, final Range b) {
+ final Range result = super.join(a, b);
+ if (!a.equals(b)) {
+ trace(result, "join", a, b);
+ }
+ return result;
+ }
+
+ @Override
+ public Range add(final Range a, final Range b) {
+ return trace(super.add(a, b), "add", a, b);
+ }
+
+ @Override
+ public Range sub(final Range a, final Range b) {
+ return trace(super.sub(a, b), "sub", a, b);
+ }
+
+ @Override
+ public Range mul(final Range a, final Range b) {
+ return trace(super.mul(a, b), "mul", a, b);
+ }
+
+ @Override
+ public Range neg(final Range a) {
+ return trace(super.neg(a), "neg", a);
+ }
+
+ @Override
+ public Range and(final Range a, final Range b) {
+ return trace(super.and(a, b), "and", a, b);
+ }
+
+ @Override
+ public Range or(final Range a, final Range b) {
+ return trace(super.or(a, b), "or", a, b);
+ }
+
+ @Override
+ public Range xor(final Range a, final Range b) {
+ return trace(super.xor(a, b), "xor", a, b);
+ }
+
+ @Override
+ public Range shl(final Range a, final Range b) {
+ return trace(super.shl(a, b), "shl", a, b);
+ }
+
+ @Override
+ public Range shr(final Range a, final Range b) {
+ return trace(super.shr(a, b), "shr", a, b);
+ }
+
+ @Override
+ public Range sar(final Range a, final Range b) {
+ return trace(super.sar(a, b), "sar", a, b);
+ }
+
+ @Override
+ public Range mod(final Range a, final Range b) {
+ return trace(super.mod(a, b), "mod", a, b);
+ }
+
+ @Override
+ public Range div(final Range a, final Range b) {
+ return trace(super.div(a, b), "div", a, b);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(getType());
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean isRepresentableAsInt(final double number) {
+ return (int)number == number && !isNegativeZero(number);
+ }
+
+ private static boolean isRepresentableAsLong(final double number) {
+ return (long)number == number && !isNegativeZero(number);
+ }
+
+ private static boolean isNegativeZero(final double number) {
+ return Double.doubleToLongBits(number) == Double.doubleToLongBits(-0.0);
+ }
+}
diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java
index 747793e8..57b0212a 100644
--- a/src/jdk/nashorn/internal/codegen/types/Type.java
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java
@@ -106,23 +106,13 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
Type(final String name, final Class<?> clazz, final int weight, final int slots) {
this.name = name;
this.clazz = clazz;
- this.descriptor = Type.getDescriptor(clazz);
+ this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
this.weight = weight;
assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
this.slots = slots;
}
/**
- * Return an internal descriptor for a type
- *
- * @param type the type
- * @return descriptor string
- */
- public static String getDescriptor(final Class<?> type) {
- return jdk.internal.org.objectweb.asm.Type.getDescriptor(type);
- }
-
- /**
* Get the weight of this type - use this e.g. for sorting method descriptors
* @return the weight
*/
diff --git a/src/jdk/nashorn/internal/ir/AccessNode.java b/src/jdk/nashorn/internal/ir/AccessNode.java
index 28b09a6c..eecc5713 100644
--- a/src/jdk/nashorn/internal/ir/AccessNode.java
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java
@@ -60,7 +60,7 @@ public final class AccessNode extends BaseNode {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterAccessNode(this)) {
return visitor.leaveAccessNode(
setBase(base.accept(visitor)).
@@ -110,7 +110,6 @@ public final class AccessNode extends BaseNode {
return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
}
-
private AccessNode setProperty(final IdentNode property) {
if (this.property == property) {
return this;
diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java
index 61454fef..4afa1945 100644
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java
@@ -59,6 +59,23 @@ public final class BinaryNode extends Node implements Assignment<Node> {
this.rhs = rhs;
}
+ @Override
+ public boolean isComparison() {
+ switch (tokenType()) {
+ case EQ:
+ case EQ_STRICT:
+ case NE:
+ case NE_STRICT:
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/**
* Return the widest possible type for this operation. This is used for compile time
* static type inference
@@ -143,7 +160,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterBinaryNode(this)) {
return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor)));
}
diff --git a/src/jdk/nashorn/internal/ir/Block.java b/src/jdk/nashorn/internal/ir/Block.java
index a0fa9372..71692144 100644
--- a/src/jdk/nashorn/internal/ir/Block.java
+++ b/src/jdk/nashorn/internal/ir/Block.java
@@ -131,7 +131,7 @@ public class Block extends BreakableNode implements Flags<Block> {
* @return new or same node
*/
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterBlock(this)) {
return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements)));
}
diff --git a/src/jdk/nashorn/internal/ir/BreakNode.java b/src/jdk/nashorn/internal/ir/BreakNode.java
index f1b9cb98..2b8fbd83 100644
--- a/src/jdk/nashorn/internal/ir/BreakNode.java
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java
@@ -59,7 +59,7 @@ public final class BreakNode extends Statement {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterBreakNode(this)) {
return visitor.leaveBreakNode(this);
}
diff --git a/src/jdk/nashorn/internal/ir/CallNode.java b/src/jdk/nashorn/internal/ir/CallNode.java
index 46cf4588..7180d9ce 100644
--- a/src/jdk/nashorn/internal/ir/CallNode.java
+++ b/src/jdk/nashorn/internal/ir/CallNode.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir;
import java.util.Collections;
import java.util.List;
+
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -194,7 +195,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @return node or replacement
*/
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCallNode(this)) {
final CallNode newCallNode = (CallNode)visitor.leaveCallNode(
setFunction(function.accept(visitor)).
diff --git a/src/jdk/nashorn/internal/ir/CaseNode.java b/src/jdk/nashorn/internal/ir/CaseNode.java
index 8a438f8f..aae370f3 100644
--- a/src/jdk/nashorn/internal/ir/CaseNode.java
+++ b/src/jdk/nashorn/internal/ir/CaseNode.java
@@ -78,7 +78,7 @@ public final class CaseNode extends Node {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCaseNode(this)) {
final Node newTest = test == null ? null : test.accept(visitor);
final Block newBody = body == null ? null : (Block)body.accept(visitor);
diff --git a/src/jdk/nashorn/internal/ir/CatchNode.java b/src/jdk/nashorn/internal/ir/CatchNode.java
index c4551492..f3818148 100644
--- a/src/jdk/nashorn/internal/ir/CatchNode.java
+++ b/src/jdk/nashorn/internal/ir/CatchNode.java
@@ -42,6 +42,11 @@ public final class CatchNode extends Statement {
/** Catch body. */
private final Block body;
+ private final int flags;
+
+ /** Is this block a synthethic rethrow created by finally inlining? */
+ public static final int IS_SYNTHETIC_RETHROW = 1;
+
/**
* Constructors
*
@@ -51,19 +56,22 @@ public final class CatchNode extends Statement {
* @param exception variable name of exception
* @param exceptionCondition exception condition
* @param body catch body
+ * @param flags flags
*/
- public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
+ public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) {
super(lineNumber, token, finish);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
this.body = body;
+ this.flags = flags;
}
- private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) {
+ private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) {
super(catchNode);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
this.body = body;
+ this.flags = flags;
}
/**
@@ -71,7 +79,7 @@ public final class CatchNode extends Statement {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCatchNode(this)) {
return visitor.leaveCatchNode(
setException((IdentNode)exception.accept(visitor)).
@@ -124,7 +132,7 @@ public final class CatchNode extends Statement {
if (this.exceptionCondition == exceptionCondition) {
return this;
}
- return new CatchNode(this, exception, exceptionCondition, body);
+ return new CatchNode(this, exception, exceptionCondition, body, flags);
}
/**
@@ -144,13 +152,25 @@ public final class CatchNode extends Statement {
if (this.exception == exception) {
return this;
}
- return new CatchNode(this, exception, exceptionCondition, body);
+ return new CatchNode(this, exception, exceptionCondition, body, flags);
}
private CatchNode setBody(final Block body) {
if (this.body == body) {
return this;
}
- return new CatchNode(this, exception, exceptionCondition, body);
+ return new CatchNode(this, exception, exceptionCondition, body, flags);
}
+
+ /**
+ * Is this catch block a non-JavaScript constructor, for example created as
+ * part of the rethrow mechanism of a finally block in Lower? Then we just
+ * pass the exception on and need not unwrap whatever is in the ECMAException
+ * object catch symbol
+ * @return true if a finally synthetic rethrow
+ */
+ public boolean isSyntheticRethrow() {
+ return (flags & IS_SYNTHETIC_RETHROW) == IS_SYNTHETIC_RETHROW;
+ }
+
}
diff --git a/src/jdk/nashorn/internal/ir/ContinueNode.java b/src/jdk/nashorn/internal/ir/ContinueNode.java
index c82813b4..579414a9 100644
--- a/src/jdk/nashorn/internal/ir/ContinueNode.java
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java
@@ -55,7 +55,7 @@ public class ContinueNode extends Statement {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterContinueNode(this)) {
return visitor.leaveContinueNode(this);
}
diff --git a/src/jdk/nashorn/internal/ir/EmptyNode.java b/src/jdk/nashorn/internal/ir/EmptyNode.java
index 9f53a602..aa86f2f8 100644
--- a/src/jdk/nashorn/internal/ir/EmptyNode.java
+++ b/src/jdk/nashorn/internal/ir/EmptyNode.java
@@ -56,7 +56,7 @@ public final class EmptyNode extends Statement {
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterEmptyNode(this)) {
return visitor.leaveEmptyNode(this);
}
diff --git a/src/jdk/nashorn/internal/ir/ExecuteNode.java b/src/jdk/nashorn/internal/ir/ExecuteNode.java
index 300254dd..c696202b 100644
--- a/src/jdk/nashorn/internal/ir/ExecuteNode.java
+++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java
@@ -62,7 +62,7 @@ public final class ExecuteNode extends Statement {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterExecuteNode(this)) {
return visitor.leaveExecuteNode(setExpression(expression.accept(visitor)));
}
diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java
index 3d0ea364..bad38c6a 100644
--- a/src/jdk/nashorn/internal/ir/ForNode.java
+++ b/src/jdk/nashorn/internal/ir/ForNode.java
@@ -86,7 +86,7 @@ public final class ForNode extends LoopNode {
}
@Override
- protected Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ protected Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterForNode(this)) {
return visitor.leaveForNode(
setInit(lc, init == null ? null : init.accept(visitor)).
diff --git a/src/jdk/nashorn/internal/ir/FunctionNode.java b/src/jdk/nashorn/internal/ir/FunctionNode.java
index 2b6d19bf..4c5eebb0 100644
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java
@@ -250,6 +250,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final FunctionNode functionNode,
final long lastToken,
final int flags,
+ final String name,
final Type returnType,
final CompileUnit compileUnit,
final EnumSet<CompilationState> compilationState,
@@ -260,6 +261,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
super(functionNode);
this.flags = flags;
+ this.name = name;
this.returnType = returnType;
this.compileUnit = compileUnit;
this.lastToken = lastToken;
@@ -271,7 +273,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
// the fields below never change - they are final and assigned in constructor
this.source = functionNode.source;
- this.name = functionNode.name;
this.ident = functionNode.ident;
this.namespace = functionNode.namespace;
this.declaredSymbols = functionNode.declaredSymbols;
@@ -280,7 +281,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterFunctionNode(this)) {
return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor)));
}
@@ -315,7 +316,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.snapshot == null) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, null, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
}
/**
@@ -331,7 +332,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (isProgram() || parameters.isEmpty()) {
return this; //never specialize anything that won't be recompiled
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, this, hints));
}
/**
@@ -339,7 +340,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
* @return true if specialization is possible
*/
public boolean canSpecialize() {
- return getFlag(CAN_SPECIALIZE);
+ return snapshot != null && getFlag(CAN_SPECIALIZE);
}
/**
@@ -389,7 +390,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
newState.add(state);
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, newState, body, parameters, snapshot, hints));
}
/**
@@ -410,7 +411,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.hints == hints) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@@ -463,7 +464,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.flags == flags) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
@Override
@@ -529,7 +530,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
/**
- * Get the identifier for this function
+ * Get the identifier for this function, this is its symbol.
* @return the identifier as an IdentityNode
*/
public IdentNode getIdent() {
@@ -572,7 +573,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if(this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@@ -640,7 +641,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.lastToken == lastToken) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@@ -651,6 +652,20 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
return name;
}
+
+ /**
+ * Set the internal name for this function
+ * @param lc lexical context
+ * @param name new name
+ * @return new function node if changed, otherwise the same
+ */
+ public FunctionNode setName(final LexicalContext lc, final String name) {
+ if (this.name.equals(name)) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ }
+
/**
* Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
* functions having with and/or eval blocks are such.
@@ -698,7 +713,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.parameters == parameters) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@@ -762,6 +777,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
this,
lastToken,
flags,
+ name,
Type.widest(this.returnType, returnType.isObject() ?
Type.OBJECT :
returnType),
@@ -801,7 +817,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.compileUnit == compileUnit) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
diff --git a/src/jdk/nashorn/internal/ir/IdentNode.java b/src/jdk/nashorn/internal/ir/IdentNode.java
index 2fb769a9..de197c3c 100644
--- a/src/jdk/nashorn/internal/ir/IdentNode.java
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java
@@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -119,7 +118,7 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIdentNode(this)) {
return visitor.leaveIdentNode(this);
}
diff --git a/src/jdk/nashorn/internal/ir/IfNode.java b/src/jdk/nashorn/internal/ir/IfNode.java
index 7731b302..1b606cb0 100644
--- a/src/jdk/nashorn/internal/ir/IfNode.java
+++ b/src/jdk/nashorn/internal/ir/IfNode.java
@@ -72,7 +72,7 @@ public final class IfNode extends Statement {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIfNode(this)) {
return visitor.leaveIfNode(
setTest(test.accept(visitor)).
diff --git a/src/jdk/nashorn/internal/ir/IndexNode.java b/src/jdk/nashorn/internal/ir/IndexNode.java
index a22c6179..0a9b7db2 100644
--- a/src/jdk/nashorn/internal/ir/IndexNode.java
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java
@@ -56,19 +56,12 @@ public final class IndexNode extends BaseNode {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIndexNode(this)) {
- final Node newBase = base.accept(visitor);
- final Node newIndex = index.accept(visitor);
- final IndexNode newNode;
- if (newBase != base || newIndex != index) {
- newNode = new IndexNode(this, newBase, newIndex, isFunction(), hasCallSiteType());
- } else {
- newNode = this;
- }
- return visitor.leaveIndexNode(newNode);
+ return visitor.leaveIndexNode(
+ setBase(base.accept(visitor)).
+ setIndex(index.accept(visitor)));
}
-
return this;
}
@@ -106,6 +99,13 @@ public final class IndexNode extends BaseNode {
return index;
}
+ private IndexNode setBase(final Node base) {
+ if (this.base == base) {
+ return this;
+ }
+ return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+ }
+
/**
* Set the index expression for this node
* @param index new index expression
diff --git a/src/jdk/nashorn/internal/ir/LabelNode.java b/src/jdk/nashorn/internal/ir/LabelNode.java
index d791f3fa..ad9979ef 100644
--- a/src/jdk/nashorn/internal/ir/LabelNode.java
+++ b/src/jdk/nashorn/internal/ir/LabelNode.java
@@ -67,11 +67,11 @@ public final class LabelNode extends LexicalContextNode {
}
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterLabelNode(this)) {
return visitor.leaveLabelNode(
- setLabel(visitor.getLexicalContext(), (IdentNode)label.accept(visitor)).
- setBody(visitor.getLexicalContext(), (Block)body.accept(visitor)));
+ setLabel(lc, (IdentNode)label.accept(visitor)).
+ setBody(lc, (Block)body.accept(visitor)));
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java
index 13eb0aa8..2ca5ec39 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java
@@ -440,6 +440,23 @@ public class LexicalContext {
}
/**
+ * Check whether the lexical context is currently inside a loop
+ * @return true if inside a loop
+ */
+ public boolean inLoop() {
+ return getCurrentLoop() != null;
+ }
+
+ /**
+ * Returns the loop header of the current loop, or null if not inside a loop
+ * @return loop header
+ */
+ public LoopNode getCurrentLoop() {
+ final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
+ return iter.hasNext() ? iter.next() : null;
+ }
+
+ /**
* Find the breakable node corresponding to this label.
* @param label label to search for, if null the closest breakable node will be returned unconditionally, e.g. a while loop with no label
* @return closest breakable node
@@ -461,8 +478,7 @@ public class LexicalContext {
}
private LoopNode getContinueTo() {
- final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
- return iter.hasNext() ? iter.next() : null;
+ return getCurrentLoop();
}
/**
diff --git a/src/jdk/nashorn/internal/ir/LexicalContextNode.java b/src/jdk/nashorn/internal/ir/LexicalContextNode.java
index 52f62f09..020faf8e 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java
@@ -60,10 +60,10 @@ public abstract class LexicalContextNode extends Statement {
*
* @return new node or same node depending on state change
*/
- protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor);
+ protected abstract Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor);
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
final LexicalContext lc = visitor.getLexicalContext();
lc.push(this);
final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
diff --git a/src/jdk/nashorn/internal/ir/LiteralNode.java b/src/jdk/nashorn/internal/ir/LiteralNode.java
index 4c2f932c..7a59c5fe 100644
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -28,6 +28,7 @@ package jdk.nashorn.internal.ir;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -208,7 +209,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterLiteralNode(this)) {
return visitor.leaveLiteralNode(this);
}
@@ -514,7 +515,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterLiteralNode(this)) {
if (value != null) {
final Node newValue = value.accept(visitor);
@@ -840,7 +841,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterLiteralNode(this)) {
final List<Node> oldValue = Arrays.asList(value);
final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
diff --git a/src/jdk/nashorn/internal/ir/Node.java b/src/jdk/nashorn/internal/ir/Node.java
index 0fb95cc3..4342c2be 100644
--- a/src/jdk/nashorn/internal/ir/Node.java
+++ b/src/jdk/nashorn/internal/ir/Node.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.List;
+
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
@@ -153,6 +154,14 @@ public abstract class Node implements Cloneable {
}
/**
+ * Returns true if this node represents a comparison operator
+ * @return true if comparison
+ */
+ public boolean isComparison() {
+ return false;
+ }
+
+ /**
* For reference copies - ensure that labels in the copy node are unique
* using an appropriate copy constructor
* @param lc lexical context
@@ -167,7 +176,7 @@ public abstract class Node implements Cloneable {
* @param visitor Node visitor.
* @return node the node or its replacement after visitation, null if no further visitations are required
*/
- public abstract Node accept(NodeVisitor visitor);
+ public abstract Node accept(NodeVisitor<? extends LexicalContext> visitor);
@Override
public String toString() {
@@ -329,7 +338,7 @@ public abstract class Node implements Cloneable {
}
//on change, we have to replace the entire list, that's we can't simple do ListIterator.set
- static <T extends Node> List<T> accept(final NodeVisitor visitor, final Class<T> clazz, final List<T> list) {
+ static <T extends Node> List<T> accept(final NodeVisitor<? extends LexicalContext> visitor, final Class<T> clazz, final List<T> list) {
boolean changed = false;
final List<T> newList = new ArrayList<>();
diff --git a/src/jdk/nashorn/internal/ir/ObjectNode.java b/src/jdk/nashorn/internal/ir/ObjectNode.java
index 34069725..8529a1fe 100644
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java
@@ -58,7 +58,7 @@ public final class ObjectNode extends Node {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterObjectNode(this)) {
return visitor.leaveObjectNode(setElements(Node.accept(visitor, Node.class, elements)));
}
diff --git a/src/jdk/nashorn/internal/ir/PropertyNode.java b/src/jdk/nashorn/internal/ir/PropertyNode.java
index 7040d414..8bf6b80f 100644
--- a/src/jdk/nashorn/internal/ir/PropertyNode.java
+++ b/src/jdk/nashorn/internal/ir/PropertyNode.java
@@ -81,7 +81,7 @@ public final class PropertyNode extends Node {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterPropertyNode(this)) {
return visitor.leavePropertyNode(
setKey((PropertyKey)((Node)key).accept(visitor)).
diff --git a/src/jdk/nashorn/internal/ir/ReturnNode.java b/src/jdk/nashorn/internal/ir/ReturnNode.java
index c0091eb4..563d0519 100644
--- a/src/jdk/nashorn/internal/ir/ReturnNode.java
+++ b/src/jdk/nashorn/internal/ir/ReturnNode.java
@@ -86,7 +86,7 @@ public class ReturnNode extends Statement {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterReturnNode(this)) {
if (expression != null) {
return visitor.leaveReturnNode(setExpression(expression.accept(visitor)));
diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java
index 47509be1..540b2eaf 100644
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java
@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -407,7 +408,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterRuntimeNode(this)) {
final List<Node> newArgs = new ArrayList<>();
for (final Node arg : args) {
diff --git a/src/jdk/nashorn/internal/ir/SplitNode.java b/src/jdk/nashorn/internal/ir/SplitNode.java
index ee6e023c..e71cd6bd 100644
--- a/src/jdk/nashorn/internal/ir/SplitNode.java
+++ b/src/jdk/nashorn/internal/ir/SplitNode.java
@@ -81,7 +81,7 @@ public class SplitNode extends LexicalContextNode {
}
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterSplitNode(this)) {
return visitor.leaveSplitNode(setBody(lc, body.accept(visitor)));
}
diff --git a/src/jdk/nashorn/internal/ir/SwitchNode.java b/src/jdk/nashorn/internal/ir/SwitchNode.java
index bfc03108..3790ad51 100644
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java
@@ -100,11 +100,11 @@ public final class SwitchNode extends BreakableNode {
}
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterSwitchNode(this)) {
return visitor.leaveSwitchNode(
- setExpression(visitor.getLexicalContext(), expression.accept(visitor)).
- setCases(visitor.getLexicalContext(), Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex));
+ setExpression(lc, expression.accept(visitor)).
+ setCases(lc, Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex));
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java
index 05495152..d26fe561 100644
--- a/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/src/jdk/nashorn/internal/ir/Symbol.java
@@ -29,6 +29,8 @@ import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
+
+import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
@@ -89,6 +91,9 @@ public final class Symbol implements Comparable<Symbol> {
/** Number of times this symbol is used in code */
private int useCount;
+ /** Range for symbol */
+ private Range range;
+
/** Debugging option - dump info and stack trace when symbols with given names are manipulated */
private static final Set<String> TRACE_SYMBOLS;
private static final Set<String> TRACE_SYMBOLS_STACKTRACE;
@@ -131,6 +136,7 @@ public final class Symbol implements Comparable<Symbol> {
this.type = type;
this.slot = slot;
this.fieldIndex = -1;
+ this.range = Range.createUnknownRange();
trace("CREATE SYMBOL");
}
@@ -157,12 +163,13 @@ public final class Symbol implements Comparable<Symbol> {
private Symbol(final Symbol base, final String name, final int flags) {
this.flags = flags;
- this.name = name;
+ this.name = name;
this.fieldIndex = base.fieldIndex;
- this.slot = base.slot;
- this.type = base.type;
- this.useCount = base.useCount;
+ this.slot = base.slot;
+ this.type = base.type;
+ this.useCount = base.useCount;
+ this.range = base.range;
}
private static String align(final String string, final int max) {
@@ -276,7 +283,7 @@ public final class Symbol implements Comparable<Symbol> {
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
+ final StringBuilder sb = new StringBuilder();
sb.append(name).
append(' ').
@@ -410,6 +417,22 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
+ * Get the range for this symbol
+ * @return range for symbol
+ */
+ public Range getRange() {
+ return range;
+ }
+
+ /**
+ * Set the range for this symbol
+ * @param range range
+ */
+ public void setRange(final Range range) {
+ this.range = range;
+ }
+
+ /**
* Check if this symbol is a function parameter of known
* narrowest type
* @return true if parameter
diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java
index 25ac1a4d..c05e6245 100644
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java
@@ -63,7 +63,7 @@ public final class TernaryNode extends Node {
}
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterTernaryNode(this)) {
final Node newLhs = lhs().accept(visitor);
final Node newRhs = rhs().accept(visitor);
diff --git a/src/jdk/nashorn/internal/ir/ThrowNode.java b/src/jdk/nashorn/internal/ir/ThrowNode.java
index e37302e6..3d33fc77 100644
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java
+++ b/src/jdk/nashorn/internal/ir/ThrowNode.java
@@ -36,6 +36,11 @@ public final class ThrowNode extends Statement {
/** Exception expression. */
private final Node expression;
+ private final int flags;
+
+ /** Is this block a synthethic rethrow created by finally inlining? */
+ public static final int IS_SYNTHETIC_RETHROW = 1;
+
/**
* Constructor
*
@@ -43,15 +48,18 @@ public final class ThrowNode extends Statement {
* @param token token
* @param finish finish
* @param expression expression to throw
+ * @param flags flags
*/
- public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression) {
+ public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression, final int flags) {
super(lineNumber, token, finish);
this.expression = expression;
+ this.flags = flags;
}
- private ThrowNode(final ThrowNode node, final Node expression) {
+ private ThrowNode(final ThrowNode node, final Node expression, final int flags) {
super(node);
this.expression = expression;
+ this.flags = flags;
}
@Override
@@ -64,7 +72,7 @@ public final class ThrowNode extends Statement {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterThrowNode(this)) {
return visitor.leaveThrowNode(setExpression(expression.accept(visitor)));
}
@@ -98,7 +106,17 @@ public final class ThrowNode extends Statement {
if (this.expression == expression) {
return this;
}
- return new ThrowNode(this, expression);
+ return new ThrowNode(this, expression, flags);
+ }
+
+ /**
+ * Is this a throw a synthetic rethrow in a synthetic catch-all block
+ * created when inlining finally statements? In that case we never
+ * wrap whatever is thrown into an ECMAException, just rethrow it.
+ * @return true if synthetic throw node
+ */
+ public boolean isSyntheticRethrow() {
+ return (flags & IS_SYNTHETIC_RETHROW) == IS_SYNTHETIC_RETHROW;
}
}
diff --git a/src/jdk/nashorn/internal/ir/TryNode.java b/src/jdk/nashorn/internal/ir/TryNode.java
index 01ea75c7..6c30118e 100644
--- a/src/jdk/nashorn/internal/ir/TryNode.java
+++ b/src/jdk/nashorn/internal/ir/TryNode.java
@@ -106,7 +106,7 @@ public final class TryNode extends Statement {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterTryNode(this)) {
// Need to do finallybody first for termination analysis. TODO still necessary?
final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor);
diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java
index ed1d8a9b..f9c971ed 100644
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java
@@ -29,7 +29,6 @@ import static jdk.nashorn.internal.parser.TokenType.BIT_NOT;
import static jdk.nashorn.internal.parser.TokenType.CONVERT;
import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -121,7 +120,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterUnaryNode(this)) {
return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
}
diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java
index c28f5456..d4f41d6d 100644
--- a/src/jdk/nashorn/internal/ir/VarNode.java
+++ b/src/jdk/nashorn/internal/ir/VarNode.java
@@ -121,7 +121,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor visitor) {
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterVarNode(this)) {
final IdentNode newName = (IdentNode)name.accept(visitor);
final Node newInit = init == null ? null : init.accept(visitor);
diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java
index c52209fc..c2d05b3d 100644
--- a/src/jdk/nashorn/internal/ir/WhileNode.java
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java
@@ -75,7 +75,7 @@ public final class WhileNode extends LoopNode {
}
@Override
- protected Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ protected Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterWhileNode(this)) {
if (isDoWhile()) {
return visitor.leaveWhileNode(
diff --git a/src/jdk/nashorn/internal/ir/WithNode.java b/src/jdk/nashorn/internal/ir/WithNode.java
index e069ff5e..387659b2 100644
--- a/src/jdk/nashorn/internal/ir/WithNode.java
+++ b/src/jdk/nashorn/internal/ir/WithNode.java
@@ -64,7 +64,7 @@ public final class WithNode extends LexicalContextNode {
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterWithNode(this)) {
return visitor.leaveWithNode(
setExpression(lc, expression.accept(visitor)).
diff --git a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
index 177fcf95..4415ebd7 100644
--- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
+++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
@@ -45,6 +45,7 @@ import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@@ -74,7 +75,8 @@ import jdk.nashorn.internal.runtime.Source;
/**
* This IR writer produces a JSON string that represents AST as a JSON string.
*/
-public final class JSONWriter extends NodeVisitor {
+public final class JSONWriter extends NodeVisitor<LexicalContext> {
+
/**
* Returns AST as JSON compatible string.
*
@@ -867,7 +869,8 @@ public final class JSONWriter extends NodeVisitor {
// Internals below
private JSONWriter(final boolean includeLocation) {
- this.buf = new StringBuilder();
+ super(new LexicalContext());
+ this.buf = new StringBuilder();
this.includeLocation = includeLocation;
}
@@ -963,7 +966,7 @@ public final class JSONWriter extends NodeVisitor {
objectStart("loc");
// source name
- final Source src = getLexicalContext().getCurrentFunction().getSource();
+ final Source src = lc.getCurrentFunction().getSource();
property("source", src.getName());
comma();
diff --git a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index 3ac50067..2e2368b1 100644
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -36,6 +36,7 @@ import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
@@ -53,7 +54,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
*
* see the flags --print-parse and --print-lower-parse
*/
-public final class PrintVisitor extends NodeVisitor {
+public final class PrintVisitor extends NodeVisitor<LexicalContext> {
/** Tab width */
private static final int TABWIDTH = 4;
@@ -84,6 +85,7 @@ public final class PrintVisitor extends NodeVisitor {
* @param printLineNumbers should line number nodes be included in the output?
*/
public PrintVisitor(final boolean printLineNumbers) {
+ super(new LexicalContext());
this.EOLN = System.lineSeparator();
this.sb = new StringBuilder();
this.printLineNumbers = printLineNumbers;
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 2beba46c..1791f92b 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -32,21 +32,15 @@ import jdk.nashorn.internal.ir.UnaryNode;
/**
* Like NodeVisitor but navigating further into operators.
+ * @param <T> Lexical context class for this NodeOperatorVisitor
*/
-public class NodeOperatorVisitor extends NodeVisitor {
- /**
- * Constructor
- */
- public NodeOperatorVisitor() {
- super();
- }
-
+public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T> {
/**
* Constructor
*
* @param lc a custom lexical context
*/
- public NodeOperatorVisitor(final LexicalContext lc) {
+ public NodeOperatorVisitor(final T lc) {
super(lc);
}
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
index 8c807df7..d8a21a64 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
@@ -60,23 +60,18 @@ import jdk.nashorn.internal.ir.WithNode;
/**
* Visitor used to navigate the IR.
+ * @param <T> lexical context class used by this visitor
*/
-public abstract class NodeVisitor {
- private final LexicalContext lc;
-
- /**
- * Constructor
- */
- public NodeVisitor() {
- this(new LexicalContext());
- }
+public abstract class NodeVisitor<T extends LexicalContext> {
+ /** lexical context in use */
+ protected final T lc;
/**
* Constructor
*
* @param lc a custom lexical context
*/
- public NodeVisitor(final LexicalContext lc) {
+ public NodeVisitor(final T lc) {
this.lc = lc;
}
@@ -84,7 +79,7 @@ public abstract class NodeVisitor {
* Get the lexical context of this node visitor
* @return lexical context
*/
- public LexicalContext getLexicalContext() {
+ public T getLexicalContext() {
return lc;
}
diff --git a/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/src/jdk/nashorn/internal/objects/ArrayBufferView.java
index a442a387..d85b31cb 100644
--- a/src/jdk/nashorn/internal/objects/ArrayBufferView.java
+++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java
@@ -59,11 +59,6 @@ abstract class ArrayBufferView extends ScriptObject {
}
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
- public static Object BYTES_PER_ELEMENT(final Object self) {
- return ((ArrayBufferView)self).bytesPerElement();
- }
-
- @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static Object buffer(final Object self) {
return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).buffer;
}
diff --git a/src/jdk/nashorn/internal/objects/DateParser.java b/src/jdk/nashorn/internal/objects/DateParser.java
index 544525b1..b66d3dc9 100644
--- a/src/jdk/nashorn/internal/objects/DateParser.java
+++ b/src/jdk/nashorn/internal/objects/DateParser.java
@@ -32,6 +32,7 @@ import static java.lang.Character.SPACE_SEPARATOR;
import static java.lang.Character.UPPERCASE_LETTER;
import java.util.HashMap;
+import java.util.Locale;
/**
* JavaScript date parser. This class first tries to parse a date string
@@ -486,7 +487,7 @@ public class DateParser {
while (pos < limit && isAsciiLetter(string.charAt(pos))) {
pos++;
}
- final String key = string.substring(start, pos).toLowerCase();
+ final String key = string.substring(start, pos).toLowerCase(Locale.ENGLISH);
final Name name = names.get(key);
// then advance to end of name
while (pos < length && isAsciiLetter(string.charAt(pos))) {
@@ -683,7 +684,7 @@ public class DateParser {
Name(final String name, final int type, final int value) {
assert name != null;
- assert name.equals(name.toLowerCase());
+ assert name.equals(name.toLowerCase(Locale.ENGLISH));
this.name = name;
// use first three characters as lookup key
diff --git a/src/jdk/nashorn/internal/objects/NativeArguments.java b/src/jdk/nashorn/internal/objects/NativeArguments.java
index afc2b57e..efab674b 100644
--- a/src/jdk/nashorn/internal/objects/NativeArguments.java
+++ b/src/jdk/nashorn/internal/objects/NativeArguments.java
@@ -603,6 +603,11 @@ public final class NativeArguments extends ScriptObject {
}
}
+ @Override
+ public Object getLength() {
+ return length;
+ }
+
private Object getArgumentsLength() {
return length;
}
diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java
index c9a71b57..6f9fbcec 100644
--- a/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -754,25 +754,11 @@ public final class NativeArray extends ScriptObject {
final Object obj = Global.toObject(self);
final ScriptObject sobj = (ScriptObject)obj;
final long len = JSType.toUint32(sobj.getLength());
- final double startNum = JSType.toNumber(start);
- final long relativeStartUint32 = JSType.toUint32(startNum);
- final long relativeStart = JSType.toInteger(startNum);
-
- long k = relativeStart < 0 ?
- Math.max(len + relativeStart, 0) :
- Math.min(
- Math.max(relativeStartUint32, relativeStart),
- len);
-
- final double endNum = (end == ScriptRuntime.UNDEFINED)? Double.NaN : JSType.toNumber(end);
- final long relativeEndUint32 = (end == ScriptRuntime.UNDEFINED)? len : JSType.toUint32(endNum);
- final long relativeEnd = (end == ScriptRuntime.UNDEFINED)? len : JSType.toInteger(endNum);
-
- final long finale = relativeEnd < 0 ?
- Math.max(len + relativeEnd, 0) :
- Math.min(
- Math.max(relativeEndUint32, relativeEnd),
- len);
+ final long relativeStart = JSType.toLong(start);
+ final long relativeEnd = (end == ScriptRuntime.UNDEFINED) ? len : JSType.toLong(end);
+
+ long k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
+ final long finale = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
if (k >= finale) {
return new NativeArray(0);
@@ -909,21 +895,10 @@ public final class NativeArray extends ScriptObject {
final ScriptObject sobj = (ScriptObject)obj;
final boolean strict = Global.isStrict();
final long len = JSType.toUint32(sobj.getLength());
- final double startNum = JSType.toNumber(start);
- final long relativeStartUint32 = JSType.toUint32(startNum);
- final long relativeStart = JSType.toInteger(startNum);
-
- //TODO: workaround overflow of relativeStart for start > Integer.MAX_VALUE
- final long actualStart = relativeStart < 0 ?
- Math.max(len + relativeStart, 0) :
- Math.min(
- Math.max(relativeStartUint32, relativeStart),
- len);
-
- final long actualDeleteCount =
- Math.min(
- Math.max(JSType.toInteger(deleteCount), 0),
- len - actualStart);
+ final long relativeStart = JSType.toLong(start);
+
+ final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
+ final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart);
final NativeArray array = new NativeArray(actualDeleteCount);
diff --git a/src/jdk/nashorn/internal/objects/NativeDate.java b/src/jdk/nashorn/internal/objects/NativeDate.java
index c97514a3..fa2c9d17 100644
--- a/src/jdk/nashorn/internal/objects/NativeDate.java
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java
@@ -770,7 +770,7 @@ public final class NativeDate extends ScriptObject {
nd.setTime(NaN);
return nd.getTime();
}
- int yearInt = JSType.toInteger(yearNum);
+ int yearInt = (int)yearNum;
if (0 <= yearInt && yearInt <= 99) {
yearInt += 1900;
}
diff --git a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
index 98db34ba..d59a4d6f 100644
--- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -38,7 +40,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Float32Array")
public final class NativeFloat32Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 4;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 4;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
index e2ce6247..0f10a867 100644
--- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -38,7 +40,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Float64Array")
public final class NativeFloat64Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 8;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 8;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/src/jdk/nashorn/internal/objects/NativeInt16Array.java
index c5951d91..d6c5349e 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -37,7 +39,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Int16Array")
public final class NativeInt16Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 2;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 2;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/src/jdk/nashorn/internal/objects/NativeInt32Array.java
index 486e7a61..a814eb61 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -37,7 +39,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Int32Array")
public final class NativeInt32Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 4;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 4;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/src/jdk/nashorn/internal/objects/NativeInt8Array.java
index 9ad7d24c..ec43bfc8 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -37,7 +39,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Int8Array")
public final class NativeInt8Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 1;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 1;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeJava.java b/src/jdk/nashorn/internal/objects/NativeJava.java
index 5faec5ea..207be979 100644
--- a/src/jdk/nashorn/internal/objects/NativeJava.java
+++ b/src/jdk/nashorn/internal/objects/NativeJava.java
@@ -30,6 +30,8 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.reflect.Array;
import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.internal.objects.annotations.Attribute;
@@ -37,6 +39,7 @@ import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.ListAdapter;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
@@ -240,39 +243,56 @@ public final class NativeJava {
}
/**
- * Given a JavaScript array and a Java type, returns a Java array with the same initial contents, and with the
- * specified component type. Example:
+ * Given a script object and a Java type, converts the script object into the desired Java type. Currently it
+ * performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example:
* <pre>
* var anArray = [1, "13", false]
- * var javaIntArray = Java.toJavaArray(anArray, "int")
+ * var javaIntArray = Java.to(anArray, "int[]")
* print(javaIntArray[0]) // prints 1
* print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
* print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
* </pre>
* @param self not used
- * @param objArray the JavaScript array. Can be null.
- * @param objType either a {@link #type(Object, Object) type object} or a String describing the component type of
- * the Java array to create. Can not be null. If undefined, Object is assumed (allowing the argument to be omitted).
- * @return a Java array with the copy of JavaScript array's contents, converted to the appropriate Java component
- * type. Returns null if objArray is null.
+ * @param obj the script object. Can be null.
+ * @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java
+ * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be
+ * omitted).
+ * @return a Java object whose value corresponds to the original script object's value. Specifically, for array
+ * target types, returns a Java array of the same type with contents converted to the array's component type. Does
+ * not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper
+ * around the object, see {@link ListAdapter} for details. Returns null if obj is null.
* @throws ClassNotFoundException if the class described by objType is not found
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object toJavaArray(final Object self, final Object objArray, final Object objType) throws ClassNotFoundException {
- final StaticClass componentType =
- objType instanceof StaticClass ?
- (StaticClass)objType :
- objType == UNDEFINED ?
- StaticClass.forClass(Object.class) :
- type(objType);
-
- if (objArray == null) {
+ public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException {
+ if (obj == null) {
return null;
}
- Global.checkObject(objArray);
+ Global.checkObject(obj);
+
+ final Class<?> targetClass;
+ if(objType == UNDEFINED) {
+ targetClass = Object[].class;
+ } else {
+ final StaticClass targetType;
+ if(objType instanceof StaticClass) {
+ targetType = (StaticClass)objType;
+ } else {
+ targetType = type(objType);
+ }
+ targetClass = targetType.getRepresentedClass();
+ }
+
+ if(targetClass.isArray()) {
+ return ((ScriptObject)obj).getArray().asArrayOfType(targetClass.getComponentType());
+ }
+
+ if(targetClass == List.class || targetClass == Deque.class) {
+ return new ListAdapter((ScriptObject)obj);
+ }
- return ((ScriptObject)objArray).getArray().asArrayOfType(componentType.getRepresentedClass());
+ throw typeError("unsupported.java.to.type", targetClass.getName());
}
/**
@@ -283,7 +303,7 @@ public final class NativeJava {
* <pre>
* var File = Java.type("java.io.File")
* var listHomeDir = new File("~").listFiles()
- * var jsListHome = Java.toJavaScriptArray(listHomeDir)
+ * var jsListHome = Java.from(listHomeDir)
* var jpegModifiedDates = jsListHome
* .filter(function(val) { return val.getName().endsWith(".jpg") })
* .map(function(val) { return val.lastModified() })
@@ -294,7 +314,7 @@ public final class NativeJava {
* null.
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object toJavaScriptArray(final Object self, final Object objArray) {
+ public static Object from(final Object self, final Object objArray) {
if (objArray == null) {
return null;
} else if (objArray instanceof Collection) {
diff --git a/src/jdk/nashorn/internal/objects/NativeMath.java b/src/jdk/nashorn/internal/objects/NativeMath.java
index 7f330efc..50a2d864 100644
--- a/src/jdk/nashorn/internal/objects/NativeMath.java
+++ b/src/jdk/nashorn/internal/objects/NativeMath.java
@@ -611,13 +611,11 @@ public final class NativeMath extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object round(final Object self, final Object x) {
- if (GlobalFunctions.isNaN(self, x)) {
- return Double.NaN;
- } else if (!GlobalFunctions.isFinite(self, x)) {
- return x;
+ final double d = JSType.toNumber(x);
+ if (Math.getExponent(d) >= 52) {
+ return d;
}
-
- return Math.round(JSType.toNumber(x));
+ return Math.copySign(Math.floor(d + 0.5), d);
}
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java
index 2715d4f4..df4aa1bf 100644
--- a/src/jdk/nashorn/internal/objects/NativeString.java
+++ b/src/jdk/nashorn/internal/objects/NativeString.java
@@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -630,17 +631,24 @@ public final class NativeString extends ScriptObject {
final String str = checkObjectToString(self);
final String searchStr = JSType.toString(search);
+ final int length = str.length();
- int from;
+ int end;
if (pos == UNDEFINED) {
- from = str.length();
+ end = length;
} else {
final double numPos = JSType.toNumber(pos);
- from = !Double.isNaN(numPos) ? (int)numPos : (int)Double.POSITIVE_INFINITY;
+ end = Double.isNaN(numPos) ? length : (int)numPos;
+ if (end < 0) {
+ end = 0;
+ } else if (end > length) {
+ end = length;
+ }
}
- return str.lastIndexOf(searchStr, from);
+
+ return str.lastIndexOf(searchStr, end);
}
/**
@@ -997,7 +1005,7 @@ public final class NativeString extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object toLowerCase(final Object self) {
- return checkObjectToString(self).toLowerCase();
+ return checkObjectToString(self).toLowerCase(Locale.ROOT);
}
/**
@@ -1017,7 +1025,7 @@ public final class NativeString extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object toUpperCase(final Object self) {
- return checkObjectToString(self).toUpperCase();
+ return checkObjectToString(self).toUpperCase(Locale.ROOT);
}
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/src/jdk/nashorn/internal/objects/NativeUint16Array.java
index 740bb394..13ce3474 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -37,7 +39,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Uint16Array")
public final class NativeUint16Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 2;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 2;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk/nashorn/internal/objects/NativeUint32Array.java
index 9be01312..fb45c282 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -38,7 +40,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Uint32Array")
public final class NativeUint32Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 4;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 4;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteBegin, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/src/jdk/nashorn/internal/objects/NativeUint8Array.java
index 7d506c1d..6cebcdb9 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -37,7 +39,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Uint8Array")
public final class NativeUint8Array extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 1;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 1;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
index e3bacc2b..de171caa 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
@@ -28,7 +28,9 @@ package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
@@ -38,7 +40,12 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
*/
@ScriptClass("Uint8ClampedArray")
public final class NativeUint8ClampedArray extends ArrayBufferView {
- private static final int BYTES_PER_ELEMENT = 1;
+ /**
+ * The size in bytes of each element in the array.
+ */
+ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
+ public static final int BYTES_PER_ELEMENT = 1;
+
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
@Override
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index efb7a391..03f65b86 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -1537,7 +1537,7 @@ loop:
endOfLine();
- appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
+ appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, 0));
}
/**
@@ -1597,7 +1597,7 @@ loop:
try {
// Get CATCH body.
final Block catchBody = getBlock(true);
- final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody);
+ final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, 0);
appendStatement(catchNode);
} finally {
catchBlock = restoreBlock(catchBlock);
diff --git a/src/jdk/nashorn/internal/parser/TokenType.java b/src/jdk/nashorn/internal/parser/TokenType.java
index 657c8c46..92f3ad74 100644
--- a/src/jdk/nashorn/internal/parser/TokenType.java
+++ b/src/jdk/nashorn/internal/parser/TokenType.java
@@ -25,6 +25,7 @@
package jdk.nashorn.internal.parser;
+import java.util.Locale;
import static jdk.nashorn.internal.parser.TokenKind.BINARY;
import static jdk.nashorn.internal.parser.TokenKind.BRACKET;
import static jdk.nashorn.internal.parser.TokenKind.FUTURE;
@@ -249,7 +250,7 @@ public enum TokenType {
}
public String getNameOrType() {
- return name == null ? super.name().toLowerCase() : name;
+ return name == null ? super.name().toLowerCase(Locale.ENGLISH) : name;
}
public TokenType getNext() {
diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index 38effdaf..13e9e1ce 100644
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -75,7 +75,23 @@ public class AccessorProperty extends Property {
private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
- private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
+ private static final MethodHandle SPILL_ELEMENT_GETTER;
+ private static final MethodHandle SPILL_ELEMENT_SETTER;
+
+ private static final int SPILL_CACHE_SIZE = 8;
+ private static final MethodHandle[] SPILL_ACCESSORS = new MethodHandle[SPILL_CACHE_SIZE * 2];
+
+ static {
+ for (int i = 0; i < NOOF_TYPES; i++) {
+ final Type type = ACCESSOR_TYPES.get(i);
+ ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
+ ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
+ }
+
+ final MethodHandle spillGetter = MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class);
+ SPILL_ELEMENT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, spillGetter);
+ SPILL_ELEMENT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, spillGetter);
+ }
/** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
private MethodHandle primitiveGetter;
@@ -96,14 +112,6 @@ public class AccessorProperty extends Property {
*/
private Class<?> currentType;
- static {
- for (int i = 0; i < NOOF_TYPES; i++) {
- final Type type = ACCESSOR_TYPES.get(i);
- ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
- ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
- }
- }
-
/**
* Delegate constructor. This is used when adding properties to the Global scope, which
* is necessary for outermost levels in a script (the ScriptObject is represented by
@@ -114,19 +122,31 @@ public class AccessorProperty extends Property {
* @param delegate delegate script object to rebind receiver to
*/
public AccessorProperty(final AccessorProperty property, final ScriptObject delegate) {
- this(property);
-
- this.getters = new MethodHandle[NOOF_TYPES];
+ super(property);
- this.primitiveGetter = bindTo(primitiveGetter, delegate);
- this.primitiveSetter = bindTo(primitiveSetter, delegate);
- this.objectGetter = bindTo(objectGetter, delegate);
- this.objectSetter = bindTo(objectSetter, delegate);
+ this.primitiveGetter = bindTo(property.primitiveGetter, delegate);
+ this.primitiveSetter = bindTo(property.primitiveSetter, delegate);
+ this.objectGetter = bindTo(property.objectGetter, delegate);
+ this.objectSetter = bindTo(property.objectSetter, delegate);
setCurrentType(property.getCurrentType());
}
/**
+ * Constructor for spill properties. Array getters and setters will be created on demand.
+ *
+ * @param key the property key
+ * @param flags the property flags
+ * @param slot spill slot
+ */
+ public AccessorProperty(final String key, final int flags, final int slot) {
+ super(key, flags, slot);
+ assert (flags & IS_SPILL) == IS_SPILL;
+
+ setCurrentType(Object.class);
+ }
+
+ /**
* Constructor. Similar to the constructor with both primitive getters and setters, the difference
* here being that only one getter and setter (setter is optional for non writable fields) is given
* to the constructor, and the rest are created from those. Used e.g. by Nasgen classes
@@ -268,7 +288,40 @@ public class AccessorProperty extends Property {
}
@Override
+ protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
+ if (isSpill()) {
+ self.spill[getSlot()] = value;
+ } else {
+ try {
+ getSetter(Object.class, self.getMap()).invokeExact((Object)self, value);
+ } catch (final Error|RuntimeException e) {
+ throw e;
+ } catch (final Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
+ if (isSpill()) {
+ return self.spill[getSlot()];
+ }
+
+ try {
+ return getGetter(Object.class).invokeExact((Object)self);
+ } catch (final Error|RuntimeException e) {
+ throw e;
+ } catch (final Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
public MethodHandle getGetter(final Class<?> type) {
+ if (isSpill() && objectGetter == null) {
+ objectGetter = getSpillGetter();
+ }
final int i = getAccessorTypeIndex(type);
if (getters[i] == null) {
getters[i] = debug(
@@ -284,7 +337,7 @@ public class AccessorProperty extends Property {
"get");
}
- return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i];
+ return getters[i];
}
private Property getWiderProperty(final Class<?> type) {
@@ -313,6 +366,9 @@ public class AccessorProperty extends Property {
}
private MethodHandle generateSetter(final Class<?> forType, final Class<?> type) {
+ if (isSpill() && objectSetter == null) {
+ objectSetter = getSpillSetter();
+ }
MethodHandle mh = createSetter(forType, type, primitiveSetter, objectSetter);
mh = MH.asType(mh, ACCESSOR_SETTER_TYPES[getAccessorTypeIndex(type)]); //has to be the case for invokeexact to work in ScriptObject
mh = debug(mh, currentType, type, "set");
@@ -343,7 +399,7 @@ public class AccessorProperty extends Property {
mh = generateSetter(forType, type);
}
- return isSpill() ? MH.filterArguments(mh, 0, SPILLGETTER) : mh;
+ return mh;
}
@Override
@@ -363,6 +419,30 @@ public class AccessorProperty extends Property {
setCurrentType(newType);
}
+ private MethodHandle getSpillGetter() {
+ final int slot = getSlot();
+ MethodHandle getter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2] : null;
+ if (getter == null) {
+ getter = MH.asType(MH.insertArguments(SPILL_ELEMENT_GETTER, 1, slot), Lookup.GET_OBJECT_TYPE);
+ if (slot < SPILL_CACHE_SIZE) {
+ SPILL_ACCESSORS[slot * 2] = getter;
+ }
+ }
+ return getter;
+ }
+
+ private MethodHandle getSpillSetter() {
+ final int slot = getSlot();
+ MethodHandle setter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2 + 1] : null;
+ if (setter == null) {
+ setter = MH.asType(MH.insertArguments(SPILL_ELEMENT_SETTER, 1, slot), Lookup.SET_OBJECT_TYPE);
+ if (slot < SPILL_CACHE_SIZE) {
+ SPILL_ACCESSORS[slot * 2 + 1] = setter;
+ }
+ }
+ return setter;
+ }
+
private static void finest(final String str) {
if (DEBUG_FIELDS) {
LOG.finest(str);
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
index d36f216c..afa3657c 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
@@ -35,21 +35,27 @@ import jdk.nashorn.internal.codegen.types.Type;
*/
final class CompiledFunction implements Comparable<CompiledFunction> {
+ /** The method type may be more specific than the invoker, if. e.g.
+ * the invoker is guarded, and a guard with a generic object only
+ * fallback, while the target is more specific, we still need the
+ * more specific type for sorting */
+ private final MethodType type;
private final MethodHandle invoker;
private MethodHandle constructor;
- CompiledFunction(final MethodHandle invoker) {
- this(invoker, null);
+ CompiledFunction(final MethodType type, final MethodHandle invoker) {
+ this(type, invoker, null);
}
- CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
- this.invoker = invoker;
- this.constructor = constructor; //isConstructor
+ CompiledFunction(final MethodType type, final MethodHandle invoker, final MethodHandle constructor) {
+ this.type = type;
+ this.invoker = invoker;
+ this.constructor = constructor;
}
@Override
public String toString() {
- return "<invoker=" + invoker + " ctor=" + constructor + ">";
+ return "<callSiteType= " + type + " invoker=" + invoker + " ctor=" + constructor + ">";
}
MethodHandle getInvoker() {
@@ -69,7 +75,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
}
MethodType type() {
- return invoker.type();
+ return type;
}
@Override
@@ -103,8 +109,8 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
return weight() > o.weight();
}
- boolean moreGenericThan(final MethodType type) {
- return weight() > weight(type);
+ boolean moreGenericThan(final MethodType mt) {
+ return weight() > weight(mt);
}
/**
@@ -112,15 +118,15 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
* It is compatible if the types are narrower than the invocation type so that
* a semantically equivalent linkage can be performed.
*
- * @param typesc
+ * @param mt type to check against
* @return
*/
- boolean typeCompatible(final MethodType type) {
- final Class<?>[] wantedParams = type.parameterArray();
+ boolean typeCompatible(final MethodType mt) {
+ final Class<?>[] wantedParams = mt.parameterArray();
final Class<?>[] existingParams = type().parameterArray();
//if we are not examining a varargs type, the number of parameters must be the same
- if (wantedParams.length != existingParams.length && !isVarArgsType(type)) {
+ if (wantedParams.length != existingParams.length && !isVarArgsType(mt)) {
return false;
}
diff --git a/src/jdk/nashorn/internal/runtime/DebugLogger.java b/src/jdk/nashorn/internal/runtime/DebugLogger.java
index dda24bbf..fa0dbede 100644
--- a/src/jdk/nashorn/internal/runtime/DebugLogger.java
+++ b/src/jdk/nashorn/internal/runtime/DebugLogger.java
@@ -35,7 +35,6 @@ import jdk.nashorn.internal.runtime.options.Options;
*/
public final class DebugLogger {
- @SuppressWarnings("NonConstantLogger")
private final Logger logger;
private final boolean isEnabled;
diff --git a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
index ed54b2e9..469245f1 100644
--- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
@@ -78,9 +78,9 @@ public final class FinalScriptFunctionData extends ScriptFunctionData {
//only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
//is too conservative a check. However, isConstructor(mh) always implies isConstructor param
assert isConstructor();
- code.add(new CompiledFunction(MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
+ code.add(new CompiledFunction(mh.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
} else {
- code.add(new CompiledFunction(mh));
+ code.add(new CompiledFunction(mh.type(), mh));
}
}
diff --git a/src/jdk/nashorn/internal/runtime/FindProperty.java b/src/jdk/nashorn/internal/runtime/FindProperty.java
index 903d1d5d..16165fe9 100644
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java
@@ -153,5 +153,24 @@ public final class FindProperty {
return prototype.isScope();
}
+ /**
+ * Get the property value from self as object.
+ *
+ * @return the property value
+ */
+ public Object getObjectValue() {
+ return property.getObjectValue(getGetterReceiver(), getOwner());
+ }
+
+ /**
+ * Set the property value in self.
+ *
+ * @param value the new value
+ * @param strict strict flag
+ */
+ public void setObjectValue(final Object value, final boolean strict) {
+ property.setObjectValue(getSetterReceiver(), getOwner(), value, strict);
+ }
+
}
diff --git a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
index 91011533..98b79150 100644
--- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
@@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.util.Locale;
/**
* Utilities used by Global class.
@@ -373,10 +374,10 @@ loop:
} else if (ch < 256) {
sb.append('%');
final byte b = (byte)ch;
- sb.append(Integer.toHexString(b & 0xFF).toUpperCase());
+ sb.append(Integer.toHexString(b & 0xFF).toUpperCase(Locale.ENGLISH));
} else {
sb.append("%u");
- sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase());
+ sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase(Locale.ENGLISH));
}
}
diff --git a/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/src/jdk/nashorn/internal/runtime/JSONFunctions.java
index 6106a314..ed4d8653 100644
--- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java
@@ -36,6 +36,8 @@ import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.parser.JSONParser;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
/**
* Utilities used by "JSON" object implementation.
@@ -94,7 +96,7 @@ public final class JSONFunctions {
if (reviver instanceof ScriptFunction) {
assert global instanceof GlobalObject;
final ScriptObject root = ((GlobalObject)global).newObject();
- root.set("", unfiltered, root.isStrictContext());
+ root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered);
return walk(root, "", (ScriptFunction)reviver);
}
return unfiltered;
@@ -115,7 +117,7 @@ public final class JSONFunctions {
if (newElement == ScriptRuntime.UNDEFINED) {
valueObj.delete(key, strict);
} else {
- valueObj.set(key, newElement, strict);
+ setPropertyValue(valueObj, key, newElement, strict);
}
}
}
@@ -175,7 +177,9 @@ public final class JSONFunctions {
final PropertyNode pNode = (PropertyNode) elem;
final Node valueNode = pNode.getValue();
- object.set(pNode.getKeyName(), convertNode(global, valueNode), strict);
+ final String name = pNode.getKeyName();
+ final Object value = convertNode(global, valueNode);
+ setPropertyValue(object, name, value, strict);
}
return object;
@@ -188,6 +192,21 @@ public final class JSONFunctions {
}
}
+ // add a new property if does not exist already, or else set old property
+ private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value, final boolean strict) {
+ final int index = getArrayIndexNoThrow(name);
+ if (isValidArrayIndex(index)) {
+ // array index key
+ sobj.defineOwnProperty(index, value);
+ } else if (sobj.getMap().findProperty(name) != null) {
+ // pre-existing non-inherited property, call set
+ sobj.set(name, value, strict);
+ } else {
+ // add new property
+ sobj.addOwnProperty(name, Property.WRITABLE_ENUMERABLE_CONFIGURABLE, value);
+ }
+ }
+
// does the given IR node represent a numeric array?
private static boolean isNumericArray(final Node[] values) {
for (final Node node : values) {
diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java
index e972a99e..8f1f1e9e 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import java.util.Locale;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.parser.Lexer;
@@ -111,7 +112,7 @@ public enum JSType {
*/
public final String typeName() {
// For NULL, "object" has to be returned!
- return ((this == NULL) ? OBJECT : this).name().toLowerCase();
+ return ((this == NULL) ? OBJECT : this).name().toLowerCase(Locale.ENGLISH);
}
/**
@@ -565,8 +566,11 @@ public enum JSType {
}
/**
- * JavaScript compliant Object to integer conversion
- * See ECMA 9.4 ToInteger
+ * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
+ *
+ * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE}
+ * for double values that exceed the int range, including positive and negative Infinity. It is the
+ * caller's responsibility to handle such values correctly.</p>
*
* @param obj an object
* @return an integer
@@ -576,8 +580,11 @@ public enum JSType {
}
/**
- * JavaScript compliant Object to long conversion
- * See ECMA 9.4 ToInteger
+ * JavaScript compliant Object to long conversion. See ECMA 9.4 ToInteger
+ *
+ * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE}
+ * for double values that exceed the long range, including positive and negative Infinity. It is the
+ * caller's responsibility to handle such values correctly.</p>
*
* @param obj an object
* @return a long
diff --git a/src/jdk/nashorn/internal/runtime/ListAdapter.java b/src/jdk/nashorn/internal/runtime/ListAdapter.java
new file mode 100644
index 00000000..cc99cd12
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java
@@ -0,0 +1,337 @@
+package jdk.nashorn.internal.runtime;
+
+import java.util.AbstractList;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.RandomAccess;
+import jdk.nashorn.internal.runtime.linker.InvokeByName;
+
+/**
+ * An adapter that can wrap any ECMAScript Array-like object (that adheres to the array rules for the property
+ * {@code length} and having conforming {@code push}, {@code pop}, {@code shift}, {@code unshift}, and {@code splice}
+ * methods) and expose it as both a Java list and double-ended queue. While script arrays aren't necessarily efficient
+ * as dequeues, it's still slightly more efficient to be able to translate dequeue operations into pushes, pops, shifts,
+ * and unshifts, than to blindly translate all list's add/remove operations into splices. Also, it is conceivable that a
+ * custom script object that implements an Array-like API can have a background data representation that is optimized
+ * for dequeue-like access. Note that with ECMAScript arrays, {@code push} and {@pop} operate at the end of the array,
+ * while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue {@link #push(Object)}
+ * and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script operations respectively,
+ * while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and {@code pop}.
+ */
+public class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
+ // These add to the back and front of the list
+ private static final InvokeByName PUSH = new InvokeByName("push", ScriptObject.class, void.class, Object.class);
+ private static final InvokeByName UNSHIFT = new InvokeByName("unshift", ScriptObject.class, void.class, Object.class);
+
+ // These remove from the back and front of the list
+ private static final InvokeByName POP = new InvokeByName("pop", ScriptObject.class, Object.class);
+ private static final InvokeByName SHIFT = new InvokeByName("shift", ScriptObject.class, Object.class);
+
+ // These insert and remove in the middle of the list
+ private static final InvokeByName SPLICE_ADD = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class);
+ private static final InvokeByName SPLICE_REMOVE = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class);
+
+ private final ScriptObject obj;
+
+ /**
+ * Creates a new list wrapper for the specified script object.
+ * @param obj script the object to wrap
+ */
+ public ListAdapter(ScriptObject obj) {
+ this.obj = obj;
+ }
+
+ @Override
+ public int size() {
+ return JSType.toInt32(obj.getLength());
+ }
+
+ @Override
+ public Object get(int index) {
+ checkRange(index);
+ return obj.get(index);
+ }
+
+ @Override
+ public Object set(int index, Object element) {
+ checkRange(index);
+ final Object prevValue = get(index);
+ obj.set(index, element, false);
+ return prevValue;
+ }
+
+ private void checkRange(int index) {
+ if(index < 0 || index >= size()) {
+ throw invalidIndex(index);
+ }
+ }
+
+ @Override
+ public void push(Object e) {
+ addFirst(e);
+ }
+
+ @Override
+ public boolean add(Object e) {
+ addLast(e);
+ return true;
+ }
+
+ @Override
+ public void addFirst(Object e) {
+ try {
+ final Object fn = UNSHIFT.getGetter().invokeExact(obj);
+ checkFunction(fn, UNSHIFT);
+ UNSHIFT.getInvoker().invokeExact(fn, obj, e);
+ } catch(RuntimeException | Error ex) {
+ throw ex;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
+ public void addLast(Object e) {
+ try {
+ final Object fn = PUSH.getGetter().invokeExact(obj);
+ checkFunction(fn, PUSH);
+ PUSH.getInvoker().invokeExact(fn, obj, e);
+ } catch(RuntimeException | Error ex) {
+ throw ex;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
+ public void add(int index, Object e) {
+ try {
+ if(index < 0) {
+ throw invalidIndex(index);
+ } else if(index == 0) {
+ addFirst(e);
+ } else {
+ final int size = size();
+ if(index < size) {
+ final Object fn = SPLICE_ADD.getGetter().invokeExact(obj);
+ checkFunction(fn, SPLICE_ADD);
+ SPLICE_ADD.getInvoker().invokeExact(fn, obj, index, 0, e);
+ } else if(index == size) {
+ addLast(e);
+ } else {
+ throw invalidIndex(index);
+ }
+ }
+ } catch(RuntimeException | Error ex) {
+ throw ex;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ private static void checkFunction(Object fn, InvokeByName invoke) {
+ if(!(fn instanceof ScriptFunction)) {
+ throw new UnsupportedOperationException("The script object doesn't have a function named " + invoke.getName());
+ }
+ }
+
+ private static IndexOutOfBoundsException invalidIndex(int index) {
+ return new IndexOutOfBoundsException(String.valueOf(index));
+ }
+
+ @Override
+ public boolean offer(Object e) {
+ return offerLast(e);
+ }
+
+ @Override
+ public boolean offerFirst(Object e) {
+ addFirst(e);
+ return true;
+ }
+
+ @Override
+ public boolean offerLast(Object e) {
+ addLast(e);
+ return true;
+ }
+
+ @Override
+ public Object pop() {
+ return removeFirst();
+ }
+
+ @Override
+ public Object remove() {
+ return removeFirst();
+ }
+
+ @Override
+ public Object removeFirst() {
+ checkNonEmpty();
+ return invokeShift();
+ }
+
+ @Override
+ public Object removeLast() {
+ checkNonEmpty();
+ return invokePop();
+ }
+
+ private void checkNonEmpty() {
+ if(isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ }
+
+ @Override
+ public Object remove(int index) {
+ if(index < 0) {
+ throw invalidIndex(index);
+ } else if (index == 0) {
+ return invokeShift();
+ } else {
+ final int maxIndex = size() - 1;
+ if(index < maxIndex) {
+ final Object prevValue = get(index);
+ invokeSpliceRemove(index, 1);
+ return prevValue;
+ } else if(index == maxIndex) {
+ return invokePop();
+ } else {
+ throw invalidIndex(index);
+ }
+ }
+ }
+
+ private Object invokeShift() {
+ try {
+ final Object fn = SHIFT.getGetter().invokeExact(obj);
+ checkFunction(fn, SHIFT);
+ return SHIFT.getInvoker().invokeExact(fn, obj);
+ } catch(RuntimeException | Error ex) {
+ throw ex;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ private Object invokePop() {
+ try {
+ final Object fn = POP.getGetter().invokeExact(obj);
+ checkFunction(fn, POP);
+ return POP.getInvoker().invokeExact(fn, obj);
+ } catch(RuntimeException | Error ex) {
+ throw ex;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ invokeSpliceRemove(fromIndex, toIndex - fromIndex);
+ }
+
+ private void invokeSpliceRemove(int fromIndex, int count) {
+ try {
+ final Object fn = SPLICE_REMOVE.getGetter().invokeExact(obj);
+ checkFunction(fn, SPLICE_REMOVE);
+ SPLICE_REMOVE.getInvoker().invokeExact(fn, obj, fromIndex, count);
+ } catch(RuntimeException | Error ex) {
+ throw ex;
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
+ public Object poll() {
+ return pollFirst();
+ }
+
+ @Override
+ public Object pollFirst() {
+ return isEmpty() ? null : invokeShift();
+ }
+
+ @Override
+ public Object pollLast() {
+ return isEmpty() ? null : invokePop();
+ }
+
+ @Override
+ public Object peek() {
+ return peekFirst();
+ }
+
+ @Override
+ public Object peekFirst() {
+ return isEmpty() ? null : get(0);
+ }
+
+ @Override
+ public Object peekLast() {
+ return isEmpty() ? null : get(size() - 1);
+ }
+
+ @Override
+ public Object element() {
+ return getFirst();
+ }
+
+ @Override
+ public Object getFirst() {
+ checkNonEmpty();
+ return get(0);
+ }
+
+ @Override
+ public Object getLast() {
+ checkNonEmpty();
+ return get(size() - 1);
+ }
+
+ @Override
+ public Iterator<Object> descendingIterator() {
+ final ListIterator<Object> it = listIterator(size());
+ return new Iterator<Object>() {
+ @Override
+ public boolean hasNext() {
+ return it.hasPrevious();
+ }
+
+ @Override
+ public Object next() {
+ return it.previous();
+ }
+
+ @Override
+ public void remove() {
+ it.remove();
+ }
+ };
+ }
+
+ @Override
+ public boolean removeFirstOccurrence(Object o) {
+ return removeOccurrence(o, iterator());
+ }
+
+ @Override
+ public boolean removeLastOccurrence(Object o) {
+ return removeOccurrence(o, descendingIterator());
+ }
+
+ private static boolean removeOccurrence(Object o, Iterator<Object> it) {
+ while(it.hasNext()) {
+ final Object e = it.next();
+ if(o == null ? e == null : o.equals(e)) {
+ it.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/Logging.java b/src/jdk/nashorn/internal/runtime/Logging.java
index 8a69ebf9..39740dd2 100644
--- a/src/jdk/nashorn/internal/runtime/Logging.java
+++ b/src/jdk/nashorn/internal/runtime/Logging.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.ConsoleHandler;
@@ -117,7 +118,7 @@ public final class Logging {
if ("".equals(value)) {
level = Level.INFO;
} else {
- level = Level.parse(value.toUpperCase());
+ level = Level.parse(value.toUpperCase(Locale.ENGLISH));
}
final String name = Logging.lastPart(key);
diff --git a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
index b10b72df..883ff85c 100644
--- a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
+++ b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
@@ -25,10 +25,16 @@
package jdk.nashorn.internal.runtime;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.support.Guards;
+import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
import jdk.nashorn.internal.objects.NativeJava;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -65,6 +71,10 @@ import jdk.nashorn.internal.objects.annotations.Function;
* </pre>
*/
public final class NativeJavaPackage extends ScriptObject {
+ private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
+ private static final MethodHandle CLASS_NOT_FOUND = findOwnMH("classNotFound", Void.TYPE, NativeJavaPackage.class);
+ private static final MethodHandle TYPE_GUARD = Guards.getClassGuard(NativeJavaPackage.class);
+
/** Full name of package (includes path.) */
private final String name;
@@ -123,6 +133,30 @@ public final class NativeJavaPackage extends ScriptObject {
return super.getDefaultValue(hint);
}
+ @Override
+ protected GuardedInvocation findNewMethod(CallSiteDescriptor desc) {
+ return createClassNotFoundInvocation(desc);
+ }
+
+ @Override
+ protected GuardedInvocation findCallMethod(CallSiteDescriptor desc, LinkRequest request) {
+ return createClassNotFoundInvocation(desc);
+ }
+
+ private static GuardedInvocation createClassNotFoundInvocation(final CallSiteDescriptor desc) {
+ // If NativeJavaPackage is invoked either as a constructor or as a function, throw a ClassNotFoundException as
+ // we can assume the user attempted to instantiate a non-existent class.
+ final MethodType type = desc.getMethodType();
+ return new GuardedInvocation(
+ MH.dropArguments(CLASS_NOT_FOUND, 1, type.parameterList().subList(1, type.parameterCount())),
+ type.parameterType(0) == NativeJavaPackage.class ? null : TYPE_GUARD);
+ }
+
+ @SuppressWarnings("unused")
+ private static void classNotFound(final NativeJavaPackage pkg) throws ClassNotFoundException {
+ throw new ClassNotFoundException(pkg.name);
+ }
+
/**
* "No such property" call placeholder.
*
@@ -188,4 +222,7 @@ public final class NativeJavaPackage extends ScriptObject {
return noSuchProperty(desc, request);
}
+ private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
+ return MH.findStatic(MethodHandles.lookup(), NativeJavaPackage.class, name, MH.type(rtype, types));
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index 585fc4b3..a5e46016 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -52,6 +52,9 @@ public abstract class Property {
* we can use leave flag byte initialized with (the default) zero value.
*/
+ /** Mask for property being both writable, enumerable and configurable */
+ public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000;
+
/** ECMA 8.6.1 - Is this property not writable? */
public static final int NOT_WRITABLE = 0b0000_0000_0001;
@@ -352,6 +355,27 @@ public abstract class Property {
}
/**
+ * Set the value of this property in {@code owner}. This allows to bypass creation of the
+ * setter MethodHandle for spill and user accessor properties.
+ *
+ * @param self the this object
+ * @param owner the owner object
+ * @param value the new property value
+ * @param strict is this a strict setter?
+ */
+ protected abstract void setObjectValue(ScriptObject self, ScriptObject owner, Object value, boolean strict);
+
+ /**
+ * Set the Object value of this property from {@code owner}. This allows to bypass creation of the
+ * getter MethodHandle for spill and user accessor properties.
+ *
+ * @param self the this object
+ * @param owner the owner object
+ * @return the property value
+ */
+ protected abstract Object getObjectValue(ScriptObject self, ScriptObject owner);
+
+ /**
* Abstract method for retrieving the setter for the property. We do not know
* anything about the internal representation when we request the setter, we only
* know that the setter will take the property as a parameter of the given type.
diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
index 03a25dab..226d83d1 100644
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -30,6 +30,8 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedList;
import jdk.nashorn.internal.codegen.Compiler;
@@ -49,9 +51,16 @@ import jdk.nashorn.internal.parser.TokenType;
*/
public final class RecompilableScriptFunctionData extends ScriptFunctionData {
+ /** FunctionNode with the code for this ScriptFunction */
private FunctionNode functionNode;
- private final PropertyMap allocatorMap;
+
+ /** Allocator map from makeMap() */
+ private final PropertyMap allocatorMap;
+
+ /** Code installer used for all further recompilation/specialization of this ScriptFunction */
private final CodeInstaller<ScriptEnvironment> installer;
+
+ /** Name of class where allocator function resides */
private final String allocatorClassName;
/** lazily generated allocator */
@@ -60,6 +69,23 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
/**
+ * Used for specialization based on runtime arguments. Whenever we specialize on
+ * callsite parameter types at runtime, we need to use a parameter type guard to
+ * ensure that the specialized version of the script function continues to be
+ * applicable for a particular callsite *
+ */
+ private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Object[].class);
+
+ /**
+ * It is usually a good gamble whever we detect a runtime callsite with a double
+ * (or java.lang.Number instance) to specialize the parameter to an integer, if the
+ * parameter in question can be represented as one. The double typically only exists
+ * because the compiler doesn't know any better than "a number type" and conservatively
+ * picks doubles when it can't prove that an integer addition wouldn't overflow
+ */
+ private static final MethodHandle ENSURE_INT = findOwnMH("ensureInt", int.class, Object.class);
+
+ /**
* Constructor - public as scripts use it
*
* @param functionNode functionNode that represents this function code
@@ -141,14 +167,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
return; // nothing to do, we have code, at least some.
}
- // check if function node is lazy, need to compile it.
- // note that currently function cloning is not working completely, which
- // means that the compiler will mutate the function node it has been given
- // once it has been compiled, it cannot be recompiled. This means that
- // lazy compilation works (not compiled yet) but e.g. specializations won't
- // until the copy-on-write changes for IR are in, making cloning meaningless.
- // therefore, currently method specialization is disabled. TODO
-
if (functionNode.isLazy()) {
Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
final Compiler compiler = new Compiler(installer);
@@ -156,38 +174,55 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
assert !functionNode.isLazy();
compiler.install(functionNode);
- // we don't need to update any flags - varArgs and needsCallee are instrincic
- // in the function world we need to get a destination node from the compile instead
- // and replace it with our function node. TODO
+ /*
+ * We don't need to update any flags - varArgs and needsCallee are instrincic
+ * in the function world we need to get a destination node from the compile instead
+ * and replace it with our function node. TODO
+ */
}
- // we can't get here unless we have bytecode, either from eager compilation or from
- // running a lazy compile on the lines above
+ /*
+ * We can't get to this program point unless we have bytecode, either from
+ * eager compilation or from running a lazy compile on the lines above
+ */
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
// code exists - look it up and add it into the automatically sorted invoker list
- addCode(functionNode, null, null);
+ addCode(functionNode);
+ }
+
+ private MethodHandle addCode(final FunctionNode fn) {
+ return addCode(fn, null, null, null);
}
- private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) {
- final MethodHandle target =
+ private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) {
+ final MethodType targetType = new FunctionSignature(fn).getMethodType();
+ MethodHandle target =
MH.findStatic(
LOOKUP,
fn.getCompileUnit().getCode(),
fn.getName(),
- new FunctionSignature(fn).
- getMethodType());
+ targetType);
+
+ /*
+ * For any integer argument. a double that is representable as an integer is OK.
+ * otherwise the guard would have failed. in that case introduce a filter that
+ * casts the double to an integer, which we know will preserve all precision.
+ */
+ for (int i = 0; i < targetType.parameterCount(); i++) {
+ if (targetType.parameterType(i) == int.class) {
+ //representable as int
+ target = MH.filterArguments(target, i, ENSURE_INT);
+ }
+ }
+
MethodHandle mh = target;
if (guard != null) {
- try {
- mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
- } catch (Throwable e) {
- e.printStackTrace();
- }
+ mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
}
- final CompiledFunction cf = new CompiledFunction(mh);
+ final CompiledFunction cf = new CompiledFunction(runtimeType == null ? targetType : runtimeType, mh);
code.add(cf);
return cf.getInvoker();
@@ -212,69 +247,162 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
return Type.OBJECT;
}
- @SuppressWarnings("unused")
- private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) {
- //System.err.println("Param type guard " + Arrays.asList(args));
+ private static boolean canCoerce(final Object arg, final Type type) {
+ Type argType = runtimeType(arg);
+ if (Type.widest(argType, type) == type || arg == ScriptRuntime.UNDEFINED) {
+ return true;
+ }
+ System.err.println(arg + " does not fit in "+ argType + " " + type + " " + arg.getClass());
+ new Throwable().printStackTrace();
return false;
}
- private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class);
+ @SuppressWarnings("unused")
+ private static boolean paramTypeGuard(final Type[] paramTypes, final Object... args) {
+ final int length = args.length;
+ assert args.length >= paramTypes.length;
+
+ //i==start, skip the this, callee params etc
+ int start = args.length - paramTypes.length;
+ for (int i = start; i < args.length; i++) {
+ final Object arg = args[i];
+ if (!canCoerce(arg, paramTypes[i - start])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @SuppressWarnings("unused")
+ private static int ensureInt(final Object arg) {
+ if (arg instanceof Number) {
+ return ((Number)arg).intValue();
+ } else if (arg instanceof Undefined) {
+ return 0;
+ }
+ throw new AssertionError(arg);
+ }
+
+ /**
+ * Given the runtime callsite args, compute a method type that is equivalent to what
+ * was passed - this is typically a lot more specific that what the compiler has been
+ * able to deduce
+ * @param callSiteType callsite type for the compiled callsite target
+ * @param args runtime arguments to the compiled callsite target
+ * @return adjusted method type, narrowed as to conform to runtime callsite type instead
+ */
+ private static MethodType runtimeType(final MethodType callSiteType, final Object[] args) {
+ if (args == null) {
+ //for example bound, or otherwise runtime arguments to callsite unavailable, then
+ //do not change the type
+ return callSiteType;
+ }
+ final Class<?>[] paramTypes = new Class<?>[callSiteType.parameterCount()];
+ final int start = args.length - callSiteType.parameterCount();
+ for (int i = start; i < args.length; i++) {
+ paramTypes[i - start] = runtimeType(args[i]).getTypeClass();
+ }
+ return MH.type(callSiteType.returnType(), paramTypes);
+ }
+
+ private static ArrayList<Type> runtimeType(final MethodType mt) {
+ final ArrayList<Type> type = new ArrayList<>();
+ for (int i = 0; i < mt.parameterCount(); i++) {
+ type.add(Type.typeFor(mt.parameterType(i)));
+ }
+ return type;
+ }
@Override
MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
- final MethodHandle mh = super.getBestInvoker(callSiteType, args);
+ final MethodType runtimeType = runtimeType(callSiteType, args);
+ assert runtimeType.parameterCount() == callSiteType.parameterCount();
+
+ final MethodHandle mh = super.getBestInvoker(runtimeType, args);
- if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) {
+ /*
+ * Not all functions can be specialized, for example, if we deemed memory
+ * footprint too large to store a parse snapshot, or if it is meaningless
+ * to do so, such as e.g. for runScript
+ */
+ if (!functionNode.canSpecialize()) {
return mh;
}
- final FunctionNode snapshot = functionNode.getSnapshot();
- if (snapshot == null) {
+ /*
+ * Check if best invoker is equally specific or more specific than runtime
+ * type. In that case, we don't need further specialization, but can use
+ * whatever we have already. We know that it will match callSiteType, or it
+ * would not have been returned from getBestInvoker
+ */
+ if (!code.isLessSpecificThan(runtimeType)) {
return mh;
}
int i;
+ final FunctionNode snapshot = functionNode.getSnapshot();
+ assert snapshot != null;
- //classes known at runtime
- final LinkedList<Type> runtimeArgs = new LinkedList<>();
- for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
- runtimeArgs.addLast(runtimeType(args[i]));
- }
-
- //classes known at compile time
+ /*
+ * Create a list of the arg types that the compiler knows about
+ * typically, the runtime args are a lot more specific, and we should aggressively
+ * try to use those whenever possible
+ * We WILL try to make an aggressive guess as possible, and add guards if needed.
+ * For example, if the compiler can deduce that we have a number type, but the runtime
+ * passes and int, we might still want to keep it an int, and the gamble to
+ * check that whatever is passed is int representable usually pays off
+ * If the compiler only knows that a parameter is an "Object", it is still worth
+ * it to try to specialize it by looking at the runtime arg.
+ */
final LinkedList<Type> compileTimeArgs = new LinkedList<>();
for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
- compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
+ compileTimeArgs.addFirst(Type.typeFor(callSiteType.parameterType(i)));
}
- //the classes known at compile time are a safe to generate as primitives without parameter guards
- //the classes known at runtime are safe to generate as primitives IFF there are parameter guards
+ /*
+ * The classes known at compile time are a safe to generate as primitives without parameter guards
+ * But the classes known at runtime (if more specific than compile time types) are safe to generate as primitives
+ * IFF there are parameter guards
+ */
MethodHandle guard = null;
+ final ArrayList<Type> runtimeParamTypes = runtimeType(runtimeType);
+ while (runtimeParamTypes.size() > functionNode.getParameters().size()) {
+ runtimeParamTypes.remove(0);
+ }
for (i = 0; i < compileTimeArgs.size(); i++) {
- final Type runtimeType = runtimeArgs.get(i);
- final Type compileType = compileTimeArgs.get(i);
+ final Type rparam = Type.typeFor(runtimeType.parameterType(i));
+ final Type cparam = compileTimeArgs.get(i);
- if (compileType.isObject() && !runtimeType.isObject()) {
+ if (cparam.isObject() && !rparam.isObject()) {
+ //check that the runtime object is still coercible to the runtime type, because compiler can't prove it's always primitive
if (guard == null) {
- guard = PARAM_TYPE_GUARD;
- guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
+ guard = MH.insertArguments(PARAM_TYPE_GUARD, 0, (Object)runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()]));
}
}
}
- //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
+ Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args));
assert snapshot != null;
assert snapshot != functionNode;
final Compiler compiler = new Compiler(installer);
- final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
+ final FunctionNode compiledSnapshot = compiler.compile(
+ snapshot.setHints(
+ null,
+ new Compiler.Hints(runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()]))));
+
+ /*
+ * No matter how narrow your types were, they can never be narrower than Attr during recompile made them. I.e. you
+ * can put an int into the function here, if you see it as a runtime type, but if the function uses a multiplication
+ * on it, it will still need to be a double. At least until we have overflow checks. Similarly, if an int is
+ * passed but it is used as a string, it makes no sense to make the parameter narrower than Object. At least until
+ * the "different types for one symbol in difference places" work is done
+ */
compiler.install(compiledSnapshot);
- final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
-
- return nmh;
+ return addCode(compiledSnapshot, runtimeType, guard, mh);
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
index 0a556f9d..2ca897db 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@@ -54,7 +54,7 @@ public final class ScriptEnvironment {
private final Namespace namespace;
/** Current Options object. */
- private Options options;
+ private final Options options;
/** Always allow functions as statements */
public final boolean _anon_functions;
@@ -155,6 +155,9 @@ public final class ScriptEnvironment {
/** print symbols and their contents for the script */
public final boolean _print_symbols;
+ /** range analysis for known types */
+ public final boolean _range_analysis;
+
/** is this environment in scripting mode? */
public final boolean _scripting;
@@ -183,7 +186,7 @@ public final class ScriptEnvironment {
* @param out output print writer
* @param err error print writer
*/
- ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) {
+ public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) {
this.out = out;
this.err = err;
this.namespace = new Namespace();
@@ -219,6 +222,7 @@ public final class ScriptEnvironment {
_print_parse = options.getBoolean("print.parse");
_print_lower_parse = options.getBoolean("print.lower.parse");
_print_symbols = options.getBoolean("print.symbols");
+ _range_analysis = options.getBoolean("range.analysis");
_scripting = options.getBoolean("scripting");
_strict = options.getBoolean("strict");
_version = options.getBoolean("version");
@@ -258,14 +262,19 @@ public final class ScriptEnvironment {
}
this._callsite_flags = callSiteFlags;
- final Option<?> option = options.get("timezone");
- if (option != null) {
- this._timezone = (TimeZone)option.getValue();
+ final Option<?> timezoneOption = options.get("timezone");
+ if (timezoneOption != null) {
+ this._timezone = (TimeZone)timezoneOption.getValue();
} else {
this._timezone = TimeZone.getDefault();
}
- this._locale = Locale.getDefault();
+ final Option<?> localeOption = options.get("locale");
+ if (localeOption != null) {
+ this._locale = (Locale)localeOption.getValue();
+ } else {
+ this._locale = Locale.getDefault();
+ }
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index f83cfa2c..f98817c8 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -25,14 +25,13 @@
package jdk.nashorn.internal.runtime;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
-
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
/**
@@ -92,12 +91,13 @@ public abstract class ScriptFunctionData {
CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args);
+ //TODO the boundinvoker.type() could actually be more specific here
if (isConstructor()) {
ensureConstructor(originalInv);
- return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
+ return new CompiledFunction(boundInvoker.type(), boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
}
- return new CompiledFunction(boundInvoker);
+ return new CompiledFunction(boundInvoker.type(), boundInvoker);
}
/**
@@ -389,7 +389,9 @@ public abstract class ScriptFunctionData {
boundInvoker = noArgBoundInvoker;
}
} else {
- final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))];
+ // If target is already bound, insert additional bound arguments after "this" argument, at position 1.
+ final int argInsertPos = isTargetBound ? 1 : 0;
+ final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))];
int next = 0;
if (!isTargetBound) {
if (needsCallee) {
@@ -403,7 +405,7 @@ public abstract class ScriptFunctionData {
// "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions
// don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args
// start at position 1. If the function is not bound, we start inserting arguments at position 0.
- boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs);
+ boundInvoker = MH.insertArguments(originalInvoker, argInsertPos, boundArgs);
}
if (isTargetBound) {
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 61cce7b1..cf89c545 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.runtime;
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
import static jdk.nashorn.internal.lookup.Lookup.MH;
@@ -151,17 +150,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Method handle for setting the user accessors of a ScriptObject */
public static final Call SET_USER_ACCESSORS = virtualCall(ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class);
- /** Method handle for getter for {@link UserAccessorProperty}, given a slot */
- static final Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), ScriptObject.class, "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class);
-
- /** Method handle for setter for {@link UserAccessorProperty}, given a slot */
- static final Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), ScriptObject.class, "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class);
-
- private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class,
- Object.class, Object.class);
- private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class,
- Object.class, Object.class, Object.class);
-
/**
* Constructor
*/
@@ -699,17 +687,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @return New property.
*/
public final Property addOwnProperty(final String key, final int propertyFlags, final Object value) {
- final MethodHandle setter = addSpill(key, propertyFlags);
-
- try {
- setter.invokeExact((Object)this, value);
- } catch (final Error|RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
-
- return getMap().findProperty(key);
+ final Property property = addSpillProperty(key, propertyFlags);
+ property.setObjectValue(this, this, value, false);
+ return property;
}
/**
@@ -744,15 +724,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
// Erase the property field value with undefined. If the property is defined
// by user-defined accessors, we don't want to call the setter!!
if (!(property instanceof UserAccessorProperty)) {
- try {
- // make the property value to be undefined
- //TODO specproperties
- property.getSetter(Object.class, getMap()).invokeExact((Object)this, (Object)UNDEFINED);
- } catch (final RuntimeException | Error e) {
- throw e;
- } catch (final Throwable t) {
- throw new RuntimeException(t);
- }
+ property.setObjectValue(this, this, UNDEFINED, false);
}
}
@@ -948,18 +920,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @return the value of the property
*/
protected static Object getObjectValue(final FindProperty find) {
- final MethodHandle getter = find.getGetter(Object.class);
- if (getter != null) {
- try {
- return getter.invokeExact((Object)find.getGetterReceiver());
- } catch (final Error|RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
- }
-
- return UNDEFINED;
+ return find.getObjectValue();
}
/**
@@ -2087,11 +2048,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
property = addOwnProperty(property);
} else {
int i = getMap().getSpillLength();
- MethodHandle getter = MH.arrayElementGetter(Object[].class);
- MethodHandle setter = MH.arrayElementSetter(Object[].class);
- getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE);
- setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE);
- property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
+ property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i);
notifyPropertyAdded(this, property);
property = addOwnProperty(property);
i = property.getSlot();
@@ -2115,20 +2072,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/**
* Add a spill entry for the given key.
- * @param key Property key.
- * @param propertyFlags Property flags.
+ * @param key Property key.
* @return Setter method handle.
*/
- private MethodHandle addSpill(final String key, final int propertyFlags) {
- final Property spillProperty = addSpillProperty(key, propertyFlags);
+ MethodHandle addSpill(final String key) {
+ final Property spillProperty = addSpillProperty(key, 0);
final Class<?> type = Object.class;
return spillProperty.getSetter(type, getMap()); //TODO specfields
}
- MethodHandle addSpill(final String key) {
- return addSpill(key, 0);
- }
-
/**
* Make sure arguments are paired correctly, with respect to more parameters than declared,
* fewer parameters than declared and other things that JavaScript allows. This might involve
@@ -2659,14 +2611,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- try {
- final MethodHandle setter = f.getSetter(Object.class, strict); //TODO specfields
- setter.invokeExact((Object)f.getSetterReceiver(), value);
- } catch (final Error|RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
+ f.setObjectValue(value, strict);
+
} else if (!isExtensible()) {
if (strict) {
throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
@@ -2677,13 +2623,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private void spill(final String key, final Object value) {
- try {
- addSpill(key).invokeExact((Object)this, value);
- } catch (final Error|RuntimeException e) {
- throw e;
- } catch (final Throwable e) {
- throw new RuntimeException(e);
- }
+ addSpillProperty(key, 0).setObjectValue(this, this, value, false);
}
@@ -3217,46 +3157,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return (index < 0 || (index >= spill.length)) ? null : spill[index];
}
- // User defined getter and setter are always called by "dyn:call". Note that the user
- // getter/setter may be inherited. If so, proto is bound during lookup. In either
- // inherited or self case, slot is also bound during lookup. Actual ScriptFunction
- // to be called is retrieved everytime and applied.
- @SuppressWarnings("unused")
- private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
- final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
- final Object func = container.getSpill(slot);
-
- if (func instanceof ScriptFunction) {
- try {
- return INVOKE_UA_GETTER.invokeExact(func, self);
- } catch(final Error|RuntimeException t) {
- throw t;
- } catch(final Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- return UNDEFINED;
- }
-
- @SuppressWarnings("unused")
- private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
- final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
- final Object func = container.getSpill(slot);
-
- if (func instanceof ScriptFunction) {
- try {
- INVOKE_UA_SETTER.invokeExact(func, self, value);
- } catch(final Error|RuntimeException t) {
- throw t;
- } catch(final Throwable t) {
- throw new RuntimeException(t);
- }
- } else if (name != null) {
- throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
- }
- }
-
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
final Class<?> own = ScriptObject.class;
final MethodType mt = MH.type(rtype, types);
diff --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
index 216b381c..25dccb7b 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
@@ -36,6 +36,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.Iterator;
+import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Objects;
import jdk.internal.dynalink.beans.StaticClass;
@@ -788,7 +789,7 @@ public final class ScriptRuntime {
return false;
}
- throw typeError("in.with.non.object", rvalType.toString().toLowerCase());
+ throw typeError("in.with.non.object", rvalType.toString().toLowerCase(Locale.ENGLISH));
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
index 596ec1bf..1d046ca9 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
@@ -46,7 +46,7 @@ import java.util.StringTokenizer;
public final class ScriptingFunctions {
/** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */
- public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class);
+ public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class, Object.class);
/** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */
public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class);
@@ -78,13 +78,17 @@ public final class ScriptingFunctions {
* Nashorn extension: global.readLine (scripting-mode-only)
* Read one line of input from the standard input.
*
- * @param self self reference
+ * @param self self reference
+ * @param prompt String used as input prompt
*
* @return line that was read
*
* @throws IOException if an exception occurs
*/
- public static Object readLine(final Object self) throws IOException {
+ public static Object readLine(final Object self, final Object prompt) throws IOException {
+ if (prompt != UNDEFINED) {
+ System.out.print(JSType.toString(prompt));
+ }
final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
return reader.readLine();
}
diff --git a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
index 5ff321fc..a6dfce0f 100644
--- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
@@ -183,17 +183,10 @@ final class SetMethodCreator {
private SetMethod createNewSpillPropertySetter() {
final int nextSpill = getMap().getSpillLength();
- final Property property = createSpillProperty(nextSpill);
+ final Property property = new AccessorProperty(getName(), Property.IS_SPILL, nextSpill);
return new SetMethod(createSpillMethodHandle(nextSpill, property), property);
}
- private Property createSpillProperty(final int nextSpill) {
- final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE);
- final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE);
-
- return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
- }
-
private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) {
final PropertyMap oldMap = getMap();
final PropertyMap newMap = getNewMap(property);
diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
index 75c285a6..5159e653 100644
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
@@ -26,7 +26,15 @@
package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+
+import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
/**
* Property with user defined getters/setters. Actual getter and setter
@@ -51,6 +59,22 @@ public final class UserAccessorProperty extends Property {
/** User defined setter function slot. */
private final int setterSlot;
+ /** Getter method handle */
+ private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
+ "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class);
+
+ /** Setter method handle */
+ private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
+ "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class);
+
+ /** Dynamic invoker for getter */
+ private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class,
+ Object.class, Object.class);
+
+ /** Dynamic invoker for setter */
+ private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class,
+ Object.class, Object.class, Object.class);
+
/**
* Constructor
*
@@ -134,8 +158,18 @@ public final class UserAccessorProperty extends Property {
}
@Override
+ protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
+ return userAccessorGetter(owner, getGetterSlot(), self);
+ }
+
+ @Override
+ protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
+ userAccessorSetter(owner, getSetterSlot(), strict ? getKey() : null, self, value);
+ }
+
+ @Override
public MethodHandle getGetter(final Class<?> type) {
- return Lookup.filterReturnType(ScriptObject.USER_ACCESSOR_GETTER.methodHandle(), type);
+ return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type);
}
@Override
@@ -146,7 +180,7 @@ public final class UserAccessorProperty extends Property {
@Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
- return ScriptObject.USER_ACCESSOR_SETTER.methodHandle();
+ return USER_ACCESSOR_SETTER.methodHandle();
}
@Override
@@ -155,4 +189,42 @@ public final class UserAccessorProperty extends Property {
return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
}
+ // User defined getter and setter are always called by "dyn:call". Note that the user
+ // getter/setter may be inherited. If so, proto is bound during lookup. In either
+ // inherited or self case, slot is also bound during lookup. Actual ScriptFunction
+ // to be called is retrieved everytime and applied.
+ static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
+ final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
+ final Object func = container.getSpill(slot);
+
+ if (func instanceof ScriptFunction) {
+ try {
+ return INVOKE_UA_GETTER.invokeExact(func, self);
+ } catch(final Error|RuntimeException t) {
+ throw t;
+ } catch(final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ return UNDEFINED;
+ }
+
+ static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
+ final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
+ final Object func = container.getSpill(slot);
+
+ if (func instanceof ScriptFunction) {
+ try {
+ INVOKE_UA_SETTER.invokeExact(func, self, value);
+ } catch(final Error|RuntimeException t) {
+ throw t;
+ } catch(final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java b/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java
index 30e91ec3..4bfb6851 100644
--- a/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java
+++ b/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java
@@ -40,7 +40,7 @@ import java.lang.invoke.MethodHandle;
* private static final InvokeByName TO_JSON = new InvokeByName("toJSON", Object.class, Object.class, Object.class);
* ...
* final Object toJSONFn = TO_JSON.getGetter().invokeExact(obj);
- * value = TO_JSON.getInvoker().invokeExact(toJSON, obj, key);
+ * value = TO_JSON.getInvoker().invokeExact(toJSONFn, obj, key);
* </pre>
* In practice, you can have stronger type assumptions if it makes sense for your code, just remember that you must use
* the same parameter types as the formal types of the arguments for {@code invokeExact} to work:
@@ -50,7 +50,7 @@ import java.lang.invoke.MethodHandle;
* final ScriptObject sobj = (ScriptObject)obj;
* final Object toJSONFn = TO_JSON.getGetter().invokeExact(sobj);
* if(toJSONFn instanceof ScriptFunction) {
- * value = TO_JSON.getInvoker().invokeExact(toJSON, sobj, key);
+ * value = TO_JSON.getInvoker().invokeExact(toJSONFn, sobj, key);
* }
* </pre>
* Note that in general you will not want to reuse a single instance of this class for implementing more than one call
@@ -59,6 +59,7 @@ import java.lang.invoke.MethodHandle;
* separate instance of this class for every place.
*/
public class InvokeByName {
+ private final String name;
private final MethodHandle getter;
private final MethodHandle invoker;
@@ -81,6 +82,7 @@ public class InvokeByName {
* @param ptypes the parameter types of the function.
*/
public InvokeByName(final String name, final Class<?> targetClass, final Class<?> rtype, final Class<?>... ptypes) {
+ this.name = name;
getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getItem:" + name, Object.class, targetClass);
final Class<?>[] finalPtypes;
@@ -97,6 +99,14 @@ public class InvokeByName {
}
/**
+ * Returns the name of the function retrieved through this invoker.
+ * @return the name of the function retrieved through this invoker.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
* Returns the property getter that can be invoked on an object to retrieve the function object that will be
* subsequently invoked by the invoker returned by {@link #getInvoker()}.
* @return the property getter method handle for the function.
diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index df9c47ff..edd75e4d 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -38,7 +38,7 @@ import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.runtime.JSType;
-import netscape.javascript.JSObject;
+import jdk.nashorn.api.scripting.JSObject;
/**
* A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
index 37786b1e..1fe76954 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
@@ -310,7 +310,34 @@ final class JavaAdapterBytecodeGenerator extends JavaAdapterGeneratorBase {
Type.getMethodDescriptor(Type.VOID_TYPE), null, null));
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getClassOverrides", GET_CLASS_INITIALIZER_DESCRIPTOR);
- // Assign MethodHandle fields through invoking getHandle()
+ final Label initGlobal;
+ if(samName != null) {
+ // If the class is a SAM, allow having a ScriptFunction passed as class overrides
+ final Label notAFunction = new Label();
+ mv.dup();
+ mv.instanceOf(SCRIPT_FUNCTION_TYPE);
+ mv.ifeq(notAFunction);
+ mv.checkcast(SCRIPT_FUNCTION_TYPE);
+
+ // Assign MethodHandle fields through invoking getHandle() for a ScriptFunction, only assigning the SAM
+ // method(s).
+ for (final MethodInfo mi : methodInfos) {
+ if(mi.getName().equals(samName)) {
+ mv.dup();
+ mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
+ mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_FUNCTION_DESCRIPTOR);
+ } else {
+ mv.visitInsn(ACONST_NULL);
+ }
+ mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
+ }
+ initGlobal = new Label();
+ mv.goTo(initGlobal);
+ mv.visitLabel(notAFunction);
+ } else {
+ initGlobal = null;
+ }
+ // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
for (final MethodInfo mi : methodInfos) {
mv.dup();
mv.aconst(mi.getName());
@@ -319,6 +346,9 @@ final class JavaAdapterBytecodeGenerator extends JavaAdapterGeneratorBase {
mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
}
+ if(initGlobal != null) {
+ mv.visitLabel(initGlobal);
+ }
// Assign "staticGlobal = Context.getGlobal()"
invokeGetGlobalWithNullCheck(mv);
mv.putstatic(generatedClassName, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java
index c791274e..a3f4718b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java
@@ -43,6 +43,7 @@ import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.SecureClassLoader;
+
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
@@ -58,6 +59,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
* "class loader", it does not, in fact, extend {@code ClassLoader}, but rather uses them internally. Instances of this
* class are normally created by {@link JavaAdapterBytecodeGenerator}.
*/
+@SuppressWarnings("javadoc")
class JavaAdapterClassLoader extends JavaAdapterGeneratorBase {
private static final Type PRIVILEGED_ACTION_TYPE = Type.getType(PrivilegedAction.class);
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
index f3f51fd8..ecec63bc 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
@@ -39,6 +39,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.LinkRequestImpl;
import jdk.nashorn.internal.objects.NativeJava;
@@ -66,6 +67,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
* </p>
*/
+@SuppressWarnings("javadoc")
public final class JavaAdapterFactory {
/**
* A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents.
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java
index 67499cbc..ff33ba6e 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java
@@ -33,6 +33,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
* Base class for both {@link JavaAdapterBytecodeGenerator} and {@link JavaAdapterClassLoader}, containing those
* bytecode types, type names and method descriptor that are used by both.
*/
+@SuppressWarnings("javadoc")
abstract class JavaAdapterGeneratorBase {
static final Type CONTEXT_TYPE = Type.getType(Context.class);
static final Type OBJECT_TYPE = Type.getType(Object.class);
diff --git a/src/jdk/nashorn/internal/runtime/options/Option.java b/src/jdk/nashorn/internal/runtime/options/Option.java
index ddbeba18..feaff1f1 100644
--- a/src/jdk/nashorn/internal/runtime/options/Option.java
+++ b/src/jdk/nashorn/internal/runtime/options/Option.java
@@ -42,10 +42,6 @@ public class Option<T> {
this.value = value;
}
- void setValue(final T value) {
- this.value = value;
- }
-
/**
* Return the value of an option
* @return the option value
diff --git a/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java b/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
index 16ff04ea..4c1c44fc 100644
--- a/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
+++ b/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
@@ -25,6 +25,7 @@
package jdk.nashorn.internal.runtime.options;
+import java.util.Locale;
import java.util.TimeZone;
import jdk.nashorn.internal.runtime.QuotedStringTokenizer;
@@ -151,6 +152,9 @@ public class OptionTemplate implements Comparable<OptionTemplate> {
case "timezone":
this.defaultValue = TimeZone.getDefault().getID();
break;
+ case "locale":
+ this.defaultValue = Locale.getDefault().toLanguageTag();
+ break;
default:
break;
}
@@ -263,7 +267,7 @@ public class OptionTemplate implements Comparable<OptionTemplate> {
this.params = arg;
break;
case "type":
- this.type = arg.toLowerCase();
+ this.type = arg.toLowerCase(Locale.ENGLISH);
break;
case "default":
this.defaultValue = arg;
diff --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java
index 286feec9..737c56b4 100644
--- a/src/jdk/nashorn/internal/runtime/options/Options.java
+++ b/src/jdk/nashorn/internal/runtime/options/Options.java
@@ -499,10 +499,10 @@ public final class Options {
case "timezone":
// default value "TimeZone.getDefault()"
return new Option<>(TimeZone.getTimeZone(value));
+ case "locale":
+ return new Option<>(Locale.forLanguageTag(value));
case "keyvalues":
return new KeyValueOption(value);
- case "values":
- return new ValueOption(value);
case "log":
final KeyValueOption kv = new KeyValueOption(value);
Logging.initialize(kv.getValues());
diff --git a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java
index e3157ba5..9250331d 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java
@@ -41,7 +41,7 @@ import java.util.regex.PatternSyntaxException;
* Note that this class is not thread-safe as it stores the current match result
* and the string being matched in instance fields.
*/
-public class DefaultRegExp extends RegExp {
+public class JdkRegExp extends RegExp {
/** Java regexp pattern to use for match. We compile to one of these */
private Pattern pattern;
@@ -56,7 +56,7 @@ public class DefaultRegExp extends RegExp {
* @param flags RegExp flag string
* @throws ParserException if flags is invalid or source string has syntax error.
*/
- public DefaultRegExp(final String source, final String flags) throws ParserException {
+ public JdkRegExp(final String source, final String flags) throws ParserException {
super(source, flags);
int intFlags = 0;
diff --git a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
index 1047221a..f797b051 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
@@ -113,7 +113,7 @@ public class JoniRegExp extends RegExp {
public static class Factory extends RegExpFactory {
@Override
- protected RegExp compile(final String pattern, final String flags) throws ParserException {
+ public RegExp compile(final String pattern, final String flags) throws ParserException {
return new JoniRegExp(pattern, flags);
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
index 4a7ac11b..08168b63 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
@@ -29,7 +29,7 @@ import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.options.Options;
/**
- * Factory class for regular expressions. This class creates instances of {@link DefaultRegExp}.
+ * Factory class for regular expressions. This class creates instances of {@link JdkRegExp}.
* An alternative factory can be installed using the {@code nashorn.regexp.impl} system property.
*/
public class RegExpFactory {
@@ -62,8 +62,8 @@ public class RegExpFactory {
* @return new RegExp
* @throws ParserException if flags is invalid or pattern string has syntax error.
*/
- protected RegExp compile(final String pattern, final String flags) throws ParserException {
- return new DefaultRegExp(pattern, flags);
+ public RegExp compile(final String pattern, final String flags) throws ParserException {
+ return new JdkRegExp(pattern, flags);
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
index 956a99d7..52829fac 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
@@ -868,6 +868,9 @@ final class RegExpScanner extends Scanner {
* \ ClassEscape
*/
private boolean classAtomNoDash() {
+ if (atEOF()) {
+ return false;
+ }
final int startIn = position;
final int startOut = sb.length();
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java
index 49a2a925..c0dbf0d8 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java
@@ -21,10 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAll;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt;
-import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsClear;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnAt;
-import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnAtSimple;
-import static jdk.nashorn.internal.runtime.regexp.joni.Option.isCaptureGroup;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindCondition;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline;
@@ -36,8 +33,6 @@ import java.util.HashSet;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.Node;
@@ -49,9 +44,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeType;
import jdk.nashorn.internal.runtime.regexp.joni.constants.RegexState;
import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel;
import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.ObjPtr;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.Ptr;
final class Analyser extends Parser {
@@ -74,38 +67,9 @@ final class Analyser extends Parser {
//regex.repeatRangeAlloc = 0;
regex.repeatRangeLo = null;
regex.repeatRangeHi = null;
- regex.numCombExpCheck = 0;
-
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) regex.numCombExpCheck = 0;
parse();
- if (Config.USE_NAMED_GROUP) {
- /* mixed use named group and no-named group */
- if (env.numNamed > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(regex.options)) {
- if (env.numNamed != env.numMem) {
- root = disableNoNameGroupCapture(root);
- } else {
- numberedRefCheck(root);
- }
- }
- } // USE_NAMED_GROUP
-
- if (Config.USE_NAMED_GROUP) {
- if (env.numCall > 0) {
- env.unsetAddrList = new UnsetAddrList(env.numCall);
- setupSubExpCall(root);
- // r != 0 ???
- subexpRecursiveCheckTrav(root);
- // r < 0 -< err, FOUND_CALLED_NODE = 1
- subexpInfRecursiveCheckTrav(root);
- // r != 0 recursion infinite ???
- regex.numCall = env.numCall;
- } else {
- regex.numCall = 0;
- }
- } // USE_NAMED_GROUP
-
if (Config.DEBUG_PARSE_TREE_RAW && Config.DEBUG_PARSE_TREE) {
Config.log.println("<RAW TREE>");
Config.log.println(root + "\n");
@@ -129,27 +93,6 @@ final class Analyser extends Parser {
regex.btMemEnd |= regex.captureHistory;
}
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (env.backrefedMem == 0 || (Config.USE_SUBEXP_CALL && env.numCall == 0)) {
- setupCombExpCheck(root, 0);
-
- if (Config.USE_SUBEXP_CALL && env.hasRecursion) {
- env.numCombExpCheck = 0;
- } else { // USE_SUBEXP_CALL
- if (env.combExpMaxRegNum > 0) {
- for (int i=1; i<env.combExpMaxRegNum; i++) {
- if (bsAt(env.backrefedMem, i)) {
- env.numCombExpCheck = 0;
- break;
- }
- }
- }
- }
-
- } // USE_SUBEXP_CALL
- regex.numCombExpCheck = env.numCombExpCheck;
- } // USE_COMBINATION_EXPLOSION_CHECK
-
regex.clearOptimizeInfo();
if (!Config.DONT_OPTIMIZE) setOptimizedInfoFromTree(root);
@@ -167,7 +110,6 @@ final class Analyser extends Parser {
}
if (Config.DEBUG_COMPILE) {
- if (Config.USE_NAMED_GROUP) Config.log.print(regex.nameTableToString());
Config.log.println("stack used: " + regex.stackNeeded);
if (Config.USE_STRING_TEMPLATES) Config.log.print("templates: " + regex.templateNum + "\n");
Config.log.println(new ByteCodePrinter(regex).byteCodeListToString());
@@ -177,157 +119,6 @@ final class Analyser extends Parser {
regex.state = RegexState.NORMAL;
}
- private void noNameDisableMapFor_cosAlt(Node node, int[]map, Ptr counter) {
- ConsAltNode can = (ConsAltNode)node;
- do {
- can.setCar(noNameDisableMap(can.car, map, counter));
- } while ((can = can.cdr) != null);
- }
-
- private void noNameDisableMapFor_quantifier(Node node, int[]map, Ptr counter) {
- QuantifierNode qn = (QuantifierNode)node;
- Node target = qn.target;
- Node old = target;
- target = noNameDisableMap(target, map, counter);
-
- if (target != old) {
- qn.setTarget(target);
- if (target.getType() == NodeType.QTFR) qn.reduceNestedQuantifier((QuantifierNode)target);
- }
- }
-
- private Node noNameDisableMapFor_enclose(Node node, int[]map, Ptr counter) {
- EncloseNode en = (EncloseNode)node;
- if (en.type == EncloseType.MEMORY) {
- if (en.isNamedGroup()) {
- counter.p++;
- map[en.regNum] = counter.p;
- en.regNum = counter.p;
- //en.target = noNameDisableMap(en.target, map, counter);
- en.setTarget(noNameDisableMap(en.target, map, counter)); // ???
- } else {
- node = en.target;
- en.target = null; // remove first enclose: /(a)(?<b>c)/
- node = noNameDisableMap(node, map, counter);
- }
- } else {
- //en.target = noNameDisableMap(en.target, map, counter);
- en.setTarget(noNameDisableMap(en.target, map, counter)); // ???
- }
- return node;
- }
-
- private void noNameDisableMapFor_anchor(Node node, int[]map, Ptr counter) {
- AnchorNode an = (AnchorNode)node;
- switch (an.type) {
- case AnchorNode.PREC_READ:
- case AnchorNode.PREC_READ_NOT:
- case AnchorNode.LOOK_BEHIND:
- case AnchorNode.LOOK_BEHIND_NOT:
- an.setTarget(noNameDisableMap(an.target, map, counter));
- }
- }
-
- private Node noNameDisableMap(Node node, int[]map, Ptr counter) {
- switch (node.getType()) {
- case NodeType.LIST:
- case NodeType.ALT:
- noNameDisableMapFor_cosAlt(node, map, counter);
- break;
- case NodeType.QTFR:
- noNameDisableMapFor_quantifier(node, map, counter);
- break;
- case NodeType.ENCLOSE:
- node = noNameDisableMapFor_enclose(node, map, counter);
- break;
- case NodeType.ANCHOR:
- noNameDisableMapFor_anchor(node, map, counter);
- break;
- } // switch
- return node;
- }
-
- private void renumberByMap(Node node, int[]map) {
- switch (node.getType()) {
- case NodeType.LIST:
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- do {
- renumberByMap(can.car, map);
- } while ((can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- renumberByMap(((QuantifierNode)node).target, map);
- break;
-
- case NodeType.ENCLOSE:
- renumberByMap(((EncloseNode)node).target, map);
- break;
-
- case NodeType.BREF:
- ((BackRefNode)node).renumber(map);
- break;
- } // switch
- }
-
- protected final void numberedRefCheck(Node node) {
- switch (node.getType()) {
- case NodeType.LIST:
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- do {
- numberedRefCheck(can.car);
- } while ((can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- numberedRefCheck(((QuantifierNode)node).target);
- break;
-
- case NodeType.ENCLOSE:
- numberedRefCheck(((EncloseNode)node).target);
- break;
-
- case NodeType.BREF:
- BackRefNode br = (BackRefNode)node;
- if (!br.isNameRef()) newValueException(ERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED);
- break;
- } // switch
- }
-
- protected final Node disableNoNameGroupCapture(Node root) {
- int[]map = new int[env.numMem + 1];
-
- for (int i=1; i<=env.numMem; i++) map[i] = 0;
-
- root = noNameDisableMap(root, map, new Ptr(0));
- renumberByMap(root, map);
-
- for (int i=1, pos=1; i<=env.numMem; i++) {
- if (map[i] > 0) {
- env.memNodes[pos] = env.memNodes[i];
- pos++;
- }
- }
-
- int loc = env.captureHistory;
- env.captureHistory = bsClear();
-
- for (int i=1; i<=Config.MAX_CAPTURE_HISTORY_GROUP; i++) {
- if (bsAt(loc, i)) {
- env.captureHistory = bsOnAtSimple(env.captureHistory, map[i]);
- }
- }
-
- env.numMem = env.numNamed;
- regex.numMem = env.numNamed;
-
- regex.renumberNameTable(map);
-
- return root;
- }
-
private void swap(Node a, Node b) {
a.swap(b);
@@ -352,17 +143,6 @@ final class Analyser extends Parser {
} while ((can = can.cdr) != null);
break;
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- CallNode cn = (CallNode)node;
- if (cn.isRecursion()) {
- return TargetInfo.IS_EMPTY_REC; /* tiny version */
- } else {
- info = quantifiersMemoryInfo(cn.target);
- }
- } // USE_SUBEXP_CALL
- break;
-
case NodeType.QTFR:
QuantifierNode qn = (QuantifierNode)node;
if (qn.upper != 0) {
@@ -417,18 +197,6 @@ final class Analyser extends Parser {
}
break;
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- CallNode cn = (CallNode)node;
- if (cn.isRecursion()) {
- EncloseNode en = (EncloseNode)cn.target;
- if (en.isMinFixed()) min = en.minLength;
- } else {
- min = getMinMatchLength(cn.target);
- }
- } // USE_SUBEXP_CALL
- break;
-
case NodeType.LIST:
ConsAltNode can = (ConsAltNode)node;
do {
@@ -474,15 +242,13 @@ final class Analyser extends Parser {
EncloseNode en = (EncloseNode)node;
switch (en.type) {
case EncloseType.MEMORY:
- if (Config.USE_SUBEXP_CALL) {
- if (en.isMinFixed()) {
- min = en.minLength;
- } else {
- min = getMinMatchLength(en.target);
- en.minLength = min;
- en.setMinFixed();
- }
- } // USE_SUBEXP_CALL
+ if (en.isMinFixed()) {
+ min = en.minLength;
+ } else {
+ min = getMinMatchLength(en.target);
+ en.minLength = min;
+ en.setMinFixed();
+ }
break;
case EncloseType.OPTION:
@@ -547,17 +313,6 @@ final class Analyser extends Parser {
}
break;
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- CallNode cn = (CallNode)node;
- if (!cn.isRecursion()) {
- max = getMaxMatchLength(cn.target);
- } else {
- max = MinMaxLen.INFINITE_DISTANCE;
- }
- } // USE_SUBEXP_CALL
- break;
-
case NodeType.QTFR:
QuantifierNode qn = (QuantifierNode)node;
if (qn.upper != 0) {
@@ -576,15 +331,13 @@ final class Analyser extends Parser {
EncloseNode en = (EncloseNode)node;
switch (en.type) {
case EncloseType.MEMORY:
- if (Config.USE_SUBEXP_CALL) {
- if (en.isMaxFixed()) {
- max = en.maxLength;
- } else {
- max = getMaxMatchLength(en.target);
- en.maxLength = max;
- en.setMaxFixed();
- }
- } // USE_SUBEXP_CALL
+ if (en.isMaxFixed()) {
+ max = en.maxLength;
+ } else {
+ max = getMaxMatchLength(en.target);
+ en.maxLength = max;
+ en.setMaxFixed();
+ }
break;
case EncloseType.OPTION:
@@ -663,17 +416,6 @@ final class Analyser extends Parser {
}
break;
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- CallNode cn = (CallNode)node;
- if (!cn.isRecursion()) {
- len = getCharLengthTree(cn.target, level);
- } else {
- returnCode = GET_CHAR_LEN_VARLEN;
- }
- } // USE_SUBEXP_CALL
- break;
-
case NodeType.CTYPE:
len = 1;
@@ -686,17 +428,15 @@ final class Analyser extends Parser {
EncloseNode en = (EncloseNode)node;
switch(en.type) {
case EncloseType.MEMORY:
- if (Config.USE_SUBEXP_CALL) {
- if (en.isCLenFixed()) {
- len = en.charLength;
- } else {
- len = getCharLengthTree(en.target, level);
- if (returnCode == 0) {
- en.charLength = len;
- en.setCLenFixed();
- }
+ if (en.isCLenFixed()) {
+ len = en.charLength;
+ } else {
+ len = getCharLengthTree(en.target, level);
+ if (returnCode == 0) {
+ en.charLength = len;
+ en.setCLenFixed();
}
- } // USE_SUBEXP_CALL
+ }
break;
case EncloseType.OPTION:
@@ -727,10 +467,6 @@ final class Analyser extends Parser {
switch(x.getType()) {
case NodeType.CTYPE:
switch(yType) {
- case NodeType.CTYPE:
- CTypeNode cny = (CTypeNode)y;
- CTypeNode cnx = (CTypeNode)x;
- return cny.ctype == cnx.ctype && cny.not != cnx.not;
case NodeType.CCLASS:
// !swap:!
@@ -756,37 +492,6 @@ final class Analyser extends Parser {
CClassNode xc = (CClassNode)x;
switch(yType) {
- case NodeType.CTYPE:
- switch(((CTypeNode)y).ctype) {
- case CharacterType.WORD:
- if (!((CTypeNode)y).not) {
- if (xc.mbuf == null && !xc.isNot()) {
- for (int i=0; i<BitSet.SINGLE_BYTE_SIZE; i++) {
- if (xc.bs.at(i)) {
- if (EncodingHelper.isWord(i)) return false;
- }
- }
- return true;
- }
- return false;
- } else {
- for (int i=0; i<BitSet.SINGLE_BYTE_SIZE; i++) {
- if (!EncodingHelper.isWord(i)) {
- if (!xc.isNot()) {
- if (xc.bs.at(i)) return false;
- } else {
- if (!xc.bs.at(i)) return false;
- }
- }
- }
- return true;
- }
- // break; not reached
-
- default:
- break;
- } // inner switch
- break;
case NodeType.CCLASS:
CClassNode yc = (CClassNode)y;
@@ -820,17 +525,6 @@ final class Analyser extends Parser {
if (xs.length() == 0) break;
switch (yType) {
- case NodeType.CTYPE:
- CTypeNode cy = ((CTypeNode)y);
- switch (cy.ctype) {
- case CharacterType.WORD:
- return !cy.not;
-
- default:
- break;
-
- } // inner switch
- break;
case NodeType.CCLASS:
CClassNode cc = (CClassNode)y;
@@ -873,9 +567,6 @@ final class Analyser extends Parser {
case NodeType.CANY:
break;
- case NodeType.CALL:
- break; // if (Config.USE_SUBEXP_CALL)
-
case NodeType.CTYPE:
case NodeType.CCLASS:
if (!exact) n = node;
@@ -977,316 +668,6 @@ final class Analyser extends Parser {
return invalid;
}
- private static final int RECURSION_EXIST = 1;
- private static final int RECURSION_INFINITE = 2;
- private int subexpInfRecursiveCheck(Node node, boolean head) {
- int r = 0;
-
- switch (node.getType()) {
- case NodeType.LIST:
- int min;
- ConsAltNode x = (ConsAltNode)node;
- do {
- int ret = subexpInfRecursiveCheck(x.car, head);
- if (ret == RECURSION_INFINITE) return ret;
- r |= ret;
- if (head) {
- min = getMinMatchLength(x.car);
- if (min != 0) head = false;
- }
- } while ((x = x.cdr) != null);
- break;
-
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- r = RECURSION_EXIST;
- do {
- int ret = subexpInfRecursiveCheck(can.car, head);
- if (ret == RECURSION_INFINITE) return ret;
- r &= ret;
- } while ((can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- QuantifierNode qn = (QuantifierNode)node;
- r = subexpInfRecursiveCheck(qn.target, head);
- if (r == RECURSION_EXIST) {
- if (qn.lower == 0) r = 0;
- }
- break;
-
- case NodeType.ANCHOR:
- AnchorNode an = (AnchorNode)node;
- switch (an.type) {
- case AnchorType.PREC_READ:
- case AnchorType.PREC_READ_NOT:
- case AnchorType.LOOK_BEHIND:
- case AnchorType.LOOK_BEHIND_NOT:
- r = subexpInfRecursiveCheck(an.target, head);
- break;
- } // inner switch
- break;
-
- case NodeType.CALL:
- r = subexpInfRecursiveCheck(((CallNode)node).target, head);
- break;
-
- case NodeType.ENCLOSE:
- EncloseNode en = (EncloseNode)node;
- if (en.isMark2()) {
- return 0;
- } else if (en.isMark1()) {
- return !head ? RECURSION_EXIST : RECURSION_INFINITE;
- // throw exception here ???
- } else {
- en.setMark2();
- r = subexpInfRecursiveCheck(en.target, head);
- en.clearMark2();
- }
- break;
-
- default:
- break;
- } // switch
- return r;
- }
-
- protected final int subexpInfRecursiveCheckTrav(Node node) {
- int r = 0;
-
- switch (node.getType()) {
- case NodeType.LIST:
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- do {
- r = subexpInfRecursiveCheckTrav(can.car);
- } while (r == 0 && (can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- r = subexpInfRecursiveCheckTrav(((QuantifierNode)node).target);
- break;
-
- case NodeType.ANCHOR:
- AnchorNode an = (AnchorNode)node;
- switch (an.type) {
- case AnchorType.PREC_READ:
- case AnchorType.PREC_READ_NOT:
- case AnchorType.LOOK_BEHIND:
- case AnchorType.LOOK_BEHIND_NOT:
- r = subexpInfRecursiveCheckTrav(an.target);
- break;
- } // inner switch
- break;
-
- case NodeType.ENCLOSE:
- EncloseNode en = (EncloseNode)node;
- if (en.isRecursion()) {
- en.setMark1();
- r = subexpInfRecursiveCheck(en.target, true);
- if (r > 0) newValueException(ERR_NEVER_ENDING_RECURSION);
- en.clearMark1();
- }
- r = subexpInfRecursiveCheckTrav(en.target);
- break;
-
- default:
- break;
- } // switch
-
- return r;
- }
-
- private int subexpRecursiveCheck(Node node) {
- int r = 0;
-
- switch (node.getType()) {
- case NodeType.LIST:
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- do {
- r |= subexpRecursiveCheck(can.car);
- } while ((can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- r = subexpRecursiveCheck(((QuantifierNode)node).target);
- break;
-
- case NodeType.ANCHOR:
- AnchorNode an = (AnchorNode)node;
- switch (an.type) {
- case AnchorType.PREC_READ:
- case AnchorType.PREC_READ_NOT:
- case AnchorType.LOOK_BEHIND:
- case AnchorType.LOOK_BEHIND_NOT:
- r = subexpRecursiveCheck(an.target);
- break;
- } // inner switch
- break;
-
- case NodeType.CALL:
- CallNode cn = (CallNode)node;
- r = subexpRecursiveCheck(cn.target);
- if (r != 0) cn.setRecursion();
- break;
-
- case NodeType.ENCLOSE:
- EncloseNode en = (EncloseNode)node;
- if (en.isMark2()) {
- return 0;
- } else if (en.isMark1()) {
- return 1; /* recursion */
- } else {
- en.setMark2();
- r = subexpRecursiveCheck(en.target);
- en.clearMark2();
- }
- break;
-
- default:
- break;
- } // switch
-
- return r;
- }
-
- private static final int FOUND_CALLED_NODE = 1;
- protected final int subexpRecursiveCheckTrav(Node node) {
- int r = 0;
-
- switch (node.getType()) {
- case NodeType.LIST:
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- do {
- int ret = subexpRecursiveCheckTrav(can.car);
- if (ret == FOUND_CALLED_NODE) {
- r = FOUND_CALLED_NODE;
- }
- // else if (ret < 0) return ret; ???
- } while ((can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- QuantifierNode qn = (QuantifierNode)node;
- r = subexpRecursiveCheckTrav(qn.target);
- if (qn.upper == 0) {
- if (r == FOUND_CALLED_NODE) qn.isRefered = true;
- }
- break;
-
- case NodeType.ANCHOR:
- AnchorNode an = (AnchorNode)node;
- switch (an.type) {
- case AnchorType.PREC_READ:
- case AnchorType.PREC_READ_NOT:
- case AnchorType.LOOK_BEHIND:
- case AnchorType.LOOK_BEHIND_NOT:
- r = subexpRecursiveCheckTrav(an.target);
- break;
- } // inner switch
- break;
-
- case NodeType.ENCLOSE:
- EncloseNode en = (EncloseNode)node;
- if (!en.isRecursion()) {
- if (en.isCalled()) {
- en.setMark1();
- r = subexpRecursiveCheck(en.target);
- if (r != 0) en.setRecursion();
- en.clearMark1();
- }
- }
- r = subexpRecursiveCheckTrav(en.target);
- if (en.isCalled()) r |= FOUND_CALLED_NODE;
- break;
-
- default:
- break;
- } // switch
-
- return r;
- }
-
- private void setCallAttr(CallNode cn) {
- cn.target = env.memNodes[cn.groupNum]; // no setTarget in call nodes!
- if (cn.target == null) newValueException(ERR_UNDEFINED_NAME_REFERENCE, cn.nameP, cn.nameEnd);
-
- ((EncloseNode)cn.target).setCalled();
- env.btMemStart = BitStatus.bsOnAt(env.btMemStart, cn.groupNum);
- cn.unsetAddrList = env.unsetAddrList;
- }
-
- protected final void setupSubExpCall(Node node) {
-
- switch(node.getType()) {
- case NodeType.LIST:
- ConsAltNode ln = (ConsAltNode)node;
- do {
- setupSubExpCall(ln.car);
- } while ((ln = ln.cdr) != null);
- break;
-
- case NodeType.ALT:
- ConsAltNode can = (ConsAltNode)node;
- do {
- setupSubExpCall(can.car);
- } while ((can = can.cdr) != null);
- break;
-
- case NodeType.QTFR:
- setupSubExpCall(((QuantifierNode)node).target);
- break;
-
- case NodeType.ENCLOSE:
- setupSubExpCall(((EncloseNode)node).target);
- break;
-
- case NodeType.CALL:
- CallNode cn = (CallNode)node;
-
- if (cn.groupNum != 0) {
- int gNum = cn.groupNum;
-
- if (Config.USE_NAMED_GROUP) {
- if (env.numNamed > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(env.option)) {
- newValueException(ERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED);
- }
- } // USE_NAMED_GROUP
- if (gNum > env.numMem) newValueException(ERR_UNDEFINED_GROUP_REFERENCE, cn.nameP, cn.nameEnd);
- setCallAttr(cn);
- } else {
- if (Config.USE_NAMED_GROUP) {
- NameEntry ne = regex.nameToGroupNumbers(cn.name, cn.nameP, cn.nameEnd);
-
- if (ne == null) {
- newValueException(ERR_UNDEFINED_NAME_REFERENCE, cn.nameP, cn.nameEnd);
- } else if (ne.backNum > 1) {
- newValueException(ERR_MULTIPLEX_DEFINITION_NAME_CALL, cn.nameP, cn.nameEnd);
- } else {
- cn.groupNum = ne.backRef1; // ne.backNum == 1 ? ne.backRef1 : ne.backRefs[0]; // ??? need to check ?
- setCallAttr(cn);
- }
- }
- }
- break;
-
- case NodeType.ANCHOR:
- AnchorNode an = (AnchorNode)node;
- switch (an.type) {
- case AnchorType.PREC_READ:
- case AnchorType.PREC_READ_NOT:
- case AnchorType.LOOK_BEHIND:
- case AnchorType.LOOK_BEHIND_NOT:
- setupSubExpCall(an.target);
- break;
- }
- break;
-
- } // switch
- }
-
/* divide different length alternatives in look-behind.
(?<=A|B) ==> (?<=A)|(?<=B)
(?<!A|B) ==> (?<!A)(?<!B)
@@ -1523,125 +904,6 @@ final class Analyser extends Parser {
return xnode;
}
- private static final int CEC_THRES_NUM_BIG_REPEAT = 512;
- private static final int CEC_INFINITE_NUM = 0x7fffffff;
-
- private static final int CEC_IN_INFINITE_REPEAT = (1<<0);
- private static final int CEC_IN_FINITE_REPEAT = (1<<1);
- private static final int CEC_CONT_BIG_REPEAT = (1<<2);
-
- protected final int setupCombExpCheck(Node node, int state) {
- int r = state;
- int ret;
-
- switch (node.getType()) {
- case NodeType.LIST:
- ConsAltNode ln = (ConsAltNode)node;
-
- do {
- r = setupCombExpCheck(ln.car, r);
- //prev = ((ConsAltNode)node).car;
- } while (r >= 0 && (ln = ln.cdr) != null);
- break;
-
- case NodeType.ALT:
- ConsAltNode an = (ConsAltNode)node;
- do {
- ret = setupCombExpCheck(an.car, state);
- r |= ret;
- } while (ret >= 0 && (an = an.cdr) != null);
- break;
-
- case NodeType.QTFR:
- QuantifierNode qn = (QuantifierNode)node;
- int childState = state;
- int addState = 0;
- int varNum;
-
- if (!isRepeatInfinite(qn.upper)) {
- if (qn.upper > 1) {
- /* {0,1}, {1,1} are allowed */
- childState |= CEC_IN_FINITE_REPEAT;
-
- /* check (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n} */
- if (env.backrefedMem == 0) {
- if (qn.target.getType() == NodeType.ENCLOSE) {
- EncloseNode en = (EncloseNode)qn.target;
- if (en.type == EncloseType.MEMORY) {
- if (en.target.getType() == NodeType.QTFR) {
- QuantifierNode q = (QuantifierNode)en.target;
- if (isRepeatInfinite(q.upper) && q.greedy == qn.greedy) {
- qn.upper = qn.lower == 0 ? 1 : qn.lower;
- if (qn.upper == 1) childState = state;
- }
- }
- }
- }
- }
- }
- }
-
- if ((state & CEC_IN_FINITE_REPEAT) != 0) {
- qn.combExpCheckNum = -1;
- } else {
- if (isRepeatInfinite(qn.upper)) {
- varNum = CEC_INFINITE_NUM;
- childState |= CEC_IN_INFINITE_REPEAT;
- } else {
- varNum = qn.upper - qn.lower;
- }
-
- if (varNum >= CEC_THRES_NUM_BIG_REPEAT) addState |= CEC_CONT_BIG_REPEAT;
-
- if (((state & CEC_IN_INFINITE_REPEAT) != 0 && varNum != 0) ||
- ((state & CEC_CONT_BIG_REPEAT) != 0 && varNum >= CEC_THRES_NUM_BIG_REPEAT)) {
- if (qn.combExpCheckNum == 0) {
- env.numCombExpCheck++;
- qn.combExpCheckNum = env.numCombExpCheck;
- if (env.currMaxRegNum > env.combExpMaxRegNum) {
- env.combExpMaxRegNum = env.currMaxRegNum;
- }
- }
- }
- }
- r = setupCombExpCheck(qn.target, childState);
- r |= addState;
- break;
-
- case NodeType.ENCLOSE:
- EncloseNode en = (EncloseNode)node;
- switch( en.type) {
- case EncloseNode.MEMORY:
- if (env.currMaxRegNum < en.regNum) {
- env.currMaxRegNum = en.regNum;
- }
- r = setupCombExpCheck(en.target, state);
- break;
-
- default:
- r = setupCombExpCheck(en.target, state);
- } // inner switch
- break;
-
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- CallNode cn = (CallNode)node;
- if (cn.isRecursion()) {
- env.hasRecursion = true;
- } else {
- r = setupCombExpCheck(cn.target, state);
- }
- } // USE_SUBEXP_CALL
- break;
-
- default:
- break;
-
- } // switch
-
- return r;
- }
-
private static final int IN_ALT = (1<<0);
private static final int IN_NOT = (1<<1);
private static final int IN_REPEAT = (1<<2);
@@ -1691,20 +953,12 @@ final class Analyser extends Parser {
case NodeType.CANY:
break;
- case NodeType.CALL: // if (Config.USE_SUBEXP_CALL) ?
- break;
-
case NodeType.BREF:
BackRefNode br = (BackRefNode)node;
for (int i=0; i<br.backNum; i++) {
if (br.back[i] > env.numMem) newValueException(ERR_INVALID_BACKREF);
env.backrefedMem = bsOnAt(env.backrefedMem, br.back[i]);
env.btMemStart = bsOnAt(env.btMemStart, br.back[i]);
- if (Config.USE_BACKREF_WITH_LEVEL) {
- if (br.isNestLevel()) {
- env.btMemEnd = bsOnAt(env.btMemEnd, br.back[i]);
- }
- } // USE_BACKREF_AT_LEVEL
((EncloseNode)env.memNodes[br.back[i]]).setMemBackrefed();
}
break;
@@ -1916,37 +1170,6 @@ final class Analyser extends Parser {
break;
}
- case NodeType.CTYPE: {
- int min;
- int max = 1;
- if (max == 1) {
- min = 1;
- CTypeNode cn = (CTypeNode)node;
-
- switch (cn.ctype) {
- case CharacterType.WORD:
- if (cn.not) {
- for (int i=0; i<BitSet.SINGLE_BYTE_SIZE; i++) {
- if (!EncodingHelper.isWord(i)) {
- opt.map.addChar(i);
- }
- }
- } else {
- for (int i=0; i<BitSet.SINGLE_BYTE_SIZE; i++) {
- if (EncodingHelper.isWord(i)) {
- opt.map.addChar(i);
- }
- }
- }
- break;
- } // inner switch
- } else {
- min = 1;
- }
- opt.length.set(min, max);
- break;
- }
-
case NodeType.CANY: {
opt.length.set(1, 1);
break;
@@ -2008,20 +1231,6 @@ final class Analyser extends Parser {
break;
}
- case NodeType.CALL: {
- if (Config.USE_SUBEXP_CALL) {
- CallNode cn = (CallNode)node;
- if (cn.isRecursion()) {
- opt.length.set(0, MinMaxLen.INFINITE_DISTANCE);
- } else {
- int safe = oenv.options;
- oenv.options = ((EncloseNode)cn.target).option;
- optimizeNodeLeft(cn.target, opt, oenv);
- oenv.options = safe;
- }
- } // USE_SUBEXP_CALL
- break;
- }
case NodeType.QTFR: {
NodeOptInfo nopt = new NodeOptInfo();
@@ -2081,7 +1290,7 @@ final class Analyser extends Parser {
break;
case EncloseType.MEMORY:
- if (Config.USE_SUBEXP_CALL && ++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) {
+ if (++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) {
int min = 0;
int max = MinMaxLen.INFINITE_DISTANCE;
if (en.isMinFixed()) min = en.minLength;
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java
index b5599169..f348a205 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java
@@ -28,8 +28,6 @@ import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepe
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.Node;
@@ -71,11 +69,6 @@ final class ArrayCompiler extends Compiler {
regex.templates = templates;
regex.templateNum = templateNum;
regex.factory = MatcherFactory.DEFAULT;
-
- if (Config.USE_SUBEXP_CALL && analyser.env.unsetAddrList != null) {
- analyser.env.unsetAddrList.fix(regex);
- analyser.env.unsetAddrList = null;
- }
}
@Override
@@ -119,7 +112,7 @@ final class ArrayCompiler extends Compiler {
return isNeedStrLenOpExact(op);
}
- private int selectStrOpcode(int mbLength, int strLength, boolean ignoreCase) {
+ private int selectStrOpcode(int strLength, boolean ignoreCase) {
int op;
if (ignoreCase) {
@@ -128,31 +121,14 @@ final class ArrayCompiler extends Compiler {
default:op = OPCode.EXACTN_IC; break;
} // switch
} else {
- switch (mbLength) {
- case 1:
- switch (strLength) {
- case 1: op = OPCode.EXACT1; break;
- case 2: op = OPCode.EXACT2; break;
- case 3: op = OPCode.EXACT3; break;
- case 4: op = OPCode.EXACT4; break;
- case 5: op = OPCode.EXACT5; break;
- default:op = OPCode.EXACTN; break;
- } // inner switch
- break;
- case 2:
- switch (strLength) {
- case 1: op = OPCode.EXACTMB2N1; break;
- case 2: op = OPCode.EXACTMB2N2; break;
- case 3: op = OPCode.EXACTMB2N3; break;
- default:op = OPCode.EXACTMB2N; break;
- } // inner switch
- break;
- case 3:
- op = OPCode.EXACTMB3N;
- break;
- default:
- op = OPCode.EXACTMBN;
- } // switch
+ switch (strLength) {
+ case 1: op = OPCode.EXACT1; break;
+ case 2: op = OPCode.EXACT2; break;
+ case 3: op = OPCode.EXACT3; break;
+ case 4: op = OPCode.EXACT4; break;
+ case 5: op = OPCode.EXACT5; break;
+ default:op = OPCode.EXACTN; break;
+ } // inner switch
}
return op;
}
@@ -185,8 +161,8 @@ final class ArrayCompiler extends Compiler {
}
}
- private int addCompileStringlength(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase) {
- int op = selectStrOpcode(mbLength, strLength, ignoreCase);
+ private int addCompileStringlength(char[] chars, int p, int strLength, boolean ignoreCase) {
+ int op = selectStrOpcode(strLength, ignoreCase);
int len = OPSize.OPCODE;
if (Config.USE_STRING_TEMPLATES && opTemplated(op)) {
@@ -194,25 +170,21 @@ final class ArrayCompiler extends Compiler {
len += OPSize.LENGTH + OPSize.INDEX + OPSize.INDEX;
} else {
if (isNeedStrLenOpExact(op)) len += OPSize.LENGTH;
- len += mbLength * strLength;
+ len += strLength;
}
if (op == OPCode.EXACTMBN) len += OPSize.LENGTH;
return len;
}
@Override
- protected final void addCompileString(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase) {
- int op = selectStrOpcode(mbLength, strLength, ignoreCase);
+ protected final void addCompileString(char[] chars, int p, int strLength, boolean ignoreCase) {
+ int op = selectStrOpcode(strLength, ignoreCase);
addOpcode(op);
- if (op == OPCode.EXACTMBN) addLength(mbLength);
+ if (op == OPCode.EXACTMBN) addLength(1);
if (isNeedStrLenOpExact(op)) {
- if (op == OPCode.EXACTN_IC || op == OPCode.EXACTN_IC_SB) {
- addLength(mbLength * strLength);
- } else {
- addLength(strLength);
- }
+ addLength(strLength);
}
if (Config.USE_STRING_TEMPLATES && opTemplated(op)) {
@@ -220,7 +192,7 @@ final class ArrayCompiler extends Compiler {
addInt(p);
addTemplate(chars);
} else {
- addChars(chars, p, mbLength * strLength);
+ addChars(chars, p, strLength);
}
}
@@ -242,14 +214,14 @@ final class ArrayCompiler extends Compiler {
slen++;
p++;
}
- int r = addCompileStringlength(chars, prev, 1, slen, ambig);
+ int r = addCompileStringlength(chars, prev, slen, ambig);
rlen += r;
return rlen;
}
private int compileLengthStringRawNode(StringNode sn) {
if (sn.length() <= 0) return 0;
- return addCompileStringlength(sn.chars, sn.p, 1 /*sb*/, sn.length(), false);
+ return addCompileStringlength(sn.chars, sn.p, sn.length(), false);
}
private void addMultiByteCClass(CodeRangeBuffer mbuf) {
@@ -312,26 +284,6 @@ final class ArrayCompiler extends Compiler {
}
@Override
- protected void compileCTypeNode(CTypeNode node) {
- CTypeNode cn = node;
- int op;
- switch (cn.ctype) {
- case CharacterType.WORD:
- if (cn.not) {
- op = OPCode.NOT_WORD;
- } else {
- op = OPCode.WORD;
- }
- break;
-
- default:
- newInternalException(ERR_PARSER_BUG);
- return; // not reached
- } // inner switch
- addOpcode(op);
- }
-
- @Override
protected void compileAnyCharNode() {
if (isMultiline(regex.options)) {
addOpcode(OPCode.ANYCHAR_ML);
@@ -341,30 +293,15 @@ final class ArrayCompiler extends Compiler {
}
@Override
- protected void compileCallNode(CallNode node) {
- addOpcode(OPCode.CALL);
- node.unsetAddrList.add(codeLength, node.target);
- addAbsAddr(0); /*dummy addr.*/
- }
-
- @Override
protected void compileBackrefNode(BackRefNode node) {
BackRefNode br = node;
- if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) {
- addOpcode(OPCode.BACKREF_WITH_LEVEL);
- addOption(regex.options & Option.IGNORECASE);
- addLength(br.nestLevel);
- // !goto add_bacref_mems;!
- addLength(br.backNum);
- for (int i=br.backNum-1; i>=0; i--) addMemNum(br.back[i]);
- return;
- } else { // USE_BACKREF_AT_LEVEL
- if (br.backNum == 1) {
- if (isIgnoreCase(regex.options)) {
- addOpcode(OPCode.BACKREFN_IC);
- addMemNum(br.back[0]);
- } else {
- switch (br.back[0]) {
+ // USE_BACKREF_AT_LEVEL
+ if (br.backNum == 1) {
+ if (isIgnoreCase(regex.options)) {
+ addOpcode(OPCode.BACKREFN_IC);
+ addMemNum(br.back[0]);
+ } else {
+ switch (br.back[0]) {
case 1:
addOpcode(OPCode.BACKREF1);
break;
@@ -375,18 +312,17 @@ final class ArrayCompiler extends Compiler {
addOpcode(OPCode.BACKREFN);
addOpcode(br.back[0]);
break;
- } // switch
- }
+ } // switch
+ }
+ } else {
+ if (isIgnoreCase(regex.options)) {
+ addOpcode(OPCode.BACKREF_MULTI_IC);
} else {
- if (isIgnoreCase(regex.options)) {
- addOpcode(OPCode.BACKREF_MULTI_IC);
- } else {
- addOpcode(OPCode.BACKREF_MULTI);
- }
- // !add_bacref_mems:!
- addLength(br.backNum);
- for (int i=br.backNum-1; i>=0; i--) addMemNum(br.back[i]);
+ addOpcode(OPCode.BACKREF_MULTI);
}
+ // !add_bacref_mems:!
+ addLength(br.backNum);
+ for (int i=br.backNum-1; i>=0; i--) addMemNum(br.back[i]);
}
}
@@ -419,7 +355,7 @@ final class ArrayCompiler extends Compiler {
compileTreeEmptyCheck(qn.target, emptyInfo);
- if ((Config.USE_SUBEXP_CALL && regex.numCall > 0) || qn.isInRepeat()) {
+ if (qn.isInRepeat()) {
addOpcode(qn.greedy ? OPCode.REPEAT_INC_SG : OPCode.REPEAT_INC_NG_SG);
} else {
addOpcode(qn.greedy ? OPCode.REPEAT_INC : OPCode.REPEAT_INC_NG);
@@ -434,193 +370,6 @@ final class ArrayCompiler extends Compiler {
return ckn > 0;
}
- private int compileCECLengthQuantifierNode(QuantifierNode qn) {
- boolean infinite = isRepeatInfinite(qn.upper);
- int emptyInfo = qn.targetEmptyInfo;
-
- int tlen = compileLengthTree(qn.target);
- int ckn = regex.numCombExpCheck > 0 ? qn.combExpCheckNum : 0;
- int cklen = cknOn(ckn) ? OPSize.STATE_CHECK_NUM : 0;
-
- /* anychar repeat */
- if (qn.target.getType() == NodeType.CANY) {
- if (qn.greedy && infinite) {
- if (qn.nextHeadExact != null && !cknOn(ckn)) {
- return OPSize.ANYCHAR_STAR_PEEK_NEXT + tlen * qn.lower + cklen;
- } else {
- return OPSize.ANYCHAR_STAR + tlen * qn.lower + cklen;
- }
- }
- }
-
- int modTLen;
- if (emptyInfo != 0) {
- modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
- } else {
- modTLen = tlen;
- }
-
- int len;
- if (infinite && qn.lower <= 1) {
- if (qn.greedy) {
- if (qn.lower == 1) {
- len = OPSize.JUMP;
- } else {
- len = 0;
- }
- len += OPSize.PUSH + cklen + modTLen + OPSize.JUMP;
- } else {
- if (qn.lower == 0) {
- len = OPSize.JUMP;
- } else {
- len = 0;
- }
- len += modTLen + OPSize.PUSH + cklen;
- }
- } else if (qn.upper == 0) {
- if (qn.isRefered) { /* /(?<n>..){0}/ */
- len = OPSize.JUMP + tlen;
- } else {
- len = 0;
- }
- } else if (qn.upper == 1 && qn.greedy) {
- if (qn.lower == 0) {
- if (cknOn(ckn)) {
- len = OPSize.STATE_CHECK_PUSH + tlen;
- } else {
- len = OPSize.PUSH + tlen;
- }
- } else {
- len = tlen;
- }
- } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0) { /* '??' */
- len = OPSize.PUSH + cklen + OPSize.JUMP + tlen;
- } else {
- len = OPSize.REPEAT_INC + modTLen + OPSize.OPCODE + OPSize.RELADDR + OPSize.MEMNUM;
-
- if (cknOn(ckn)) {
- len += OPSize.STATE_CHECK;
- }
- }
- return len;
- }
-
- @Override
- protected void compileCECQuantifierNode(QuantifierNode qn) {
- boolean infinite = isRepeatInfinite(qn.upper);
- int emptyInfo = qn.targetEmptyInfo;
-
- int tlen = compileLengthTree(qn.target);
-
- int ckn = regex.numCombExpCheck > 0 ? qn.combExpCheckNum : 0;
-
- if (qn.isAnyCharStar()) {
- compileTreeNTimes(qn.target, qn.lower);
- if (qn.nextHeadExact != null && !cknOn(ckn)) {
- if (isMultiline(regex.options)) {
- addOpcode(OPCode.ANYCHAR_ML_STAR_PEEK_NEXT);
- } else {
- addOpcode(OPCode.ANYCHAR_STAR_PEEK_NEXT);
- }
- if (cknOn(ckn)) {
- addStateCheckNum(ckn);
- }
- StringNode sn = (StringNode)qn.nextHeadExact;
- addChars(sn.chars, sn.p, 1);
- return;
- } else {
- if (isMultiline(regex.options)) {
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK_ANYCHAR_ML_STAR);
- } else {
- addOpcode(OPCode.ANYCHAR_ML_STAR);
- }
- } else {
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK_ANYCHAR_STAR);
- } else {
- addOpcode(OPCode.ANYCHAR_STAR);
- }
- }
- if (cknOn(ckn)) {
- addStateCheckNum(ckn);
- }
- return;
- }
- }
-
- int modTLen;
- if (emptyInfo != 0) {
- modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
- } else {
- modTLen = tlen;
- }
- if (infinite && qn.lower <= 1) {
- if (qn.greedy) {
- if (qn.lower == 1) {
- addOpcodeRelAddr(OPCode.JUMP, cknOn(ckn) ? OPSize.STATE_CHECK_PUSH :
- OPSize.PUSH);
- }
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK_PUSH);
- addStateCheckNum(ckn);
- addRelAddr(modTLen + OPSize.JUMP);
- } else {
- addOpcodeRelAddr(OPCode.PUSH, modTLen + OPSize.JUMP);
- }
- compileTreeEmptyCheck(qn.target, emptyInfo);
- addOpcodeRelAddr(OPCode.JUMP, -(modTLen + OPSize.JUMP + (cknOn(ckn) ?
- OPSize.STATE_CHECK_PUSH :
- OPSize.PUSH)));
- } else {
- if (qn.lower == 0) {
- addOpcodeRelAddr(OPCode.JUMP, modTLen);
- }
- compileTreeEmptyCheck(qn.target, emptyInfo);
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK_PUSH_OR_JUMP);
- addStateCheckNum(ckn);
- addRelAddr(-(modTLen + OPSize.STATE_CHECK_PUSH_OR_JUMP));
- } else {
- addOpcodeRelAddr(OPCode.PUSH, -(modTLen + OPSize.PUSH));
- }
- }
- } else if (qn.upper == 0) {
- if (qn.isRefered) { /* /(?<n>..){0}/ */
- addOpcodeRelAddr(OPCode.JUMP, tlen);
- compileTree(qn.target);
- } // else r=0 ???
- } else if (qn.upper == 1 && qn.greedy) {
- if (qn.lower == 0) {
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK_PUSH);
- addStateCheckNum(ckn);
- addRelAddr(tlen);
- } else {
- addOpcodeRelAddr(OPCode.PUSH, tlen);
- }
- }
- compileTree(qn.target);
- } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0){ /* '??' */
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK_PUSH);
- addStateCheckNum(ckn);
- addRelAddr(OPSize.JUMP);
- } else {
- addOpcodeRelAddr(OPCode.PUSH, OPSize.JUMP);
- }
-
- addOpcodeRelAddr(OPCode.JUMP, tlen);
- compileTree(qn.target);
- } else {
- compileRangeRepeatNode(qn, modTLen, emptyInfo);
- if (cknOn(ckn)) {
- addOpcode(OPCode.STATE_CHECK);
- addStateCheckNum(ckn);
- }
- }
- }
-
private int compileNonCECLengthQuantifierNode(QuantifierNode qn) {
boolean infinite = isRepeatInfinite(qn.upper);
int emptyInfo = qn.targetEmptyInfo;
@@ -821,21 +570,12 @@ final class ArrayCompiler extends Compiler {
int len;
switch (node.type) {
case EncloseType.MEMORY:
- if (Config.USE_SUBEXP_CALL && node.isCalled()) {
- len = OPSize.MEMORY_START_PUSH + tlen + OPSize.CALL + OPSize.JUMP + OPSize.RETURN;
- if (bsAt(regex.btMemEnd, node.regNum)) {
- len += node.isRecursion() ? OPSize.MEMORY_END_PUSH_REC : OPSize.MEMORY_END_PUSH;
- } else {
- len += node.isRecursion() ? OPSize.MEMORY_END_REC : OPSize.MEMORY_END;
- }
- } else { // USE_SUBEXP_CALL
- if (bsAt(regex.btMemStart, node.regNum)) {
- len = OPSize.MEMORY_START_PUSH;
- } else {
- len = OPSize.MEMORY_START;
- }
- len += tlen + (bsAt(regex.btMemEnd, node.regNum) ? OPSize.MEMORY_END_PUSH : OPSize.MEMORY_END);
+ if (bsAt(regex.btMemStart, node.regNum)) {
+ len = OPSize.MEMORY_START_PUSH;
+ } else {
+ len = OPSize.MEMORY_START;
}
+ len += tlen + (bsAt(regex.btMemEnd, node.regNum) ? OPSize.MEMORY_END_PUSH : OPSize.MEMORY_END);
break;
case EncloseType.STOP_BACKTRACK:
@@ -860,23 +600,6 @@ final class ArrayCompiler extends Compiler {
int len;
switch (node.type) {
case EncloseType.MEMORY:
- if (Config.USE_SUBEXP_CALL) {
- if (node.isCalled()) {
- addOpcode(OPCode.CALL);
- node.callAddr = codeLength + OPSize.ABSADDR + OPSize.JUMP;
- node.setAddrFixed();
- addAbsAddr(node.callAddr);
- len = compileLengthTree(node.target);
- len += OPSize.MEMORY_START_PUSH + OPSize.RETURN;
- if (bsAt(regex.btMemEnd, node.regNum)) {
- len += node.isRecursion() ? OPSize.MEMORY_END_PUSH_REC : OPSize.MEMORY_END_PUSH;
- } else {
- len += node.isRecursion() ? OPSize.MEMORY_END_REC : OPSize.MEMORY_END;
- }
- addOpcodeRelAddr(OPCode.JUMP, len);
- }
- } // USE_SUBEXP_CALL
-
if (bsAt(regex.btMemStart, node.regNum)) {
addOpcode(OPCode.MEMORY_START_PUSH);
} else {
@@ -886,22 +609,12 @@ final class ArrayCompiler extends Compiler {
addMemNum(node.regNum);
compileTree(node.target);
- if (Config.USE_SUBEXP_CALL && node.isCalled()) {
- if (bsAt(regex.btMemEnd, node.regNum)) {
- addOpcode(node.isRecursion() ? OPCode.MEMORY_END_PUSH_REC : OPCode.MEMORY_END_PUSH);
- } else {
- addOpcode(node.isRecursion() ? OPCode.MEMORY_END_REC : OPCode.MEMORY_END);
- }
- addMemNum(node.regNum);
- addOpcode(OPCode.RETURN);
- } else { // USE_SUBEXP_CALL
- if (bsAt(regex.btMemEnd, node.regNum)) {
- addOpcode(OPCode.MEMORY_END_PUSH);
- } else {
- addOpcode(OPCode.MEMORY_END);
- }
- addMemNum(node.regNum);
+ if (bsAt(regex.btMemEnd, node.regNum)) {
+ addOpcode(OPCode.MEMORY_END_PUSH);
+ } else {
+ addOpcode(OPCode.MEMORY_END);
}
+ addMemNum(node.regNum);
break;
case EncloseType.STOP_BACKTRACK:
@@ -1078,32 +791,17 @@ final class ArrayCompiler extends Compiler {
case NodeType.BREF:
BackRefNode br = (BackRefNode)node;
- if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) {
- len = OPSize.OPCODE + OPSize.OPTION + OPSize.LENGTH +
- OPSize.LENGTH + (OPSize.MEMNUM * br.backNum);
- } else { // USE_BACKREF_AT_LEVEL
- if (br.backNum == 1) {
- len = ((!isIgnoreCase(regex.options) && br.back[0] <= 2)
- ? OPSize.OPCODE : (OPSize.OPCODE + OPSize.MEMNUM));
- } else {
- len = OPSize.OPCODE + OPSize.LENGTH + (OPSize.MEMNUM * br.backNum);
- }
+ // USE_BACKREF_AT_LEVEL
+ if (br.backNum == 1) {
+ len = ((!isIgnoreCase(regex.options) && br.back[0] <= 2)
+ ? OPSize.OPCODE : (OPSize.OPCODE + OPSize.MEMNUM));
+ } else {
+ len = OPSize.OPCODE + OPSize.LENGTH + (OPSize.MEMNUM * br.backNum);
}
break;
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- len = OPSize.CALL;
- break;
- } // USE_SUBEXP_CALL
- break;
-
case NodeType.QTFR:
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- len = compileCECLengthQuantifierNode((QuantifierNode)node);
- } else {
- len = compileNonCECLengthQuantifierNode((QuantifierNode)node);
- }
+ len = compileNonCECLengthQuantifierNode((QuantifierNode)node);
break;
case NodeType.ENCLOSE:
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java b/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java
deleted file mode 100644
index 475d6595..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni;
-
-import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode;
-
-final class AsmCompiler extends AsmCompilerSupport {
-
- public AsmCompiler(Analyser analyser) {
- super(analyser);
- }
-
- @Override
- protected void prepare() {
- REG_NUM++;
- prepareMachine();
- prepareMachineInit();
- prepareMachineMatch();
-
- prepareFactory();
- prepareFactoryInit();
- }
-
- @Override
- protected void finish() {
- setupFactoryInit();
-
- setupMachineInit();
- setupMachineMatch();
-
- setupClasses();
- }
-
- @Override
- protected void compileAltNode(ConsAltNode node) {
- }
-
- @Override
- protected void addCompileString(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase) {
- String template = installTemplate(chars, p, strLength);
- }
-
- @Override
- protected void compileCClassNode(CClassNode node) {
- if (node.bs != null) {
- String bitsetName = installBitSet(node.bs.bits);
- }
- }
-
- @Override
- protected void compileCTypeNode(CTypeNode node) {
- }
-
- @Override
- protected void compileAnyCharNode() {
- }
-
- @Override
- protected void compileBackrefNode(BackRefNode node) {
- }
-
- @Override
- protected void compileCallNode(CallNode node) {
- }
-
- @Override
- protected void compileCECQuantifierNode(QuantifierNode node) {
- }
-
- @Override
- protected void compileNonCECQuantifierNode(QuantifierNode node) {
- }
-
- @Override
- protected void compileOptionNode(EncloseNode node) {
- }
-
- @Override
- protected void compileEncloseNode(EncloseNode node) {
- }
-
- @Override
- protected void compileAnchorNode(AnchorNode node) {
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java b/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java
deleted file mode 100644
index 06ca21a9..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import jdk.nashorn.internal.runtime.regexp.joni.constants.AsmConstants;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
-
-abstract class AsmCompilerSupport extends Compiler implements Opcodes, AsmConstants {
- protected ClassWriter factory; // matcher allocator, also bit set, code rage and string template container
- protected MethodVisitor factoryInit;// factory constructor
- protected String factoryName;
-
- protected ClassWriter machine; // matcher
- protected MethodVisitor machineInit;// matcher constructor
- protected MethodVisitor match; // actual matcher implementation (the matchAt method)
- protected String machineName;
-
- // we will? try to manage visitMaxs ourselves for efficiency
- protected int maxStack = 1;
- protected int maxVars = LAST_INDEX;
-
- // for field generation
- protected int bitsets, ranges, templates;
-
- // simple class name postfix scheme for now
- static int REG_NUM = 0;
-
- // dummy class loader for now
- private static final class DummyClassLoader extends ClassLoader {
- public Class<?> defineClass(String name, byte[] bytes) {
- return super.defineClass(name, bytes, 0, bytes.length);
- }
- };
-
- private static final DummyClassLoader loader = new DummyClassLoader();
-
- AsmCompilerSupport(Analyser analyser) {
- super(analyser);
- }
-
- protected final void prepareFactory() {
- factory = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- factoryName = "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory" + REG_NUM;
-
- factory.visit(V1_4, ACC_PUBLIC + ACC_FINAL, factoryName, null, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", null);
-
- MethodVisitor create = factory.visitMethod(ACC_SYNTHETIC, "create", "(Lorg/joni/Regex;[BII)Lorg/joni/Matcher;", null, null);
- create.visitTypeInsn(NEW, machineName);
- create.visitInsn(DUP); // instance
- create.visitVarInsn(ALOAD, 1); // Regex
- create.visitVarInsn(ALOAD, 2); // bytes[]
- create.visitVarInsn(ILOAD, 3); // p
- create.visitVarInsn(ILOAD, 4); // end
- create.visitMethodInsn(INVOKESPECIAL, machineName, "<init>", "(Lorg/joni/Regex;[BII)V");
- create.visitInsn(ARETURN);
- create.visitMaxs(0, 0);
- //create.visitMaxs(6, 5);
- create.visitEnd();
- }
-
- protected final void prepareFactoryInit() {
- factoryInit = factory.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
- factoryInit.visitVarInsn(ALOAD, 0);
- factoryInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", "<init>", "()V");
- }
-
- protected final void setupFactoryInit() {
- factoryInit.visitInsn(RETURN);
- factoryInit.visitMaxs(0, 0);
- //init.visitMaxs(1, 1);
- factoryInit.visitEnd();
- }
-
- protected final void prepareMachine() {
- machine = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- machineName = "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine" + REG_NUM;
- }
-
- protected final void prepareMachineInit() {
- machine.visit(V1_4, ACC_PUBLIC + ACC_FINAL, machineName, null, "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine", null);
- machineInit = machine.visitMethod(ACC_PROTECTED, "<init>", "(Lorg/joni/Regex;[BII)V", null, null);
- machineInit.visitVarInsn(ALOAD, THIS); // this
- machineInit.visitVarInsn(ALOAD, 1); // Regex
- machineInit.visitVarInsn(ALOAD, 2); // bytes[]
- machineInit.visitVarInsn(ILOAD, 3); // p
- machineInit.visitVarInsn(ILOAD, 4); // end
- machineInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine", "<init>", "(Lorg/joni/Regex;[BII)V");
- }
-
- protected final void setupMachineInit() {
- if (bitsets + ranges + templates > 0) { // ok, some of these are in use, we'd like to cache the factory
- machine.visitField(ACC_PRIVATE + ACC_FINAL, "factory", "L" + factoryName + ";", null, null);
- machineInit.visitVarInsn(ALOAD, THIS); // this
- machineInit.visitVarInsn(ALOAD, 1); // this, Regex
- machineInit.visitFieldInsn(GETFIELD, "jdk/nashorn/internal/runtime/regexp/joni/Regex", "factory", "Lorg/joni/MatcherFactory;"); // this, factory
- machineInit.visitTypeInsn(CHECKCAST, factoryName);
- machineInit.visitFieldInsn(PUTFIELD, machineName, "factory", "L" + factoryName + ";"); // []
- }
-
- machineInit.visitInsn(RETURN);
- machineInit.visitMaxs(0, 0);
- //init.visitMaxs(5, 5);
- machineInit.visitEnd();
- }
-
- protected final void prepareMachineMatch() {
- match = machine.visitMethod(ACC_SYNTHETIC, "matchAt", "(III)I", null, null);
- move(S, SSTART); // s = sstart
- load("bytes", "[B"); //
- astore(BYTES); // byte[]bytes = this.bytes
- }
-
- protected final void setupMachineMatch() {
- match.visitInsn(ICONST_M1);
- match.visitInsn(IRETURN);
-
- match.visitMaxs(maxStack, maxVars);
- match.visitEnd();
- }
-
- protected final void setupClasses() {
- byte[]factoryCode = factory.toByteArray();
- byte[]machineCode = machine.toByteArray();
-
- if (Config.DEBUG_ASM) {
- try {
- FileOutputStream fos;
- fos = new FileOutputStream(factoryName.substring(factoryName.lastIndexOf('/') + 1) + ".class");
- fos.write(factoryCode);
- fos.close();
- fos = new FileOutputStream(machineName.substring(machineName.lastIndexOf('/') + 1) + ".class");
- fos.write(machineCode);
- fos.close();
- } catch (IOException ioe) {
- ioe.printStackTrace(Config.err);
- }
- }
-
- loader.defineClass(machineName.replace('/', '.'), machineCode);
- Class<?> cls = loader.defineClass(factoryName.replace('/', '.'), factoryCode);
- try {
- regex.factory = (MatcherFactory)cls.newInstance();
- } catch(Exception e) {
- e.printStackTrace(Config.err);
- }
- }
-
- protected final void aload(int var) {
- match.visitVarInsn(ALOAD, var);
- }
-
- protected final void astore(int var) {
- match.visitVarInsn(ASTORE, var);
- }
-
- protected final void loadThis() {
- match.visitVarInsn(ALOAD, THIS);
- }
-
- protected final void load(int var) {
- match.visitVarInsn(ILOAD, var);
- }
-
- protected final void store(int var) {
- match.visitVarInsn(ISTORE, var);
- }
-
- protected final void move(int to, int from) {
- load(from);
- store(to);
- }
-
- protected final void load(String field, String singature) {
- loadThis();
- match.visitFieldInsn(GETFIELD, machineName, field, singature);
- }
-
- protected final void load(String field) {
- load(field, "I");
- }
-
- protected final void store(String field, String singature) {
- loadThis();
- match.visitFieldInsn(PUTFIELD, machineName, field, singature);
- }
-
- protected final void store(String field) {
- store(field, "I");
- }
-
- protected final String installTemplate(char[] arr, int p, int length) {
- String templateName = TEMPLATE + ++templates;
- installArray(templateName, arr, p, length);
- return templateName;
- }
-
- protected final String installCodeRange(int[]arr) {
- String coreRangeName = CODERANGE + ++ranges;
- installArray(coreRangeName, arr);
- return coreRangeName;
- }
-
- protected final String installBitSet(int[]arr) {
- String bitsetName = BITSET + ++bitsets;
- installArray(bitsetName, arr);
- return bitsetName;
- }
-
- private void installArray(String name, int[]arr) {
- factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[I", null, null);
- factoryInit.visitVarInsn(ALOAD, THIS); // this;
- loadInt(factoryInit, arr.length); // this, length
- factoryInit.visitIntInsn(NEWARRAY, T_INT); // this, arr
- for (int i=0;i < arr.length; i++) buildArray(i, arr[i], IASTORE);
- factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[I");
- }
-
- private void installArray(String name, char[]arr, int p, int length) {
- factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[B", null, null);
- factoryInit.visitVarInsn(ALOAD, THIS); // this;
- loadInt(factoryInit, arr.length); // this, length
- factoryInit.visitIntInsn(NEWARRAY, T_BYTE); // this, arr
- for (int i=p, j=0; i < p + length; i++, j++) buildArray(j, arr[i] & 0xff, BASTORE);
- factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[B");
- }
-
- private void buildArray(int index, int value, int type) {
- factoryInit.visitInsn(DUP); // ... arr, arr
- loadInt(factoryInit, index); // ... arr, arr, index
- loadInt(factoryInit, value); // ... arr, arr, index, value
- factoryInit.visitInsn(type); // ... arr
- }
-
- private void loadInt(MethodVisitor mv, int value) {
- if (value >= -1 && value <= 5) {
- mv.visitInsn(value + ICONST_0); // ICONST_0 == 3
- } else if (value >= 6 && value <= 127 || value >= -128 && value <= -2) {
- mv.visitIntInsn(BIPUSH, value);
- } else if (value >= 128 && value <= 32767 || value >= -32768 && value <= -129) {
- mv.visitIntInsn(SIPUSH, value);
- } else {
- mv.visitLdcInsn(new Integer(value));
- }
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java b/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java
index bf715987..5f98fe64 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java
@@ -51,10 +51,6 @@ public final class BitSet {
bits[pos >>> ROOM_SHIFT] &= ~bit(pos);
}
- public void invert(int pos) {
- bits[pos >>> ROOM_SHIFT] ^= bit(pos);
- }
-
public void clear() {
for (int i=0; i<BITSET_SIZE; i++) bits[i]=0;
}
@@ -70,10 +66,6 @@ public final class BitSet {
for (int i=from; i<=to && i < SINGLE_BYTE_SIZE; i++) set(i);
}
- public void setAll() {
- for (int i=0; i<BITSET_SIZE; i++) bits[i] = ~0;
- }
-
public void invert() {
for (int i=0; i<BITSET_SIZE; i++) bits[i] = ~bits[i];
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java b/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java
index 758a4e57..30528598 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java
@@ -25,12 +25,15 @@ final class BitStatus {
public static int bsClear() {
return 0;
}
+
public static int bsAll() {
return -1;
}
+
public static boolean bsAt(int stats, int n) {
return (n < BIT_STATUS_BITS_NUM ? stats & (1 << n) : (stats & 1)) != 0;
}
+
public static int bsOnAt(int stats, int n) {
if (n < BIT_STATUS_BITS_NUM) {
stats |= (1 << n);
@@ -39,10 +42,6 @@ final class BitStatus {
}
return stats;
}
- public static int bsOnAtSimple(int stats, int n) {
- if (n < BIT_STATUS_BITS_NUM) stats |= (1 << n);
- return stats;
- }
public static int bsOnOff(int v, int f, boolean negative) {
if (negative) {
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java
index 43cc5188..855e1ced 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java
@@ -53,56 +53,6 @@ class ByteCodeMachine extends StackMachine {
this.code = regex.code;
}
- protected int stkp; // a temporary
- private boolean makeCaptureHistoryTree(CaptureTreeNode node) {
- //CaptureTreeNode child;
- int k = stkp;
- //int k = kp;
-
- while (k < stk) {
- StackEntry e = stack[k];
- if (e.type == MEM_START) {
- int n = e.getMemNum();
- if (n <= Config.MAX_CAPTURE_HISTORY_GROUP && bsAt(regex.captureHistory, n)) {
- CaptureTreeNode child = new CaptureTreeNode();
- child.group = n;
- child.beg = e.getMemPStr() - str;
- node.addChild(child);
- stkp = k + 1;
- if (makeCaptureHistoryTree(child)) return true;
-
- k = stkp;
- child.end = e.getMemPStr() - str;
- }
- } else if (e.type == MEM_END) {
- if (e.getMemNum() == node.group) {
- node.end = e.getMemPStr() - str;
- stkp = k;
- return false;
- }
- }
- }
- return true; /* 1: root node ending. */
- }
-
- private void checkCaptureHistory(Region region) {
- CaptureTreeNode node;
- if (region.historyRoot == null) {
- node = region.historyRoot = new CaptureTreeNode();
- } else {
- node = region.historyRoot;
- node.clear();
- }
-
- // was clear ???
- node.group = 0;
- node.beg = sstart - str;
- node.end = s - str;
-
- stkp = 0;
- makeCaptureHistoryTree(region.historyRoot);
- }
-
private boolean stringCmpIC(int caseFlodFlag, int s1, IntHolder ps2, int mbLen, int textEnd) {
int s2 = ps2.value;
@@ -175,13 +125,6 @@ class ByteCodeMachine extends StackMachine {
case OPCode.EXACT5: opExact5(); continue;
case OPCode.EXACTN: opExactN(); continue;
- case OPCode.EXACTMB2N1: opExactMB2N1(); break;
- case OPCode.EXACTMB2N2: opExactMB2N2(); continue;
- case OPCode.EXACTMB2N3: opExactMB2N3(); continue;
- case OPCode.EXACTMB2N: opExactMB2N(); continue;
- case OPCode.EXACTMB3N: opExactMB3N(); continue;
- case OPCode.EXACTMBN: opExactMBN(); continue;
-
case OPCode.EXACT1_IC: opExact1IC(); break;
case OPCode.EXACTN_IC: opExactNIC(); continue;
@@ -199,8 +142,6 @@ class ByteCodeMachine extends StackMachine {
case OPCode.ANYCHAR_ML_STAR: opAnyCharMLStar(); break;
case OPCode.ANYCHAR_STAR_PEEK_NEXT: opAnyCharStarPeekNext(); break;
case OPCode.ANYCHAR_ML_STAR_PEEK_NEXT: opAnyCharMLStarPeekNext(); break;
- case OPCode.STATE_CHECK_ANYCHAR_STAR: opStateCheckAnyCharStar(); break;
- case OPCode.STATE_CHECK_ANYCHAR_ML_STAR:opStateCheckAnyCharMLStar();break;
case OPCode.WORD: opWord(); break;
case OPCode.NOT_WORD: opNotWord(); break;
@@ -239,11 +180,6 @@ class ByteCodeMachine extends StackMachine {
case OPCode.JUMP: opJump(); continue;
case OPCode.PUSH: opPush(); continue;
- // CEC
- case OPCode.STATE_CHECK_PUSH: opStateCheckPush(); continue;
- case OPCode.STATE_CHECK_PUSH_OR_JUMP: opStateCheckPushOrJump(); continue;
- case OPCode.STATE_CHECK: opStateCheck(); continue;
-
case OPCode.POP: opPop(); continue;
case OPCode.PUSH_OR_JUMP_EXACT1: opPushOrJumpExact1(); continue;
case OPCode.PUSH_IF_PEEK_NEXT: opPushIfPeekNext(); continue;
@@ -266,10 +202,6 @@ class ByteCodeMachine extends StackMachine {
case OPCode.PUSH_LOOK_BEHIND_NOT: opPushLookBehindNot(); continue;
case OPCode.FAIL_LOOK_BEHIND_NOT: opFailLookBehindNot(); continue;
- // USE_SUBEXP_CALL
- case OPCode.CALL: opCall(); continue;
- case OPCode.RETURN: opReturn(); continue;
-
case OPCode.FINISH:
return finish();
@@ -322,9 +254,6 @@ class ByteCodeMachine extends StackMachine {
}
- if (Config.USE_CAPTURE_HISTORY) {
- if (regex.captureHistory != 0) checkCaptureHistory(region);
- }
} else {
msaBegin = sstart - str;
msaEnd = s - str;
@@ -437,125 +366,6 @@ class ByteCodeMachine extends StackMachine {
sprev = s - 1;
}
- private void opExactMB2N1() {
- if (s + 2 > range) {opFail(); return;}
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- sprev = sbegin; // break;
- }
-
- private void opExactMB2N2() {
- if (s + 4 > range) {opFail(); return;}
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- sprev = s;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- }
-
- private void opExactMB2N3() {
- if (s + 6 > range) {opFail(); return;}
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- sprev = s;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- }
-
- private void opExactMB2N() {
- int tlen = code[ip++];
- if (s + tlen * 2 > range) {opFail(); return;}
-
- if (Config.USE_STRING_TEMPLATES) {
- char[] bs = regex.templates[code[ip++]];
- int ps = code[ip++];
-
- while(tlen-- > 0) {
- if (bs[ps] != chars[s]) {opFail(); return;}
- ps++; s++;
- if (bs[ps] != chars[s]) {opFail(); return;}
- ps++; s++;
- }
- } else {
- while(tlen-- > 0) {
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- }
- }
- sprev = s - 2;
- }
-
- private void opExactMB3N() {
- int tlen = code[ip++];
- if (s + tlen * 3 > range) {opFail(); return;}
-
- if (Config.USE_STRING_TEMPLATES) {
- char[] bs = regex.templates[code[ip++]];
- int ps = code[ip++];
-
- while (tlen-- > 0) {
- if (bs[ps] != chars[s]) {opFail(); return;}
- ps++; s++;
- if (bs[ps] != chars[s]) {opFail(); return;}
- ps++; s++;
- if (bs[ps] != chars[s]) {opFail(); return;}
- ps++; s++;
- }
- } else {
- while (tlen-- > 0) {
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- }
- }
-
- sprev = s - 3;
- }
-
- private void opExactMBN() {
- int tlen = code[ip++]; /* mb-len */
- int tlen2= code[ip++]; /* string len */
-
- tlen2 *= tlen;
- if (s + tlen2 > range) {opFail(); return;}
-
- if (Config.USE_STRING_TEMPLATES) {
- char[] bs = regex.templates[code[ip++]];
- int ps = code[ip++];
-
- while (tlen2-- > 0) {
- if (bs[ps] != chars[s]) {opFail(); return;}
- ps++; s++;
- }
- } else {
- while (tlen2-- > 0) {
- if (code[ip] != chars[s]) {opFail(); return;}
- ip++; s++;
- }
- }
-
- sprev = s - tlen;
- }
-
private void opExact1IC() {
if (s >= range || code[ip] != Character.toLowerCase(chars[s++])) {opFail(); return;}
ip++;
@@ -748,34 +558,6 @@ class ByteCodeMachine extends StackMachine {
sprev = sbegin; // break;
}
- // CEC
- private void opStateCheckAnyCharStar() {
- int mem = code[ip++];
- final char[] chars = this.chars;
-
- while (s < range) {
- if (stateCheckVal(s, mem)) {opFail(); return;}
- pushAltWithStateCheck(ip, s, sprev, mem);
- if (chars[s] == EncodingHelper.NEW_LINE) {opFail(); return;}
- sprev = s;
- s++;
- }
- sprev = sbegin; // break;
- }
-
- // CEC
- private void opStateCheckAnyCharMLStar() {
- int mem = code[ip++];
-
- while (s < range) {
- if (stateCheckVal(s, mem)) {opFail(); return;}
- pushAltWithStateCheck(ip, s, sprev, mem);
- sprev = s;
- s++;
- }
- sprev = sbegin; // break;
- }
-
private void opWord() {
if (s >= range || !EncodingHelper.isWord(chars[s])) {opFail(); return;}
s++;
@@ -1223,33 +1005,6 @@ class ByteCodeMachine extends StackMachine {
pushAlt(ip + addr, s, sprev);
}
- // CEC
- private void opStateCheckPush() {
- int mem = code[ip++];
- if (stateCheckVal(s, mem)) {opFail(); return;}
- int addr = code[ip++];
- pushAltWithStateCheck(ip + addr, s, sprev, mem);
- }
-
- // CEC
- private void opStateCheckPushOrJump() {
- int mem = code[ip++];
- int addr= code[ip++];
-
- if (stateCheckVal(s, mem)) {
- ip += addr;
- } else {
- pushAltWithStateCheck(ip + addr, s, sprev, mem);
- }
- }
-
- // CEC
- private void opStateCheck() {
- int mem = code[ip++];
- if (stateCheckVal(s, mem)) {opFail(); return;}
- pushStateCheck(s, mem);
- }
-
private void opPop() {
popOne();
}
@@ -1425,17 +1180,6 @@ class ByteCodeMachine extends StackMachine {
opFail();
}
- private void opCall() {
- int addr = code[ip++];
- pushCallFrame(ip);
- ip = addr; // absolute address
- }
-
- private void opReturn() {
- ip = sreturn();
- pushReturn();
- }
-
private void opFail() {
if (stack == null) {
ip = regex.codeLength - 1;
@@ -1447,13 +1191,6 @@ class ByteCodeMachine extends StackMachine {
ip = e.getStatePCode();
s = e.getStatePStr();
sprev = e.getStatePStrPrev();
-
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (e.getStateCheck() != 0) {
- e.type = STATE_CHECK_MARK;
- stk++;
- }
- }
}
private int finish() {
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java
index 86a558b0..d56164d1 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java
@@ -34,6 +34,239 @@ class ByteCodePrinter {
int operantCount;
WarnCallback warnings;
+ private final static String OpCodeNames[] = new String[] {
+ "finish", /*OP_FINISH*/
+ "end", /*OP_END*/
+ "exact1", /*OP_EXACT1*/
+ "exact2", /*OP_EXACT2*/
+ "exact3", /*OP_EXACT3*/
+ "exact4", /*OP_EXACT4*/
+ "exact5", /*OP_EXACT5*/
+ "exactn", /*OP_EXACTN*/
+ "exactmb2-n1", /*OP_EXACTMB2N1*/
+ "exactmb2-n2", /*OP_EXACTMB2N2*/
+ "exactmb2-n3", /*OP_EXACTMB2N3*/
+ "exactmb2-n", /*OP_EXACTMB2N*/
+ "exactmb3n", /*OP_EXACTMB3N*/
+ "exactmbn", /*OP_EXACTMBN*/
+ "exact1-ic", /*OP_EXACT1_IC*/
+ "exactn-ic", /*OP_EXACTN_IC*/
+ "cclass", /*OP_CCLASS*/
+ "cclass-mb", /*OP_CCLASS_MB*/
+ "cclass-mix", /*OP_CCLASS_MIX*/
+ "cclass-not", /*OP_CCLASS_NOT*/
+ "cclass-mb-not", /*OP_CCLASS_MB_NOT*/
+ "cclass-mix-not", /*OP_CCLASS_MIX_NOT*/
+ "cclass-node", /*OP_CCLASS_NODE*/
+ "anychar", /*OP_ANYCHAR*/
+ "anychar-ml", /*OP_ANYCHAR_ML*/
+ "anychar*", /*OP_ANYCHAR_STAR*/
+ "anychar-ml*", /*OP_ANYCHAR_ML_STAR*/
+ "anychar*-peek-next", /*OP_ANYCHAR_STAR_PEEK_NEXT*/
+ "anychar-ml*-peek-next", /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
+ "word", /*OP_WORD*/
+ "not-word", /*OP_NOT_WORD*/
+ "word-bound", /*OP_WORD_BOUND*/
+ "not-word-bound", /*OP_NOT_WORD_BOUND*/
+ "word-begin", /*OP_WORD_BEGIN*/
+ "word-end", /*OP_WORD_END*/
+ "begin-buf", /*OP_BEGIN_BUF*/
+ "end-buf", /*OP_END_BUF*/
+ "begin-line", /*OP_BEGIN_LINE*/
+ "end-line", /*OP_END_LINE*/
+ "semi-end-buf", /*OP_SEMI_END_BUF*/
+ "begin-position", /*OP_BEGIN_POSITION*/
+ "backref1", /*OP_BACKREF1*/
+ "backref2", /*OP_BACKREF2*/
+ "backrefn", /*OP_BACKREFN*/
+ "backrefn-ic", /*OP_BACKREFN_IC*/
+ "backref_multi", /*OP_BACKREF_MULTI*/
+ "backref_multi-ic", /*OP_BACKREF_MULTI_IC*/
+ "backref_at_level", /*OP_BACKREF_AT_LEVEL*/
+ "mem-start", /*OP_MEMORY_START*/
+ "mem-start-push", /*OP_MEMORY_START_PUSH*/
+ "mem-end-push", /*OP_MEMORY_END_PUSH*/
+ "mem-end-push-rec", /*OP_MEMORY_END_PUSH_REC*/
+ "mem-end", /*OP_MEMORY_END*/
+ "mem-end-rec", /*OP_MEMORY_END_REC*/
+ "fail", /*OP_FAIL*/
+ "jump", /*OP_JUMP*/
+ "push", /*OP_PUSH*/
+ "pop", /*OP_POP*/
+ "push-or-jump-e1", /*OP_PUSH_OR_JUMP_EXACT1*/
+ "push-if-peek-next", /*OP_PUSH_IF_PEEK_NEXT*/
+ "repeat", /*OP_REPEAT*/
+ "repeat-ng", /*OP_REPEAT_NG*/
+ "repeat-inc", /*OP_REPEAT_INC*/
+ "repeat-inc-ng", /*OP_REPEAT_INC_NG*/
+ "repeat-inc-sg", /*OP_REPEAT_INC_SG*/
+ "repeat-inc-ng-sg", /*OP_REPEAT_INC_NG_SG*/
+ "null-check-start", /*OP_NULL_CHECK_START*/
+ "null-check-end", /*OP_NULL_CHECK_END*/
+ "null-check-end-memst", /*OP_NULL_CHECK_END_MEMST*/
+ "null-check-end-memst-push", /*OP_NULL_CHECK_END_MEMST_PUSH*/
+ "push-pos", /*OP_PUSH_POS*/
+ "pop-pos", /*OP_POP_POS*/
+ "push-pos-not", /*OP_PUSH_POS_NOT*/
+ "fail-pos", /*OP_FAIL_POS*/
+ "push-stop-bt", /*OP_PUSH_STOP_BT*/
+ "pop-stop-bt", /*OP_POP_STOP_BT*/
+ "look-behind", /*OP_LOOK_BEHIND*/
+ "push-look-behind-not", /*OP_PUSH_LOOK_BEHIND_NOT*/
+ "fail-look-behind-not", /*OP_FAIL_LOOK_BEHIND_NOT*/
+ "call", /*OP_CALL*/
+ "return", /*OP_RETURN*/
+ "state-check-push", /*OP_STATE_CHECK_PUSH*/
+ "state-check-push-or-jump", /*OP_STATE_CHECK_PUSH_OR_JUMP*/
+ "state-check", /*OP_STATE_CHECK*/
+ "state-check-anychar*", /*OP_STATE_CHECK_ANYCHAR_STAR*/
+ "state-check-anychar-ml*", /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
+ "set-option-push", /*OP_SET_OPTION_PUSH*/
+ "set-option", /*OP_SET_OPTION*/
+
+ // single byte versions
+ "anychar-sb", /*OP_ANYCHAR*/
+ "anychar-ml-sb", /*OP_ANYCHAR_ML*/
+ "anychar*-sb", /*OP_ANYCHAR_STAR*/
+ "anychar-ml*-sb", /*OP_ANYCHAR_ML_STAR*/
+ "anychar*-peek-next-sb", /*OP_ANYCHAR_STAR_PEEK_NEXT*/
+ "anychar-ml*-peek-next-sb", /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
+ "state-check-anychar*-sb", /*OP_STATE_CHECK_ANYCHAR_STAR*/
+ "state-check-anychar-ml*-sb", /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
+
+ "cclass-sb", /*OP_CCLASS*/
+ "cclass-not-sb", /*OP_CCLASS_NOT*/
+
+ "word-sb", /*OP_WORD*/
+ "not-word-sb", /*OP_NOT_WORD*/
+ "word-bound-sb", /*OP_WORD_BOUND*/
+ "not-word-bound-sb", /*OP_NOT_WORD_BOUND*/
+ "word-begin-sb", /*OP_WORD_BEGIN*/
+ "word-end-sb", /*OP_WORD_END*/
+
+ "look-behind-sb", /*OP_LOOK_BEHIND*/
+
+ "exact1-ic-sb", /*OP_EXACT1_IC*/
+ "exactn-ic-sb", /*OP_EXACTN_IC*/
+
+ };
+
+ private final static int OpCodeArgTypes[] = new int[] {
+ Arguments.NON, /*OP_FINISH*/
+ Arguments.NON, /*OP_END*/
+ Arguments.SPECIAL, /*OP_EXACT1*/
+ Arguments.SPECIAL, /*OP_EXACT2*/
+ Arguments.SPECIAL, /*OP_EXACT3*/
+ Arguments.SPECIAL, /*OP_EXACT4*/
+ Arguments.SPECIAL, /*OP_EXACT5*/
+ Arguments.SPECIAL, /*OP_EXACTN*/
+ Arguments.SPECIAL, /*OP_EXACTMB2N1*/
+ Arguments.SPECIAL, /*OP_EXACTMB2N2*/
+ Arguments.SPECIAL, /*OP_EXACTMB2N3*/
+ Arguments.SPECIAL, /*OP_EXACTMB2N*/
+ Arguments.SPECIAL, /*OP_EXACTMB3N*/
+ Arguments.SPECIAL, /*OP_EXACTMBN*/
+ Arguments.SPECIAL, /*OP_EXACT1_IC*/
+ Arguments.SPECIAL, /*OP_EXACTN_IC*/
+ Arguments.SPECIAL, /*OP_CCLASS*/
+ Arguments.SPECIAL, /*OP_CCLASS_MB*/
+ Arguments.SPECIAL, /*OP_CCLASS_MIX*/
+ Arguments.SPECIAL, /*OP_CCLASS_NOT*/
+ Arguments.SPECIAL, /*OP_CCLASS_MB_NOT*/
+ Arguments.SPECIAL, /*OP_CCLASS_MIX_NOT*/
+ Arguments.SPECIAL, /*OP_CCLASS_NODE*/
+ Arguments.NON, /*OP_ANYCHAR*/
+ Arguments.NON, /*OP_ANYCHAR_ML*/
+ Arguments.NON, /*OP_ANYCHAR_STAR*/
+ Arguments.NON, /*OP_ANYCHAR_ML_STAR*/
+ Arguments.SPECIAL, /*OP_ANYCHAR_STAR_PEEK_NEXT*/
+ Arguments.SPECIAL, /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
+ Arguments.NON, /*OP_WORD*/
+ Arguments.NON, /*OP_NOT_WORD*/
+ Arguments.NON, /*OP_WORD_BOUND*/
+ Arguments.NON, /*OP_NOT_WORD_BOUND*/
+ Arguments.NON, /*OP_WORD_BEGIN*/
+ Arguments.NON, /*OP_WORD_END*/
+ Arguments.NON, /*OP_BEGIN_BUF*/
+ Arguments.NON, /*OP_END_BUF*/
+ Arguments.NON, /*OP_BEGIN_LINE*/
+ Arguments.NON, /*OP_END_LINE*/
+ Arguments.NON, /*OP_SEMI_END_BUF*/
+ Arguments.NON, /*OP_BEGIN_POSITION*/
+ Arguments.NON, /*OP_BACKREF1*/
+ Arguments.NON, /*OP_BACKREF2*/
+ Arguments.MEMNUM, /*OP_BACKREFN*/
+ Arguments.SPECIAL, /*OP_BACKREFN_IC*/
+ Arguments.SPECIAL, /*OP_BACKREF_MULTI*/
+ Arguments.SPECIAL, /*OP_BACKREF_MULTI_IC*/
+ Arguments.SPECIAL, /*OP_BACKREF_AT_LEVEL*/
+ Arguments.MEMNUM, /*OP_MEMORY_START*/
+ Arguments.MEMNUM, /*OP_MEMORY_START_PUSH*/
+ Arguments.MEMNUM, /*OP_MEMORY_END_PUSH*/
+ Arguments.MEMNUM, /*OP_MEMORY_END_PUSH_REC*/
+ Arguments.MEMNUM, /*OP_MEMORY_END*/
+ Arguments.MEMNUM, /*OP_MEMORY_END_REC*/
+ Arguments.NON, /*OP_FAIL*/
+ Arguments.RELADDR, /*OP_JUMP*/
+ Arguments.RELADDR, /*OP_PUSH*/
+ Arguments.NON, /*OP_POP*/
+ Arguments.SPECIAL, /*OP_PUSH_OR_JUMP_EXACT1*/
+ Arguments.SPECIAL, /*OP_PUSH_IF_PEEK_NEXT*/
+ Arguments.SPECIAL, /*OP_REPEAT*/
+ Arguments.SPECIAL, /*OP_REPEAT_NG*/
+ Arguments.MEMNUM, /*OP_REPEAT_INC*/
+ Arguments.MEMNUM, /*OP_REPEAT_INC_NG*/
+ Arguments.MEMNUM, /*OP_REPEAT_INC_SG*/
+ Arguments.MEMNUM, /*OP_REPEAT_INC_NG_SG*/
+ Arguments.MEMNUM, /*OP_NULL_CHECK_START*/
+ Arguments.MEMNUM, /*OP_NULL_CHECK_END*/
+ Arguments.MEMNUM, /*OP_NULL_CHECK_END_MEMST*/
+ Arguments.MEMNUM, /*OP_NULL_CHECK_END_MEMST_PUSH*/
+ Arguments.NON, /*OP_PUSH_POS*/
+ Arguments.NON, /*OP_POP_POS*/
+ Arguments.RELADDR, /*OP_PUSH_POS_NOT*/
+ Arguments.NON, /*OP_FAIL_POS*/
+ Arguments.NON, /*OP_PUSH_STOP_BT*/
+ Arguments.NON, /*OP_POP_STOP_BT*/
+ Arguments.SPECIAL, /*OP_LOOK_BEHIND*/
+ Arguments.SPECIAL, /*OP_PUSH_LOOK_BEHIND_NOT*/
+ Arguments.NON, /*OP_FAIL_LOOK_BEHIND_NOT*/
+ Arguments.ABSADDR, /*OP_CALL*/
+ Arguments.NON, /*OP_RETURN*/
+ Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH*/
+ Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH_OR_JUMP*/
+ Arguments.STATE_CHECK, /*OP_STATE_CHECK*/
+ Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_STAR*/
+ Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
+ Arguments.OPTION, /*OP_SET_OPTION_PUSH*/
+ Arguments.OPTION, /*OP_SET_OPTION*/
+
+ // single byte versions
+ Arguments.NON, /*OP_ANYCHAR*/
+ Arguments.NON, /*OP_ANYCHAR_ML*/
+ Arguments.NON, /*OP_ANYCHAR_STAR*/
+ Arguments.NON, /*OP_ANYCHAR_ML_STAR*/
+ Arguments.SPECIAL, /*OP_ANYCHAR_STAR_PEEK_NEXT*/
+ Arguments.SPECIAL, /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
+ Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_STAR*/
+ Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
+
+ Arguments.SPECIAL, /*OP_CCLASS*/
+ Arguments.SPECIAL, /*OP_CCLASS_NOT*/
+
+ Arguments.NON, /*OP_WORD*/
+ Arguments.NON, /*OP_NOT_WORD*/
+ Arguments.NON, /*OP_WORD_BOUND*/
+ Arguments.NON, /*OP_NOT_WORD_BOUND*/
+ Arguments.NON, /*OP_WORD_BEGIN*/
+ Arguments.NON, /*OP_WORD_END*/
+
+ Arguments.SPECIAL, /*OP_LOOK_BEHIND*/
+
+ Arguments.SPECIAL, /*OP_EXACT1_IC*/
+ Arguments.SPECIAL, /*OP_EXACTN_IC*/
+ };
+
public ByteCodePrinter(Regex regex) {
code = regex.code;
codeLength = regex.codeLength;
@@ -76,8 +309,8 @@ class ByteCodePrinter {
CClassNode cc;
int tm, idx;
- sb.append("[" + OPCode.OpCodeNames[code[bp]]);
- int argType = OPCode.OpCodeArgTypes[code[bp]];
+ sb.append("[" + OpCodeNames[code[bp]]);
+ int argType = OpCodeArgTypes[code[bp]];
int ip = bp;
if (argType != Arguments.SPECIAL) {
bp++;
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java
deleted file mode 100644
index 268f682c..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni;
-
-public class CaptureTreeNode {
-
-
- int group;
- int beg;
- int end;
- // int allocated;
- int numChildren;
- CaptureTreeNode[]children;
-
- CaptureTreeNode() {
- beg = Region.REGION_NOTPOS;
- end = Region.REGION_NOTPOS;
- group = -1;
- }
-
- static final int HISTORY_TREE_INIT_ALLOC_SIZE = 8;
- void addChild(CaptureTreeNode child) {
- if (children == null) {
- children = new CaptureTreeNode[HISTORY_TREE_INIT_ALLOC_SIZE];
- } else if (numChildren >= children.length) {
- CaptureTreeNode[]tmp = new CaptureTreeNode[children.length << 1];
- System.arraycopy(children, 0, tmp, 0, children.length);
- children = tmp;
- }
-
- children[numChildren] = child;
- numChildren++;
- }
-
- void clear() {
- for (int i=0; i<numChildren; i++) {
- children[i] = null; // ???
- }
- numChildren = 0;
- beg = end = Region.REGION_NOTPOS;
- group = -1;
- }
-
- CaptureTreeNode cloneTree() {
- CaptureTreeNode clone = new CaptureTreeNode();
- clone.beg = beg;
- clone.end = end;
-
- for (int i=0; i<numChildren; i++) {
- CaptureTreeNode child = children[i].cloneTree();
- clone.addChild(child);
- }
- return clone;
- }
-
-
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java
index 8fdc240f..c3356add 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java
@@ -22,8 +22,6 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.Node;
@@ -56,7 +54,7 @@ abstract class Compiler implements ErrorMessages {
private void compileStringRawNode(StringNode sn) {
if (sn.length() <= 0) return;
- addCompileString(sn.chars, sn.p, 1 /*sb*/, sn.length(), false);
+ addCompileString(sn.chars, sn.p, sn.length(), false);
}
private void compileStringNode(StringNode node) {
@@ -76,17 +74,14 @@ abstract class Compiler implements ErrorMessages {
slen++;
p++;
}
- addCompileString(chars, prev, 1, slen, ambig);
+ addCompileString(chars, prev, slen, ambig);
}
- protected abstract void addCompileString(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase);
+ protected abstract void addCompileString(char[] chars, int p, int strLength, boolean ignoreCase);
protected abstract void compileCClassNode(CClassNode node);
- protected abstract void compileCTypeNode(CTypeNode node);
protected abstract void compileAnyCharNode();
- protected abstract void compileCallNode(CallNode node);
protected abstract void compileBackrefNode(BackRefNode node);
- protected abstract void compileCECQuantifierNode(QuantifierNode node);
protected abstract void compileNonCECQuantifierNode(QuantifierNode node);
protected abstract void compileOptionNode(EncloseNode node);
protected abstract void compileEncloseNode(EncloseNode node);
@@ -118,10 +113,6 @@ abstract class Compiler implements ErrorMessages {
compileCClassNode((CClassNode)node);
break;
- case NodeType.CTYPE:
- compileCTypeNode((CTypeNode)node);
- break;
-
case NodeType.CANY:
compileAnyCharNode();
break;
@@ -130,19 +121,8 @@ abstract class Compiler implements ErrorMessages {
compileBackrefNode((BackRefNode)node);
break;
- case NodeType.CALL:
- if (Config.USE_SUBEXP_CALL) {
- compileCallNode((CallNode)node);
- break;
- } // USE_SUBEXP_CALL
- break;
-
case NodeType.QTFR:
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- compileCECQuantifierNode((QuantifierNode)node);
- } else {
- compileNonCECQuantifierNode((QuantifierNode)node);
- }
+ compileNonCECQuantifierNode((QuantifierNode)node);
break;
case NodeType.ENCLOSE:
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java
index 04f5b47b..b8ade1fa 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java
@@ -31,10 +31,6 @@ public interface Config {
final int ENC_CASE_FOLD_DEFAULT = ENC_CASE_FOLD_MIN;
final boolean USE_CRNL_AS_LINE_TERMINATOR = false;
- final boolean USE_NAMED_GROUP = true;
- final boolean USE_SUBEXP_CALL = true;
- final boolean USE_BACKREF_WITH_LEVEL = true; /* \k<name+n>, \k<name-n> */
-
final boolean USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT = true; /* /(?:()|())*\2/ */
final boolean USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE = true; /* /\n$/ =~ "\n" */
final boolean USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR = false;
@@ -42,12 +38,10 @@ public interface Config {
final boolean CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS = true;
final boolean USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE = false;
- final boolean USE_CAPTURE_HISTORY = false;
final boolean USE_VARIABLE_META_CHARS = true;
final boolean USE_WORD_BEGIN_END = true; /* "\<": word-begin, "\>": word-end */
- final boolean USE_POSIX_API_REGION_OPTION = true; /* needed for POSIX API support */
+ final boolean USE_POSIX_API_REGION_OPTION = false; /* needed for POSIX API support */
final boolean USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE = true;
- final boolean USE_COMBINATION_EXPLOSION_CHECK = false;
final int NREGION = 10;
final int MAX_BACKREF_NUM = 1000;
@@ -73,13 +67,6 @@ public interface Config {
final boolean USE_STRING_TEMPLATES = true; // use embeded string templates in Regex object as byte arrays instead of compiling them into int bytecode array
-
- final int MAX_CAPTURE_HISTORY_GROUP = 31;
-
-
- final int CHECK_STRING_THRESHOLD_LEN = 7;
- final int CHECK_BUFF_MAX_SIZE = 0x4000;
-
final boolean NON_UNICODE_SDW = true;
@@ -95,6 +82,4 @@ public interface Config {
final boolean DEBUG_COMPILE_BYTE_CODE_INFO = DEBUG_ALL;
final boolean DEBUG_SEARCH = DEBUG_ALL;
final boolean DEBUG_MATCH = DEBUG_ALL;
- final boolean DEBUG_ASM = true;
- final boolean DEBUG_ASM_EXEC = true;
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java
index d3e54947..8c274fe0 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java
@@ -95,20 +95,6 @@ public class EncodingHelper {
return s;
}
- /* onigenc_with_ascii_strncmp */
- public static int strNCmp(char[] chars1, int p1, int end, char[] chars2, int p2, int n) {
- while (n-- > 0) {
- if (p1 >= end) return chars2[p2];
- int c = chars1[p1];
- int x = chars2[p2] - c;
- if (x != 0) return x;
-
- p2++;
- p1++;
- }
- return 0;
- }
-
public static int mbcToCode(byte[] bytes, int p, int end) {
int code = 0;
for (int i = p; i < end; i++) {
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java
index c289f33d..53ab3ec0 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java
@@ -27,10 +27,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType;
import jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar;
import jdk.nashorn.internal.runtime.regexp.joni.constants.TokenType;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.PosixBracket;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.Ptr;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
-import jdk.nashorn.internal.runtime.regexp.joni.exception.JOniException;
class Lexer extends ScannerSupport {
protected final ScanEnvironment env;
@@ -215,198 +212,6 @@ class Lexer extends ScannerSupport {
\k<-num+n>, \k<-num-n>
*/
- // value implicit (rnameEnd)
- private boolean fetchNameWithLevel(int startCode, Ptr rbackNum, Ptr rlevel) {
- int src = p;
- boolean existLevel = false;
- int isNum = 0;
- int sign = 1;
-
- int endCode = nameEndCodePoint(startCode);
- int pnumHead = p;
- int nameEnd = stop;
-
- String err = null;
- if (!left()) {
- newValueException(ERR_EMPTY_GROUP_NAME);
- } else {
- fetch();
- if (c == endCode) newValueException(ERR_EMPTY_GROUP_NAME);
- if (Character.isDigit(c)) {
- isNum = 1;
- } else if (c == '-') {
- isNum = 2;
- sign = -1;
- pnumHead = p;
- } else if (!EncodingHelper.isWord(c)) {
- err = ERR_INVALID_GROUP_NAME;
- }
- }
-
- while (left()) {
- nameEnd = p;
- fetch();
- if (c == endCode || c == ')' || c == '+' || c == '-') {
- if (isNum == 2) err = ERR_INVALID_GROUP_NAME;
- break;
- }
-
- if (isNum != 0) {
- if (EncodingHelper.isDigit(c)) {
- isNum = 1;
- } else {
- err = ERR_INVALID_GROUP_NAME;
- // isNum = 0;
- }
- } else if (!EncodingHelper.isWord(c)) {
- err = ERR_INVALID_CHAR_IN_GROUP_NAME;
- }
- }
-
- boolean isEndCode = false;
- if (err == null && c != endCode) {
- if (c == '+' || c == '-') {
- int flag = c == '-' ? -1 : 1;
-
- fetch();
- if (!EncodingHelper.isDigit(c)) newValueException(ERR_INVALID_GROUP_NAME, src, stop);
- unfetch();
- int level = scanUnsignedNumber();
- if (level < 0) newValueException(ERR_TOO_BIG_NUMBER);
- rlevel.p = level * flag;
- existLevel = true;
-
- fetch();
- isEndCode = c == endCode;
- }
-
- if (!isEndCode) {
- err = ERR_INVALID_GROUP_NAME;
- nameEnd = stop;
- }
- }
-
- if (err == null) {
- if (isNum != 0) {
- mark();
- p = pnumHead;
- int backNum = scanUnsignedNumber();
- restore();
- if (backNum < 0) {
- newValueException(ERR_TOO_BIG_NUMBER);
- } else if (backNum == 0) {
- newValueException(ERR_INVALID_GROUP_NAME, src, stop);
- }
- rbackNum.p = backNum * sign;
- }
- value = nameEnd;
- return existLevel;
- } else {
- newValueException(ERR_INVALID_GROUP_NAME, src, nameEnd);
- return false; // not reached
- }
- }
-
- // USE_NAMED_GROUP
- // ref: 0 -> define name (don't allow number name)
- // 1 -> reference name (allow number name)
- private int fetchNameForNamedGroup(int startCode, boolean ref) {
- int src = p;
- value = 0;
-
- int isNum = 0;
- int sign = 1;
-
- int endCode = nameEndCodePoint(startCode);
- int pnumHead = p;
- int nameEnd = stop;
-
- String err = null;
- if (!left()) {
- newValueException(ERR_EMPTY_GROUP_NAME);
- } else {
- fetch();
- if (c == endCode) newValueException(ERR_EMPTY_GROUP_NAME);
- if (EncodingHelper.isDigit(c)) {
- if (ref) {
- isNum = 1;
- } else {
- err = ERR_INVALID_GROUP_NAME;
- // isNum = 0;
- }
- } else if (c == '-') {
- if (ref) {
- isNum = 2;
- sign = -1;
- pnumHead = p;
- } else {
- err = ERR_INVALID_GROUP_NAME;
- // isNum = 0;
- }
- } else if (!EncodingHelper.isWord(c)) {
- err = ERR_INVALID_CHAR_IN_GROUP_NAME;
- }
- }
-
- if (err == null) {
- while (left()) {
- nameEnd = p;
- fetch();
- if (c == endCode || c == ')') {
- if (isNum == 2) err = ERR_INVALID_GROUP_NAME;
- break;
- }
-
- if (isNum != 0) {
- if (EncodingHelper.isDigit(c)) {
- isNum = 1;
- } else {
- if (!EncodingHelper.isWord(c)) {
- err = ERR_INVALID_CHAR_IN_GROUP_NAME;
- } else {
- err = ERR_INVALID_GROUP_NAME;
- }
- // isNum = 0;
- }
- } else {
- if (!EncodingHelper.isWord(c)) {
- err = ERR_INVALID_CHAR_IN_GROUP_NAME;
- }
- }
- }
-
- if (c != endCode) {
- err = ERR_INVALID_GROUP_NAME;
- nameEnd = stop;
- }
-
- int backNum = 0;
- if (isNum != 0) {
- mark();
- p = pnumHead;
- backNum = scanUnsignedNumber();
- restore();
- if (backNum < 0) {
- newValueException(ERR_TOO_BIG_NUMBER);
- } else if (backNum == 0) {
- newValueException(ERR_INVALID_GROUP_NAME, src, nameEnd);
- }
- backNum *= sign;
- }
- value = nameEnd;
- return backNum;
- } else {
- while (left()) {
- nameEnd = p;
- fetch();
- if (c == endCode || c == ')') break;
- }
- if (!left()) nameEnd = stop;
- newValueException(err, src, nameEnd);
- return 0; // not reached
- }
- }
-
// #else USE_NAMED_GROUP
// make it return nameEnd!
private final int fetchNameForNoNamedGroup(int startCode, boolean ref) {
@@ -472,11 +277,7 @@ class Lexer extends ScannerSupport {
}
protected final int fetchName(int startCode, boolean ref) {
- if (Config.USE_NAMED_GROUP) {
- return fetchNameForNamedGroup(startCode, ref);
- } else {
- return fetchNameForNoNamedGroup(startCode, ref);
- }
+ return fetchNameForNoNamedGroup(startCode, ref);
}
private boolean strExistCheckWithEsc(int[]s, int n, int bad) {
@@ -519,26 +320,6 @@ class Lexer extends ScannerSupport {
token.setPropNot(flag);
}
- private void fetchTokenInCCFor_p() {
- int c2 = peek(); // !!! migrate to peekIs
- if (c2 == '{' && syntax.op2EscPBraceCharProperty()) {
- inc();
- token.type = TokenType.CHAR_PROPERTY;
- token.setPropNot(c == 'P');
-
- if (syntax.op2EscPBraceCircumflexNot()) {
- c2 = fetchTo();
- if (c2 == '^') {
- token.setPropNot(!token.getPropNot());
- } else {
- unfetch();
- }
- }
- } else {
- syntaxWarn(Warnings.INVALID_UNICODE_PROPERTY, (char)c);
- }
- }
-
private void fetchTokenInCCFor_x() {
if (!left()) return;
int last = p;
@@ -604,30 +385,6 @@ class Lexer extends ScannerSupport {
}
}
- private void fetchTokenInCCFor_posixBracket() {
- if (syntax.opPosixBracket() && peekIs(':')) {
- token.backP = p; /* point at '[' is readed */
- inc();
- if (strExistCheckWithEsc(send, send.length, ']')) {
- token.type = TokenType.POSIX_BRACKET_OPEN;
- } else {
- unfetch();
- // remove duplication, goto cc_in_cc;
- if (syntax.op2CClassSetOp()) {
- token.type = TokenType.CC_CC_OPEN;
- } else {
- env.ccEscWarn("[");
- }
- }
- } else { // cc_in_cc:
- if (syntax.op2CClassSetOp()) {
- token.type = TokenType.CC_CC_OPEN;
- } else {
- env.ccEscWarn("[");
- }
- }
- }
-
private void fetchTokenInCCFor_and() {
if (syntax.op2CClassSetOp() && left() && peekIs('&')) {
inc();
@@ -683,10 +440,6 @@ class Lexer extends ScannerSupport {
case 'H':
if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(true, CharacterType.XDIGIT);
break;
- case 'p':
- case 'P':
- fetchTokenInCCFor_p();
- break;
case 'x':
fetchTokenInCCFor_x();
break;
@@ -714,18 +467,12 @@ class Lexer extends ScannerSupport {
break;
} // switch
- } else if (c == '[') {
- fetchTokenInCCFor_posixBracket();
} else if (c == '&') {
fetchTokenInCCFor_and();
}
return token.type;
}
- protected final int backrefRelToAbs(int relNo) {
- return env.numMem + 1 + relNo;
- }
-
private void fetchTokenFor_repeat(int lower, int upper) {
token.type = TokenType.OP_REPEAT;
token.setRepeatLower(lower);
@@ -815,7 +562,6 @@ class Lexer extends ScannerSupport {
token.setBackrefNum(1);
token.setBackrefRef1(num);
token.setBackrefByName(false);
- if (Config.USE_BACKREF_WITH_LEVEL) token.setBackrefExistLevel(false);
return;
}
@@ -845,76 +591,6 @@ class Lexer extends ScannerSupport {
}
}
- private void fetchTokenFor_namedBackref() {
- if (syntax.op2EscKNamedBackref()) {
- if (left()) {
- fetch();
- if (c =='<' || c == '\'') {
- int last = p;
- int backNum;
- if (Config.USE_BACKREF_WITH_LEVEL) {
- Ptr rbackNum = new Ptr();
- Ptr rlevel = new Ptr();
- token.setBackrefExistLevel(fetchNameWithLevel(c, rbackNum, rlevel));
- token.setBackrefLevel(rlevel.p);
- backNum = rbackNum.p;
- } else {
- backNum = fetchName(c, true);
- } // USE_BACKREF_AT_LEVEL
- int nameEnd = value; // set by fetchNameWithLevel/fetchName
-
- if (backNum != 0) {
- if (backNum < 0) {
- backNum = backrefRelToAbs(backNum);
- if (backNum <= 0) newValueException(ERR_INVALID_BACKREF);
- }
-
- if (syntax.strictCheckBackref() && (backNum > env.numMem || env.memNodes == null)) {
- newValueException(ERR_INVALID_BACKREF);
- }
- token.type = TokenType.BACKREF;
- token.setBackrefByName(false);
- token.setBackrefNum(1);
- token.setBackrefRef1(backNum);
- } else {
- NameEntry e = env.reg.nameToGroupNumbers(chars, last, nameEnd);
- if (e == null) newValueException(ERR_UNDEFINED_NAME_REFERENCE, last, nameEnd);
-
- if (syntax.strictCheckBackref()) {
- if (e.backNum == 1) {
- if (e.backRef1 > env.numMem ||
- env.memNodes == null ||
- env.memNodes[e.backRef1] == null) newValueException(ERR_INVALID_BACKREF);
- } else {
- for (int i=0; i<e.backNum; i++) {
- if (e.backRefs[i] > env.numMem ||
- env.memNodes == null ||
- env.memNodes[e.backRefs[i]] == null) newValueException(ERR_INVALID_BACKREF);
- }
- }
- }
-
- token.type = TokenType.BACKREF;
- token.setBackrefByName(true);
-
- if (e.backNum == 1) {
- token.setBackrefNum(1);
- token.setBackrefRef1(e.backRef1);
- } else {
- token.setBackrefNum(e.backNum);
- token.setBackrefRefs(e.backRefs);
- }
- }
- } else {
- unfetch();
- syntaxWarn(Warnings.INVALID_BACKREFERENCE);
- }
- } else {
- syntaxWarn(Warnings.INVALID_BACKREFERENCE);
- }
- }
- }
-
private void fetchTokenFor_subexpCall() {
if (syntax.op2EscGSubexpCall()) {
if (left()) {
@@ -937,25 +613,6 @@ class Lexer extends ScannerSupport {
}
}
- private void fetchTokenFor_charProperty() {
- if (peekIs('{') && syntax.op2EscPBraceCharProperty()) {
- inc();
- token.type = TokenType.CHAR_PROPERTY;
- token.setPropNot(c == 'P');
-
- if (syntax.op2EscPBraceCircumflexNot()) {
- fetch();
- if (c == '^') {
- token.setPropNot(!token.getPropNot());
- } else {
- unfetch();
- }
- }
- } else {
- syntaxWarn(Warnings.INVALID_UNICODE_PROPERTY, (char)c);
- }
- }
-
private void fetchTokenFor_metaChars() {
if (c == syntax.metaCharTable.anyChar) {
token.type = TokenType.ANYCHAR;
@@ -1091,19 +748,6 @@ class Lexer extends ScannerSupport {
case '0':
fetchTokenFor_zero();
break;
- case 'k':
- if (Config.USE_NAMED_GROUP) fetchTokenFor_namedBackref();
- break;
- case 'g':
- if (Config.USE_SUBEXP_CALL) fetchTokenFor_subexpCall();
- break;
- case 'Q':
- if (syntax.op2EscCapitalQQuote()) token.type = TokenType.QUOTE_OPEN;
- break;
- case 'p':
- case 'P':
- fetchTokenFor_charProperty();
- break;
default:
unfetch();
@@ -1244,24 +888,6 @@ class Lexer extends ScannerSupport {
}
}
- protected final int fetchCharPropertyToCType() {
- mark();
-
- while (left()) {
- int last = p;
- fetch();
- if (c == '}') {
- String name = new String(chars, _p, last - _p);
- return PosixBracket.propertyNameToCType(name);
- } else if (c == '(' || c == ')' || c == '{' || c == '|') {
- String name = new String(chars, _p, last - _p);
- throw new JOniException(ERR_INVALID_CHAR_PROPERTY_NAME.replaceAll("%n", name));
- }
- }
- newInternalException(ERR_PARSER_BUG);
- return 0; // not reached
- }
-
protected final void syntaxWarn(String message, char c) {
syntaxWarn(message.replace("<%n>", Character.toString(c)));
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java
index 4aea4acb..911b23b3 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java
@@ -58,17 +58,10 @@ public abstract class Matcher extends IntHolder {
// main matching method
protected abstract int matchAt(int range, int sstart, int sprev);
- protected abstract void stateCheckBuffInit(int strLength, int offset, int stateNum);
- protected abstract void stateCheckBuffClear();
-
public final Region getRegion() {
return msaRegion;
}
- public final Region getEagerRegion() {
- return msaRegion != null ? msaRegion : new Region(msaBegin, msaEnd);
- }
-
public final int getBegin() {
return msaBegin;
}
@@ -86,11 +79,6 @@ public abstract class Matcher extends IntHolder {
public final int match(int at, int range, int option) {
msaInit(option, at);
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- int offset = at = str;
- stateCheckBuffInit(end - str, offset, regex.numCombExpCheck); // move it to construction?
- } // USE_COMBINATION_EXPLOSION_CHECK
-
int prev = EncodingHelper.prevCharHead(str, at);
if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) {
@@ -377,8 +365,6 @@ public abstract class Matcher extends IntHolder {
prev = -1;
msaInit(option, start);
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) stateCheckBuffClear();
-
if (matchCheck(end, s, prev)) return match(s);
return mismatch();
}
@@ -393,10 +379,6 @@ public abstract class Matcher extends IntHolder {
}
msaInit(option, origStart);
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- int offset = Math.min(start, range) - str;
- stateCheckBuffInit(end - str, offset, regex.numCombExpCheck);
- }
s = start;
if (range > start) { /* forward search */
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java b/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java
deleted file mode 100644
index d35f7251..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni;
-
-public final class NameEntry {
- static final int INIT_NAME_BACKREFS_ALLOC_NUM = 8;
-
- public final char[] name;
- public final int nameP;
- public final int nameEnd;
-
- int backNum;
- int backRef1;
- int backRefs[];
-
- public NameEntry(char[] chars, int p, int end) {
- name = chars;
- nameP = p;
- nameEnd = end;
- }
-
- public int[] getBackRefs() {
- switch (backNum) {
- case 0:
- return new int[]{};
- case 1:
- return new int[]{backRef1};
- default:
- int[]result = new int[backNum];
- System.arraycopy(backRefs, 0, result, 0, backNum);
- return result;
- }
- }
-
- private void alloc() {
- backRefs = new int[INIT_NAME_BACKREFS_ALLOC_NUM];
- }
-
- private void ensureSize() {
- if (backNum > backRefs.length) {
- int[]tmp = new int[backRefs.length << 1];
- System.arraycopy(backRefs, 0, tmp, 0, backRefs.length);
- backRefs = tmp;
- }
- }
-
- public void addBackref(int backRef) {
- backNum++;
-
- switch (backNum) {
- case 1:
- backRef1 = backRef;
- break;
- case 2:
- alloc();
- backRefs[0] = backRef1;
- backRefs[1] = backRef;
- break;
- default:
- ensureSize();
- backRefs[backNum - 1] = backRef;
- }
- }
-
- public String toString() {
- StringBuilder buff = new StringBuilder(new String(name, nameP, nameEnd - nameP) + " ");
- if (backNum == 0) {
- buff.append("-");
- } else if (backNum == 1){
- buff.append(backRef1);
- } else {
- for (int i=0; i<backNum; i++){
- if (i > 0) buff.append(", ");
- buff.append(backRefs[i]);
- }
- }
- return buff.toString();
- }
-
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java
deleted file mode 100644
index 2a3f2a13..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni;
-
-public abstract class NativeMachine extends Matcher {
-
- protected NativeMachine(Regex regex, char[] chars, int p, int end) {
- super(regex, chars, p, end);
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java
index 13d569b7..749b1d41 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java
@@ -19,20 +19,15 @@
*/
package jdk.nashorn.internal.runtime.regexp.joni;
-import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnAtSimple;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnOff;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isDontCaptureGroup;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.PosixBracket;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.Ptr;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnyCharNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.Node;
@@ -66,65 +61,6 @@ class Parser extends Lexer {
return root;
}
- private static final int POSIX_BRACKET_NAME_MIN_LEN = 4;
- private static final int POSIX_BRACKET_CHECK_LIMIT_LENGTH = 20;
- private static final char BRACKET_END[] = ":]".toCharArray();
- private boolean parsePosixBracket(CClassNode cc) {
- mark();
-
- boolean not;
- if (peekIs('^')) {
- inc();
- not = true;
- } else {
- not = false;
- }
- if (stop - p >= POSIX_BRACKET_NAME_MIN_LEN + 3) { // else goto not_posix_bracket
- char[][] pbs = PosixBracket.PBSNamesLower;
- for (int i=0; i<pbs.length; i++) {
- char[] name = pbs[i];
- // hash lookup here ?
- if (EncodingHelper.strNCmp(chars, p, stop, name, 0, name.length) == 0) {
- p += name.length;
- if (EncodingHelper.strNCmp(chars, p, stop, BRACKET_END, 0, BRACKET_END.length) != 0) {
- newSyntaxException(ERR_INVALID_POSIX_BRACKET_TYPE);
- }
- cc.addCType(PosixBracket.PBSValues[i], not, env, this);
- inc();
- inc();
- return false;
- }
- }
-
- }
-
- // not_posix_bracket:
- c = 0;
- int i= 0;
- while (left() && ((c=peek()) != ':') && c != ']') {
- inc();
- if (++i > POSIX_BRACKET_CHECK_LIMIT_LENGTH) break;
- }
-
- if (c == ':' && left()) {
- inc();
- if (left()) {
- fetch();
- if (c == ']') newSyntaxException(ERR_INVALID_POSIX_BRACKET_TYPE);
- }
- }
- restore();
- return true; /* 1: is not POSIX bracket, but no error. */
- }
-
- private CClassNode parseCharProperty() {
- int ctype = fetchCharPropertyToCType();
- CClassNode n = new CClassNode();
- n.addCType(ctype, false, env, this);
- if (token.getPropNot()) n.setNot();
- return n;
- }
-
private boolean codeExistCheck(int code, boolean ignoreEscaped) {
mark();
@@ -225,29 +161,11 @@ class Parser extends Lexer {
parseCharClassValEntry(cc, arg); // val_entry:, val_entry2
break;
- case POSIX_BRACKET_OPEN:
- if (parsePosixBracket(cc)) { /* true: is not POSIX bracket */
- env.ccEscWarn("[");
- p = token.backP;
- arg.v = token.getC();
- arg.vIsRaw = false;
- parseCharClassValEntry(cc, arg); // goto val_entry
- break;
- }
- cc.nextStateClass(arg, env); // goto next_class
- break;
-
case CHAR_TYPE:
cc.addCType(token.getPropCType(), token.getPropNot(), env, this);
cc.nextStateClass(arg, env); // next_class:
break;
- case CHAR_PROPERTY:
- int ctype = fetchCharPropertyToCType();
- cc.addCType(ctype, token.getPropNot(), env, this);
- cc.nextStateClass(arg, env); // goto next_class
- break;
-
case CC_RANGE:
if (arg.state == CCSTATE.VALUE) {
fetchTokenInCC();
@@ -413,15 +331,6 @@ class Parser extends Lexer {
node = new EncloseNode(EncloseType.STOP_BACKTRACK); // node_new_enclose
break;
case '\'':
- if (Config.USE_NAMED_GROUP) {
- if (syntax.op2QMarkLtNamedGroup()) {
- listCapture = false; // goto named_group1
- node = parseEncloseNamedGroup2(listCapture);
- break;
- } else {
- newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
- }
- } // USE_NAMED_GROUP
break;
case '<': /* look behind (?<=...), (?<!...) */
fetch();
@@ -430,36 +339,12 @@ class Parser extends Lexer {
} else if (c == '!') {
node = new AnchorNode(AnchorType.LOOK_BEHIND_NOT);
} else {
- if (Config.USE_NAMED_GROUP) {
- if (syntax.op2QMarkLtNamedGroup()) {
- unfetch();
- c = '<';
-
- listCapture = false; // named_group1:
- node = parseEncloseNamedGroup2(listCapture); // named_group2:
- break;
- } else {
- newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
- }
-
- } else { // USE_NAMED_GROUP
- newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
- } // USE_NAMED_GROUP
+ newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
}
break;
case '@':
if (syntax.op2AtMarkCaptureHistory()) {
- if (Config.USE_NAMED_GROUP) {
- if (syntax.op2QMarkLtNamedGroup()) {
- fetch();
- if (c == '<' || c == '\'') {
- listCapture = true;
- node = parseEncloseNamedGroup2(listCapture); // goto named_group2 /* (?@<name>...) */
- }
- unfetch();
- }
- } // USE_NAMED_GROUP
- EncloseNode en = new EncloseNode(env.option, false); // node_new_enclose_memory
+ EncloseNode en = new EncloseNode(); // node_new_enclose_memory
int num = env.addMemEntry();
if (num >= BitStatus.BIT_STATUS_BITS_NUM) newValueException(ERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY);
en.regNum = num;
@@ -546,7 +431,7 @@ class Parser extends Lexer {
returnCode = 1; /* group */
return node;
}
- EncloseNode en = new EncloseNode(env.option, false); // node_new_enclose_memory
+ EncloseNode en = new EncloseNode(); // node_new_enclose_memory
int num = env.addMemEntry();
en.regNum = num;
node = en;
@@ -570,48 +455,6 @@ class Parser extends Lexer {
return node; // ??
}
- private Node parseEncloseNamedGroup2(boolean listCapture) {
- int nm = p;
- int num = fetchName(c, false);
- int nameEnd = value;
- num = env.addMemEntry();
- if (listCapture && num >= BitStatus.BIT_STATUS_BITS_NUM) newValueException(ERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY);
-
- regex.nameAdd(chars, nm, nameEnd, num, syntax);
- EncloseNode en = new EncloseNode(env.option, true); // node_new_enclose_memory
- en.regNum = num;
-
- Node node = en;
-
- if (listCapture) env.captureHistory = bsOnAtSimple(env.captureHistory, num);
- env.numNamed++;
- return node;
- }
-
- private int findStrPosition(int[]s, int n, int from, int to, Ptr nextChar) {
- int x;
- int q;
- int p = from;
- int i = 0;
- while (p < to) {
- x = chars[p];
- q = p + 1;
- if (x == s[0]) {
- for (i=1; i<n && q<to; i++) {
- x = chars[q];
- if (x != s[i]) break;
- q++;
- }
- if (i >= n) {
- if (chars[nextChar.p] != 0) nextChar.p = q; // we may need zero term semantics...
- return p;
- }
- }
- p = q;
- }
- return -1;
- }
-
private Node parseExp(TokenType term) {
if (token.type == term) return StringNode.EMPTY; // goto end_of_token
@@ -656,16 +499,6 @@ class Parser extends Lexer {
node = new StringNode(buf, 0, 1);
break;
- case QUOTE_OPEN:
- int[] endOp = new int[] {syntax.metaCharTable.esc, 'E'};
- int qstart = p;
- Ptr nextChar = new Ptr();
- int qend = findStrPosition(endOp, endOp.length, qstart, stop, nextChar);
- if (qend == -1) nextChar.p = qend = stop;
- node = new StringNode(chars, qstart, qend);
- p = nextChar.p;
- break;
-
case CHAR_TYPE:
switch(token.getPropCType()) {
case CharacterType.D:
@@ -679,10 +512,6 @@ class Parser extends Lexer {
}
break;
- case CharacterType.WORD:
- node = new CTypeNode(token.getPropCType(), token.getPropNot());
- break;
-
case CharacterType.SPACE:
case CharacterType.DIGIT:
case CharacterType.XDIGIT:
@@ -699,10 +528,6 @@ class Parser extends Lexer {
} // inner switch
break;
- case CHAR_PROPERTY:
- node = parseCharProperty();
- break;
-
case CC_CC_OPEN:
CClassNode cc = parseCharClass();
node = cc;
@@ -735,20 +560,6 @@ class Parser extends Lexer {
token.getBackrefExistLevel(), // #ifdef USE_BACKREF_AT_LEVEL
token.getBackrefLevel(), // ...
env);
-
- break;
-
- case CALL:
- if (Config.USE_SUBEXP_CALL) {
- int gNum = token.getCallGNum();
-
- if (gNum < 0) {
- gNum = backrefRelToAbs(gNum);
- if (gNum <= 0) newValueException(ERR_INVALID_BACKREF);
- }
- node = new CallNode(chars, token.getCallNameP(), token.getCallNameEnd(), gNum);
- env.numCall++;
- } // USE_SUBEXP_CALL
break;
case ANCHOR:
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java
index da5b9827..b27814a7 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java
@@ -23,9 +23,11 @@ import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isCaptureGroup;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isDontCaptureGroup;
+import java.nio.file.Files;
import java.util.HashMap;
import java.util.Iterator;
+import jdk.nashorn.internal.runtime.regexp.joni.ast.Node;
import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType;
import jdk.nashorn.internal.runtime.regexp.joni.constants.RegexState;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
@@ -44,7 +46,6 @@ public final class Regex implements RegexState {
int numMem; /* used memory(...) num counted from 1 */
int numRepeat; /* OP_REPEAT/OP_REPEAT_NG id-counter */
int numNullCheck; /* OP_NULL_CHECK_START/END id counter */
- int numCombExpCheck; /* combination explosion check */
int numCall; /* number of subexp call */
int captureHistory; /* (?@...) flag (1-31) */
int btMemStart; /* need backtrack flag */
@@ -57,7 +58,7 @@ public final class Regex implements RegexState {
WarnCallback warnings;
MatcherFactory factory;
- private Analyser analyser;
+ protected Analyser analyser;
int options;
int userOptions;
@@ -65,8 +66,6 @@ public final class Regex implements RegexState {
//final Syntax syntax;
final int caseFoldFlag;
- HashMap<String,NameEntry> nameTable; // named entries
-
/* optimization info (string search, char-map and anchors) */
SearchAlgorithm searchAlgorithm; /* optimize flag */
int thresholdLength; /* search str-length for apply optimize */
@@ -172,112 +171,6 @@ public final class Regex implements RegexState {
return numMem;
}
- public int numberOfCaptureHistories() {
- if (Config.USE_CAPTURE_HISTORY) {
- int n = 0;
- for (int i=0; i<=Config.MAX_CAPTURE_HISTORY_GROUP; i++) {
- if (bsAt(captureHistory, i)) n++;
- }
- return n;
- } else {
- return 0;
- }
- }
-
- String nameTableToString() {
- StringBuilder sb = new StringBuilder();
-
- if (nameTable != null) {
- sb.append("name table\n");
- for (NameEntry ne : nameTable.values()) {
- sb.append(" " + ne + "\n");
- }
- sb.append("\n");
- }
- return sb.toString();
- }
-
- NameEntry nameFind(char[] name, int nameP, int nameEnd) {
- if (nameTable != null) return nameTable.get(new String(name, nameP, nameEnd - nameP));
- return null;
- }
-
- void renumberNameTable(int[]map) {
- if (nameTable != null) {
- for (NameEntry e : nameTable.values()) {
- if (e.backNum > 1) {
- for (int i=0; i<e.backNum; i++) {
- e.backRefs[i] = map[e.backRefs[i]];
- }
- } else if (e.backNum == 1) {
- e.backRef1 = map[e.backRef1];
- }
- }
- }
- }
-
- public int numberOfNames() {
- return nameTable == null ? 0 : nameTable.size();
- }
-
- void nameAdd(char[] name, int nameP, int nameEnd, int backRef, Syntax syntax) {
- if (nameEnd - nameP <= 0) throw new ValueException(ErrorMessages.ERR_EMPTY_GROUP_NAME);
-
- NameEntry e = null;
- if (nameTable == null) {
- nameTable = new HashMap<String,NameEntry>(); // 13, oni defaults to 5
- } else {
- e = nameFind(name, nameP, nameEnd);
- }
-
- if (e == null) {
- // dup the name here as oni does ?, what for ? (it has to manage it, we don't)
- e = new NameEntry(name, nameP, nameEnd);
- nameTable.put(new String(name, nameP, nameEnd - nameP), e);
- } else if (e.backNum >= 1 && !syntax.allowMultiplexDefinitionName()) {
- throw new ValueException(ErrorMessages.ERR_MULTIPLEX_DEFINED_NAME, new String(name, nameP, nameEnd - nameP));
- }
-
- e.addBackref(backRef);
- }
-
- NameEntry nameToGroupNumbers(char[] name, int nameP, int nameEnd) {
- return nameFind(name, nameP, nameEnd);
- }
-
- public int nameToBackrefNumber(char[] name, int nameP, int nameEnd, Region region) {
- NameEntry e = nameToGroupNumbers(name, nameP, nameEnd);
- if (e == null) throw new ValueException(ErrorMessages.ERR_UNDEFINED_NAME_REFERENCE,
- new String(name, nameP, nameEnd - nameP));
-
- switch(e.backNum) {
- case 0:
- throw new InternalException(ErrorMessages.ERR_PARSER_BUG);
- case 1:
- return e.backRef1;
- default:
- if (region != null) {
- for (int i = e.backNum - 1; i >= 0; i--) {
- if (region.beg[e.backRefs[i]] != Region.REGION_NOTPOS) return e.backRefs[i];
- }
- }
- return e.backRefs[e.backNum - 1];
- }
- }
-
- public Iterator<NameEntry> namedBackrefIterator() {
- return nameTable.values().iterator();
- }
-
- public boolean noNameGroupIsActive(Syntax syntax) {
- if (isDontCaptureGroup(options)) return false;
-
- if (Config.USE_NAMED_GROUP) {
- if (numberOfNames() > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(options)) return false;
- }
- return true;
- }
-
/* set skip map for Boyer-Moor search */
void setupBMSkipMap() {
char[] chars = exact;
@@ -353,16 +246,6 @@ public final class Regex implements RegexState {
exactP = exactEnd = 0;
}
- public String encStringToString(byte[]bytes, int p, int end) {
- StringBuilder sb = new StringBuilder("\nPATTERN: /");
-
- while (p < end) {
- sb.append(new String(new byte[]{bytes[p]}));
- p++;
- }
- return sb.append("/").toString();
- }
-
public String optimizeInfoToString() {
String s = "";
s += "optimize: " + searchAlgorithm.getName() + "\n";
@@ -410,19 +293,13 @@ public final class Regex implements RegexState {
return options;
}
- public void setUserOptions(int options) {
- this.userOptions = options;
- }
-
- public int getUserOptions() {
- return userOptions;
+ public String dumpTree() {
+ return analyser == null ? null : analyser.root.toString();
}
- public void setUserObject(Object object) {
- this.userObject = object;
+ public String dumpByteCode() {
+ compile();
+ return new ByteCodePrinter(this).byteCodeListToString();
}
- public Object getUserObject() {
- return userObject;
- }
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java
index d685a249..ee9eb168 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java
@@ -25,7 +25,6 @@ public final class Region {
public final int numRegs;
public final int[]beg;
public final int[]end;
- public CaptureTreeNode historyRoot;
public Region(int num) {
this.numRegs = num;
@@ -33,20 +32,6 @@ public final class Region {
this.end = new int[num];
}
- public Region(int begin, int end) {
- this.numRegs = 1;
- this.beg = new int[]{begin};
- this.end = new int[]{end};
- }
-
- public Region clone() {
- Region region = new Region(numRegs);
- System.arraycopy(beg, 0, region.beg, 0, beg.length);
- System.arraycopy(end, 0, region.end, 0, end.length);
- if (historyRoot != null) region.historyRoot = historyRoot.cloneTree();
- return region;
- }
-
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Region: \n");
@@ -54,10 +39,6 @@ public final class Region {
return sb.toString();
}
- CaptureTreeNode getCaptureTree() {
- return historyRoot;
- }
-
void clear() {
for (int i=0; i<beg.length; i++) {
beg[i] = end[i] = REGION_NOTPOS;
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java
index a604bfa2..dd65939d 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java
@@ -40,16 +40,10 @@ public final class ScanEnvironment {
final public Regex reg;
int numCall;
- UnsetAddrList unsetAddrList; // USE_SUBEXP_CALL
public int numMem;
- int numNamed; // USE_NAMED_GROUP
-
public Node memNodes[];
- // USE_COMBINATION_EXPLOSION_CHECK
- int numCombExpCheck;
- int combExpMaxRegNum;
int currMaxRegNum;
boolean hasRecursion;
@@ -69,12 +63,8 @@ public final class ScanEnvironment {
numCall = 0;
numMem = 0;
- numNamed = 0;
-
memNodes = null;
- numCombExpCheck = 0;
- combExpMaxRegNum = 0;
currMaxRegNum = 0;
hasRecursion = false;
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java
index f3d8165c..abe51be2 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java
@@ -37,6 +37,8 @@ abstract class ScannerSupport extends IntHolder implements ErrorMessages {
private final int end; // pattern end position for reset() support
protected int _p; // used by mark()/restore() to mark positions
+ private final static int INT_SIGN_BIT = 1 << 31;
+
protected ScannerSupport(char[] chars, int p, int end) {
this.chars = chars;
this.begin = p;
@@ -53,8 +55,6 @@ abstract class ScannerSupport extends IntHolder implements ErrorMessages {
return end;
}
- private final int INT_SIGN_BIT = 1 << 31;
-
protected final int scanUnsignedNumber() {
int last = c;
int num = 0; // long ???
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java
index 898a4f10..eb6fb7d4 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java
@@ -22,7 +22,6 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt;
import java.lang.ref.WeakReference;
-import java.util.Arrays;
import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel;
import jdk.nashorn.internal.runtime.regexp.joni.constants.StackType;
@@ -36,10 +35,6 @@ abstract class StackMachine extends Matcher implements StackType {
protected final int[]repeatStk;
protected final int memStartStk, memEndStk;
- // CEC
- protected byte[] stateCheckBuff; // move to int[] ?
- int stateCheckBuffSize;
-
protected StackMachine(Regex regex, char[] chars, int p , int end) {
super(regex, chars, p, end);
@@ -104,67 +99,12 @@ abstract class StackMachine extends Matcher implements StackType {
stk++;
}
- // CEC
-
- // STATE_CHECK_POS
- private int stateCheckPos(int s, int snum) {
- return (s - str) * regex.numCombExpCheck + (snum - 1);
- }
-
- // STATE_CHECK_VAL
- protected final boolean stateCheckVal(int s, int snum) {
- if (stateCheckBuff != null) {
- int x = stateCheckPos(s, snum);
- return (stateCheckBuff[x / 8] & (1 << (x % 8))) != 0;
- }
- return false;
- }
-
- // ELSE_IF_STATE_CHECK_MARK
- private void stateCheckMark() {
- StackEntry e = stack[stk];
- int x = stateCheckPos(e.getStatePStr(), e.getStateCheck());
- stateCheckBuff[x / 8] |= (1 << (x % 8));
- }
-
- // STATE_CHECK_BUFF_INIT
- private static final int STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE = 16;
- protected final void stateCheckBuffInit(int strLength, int offset, int stateNum) {
- if (stateNum > 0 && strLength >= Config.CHECK_STRING_THRESHOLD_LEN) {
- int size = ((strLength + 1) * stateNum + 7) >>> 3;
- offset = (offset * stateNum) >>> 3;
-
- if (size > 0 && offset < size && size < Config.CHECK_BUFF_MAX_SIZE) {
- if (size >= STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE) {
- stateCheckBuff = new byte[size];
- } else {
- // same impl, reduce...
- stateCheckBuff = new byte[size];
- }
- Arrays.fill(stateCheckBuff, offset, (size - offset), (byte)0);
- stateCheckBuffSize = size;
- } else {
- stateCheckBuff = null; // reduce
- stateCheckBuffSize = 0;
- }
- } else {
- stateCheckBuff = null; // reduce
- stateCheckBuffSize = 0;
- }
- }
-
- protected final void stateCheckBuffClear() {
- stateCheckBuff = null;
- stateCheckBuffSize = 0;
- }
-
private void push(int type, int pat, int s, int prev) {
StackEntry e = ensure1();
e.type = type;
e.setStatePCode(pat);
e.setStatePStr(s);
e.setStatePStrPrev(prev);
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) e.setStateCheck(0);
stk++;
}
@@ -172,30 +112,9 @@ abstract class StackMachine extends Matcher implements StackType {
StackEntry e = stack[stk];
e.type = type;
e.setStatePCode(pat);
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) e.setStateCheck(0);
stk++;
}
- protected final void pushAltWithStateCheck(int pat, int s, int sprev, int snum) {
- StackEntry e = ensure1();
- e.type = ALT;
- e.setStatePCode(pat);
- e.setStatePStr(s);
- e.setStatePStrPrev(sprev);
- if (Config.USE_COMBINATION_EXPLOSION_CHECK) e.setStateCheck(stateCheckBuff != null ? snum : 0);
- stk++;
- }
-
- protected final void pushStateCheck(int s, int snum) {
- if (stateCheckBuff != null) {
- StackEntry e = ensure1();
- e.type = STATE_CHECK_MARK;
- e.setStatePStr(s);
- e.setStateCheck(snum);
- stk++;
- }
- }
-
protected final void pushAlt(int pat, int s, int prev) {
push(ALT, pat, s, prev);
}
@@ -294,19 +213,6 @@ abstract class StackMachine extends Matcher implements StackType {
stk++;
}
- protected final void pushCallFrame(int pat) {
- StackEntry e = ensure1();
- e.type = CALL_FRAME;
- e.setCallFrameRetAddr(pat);
- stk++;
- }
-
- protected final void pushReturn() {
- StackEntry e = ensure1();
- e.type = RETURN;
- stk++;
- }
-
// stack debug routines here
// ...
@@ -331,8 +237,6 @@ abstract class StackMachine extends Matcher implements StackType {
if ((e.type & MASK_POP_USED) != 0) {
return e;
- } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (e.type == STATE_CHECK_MARK) stateCheckMark();
}
}
}
@@ -346,8 +250,6 @@ abstract class StackMachine extends Matcher implements StackType {
} else if (e.type == MEM_START) {
repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
- } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (e.type == STATE_CHECK_MARK) stateCheckMark();
}
}
}
@@ -368,8 +270,6 @@ abstract class StackMachine extends Matcher implements StackType {
} else if (e.type == MEM_END) {
repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
- } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (e.type == STATE_CHECK_MARK) stateCheckMark();
}
}
}
@@ -391,8 +291,6 @@ abstract class StackMachine extends Matcher implements StackType {
} else if (e.type == MEM_END){
repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
repeatStk[memEndStk + e.getMemNum()] = e.getMemStart();
- } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (e.type == STATE_CHECK_MARK) stateCheckMark();
}
}
}
@@ -414,8 +312,6 @@ abstract class StackMachine extends Matcher implements StackType {
} else if (e.type == MEM_END) {
repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
- } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
- if (e.type == STATE_CHECK_MARK) stateCheckMark();
}
}
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java
index 07b52626..518a416e 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java
@@ -609,7 +609,7 @@ public final class Syntax implements SyntaxProperties{
OP_ESC_CONTROL_CHARS | OP_ESC_C_CONTROL | OP_ESC_X_HEX2)
& ~OP_ESC_LTGT_WORD_BEGIN_END ),
- ( OP2_QMARK_GROUP_EFFECT | OP2_CCLASS_SET_OP |
+ ( OP2_QMARK_GROUP_EFFECT |
OP2_ESC_V_VTAB | OP2_ESC_U_HEX4 ),
( GNU_REGEX_BV | DIFFERENT_LEN_ALT_LOOK_BEHIND ),
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java b/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java
deleted file mode 100644
index ca72e167..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni;
-
-import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode;
-import jdk.nashorn.internal.runtime.regexp.joni.ast.Node;
-import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
-import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
-
-public final class UnsetAddrList {
- int num;
- Node[]targets;
- int[]offsets;
-
- public UnsetAddrList(int size) {
- targets = new Node[size];
- offsets = new int[size];
- }
-
- public void add(int offset, Node node) {
- if (num >= offsets.length) {
- Node []ttmp = new Node[targets.length << 1];
- System.arraycopy(targets, 0, ttmp, 0, num);
- targets = ttmp;
- int[]otmp = new int[offsets.length << 1];
- System.arraycopy(offsets, 0, otmp, 0, num);
- offsets = otmp;
- }
- targets[num] = node;
- offsets[num] = offset;
-
- num++;
- }
-
- public void fix(Regex regex) {
- for (int i=0; i<num; i++) {
- EncloseNode en = (EncloseNode)targets[i];
- if (!en.isAddrFixed()) new InternalException(ErrorMessages.ERR_PARSER_BUG);
- regex.code[offsets[i]] = en.callAddr; // is this safe ?
- }
- }
-
- public String toString() {
- StringBuilder value = new StringBuilder();
- if (num > 0) {
- for (int i=0; i<num; i++) {
- value.append("offset + " + offsets[i] + " target: " + targets[i].getAddressName());
- }
- }
- return value.toString();
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java
index 4a73e266..f60c21a3 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java
@@ -22,7 +22,6 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.*;
import jdk.nashorn.internal.runtime.regexp.joni.constants.CCSTATE;
import jdk.nashorn.internal.runtime.regexp.joni.constants.CCVALTYPE;
-import jdk.nashorn.internal.runtime.regexp.joni.encoding.AsciiTables;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
@@ -40,6 +39,41 @@ public final class CClassNode extends Node {
private int ctype; // for hashing purposes
+ private final static short AsciiCtypeTable[] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+ };
+
// node_new_cclass
public CClassNode() {}
@@ -330,13 +364,13 @@ public final class CClassNode extends Node {
if (not) {
for (int c = 0; c < BitSet.SINGLE_BYTE_SIZE; c++) {
// if (!ASCIIEncoding.INSTANCE.isCodeCType(c, ctype)) bs.set(c);
- if ((AsciiTables.AsciiCtypeTable[c] & (1 << ctype)) == 0) bs.set(c);
+ if ((AsciiCtypeTable[c] & (1 << ctype)) == 0) bs.set(c);
}
addAllMultiByteRange();
} else {
for (int c = 0; c < BitSet.SINGLE_BYTE_SIZE; c++) {
// if (ASCIIEncoding.INSTANCE.isCodeCType(c, ctype)) bs.set(c);
- if ((AsciiTables.AsciiCtypeTable[c] & (1 << ctype)) != 0) bs.set(c);
+ if ((AsciiCtypeTable[c] & (1 << ctype)) != 0) bs.set(c);
}
}
return;
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CTypeNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CTypeNode.java
deleted file mode 100644
index b03f9900..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CTypeNode.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni.ast;
-
-public final class CTypeNode extends Node {
- public int ctype;
- public boolean not;
-
- public CTypeNode(int type, boolean not) {
- this.ctype= type;
- this.not = not;
- }
-
- @Override
- public int getType() {
- return CTYPE;
- }
-
- @Override
- public String getName() {
- return "Character Type";
- }
-
- @Override
- public String toString(int level) {
- StringBuilder value = new StringBuilder();
- value.append("\n ctype: " + ctype);
- value.append("\n not: " + not);
-
- return value.toString();
- }
-
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CallNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CallNode.java
deleted file mode 100644
index 361471b5..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CallNode.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni.ast;
-
-import java.util.Set;
-
-import jdk.nashorn.internal.runtime.regexp.joni.UnsetAddrList;
-import jdk.nashorn.internal.runtime.regexp.joni.WarnCallback;
-
-public final class CallNode extends StateNode {
- public char[] name;
- public int nameP;
- public int nameEnd;
-
- public int groupNum;
- public Node target; // is it an EncloseNode always ?
- public UnsetAddrList unsetAddrList;
-
- public CallNode(char[] name, int nameP, int nameEnd, int gnum) {
- this.name = name;
- this.nameP = nameP;
- this.nameEnd = nameEnd;
- this.groupNum = gnum; /* call by number if gnum != 0 */
- }
-
- @Override
- public int getType() {
- return CALL;
- }
-
- @Override
- protected void setChild(Node newChild) {
- target = newChild;
- }
-
- @Override
- protected Node getChild() {
- return target;
- }
-
- public void setTarget(Node tgt) {
- target = tgt;
- tgt.parent = this;
- }
-
- @Override
- public String getName() {
- return "Call";
- }
-
- @Override
- public void verifyTree(Set<Node> set, WarnCallback warnings) {
- if (target == null || target.parent == this)
- warnings.warn(this.getAddressName() + " doesn't point to a target or the target has been stolen");
- // do not recurse here
- }
-
- @Override
- public String toString(int level) {
- StringBuilder value = new StringBuilder(super.toString(level));
- value.append("\n name: " + new String(name, nameP, nameEnd - nameP));
- value.append("\n groupNum: " + groupNum);
- value.append("\n target: " + pad(target.getAddressName(), level + 1));
- value.append("\n unsetAddrList: " + pad(unsetAddrList, level + 1));
-
- return value.toString();
- }
-
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java
index a60afb1d..1c5bfe7d 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java
@@ -25,7 +25,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.EncloseType;
public final class EncloseNode extends StateNode implements EncloseType {
- public int type; // enclose type
+ public final int type; // enclose type
public int regNum;
public int option;
public Node target; /* EncloseNode : ENCLOSE_MEMORY */
@@ -42,10 +42,8 @@ public final class EncloseNode extends StateNode implements EncloseType {
}
// node_new_enclose_memory
- public EncloseNode(int option, boolean isNamed) {
+ public EncloseNode() {
this(MEMORY);
- if (isNamed) setNamedGroup();
- if (Config.USE_SUBEXP_CALL) this.option = option;
}
// node_new_option
@@ -104,46 +102,14 @@ public final class EncloseNode extends StateNode implements EncloseType {
return types.toString();
}
- public void setEncloseStatus(int flag) {
- state |= flag;
- }
-
- public void clearEncloseStatus(int flag) {
- state &= ~flag;
- }
-
- public void clearMemory() {
- type &= ~MEMORY;
- }
-
- public void setMemory() {
- type |= MEMORY;
- }
-
public boolean isMemory() {
return (type & MEMORY) != 0;
}
- public void clearOption() {
- type &= ~OPTION;
- }
-
- public void setOption() {
- type |= OPTION;
- }
-
public boolean isOption() {
return (type & OPTION) != 0;
}
- public void clearStopBacktrack() {
- type &= ~STOP_BACKTRACK;
- }
-
- public void setStopBacktrack() {
- type |= STOP_BACKTRACK;
- }
-
public boolean isStopBacktrack() {
return (type & STOP_BACKTRACK) != 0;
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java
index 26cde985..c87de29d 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java
@@ -21,9 +21,10 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.Config;
import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment;
-import jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce;
import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo;
+import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.*;
+
public final class QuantifierNode extends StateNode {
public Node target;
@@ -37,8 +38,33 @@ public final class QuantifierNode extends StateNode {
public Node nextHeadExact;
public boolean isRefered; /* include called node. don't eliminate even if {0} */
- // USE_COMBINATION_EXPLOSION_CHECK
- public int combExpCheckNum; /* 1,2,3...: check, 0: no check */
+ enum ReduceType {
+ ASIS, /* as is */
+ DEL, /* delete parent */
+ A, /* to '*' */
+ AQ, /* to '*?' */
+ QQ, /* to '??' */
+ P_QQ, /* to '+)??' */
+ PQ_Q, /* to '+?)?' */
+ }
+
+ private final static ReduceType[][] REDUCE_TABLE = {
+ {DEL, A, A, QQ, AQ, ASIS}, /* '?' */
+ {DEL, DEL, DEL, P_QQ, P_QQ, DEL}, /* '*' */
+ {A, A, DEL, ASIS, P_QQ, DEL}, /* '+' */
+ {DEL, AQ, AQ, DEL, AQ, AQ}, /* '??' */
+ {DEL, DEL, DEL, DEL, DEL, DEL}, /* '*?' */
+ {ASIS, PQ_Q, DEL, AQ, AQ, DEL} /* '+?' */
+ };
+
+ private final static String PopularQStr[] = new String[] {
+ "?", "*", "+", "??", "*?", "+?"
+ };
+
+ private final static String ReduceQStr[]= new String[] {
+ "", "", "*", "*?", "??", "+ and ??", "+? and ?"
+ };
+
public QuantifierNode(int lower, int upper, boolean byNumber) {
this.lower = lower;
@@ -92,7 +118,6 @@ public final class QuantifierNode extends StateNode {
value.append("\n headExact: " + pad(headExact, level + 1));
value.append("\n nextHeadExact: " + pad(nextHeadExact, level + 1));
value.append("\n isRefered: " + isRefered);
- value.append("\n combExpCheckNum: " + combExpCheckNum);
return value.toString();
}
@@ -134,7 +159,6 @@ public final class QuantifierNode extends StateNode {
headExact = other.headExact;
nextHeadExact = other.nextHeadExact;
isRefered = other.isRefered;
- combExpCheckNum = other.combExpCheckNum;
}
public void reduceNestedQuantifier(QuantifierNode other) {
@@ -143,7 +167,7 @@ public final class QuantifierNode extends StateNode {
if (pnum < 0 || cnum < 0) return;
- switch(Reduce.REDUCE_TABLE[cnum][pnum]) {
+ switch(REDUCE_TABLE[cnum][pnum]) {
case DEL:
// no need to set the parent here...
// swap ?
@@ -226,7 +250,7 @@ public final class QuantifierNode extends StateNode {
if (Config.USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR) {
if (!isByNumber() && !qnt.isByNumber() && env.syntax.warnReduntantNestedRepeat()) {
- switch(Reduce.REDUCE_TABLE[targetQNum][nestQNum]) {
+ switch(REDUCE_TABLE[targetQNum][nestQNum]) {
case ASIS:
break;
@@ -237,9 +261,9 @@ public final class QuantifierNode extends StateNode {
default:
env.reg.getWarnings().warn(new String(chars, p, end) +
- " nested repeat operator " + Reduce.PopularQStr[targetQNum] +
- " and " + Reduce.PopularQStr[nestQNum] + " was replaced with '" +
- Reduce.ReduceQStr[Reduce.REDUCE_TABLE[targetQNum][nestQNum].ordinal()] + "'");
+ " nested repeat operator " + PopularQStr[targetQNum] +
+ " and " + PopularQStr[nestQNum] + " was replaced with '" +
+ ReduceQStr[REDUCE_TABLE[targetQNum][nestQNum].ordinal()] + "'");
}
}
} // USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java
index 18101a4a..3f75f863 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java
@@ -40,7 +40,6 @@ public abstract class StateNode extends Node implements NodeStatus {
if (isRecursion()) states.append("RECURSION ");
if (isCalled()) states.append("CALLED ");
if (isAddrFixed()) states.append("ADDR_FIXED ");
- if (isNamedGroup()) states.append("NAMED_GROUP ");
if (isNameRef()) states.append("NAME_REF ");
if (isInRepeat()) states.append("IN_REPEAT ");
if (isNestLevel()) states.append("NEST_LEVEL ");
@@ -57,10 +56,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_MIN_FIXED;
}
- public void clearMinFixed() {
- state &= ~NST_MIN_FIXED;
- }
-
public boolean isMaxFixed() {
return (state & NST_MAX_FIXED) != 0;
}
@@ -69,10 +64,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_MAX_FIXED;
}
- public void clearMaxFixed() {
- state &= ~NST_MAX_FIXED;
- }
-
public boolean isCLenFixed() {
return (state & NST_CLEN_FIXED) != 0;
}
@@ -81,10 +72,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_CLEN_FIXED;
}
- public void clearCLenFixed() {
- state &= ~NST_CLEN_FIXED;
- }
-
public boolean isMark1() {
return (state & NST_MARK1) != 0;
}
@@ -93,10 +80,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_MARK1;
}
- public void clearMark1() {
- state &= ~NST_MARK1;
- }
-
public boolean isMark2() {
return (state & NST_MARK2) != 0;
}
@@ -117,10 +100,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_MEM_BACKREFED;
}
- public void clearMemBackrefed() {
- state &= ~NST_MEM_BACKREFED;
- }
-
public boolean isStopBtSimpleRepeat() {
return (state & NST_STOP_BT_SIMPLE_REPEAT) != 0;
}
@@ -129,10 +108,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_STOP_BT_SIMPLE_REPEAT;
}
- public void clearStopBtSimpleRepeat() {
- state &= ~NST_STOP_BT_SIMPLE_REPEAT;
- }
-
public boolean isRecursion() {
return (state & NST_RECURSION) != 0;
}
@@ -141,10 +116,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_RECURSION;
}
- public void clearRecursion() {
- state &= ~NST_RECURSION;
- }
-
public boolean isCalled() {
return (state & NST_CALLED) != 0;
}
@@ -153,10 +124,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_CALLED;
}
- public void clearCAlled() {
- state &= ~NST_CALLED;
- }
-
public boolean isAddrFixed() {
return (state & NST_ADDR_FIXED) != 0;
}
@@ -165,22 +132,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_ADDR_FIXED;
}
- public void clearAddrFixed() {
- state &= ~NST_ADDR_FIXED;
- }
-
- public boolean isNamedGroup() {
- return (state & NST_NAMED_GROUP) != 0;
- }
-
- public void setNamedGroup() {
- state |= NST_NAMED_GROUP;
- }
-
- public void clearNamedGroup() {
- state &= ~NST_NAMED_GROUP;
- }
-
public boolean isNameRef() {
return (state & NST_NAME_REF) != 0;
}
@@ -189,10 +140,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_NAME_REF;
}
- public void clearNameRef() {
- state &= ~NST_NAME_REF;
- }
-
public boolean isInRepeat() {
return (state & NST_IN_REPEAT) != 0;
}
@@ -201,10 +148,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_IN_REPEAT;
}
- public void clearInRepeat() {
- state &= ~NST_IN_REPEAT;
- }
-
public boolean isNestLevel() {
return (state & NST_NEST_LEVEL) != 0;
}
@@ -213,10 +156,6 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_NEST_LEVEL;
}
- public void clearNestLevel() {
- state &= ~NST_NEST_LEVEL;
- }
-
public boolean isByNumber() {
return (state & NST_BY_NUMBER) != 0;
}
@@ -225,8 +164,4 @@ public abstract class StateNode extends Node implements NodeStatus {
state |= NST_BY_NUMBER;
}
- public void clearByNumber() {
- state &= ~NST_BY_NUMBER;
- }
-
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java b/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java
deleted file mode 100644
index 9751b51d..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package jdk.nashorn.internal.runtime.regexp.joni.bench;
-
-import jdk.nashorn.internal.runtime.regexp.joni.Option;
-import jdk.nashorn.internal.runtime.regexp.joni.Regex;
-import jdk.nashorn.internal.runtime.regexp.joni.Syntax;
-
-public abstract class AbstractBench {
- protected void bench(String _reg, String _str, int warmup, int times) throws Exception {
- char[] reg = _reg.toCharArray();
- char[] str = _str.toCharArray();
-
- Regex p = new Regex(reg,0,reg.length,Option.DEFAULT,Syntax.DEFAULT);
-
- System.err.println("::: /" + _reg + "/ =~ \"" + _str + "\", " + warmup + " * " + times + " times");
-
- for(int j=0;j<warmup;j++) {
- long before = System.currentTimeMillis();
- for(int i = 0; i < times; i++) {
- p.matcher(str, 0, str.length).search(0, str.length, Option.NONE);
- }
- long time = System.currentTimeMillis() - before;
- System.err.println(": " + time + "ms");
- }
- }
-
- protected void benchBestOf(String _reg, String _str, int warmup, int times) throws Exception {
- char[] reg = _reg.toCharArray();
- char[] str = _str.toCharArray();
-
- Regex p = new Regex(reg,0,reg.length,Option.DEFAULT,Syntax.DEFAULT);
-
- System.err.println("::: /" + _reg + "/ =~ \"" + _str + "\", " + warmup + " * " + times + " times");
-
- long best = Long.MAX_VALUE;
-
- for(int j=0;j<warmup;j++) {
- long before = System.currentTimeMillis();
- for(int i = 0; i < times; i++) {
- p.matcher(str, 0, str.length).search(0, str.length, Option.NONE);
- }
- long time = System.currentTimeMillis() - before;
- if(time < best) {
- best = time;
- }
- System.err.print(".");
- }
- System.err.println(": " + best + "ms");
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchGreedyBacktrack.java b/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchGreedyBacktrack.java
deleted file mode 100644
index 116352da..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchGreedyBacktrack.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package jdk.nashorn.internal.runtime.regexp.joni.bench;
-
-public class BenchGreedyBacktrack extends AbstractBench {
- public static void main(String[] args) throws Exception {
- new BenchGreedyBacktrack().bench(".*_p","_petstore_session_id=1b341ffe23b5298676d535fcabd3d0d7; path=/",10,1000000);
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchRailsRegs.java b/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchRailsRegs.java
deleted file mode 100644
index eb339af3..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchRailsRegs.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package jdk.nashorn.internal.runtime.regexp.joni.bench;
-
-public class BenchRailsRegs extends AbstractBench {
- public static void main(String[] args) throws Exception {
- final String[][] regexps = {{"a.*?[b-z]{2,4}aaaaaa","afdgdsgderaabxxaaaaaaaaaaaaaaaaaaaaaaaa"},
- {"://","/shop/viewCategory.shtml?category=DOGS"},
- {"^\\w+\\://[^/]+(/.*|$)$","/shop/viewCategory.shtml?category=DOGS"},
- {"\\A/?\\Z","/shop/viewCategory.shtml"},
- {"\\A/shop/signonForm\\.shtml/?\\Z","/shop/viewCategory.shtml"},
- {"\\A/shop/newAccountForm\\.shtml/?\\Z","/shop/viewCategory.shtml"},
- {"\\A/shop/newAccount\\.shtml/?\\Z","/shop/viewCategory.shtml"},
- {"\\A/shop/viewCart\\.shtml/?\\Z","/shop/viewCategory.shtml"},
- {"\\A/shop/index\\.shtml/?\\Z","/shop/viewCategory.shtml"},
- {"\\A/shop/viewCategory\\.shtml/?\\Z","/shop/viewCategory.shtml"},
- {"\\A(?:::)?([A-Z]\\w*(?:::[A-Z]\\w*)*)\\z","CategoriesController"},
- {"\\Ainsert","SELECT * FROM sessions WHERE (session_id = '1b341ffe23b5298676d535fcabd3d0d7') LIMIT 1"},
- {"\\A\\(?\\s*(select|show)","SELECT * FROM sessions WHERE (session_id = '1b341ffe23b5298676d535fcabd3d0d7') LIMIT 1"},
- {".*?\n","1b341ffe23b5298676d535fcabd3d0d7"},
- {"^find_(all_by|by)_([_a-zA-Z]\\w*)$","find_by_string_id"},
- {"\\.rjs$","categories/show.rhtml"},
- {"^[-a-z]+://","petstore.css"},
- {"^get$",""},
- {"^post$",""},
- {"^[^:]+","www.example.com"},
- {"(=|\\?|_before_type_cast)$", "updated_on"},
- {"^(.*?)=(.*?);","_petstore_session_id=1b341ffe23b5298676d535fcabd3d0d7; path=/"}};
- for(String[] reg : regexps) {
- new BenchRailsRegs().benchBestOf(reg[0],reg[1],10,1000000);
- }
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchSeveralRegexps.java b/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchSeveralRegexps.java
deleted file mode 100644
index 3c118cfe..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchSeveralRegexps.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package jdk.nashorn.internal.runtime.regexp.joni.bench;
-
-public class BenchSeveralRegexps extends AbstractBench {
- public static void main(String[] args) throws Exception {
- int BASE = 1000000;
-
- new BenchSeveralRegexps().benchBestOf("a"," a",10,4*BASE);
-
- new BenchSeveralRegexps().benchBestOf(".*?=","_petstore_session_id=1b341ffe23b5298676d535fcabd3d0d7; path=/",10,BASE);
-
- new BenchSeveralRegexps().benchBestOf("^(.*?)=(.*?);","_petstore_session_id=1b341ffe23b5298676d535fcabd3d0d7; path=/",10,BASE);
-
- new BenchSeveralRegexps().benchBestOf(".*_p","_petstore_session_id=1b341ffe23b5298676d535fcabd3d0d7; path=/",10,4*BASE);
-
- new BenchSeveralRegexps().benchBestOf(".*=","_petstore_session_id=1b341ffe23b5298676d535fcabd3d0d7; path=/",10,4*BASE);
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java
index 7f2c534b..06c50117 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java
@@ -19,8 +19,6 @@
*/
package jdk.nashorn.internal.runtime.regexp.joni.constants;
-import jdk.nashorn.internal.runtime.regexp.joni.Config;
-
public interface OPCode {
final int FINISH = 0; /* matching process terminator (no more alternative) */
final int END = 1; /* pattern code terminator (success end) */
@@ -151,237 +149,4 @@ public interface OPCode {
final int EXACT1_IC_SB = 105; /* single byte, N = 1, ignore case */
final int EXACTN_IC_SB = 106; /* single byte, ignore case */
-
- public final String OpCodeNames[] = Config.DEBUG_COMPILE ? new String[] {
- "finish", /*OP_FINISH*/
- "end", /*OP_END*/
- "exact1", /*OP_EXACT1*/
- "exact2", /*OP_EXACT2*/
- "exact3", /*OP_EXACT3*/
- "exact4", /*OP_EXACT4*/
- "exact5", /*OP_EXACT5*/
- "exactn", /*OP_EXACTN*/
- "exactmb2-n1", /*OP_EXACTMB2N1*/
- "exactmb2-n2", /*OP_EXACTMB2N2*/
- "exactmb2-n3", /*OP_EXACTMB2N3*/
- "exactmb2-n", /*OP_EXACTMB2N*/
- "exactmb3n", /*OP_EXACTMB3N*/
- "exactmbn", /*OP_EXACTMBN*/
- "exact1-ic", /*OP_EXACT1_IC*/
- "exactn-ic", /*OP_EXACTN_IC*/
- "cclass", /*OP_CCLASS*/
- "cclass-mb", /*OP_CCLASS_MB*/
- "cclass-mix", /*OP_CCLASS_MIX*/
- "cclass-not", /*OP_CCLASS_NOT*/
- "cclass-mb-not", /*OP_CCLASS_MB_NOT*/
- "cclass-mix-not", /*OP_CCLASS_MIX_NOT*/
- "cclass-node", /*OP_CCLASS_NODE*/
- "anychar", /*OP_ANYCHAR*/
- "anychar-ml", /*OP_ANYCHAR_ML*/
- "anychar*", /*OP_ANYCHAR_STAR*/
- "anychar-ml*", /*OP_ANYCHAR_ML_STAR*/
- "anychar*-peek-next", /*OP_ANYCHAR_STAR_PEEK_NEXT*/
- "anychar-ml*-peek-next", /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
- "word", /*OP_WORD*/
- "not-word", /*OP_NOT_WORD*/
- "word-bound", /*OP_WORD_BOUND*/
- "not-word-bound", /*OP_NOT_WORD_BOUND*/
- "word-begin", /*OP_WORD_BEGIN*/
- "word-end", /*OP_WORD_END*/
- "begin-buf", /*OP_BEGIN_BUF*/
- "end-buf", /*OP_END_BUF*/
- "begin-line", /*OP_BEGIN_LINE*/
- "end-line", /*OP_END_LINE*/
- "semi-end-buf", /*OP_SEMI_END_BUF*/
- "begin-position", /*OP_BEGIN_POSITION*/
- "backref1", /*OP_BACKREF1*/
- "backref2", /*OP_BACKREF2*/
- "backrefn", /*OP_BACKREFN*/
- "backrefn-ic", /*OP_BACKREFN_IC*/
- "backref_multi", /*OP_BACKREF_MULTI*/
- "backref_multi-ic", /*OP_BACKREF_MULTI_IC*/
- "backref_at_level", /*OP_BACKREF_AT_LEVEL*/
- "mem-start", /*OP_MEMORY_START*/
- "mem-start-push", /*OP_MEMORY_START_PUSH*/
- "mem-end-push", /*OP_MEMORY_END_PUSH*/
- "mem-end-push-rec", /*OP_MEMORY_END_PUSH_REC*/
- "mem-end", /*OP_MEMORY_END*/
- "mem-end-rec", /*OP_MEMORY_END_REC*/
- "fail", /*OP_FAIL*/
- "jump", /*OP_JUMP*/
- "push", /*OP_PUSH*/
- "pop", /*OP_POP*/
- "push-or-jump-e1", /*OP_PUSH_OR_JUMP_EXACT1*/
- "push-if-peek-next", /*OP_PUSH_IF_PEEK_NEXT*/
- "repeat", /*OP_REPEAT*/
- "repeat-ng", /*OP_REPEAT_NG*/
- "repeat-inc", /*OP_REPEAT_INC*/
- "repeat-inc-ng", /*OP_REPEAT_INC_NG*/
- "repeat-inc-sg", /*OP_REPEAT_INC_SG*/
- "repeat-inc-ng-sg", /*OP_REPEAT_INC_NG_SG*/
- "null-check-start", /*OP_NULL_CHECK_START*/
- "null-check-end", /*OP_NULL_CHECK_END*/
- "null-check-end-memst", /*OP_NULL_CHECK_END_MEMST*/
- "null-check-end-memst-push", /*OP_NULL_CHECK_END_MEMST_PUSH*/
- "push-pos", /*OP_PUSH_POS*/
- "pop-pos", /*OP_POP_POS*/
- "push-pos-not", /*OP_PUSH_POS_NOT*/
- "fail-pos", /*OP_FAIL_POS*/
- "push-stop-bt", /*OP_PUSH_STOP_BT*/
- "pop-stop-bt", /*OP_POP_STOP_BT*/
- "look-behind", /*OP_LOOK_BEHIND*/
- "push-look-behind-not", /*OP_PUSH_LOOK_BEHIND_NOT*/
- "fail-look-behind-not", /*OP_FAIL_LOOK_BEHIND_NOT*/
- "call", /*OP_CALL*/
- "return", /*OP_RETURN*/
- "state-check-push", /*OP_STATE_CHECK_PUSH*/
- "state-check-push-or-jump", /*OP_STATE_CHECK_PUSH_OR_JUMP*/
- "state-check", /*OP_STATE_CHECK*/
- "state-check-anychar*", /*OP_STATE_CHECK_ANYCHAR_STAR*/
- "state-check-anychar-ml*", /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
- "set-option-push", /*OP_SET_OPTION_PUSH*/
- "set-option", /*OP_SET_OPTION*/
-
- // single byte versions
- "anychar-sb", /*OP_ANYCHAR*/
- "anychar-ml-sb", /*OP_ANYCHAR_ML*/
- "anychar*-sb", /*OP_ANYCHAR_STAR*/
- "anychar-ml*-sb", /*OP_ANYCHAR_ML_STAR*/
- "anychar*-peek-next-sb", /*OP_ANYCHAR_STAR_PEEK_NEXT*/
- "anychar-ml*-peek-next-sb", /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
- "state-check-anychar*-sb", /*OP_STATE_CHECK_ANYCHAR_STAR*/
- "state-check-anychar-ml*-sb", /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
-
- "cclass-sb", /*OP_CCLASS*/
- "cclass-not-sb", /*OP_CCLASS_NOT*/
-
- "word-sb", /*OP_WORD*/
- "not-word-sb", /*OP_NOT_WORD*/
- "word-bound-sb", /*OP_WORD_BOUND*/
- "not-word-bound-sb", /*OP_NOT_WORD_BOUND*/
- "word-begin-sb", /*OP_WORD_BEGIN*/
- "word-end-sb", /*OP_WORD_END*/
-
- "look-behind-sb", /*OP_LOOK_BEHIND*/
-
- "exact1-ic-sb", /*OP_EXACT1_IC*/
- "exactn-ic-sb", /*OP_EXACTN_IC*/
-
- } : null;
-
- public final int OpCodeArgTypes[] = Config.DEBUG_COMPILE ? new int[] {
- Arguments.NON, /*OP_FINISH*/
- Arguments.NON, /*OP_END*/
- Arguments.SPECIAL, /*OP_EXACT1*/
- Arguments.SPECIAL, /*OP_EXACT2*/
- Arguments.SPECIAL, /*OP_EXACT3*/
- Arguments.SPECIAL, /*OP_EXACT4*/
- Arguments.SPECIAL, /*OP_EXACT5*/
- Arguments.SPECIAL, /*OP_EXACTN*/
- Arguments.SPECIAL, /*OP_EXACTMB2N1*/
- Arguments.SPECIAL, /*OP_EXACTMB2N2*/
- Arguments.SPECIAL, /*OP_EXACTMB2N3*/
- Arguments.SPECIAL, /*OP_EXACTMB2N*/
- Arguments.SPECIAL, /*OP_EXACTMB3N*/
- Arguments.SPECIAL, /*OP_EXACTMBN*/
- Arguments.SPECIAL, /*OP_EXACT1_IC*/
- Arguments.SPECIAL, /*OP_EXACTN_IC*/
- Arguments.SPECIAL, /*OP_CCLASS*/
- Arguments.SPECIAL, /*OP_CCLASS_MB*/
- Arguments.SPECIAL, /*OP_CCLASS_MIX*/
- Arguments.SPECIAL, /*OP_CCLASS_NOT*/
- Arguments.SPECIAL, /*OP_CCLASS_MB_NOT*/
- Arguments.SPECIAL, /*OP_CCLASS_MIX_NOT*/
- Arguments.SPECIAL, /*OP_CCLASS_NODE*/
- Arguments.NON, /*OP_ANYCHAR*/
- Arguments.NON, /*OP_ANYCHAR_ML*/
- Arguments.NON, /*OP_ANYCHAR_STAR*/
- Arguments.NON, /*OP_ANYCHAR_ML_STAR*/
- Arguments.SPECIAL, /*OP_ANYCHAR_STAR_PEEK_NEXT*/
- Arguments.SPECIAL, /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
- Arguments.NON, /*OP_WORD*/
- Arguments.NON, /*OP_NOT_WORD*/
- Arguments.NON, /*OP_WORD_BOUND*/
- Arguments.NON, /*OP_NOT_WORD_BOUND*/
- Arguments.NON, /*OP_WORD_BEGIN*/
- Arguments.NON, /*OP_WORD_END*/
- Arguments.NON, /*OP_BEGIN_BUF*/
- Arguments.NON, /*OP_END_BUF*/
- Arguments.NON, /*OP_BEGIN_LINE*/
- Arguments.NON, /*OP_END_LINE*/
- Arguments.NON, /*OP_SEMI_END_BUF*/
- Arguments.NON, /*OP_BEGIN_POSITION*/
- Arguments.NON, /*OP_BACKREF1*/
- Arguments.NON, /*OP_BACKREF2*/
- Arguments.MEMNUM, /*OP_BACKREFN*/
- Arguments.SPECIAL, /*OP_BACKREFN_IC*/
- Arguments.SPECIAL, /*OP_BACKREF_MULTI*/
- Arguments.SPECIAL, /*OP_BACKREF_MULTI_IC*/
- Arguments.SPECIAL, /*OP_BACKREF_AT_LEVEL*/
- Arguments.MEMNUM, /*OP_MEMORY_START*/
- Arguments.MEMNUM, /*OP_MEMORY_START_PUSH*/
- Arguments.MEMNUM, /*OP_MEMORY_END_PUSH*/
- Arguments.MEMNUM, /*OP_MEMORY_END_PUSH_REC*/
- Arguments.MEMNUM, /*OP_MEMORY_END*/
- Arguments.MEMNUM, /*OP_MEMORY_END_REC*/
- Arguments.NON, /*OP_FAIL*/
- Arguments.RELADDR, /*OP_JUMP*/
- Arguments.RELADDR, /*OP_PUSH*/
- Arguments.NON, /*OP_POP*/
- Arguments.SPECIAL, /*OP_PUSH_OR_JUMP_EXACT1*/
- Arguments.SPECIAL, /*OP_PUSH_IF_PEEK_NEXT*/
- Arguments.SPECIAL, /*OP_REPEAT*/
- Arguments.SPECIAL, /*OP_REPEAT_NG*/
- Arguments.MEMNUM, /*OP_REPEAT_INC*/
- Arguments.MEMNUM, /*OP_REPEAT_INC_NG*/
- Arguments.MEMNUM, /*OP_REPEAT_INC_SG*/
- Arguments.MEMNUM, /*OP_REPEAT_INC_NG_SG*/
- Arguments.MEMNUM, /*OP_NULL_CHECK_START*/
- Arguments.MEMNUM, /*OP_NULL_CHECK_END*/
- Arguments.MEMNUM, /*OP_NULL_CHECK_END_MEMST*/
- Arguments.MEMNUM, /*OP_NULL_CHECK_END_MEMST_PUSH*/
- Arguments.NON, /*OP_PUSH_POS*/
- Arguments.NON, /*OP_POP_POS*/
- Arguments.RELADDR, /*OP_PUSH_POS_NOT*/
- Arguments.NON, /*OP_FAIL_POS*/
- Arguments.NON, /*OP_PUSH_STOP_BT*/
- Arguments.NON, /*OP_POP_STOP_BT*/
- Arguments.SPECIAL, /*OP_LOOK_BEHIND*/
- Arguments.SPECIAL, /*OP_PUSH_LOOK_BEHIND_NOT*/
- Arguments.NON, /*OP_FAIL_LOOK_BEHIND_NOT*/
- Arguments.ABSADDR, /*OP_CALL*/
- Arguments.NON, /*OP_RETURN*/
- Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH*/
- Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH_OR_JUMP*/
- Arguments.STATE_CHECK, /*OP_STATE_CHECK*/
- Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_STAR*/
- Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
- Arguments.OPTION, /*OP_SET_OPTION_PUSH*/
- Arguments.OPTION, /*OP_SET_OPTION*/
-
- // single byte versions
- Arguments.NON, /*OP_ANYCHAR*/
- Arguments.NON, /*OP_ANYCHAR_ML*/
- Arguments.NON, /*OP_ANYCHAR_STAR*/
- Arguments.NON, /*OP_ANYCHAR_ML_STAR*/
- Arguments.SPECIAL, /*OP_ANYCHAR_STAR_PEEK_NEXT*/
- Arguments.SPECIAL, /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/
- Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_STAR*/
- Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/
-
- Arguments.SPECIAL, /*OP_CCLASS*/
- Arguments.SPECIAL, /*OP_CCLASS_NOT*/
-
- Arguments.NON, /*OP_WORD*/
- Arguments.NON, /*OP_NOT_WORD*/
- Arguments.NON, /*OP_WORD_BOUND*/
- Arguments.NON, /*OP_NOT_WORD_BOUND*/
- Arguments.NON, /*OP_WORD_BEGIN*/
- Arguments.NON, /*OP_WORD_END*/
-
- Arguments.SPECIAL, /*OP_LOOK_BEHIND*/
-
- Arguments.SPECIAL, /*OP_EXACT1_IC*/
- Arguments.SPECIAL, /*OP_EXACTN_IC*/
- } : null;
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/constants/Reduce.java b/src/jdk/nashorn/internal/runtime/regexp/joni/constants/Reduce.java
deleted file mode 100644
index a906e84d..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/constants/Reduce.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni.constants;
-
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.A;
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.AQ;
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.ASIS;
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.DEL;
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.PQ_Q;
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.P_QQ;
-import static jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce.ReduceType.QQ;
-
-public interface Reduce {
-
- enum ReduceType {
- ASIS, /* as is */
- DEL, /* delete parent */
- A, /* to '*' */
- AQ, /* to '*?' */
- QQ, /* to '??' */
- P_QQ, /* to '+)??' */
- PQ_Q, /* to '+?)?' */
- }
-
- final ReduceType[][]REDUCE_TABLE = {
- {DEL, A, A, QQ, AQ, ASIS}, /* '?' */
- {DEL, DEL, DEL, P_QQ, P_QQ, DEL}, /* '*' */
- {A, A, DEL, ASIS, P_QQ, DEL}, /* '+' */
- {DEL, AQ, AQ, DEL, AQ, AQ}, /* '??' */
- {DEL, DEL, DEL, DEL, DEL, DEL}, /* '*?' */
- {ASIS, PQ_Q, DEL, AQ, AQ, DEL} /* '+?' */
- };
-
-
- final String PopularQStr[] = new String[] {
- "?", "*", "+", "??", "*?", "+?"
- };
-
- String ReduceQStr[]= new String[] {
- "", "", "*", "*?", "??", "+ and ??", "+? and ?"
- };
-
-}
-
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java b/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java
deleted file mode 100644
index 3dec4ba2..00000000
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package jdk.nashorn.internal.runtime.regexp.joni.encoding;
-
-public class AsciiTables {
-
- public static final short AsciiCtypeTable[] = {
- 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
- 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
- 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
- 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
- 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
- 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
- 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
- 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
- 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
- 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
- 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
- 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
- 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
- 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
- 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
- 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
- };
-
- public static final byte ToLowerCaseTable[] = {
- (byte)'\000', (byte)'\001', (byte)'\002', (byte)'\003', (byte)'\004', (byte)'\005', (byte)'\006', (byte)'\007',
- (byte)'\010', (byte)'\011', (byte)'\012', (byte)'\013', (byte)'\014', (byte)'\015', (byte)'\016', (byte)'\017',
- (byte)'\020', (byte)'\021', (byte)'\022', (byte)'\023', (byte)'\024', (byte)'\025', (byte)'\026', (byte)'\027',
- (byte)'\030', (byte)'\031', (byte)'\032', (byte)'\033', (byte)'\034', (byte)'\035', (byte)'\036', (byte)'\037',
- (byte)'\040', (byte)'\041', (byte)'\042', (byte)'\043', (byte)'\044', (byte)'\045', (byte)'\046', (byte)'\047',
- (byte)'\050', (byte)'\051', (byte)'\052', (byte)'\053', (byte)'\054', (byte)'\055', (byte)'\056', (byte)'\057',
- (byte)'\060', (byte)'\061', (byte)'\062', (byte)'\063', (byte)'\064', (byte)'\065', (byte)'\066', (byte)'\067',
- (byte)'\070', (byte)'\071', (byte)'\072', (byte)'\073', (byte)'\074', (byte)'\075', (byte)'\076', (byte)'\077',
- (byte)'\100', (byte)'\141', (byte)'\142', (byte)'\143', (byte)'\144', (byte)'\145', (byte)'\146', (byte)'\147',
- (byte)'\150', (byte)'\151', (byte)'\152', (byte)'\153', (byte)'\154', (byte)'\155', (byte)'\156', (byte)'\157',
- (byte)'\160', (byte)'\161', (byte)'\162', (byte)'\163', (byte)'\164', (byte)'\165', (byte)'\166', (byte)'\167',
- (byte)'\170', (byte)'\171', (byte)'\172', (byte)'\133', (byte)'\134', (byte)'\135', (byte)'\136', (byte)'\137',
- (byte)'\140', (byte)'\141', (byte)'\142', (byte)'\143', (byte)'\144', (byte)'\145', (byte)'\146', (byte)'\147',
- (byte)'\150', (byte)'\151', (byte)'\152', (byte)'\153', (byte)'\154', (byte)'\155', (byte)'\156', (byte)'\157',
- (byte)'\160', (byte)'\161', (byte)'\162', (byte)'\163', (byte)'\164', (byte)'\165', (byte)'\166', (byte)'\167',
- (byte)'\170', (byte)'\171', (byte)'\172', (byte)'\173', (byte)'\174', (byte)'\175', (byte)'\176', (byte)'\177',
- (byte)'\200', (byte)'\201', (byte)'\202', (byte)'\203', (byte)'\204', (byte)'\205', (byte)'\206', (byte)'\207',
- (byte)'\210', (byte)'\211', (byte)'\212', (byte)'\213', (byte)'\214', (byte)'\215', (byte)'\216', (byte)'\217',
- (byte)'\220', (byte)'\221', (byte)'\222', (byte)'\223', (byte)'\224', (byte)'\225', (byte)'\226', (byte)'\227',
- (byte)'\230', (byte)'\231', (byte)'\232', (byte)'\233', (byte)'\234', (byte)'\235', (byte)'\236', (byte)'\237',
- (byte)'\240', (byte)'\241', (byte)'\242', (byte)'\243', (byte)'\244', (byte)'\245', (byte)'\246', (byte)'\247',
- (byte)'\250', (byte)'\251', (byte)'\252', (byte)'\253', (byte)'\254', (byte)'\255', (byte)'\256', (byte)'\257',
- (byte)'\260', (byte)'\261', (byte)'\262', (byte)'\263', (byte)'\264', (byte)'\265', (byte)'\266', (byte)'\267',
- (byte)'\270', (byte)'\271', (byte)'\272', (byte)'\273', (byte)'\274', (byte)'\275', (byte)'\276', (byte)'\277',
- (byte)'\300', (byte)'\301', (byte)'\302', (byte)'\303', (byte)'\304', (byte)'\305', (byte)'\306', (byte)'\307',
- (byte)'\310', (byte)'\311', (byte)'\312', (byte)'\313', (byte)'\314', (byte)'\315', (byte)'\316', (byte)'\317',
- (byte)'\320', (byte)'\321', (byte)'\322', (byte)'\323', (byte)'\324', (byte)'\325', (byte)'\326', (byte)'\327',
- (byte)'\330', (byte)'\331', (byte)'\332', (byte)'\333', (byte)'\334', (byte)'\335', (byte)'\336', (byte)'\337',
- (byte)'\340', (byte)'\341', (byte)'\342', (byte)'\343', (byte)'\344', (byte)'\345', (byte)'\346', (byte)'\347',
- (byte)'\350', (byte)'\351', (byte)'\352', (byte)'\353', (byte)'\354', (byte)'\355', (byte)'\356', (byte)'\357',
- (byte)'\360', (byte)'\361', (byte)'\362', (byte)'\363', (byte)'\364', (byte)'\365', (byte)'\366', (byte)'\367',
- (byte)'\370', (byte)'\371', (byte)'\372', (byte)'\373', (byte)'\374', (byte)'\375', (byte)'\376', (byte)'\377',
- };
-
- public static final byte ToUpperCaseTable[] = {
- (byte)'\000', (byte)'\001', (byte)'\002', (byte)'\003', (byte)'\004', (byte)'\005', (byte)'\006', (byte)'\007',
- (byte)'\010', (byte)'\011', (byte)'\012', (byte)'\013', (byte)'\014', (byte)'\015', (byte)'\016', (byte)'\017',
- (byte)'\020', (byte)'\021', (byte)'\022', (byte)'\023', (byte)'\024', (byte)'\025', (byte)'\026', (byte)'\027',
- (byte)'\030', (byte)'\031', (byte)'\032', (byte)'\033', (byte)'\034', (byte)'\035', (byte)'\036', (byte)'\037',
- (byte)'\040', (byte)'\041', (byte)'\042', (byte)'\043', (byte)'\044', (byte)'\045', (byte)'\046', (byte)'\047',
- (byte)'\050', (byte)'\051', (byte)'\052', (byte)'\053', (byte)'\054', (byte)'\055', (byte)'\056', (byte)'\057',
- (byte)'\060', (byte)'\061', (byte)'\062', (byte)'\063', (byte)'\064', (byte)'\065', (byte)'\066', (byte)'\067',
- (byte)'\070', (byte)'\071', (byte)'\072', (byte)'\073', (byte)'\074', (byte)'\075', (byte)'\076', (byte)'\077',
- (byte)'\100', (byte)'\101', (byte)'\102', (byte)'\103', (byte)'\104', (byte)'\105', (byte)'\106', (byte)'\107',
- (byte)'\110', (byte)'\111', (byte)'\112', (byte)'\113', (byte)'\114', (byte)'\115', (byte)'\116', (byte)'\117',
- (byte)'\120', (byte)'\121', (byte)'\122', (byte)'\123', (byte)'\124', (byte)'\125', (byte)'\126', (byte)'\127',
- (byte)'\130', (byte)'\131', (byte)'\132', (byte)'\133', (byte)'\134', (byte)'\135', (byte)'\136', (byte)'\137',
- (byte)'\140', (byte)'\101', (byte)'\102', (byte)'\103', (byte)'\104', (byte)'\105', (byte)'\106', (byte)'\107',
- (byte)'\110', (byte)'\111', (byte)'\112', (byte)'\113', (byte)'\114', (byte)'\115', (byte)'\116', (byte)'\117',
- (byte)'\120', (byte)'\121', (byte)'\122', (byte)'\123', (byte)'\124', (byte)'\125', (byte)'\126', (byte)'\127',
- (byte)'\130', (byte)'\131', (byte)'\132', (byte)'\173', (byte)'\174', (byte)'\175', (byte)'\176', (byte)'\177',
- (byte)'\200', (byte)'\201', (byte)'\202', (byte)'\203', (byte)'\204', (byte)'\205', (byte)'\206', (byte)'\207',
- (byte)'\210', (byte)'\211', (byte)'\212', (byte)'\213', (byte)'\214', (byte)'\215', (byte)'\216', (byte)'\217',
- (byte)'\220', (byte)'\221', (byte)'\222', (byte)'\223', (byte)'\224', (byte)'\225', (byte)'\226', (byte)'\227',
- (byte)'\230', (byte)'\231', (byte)'\232', (byte)'\233', (byte)'\234', (byte)'\235', (byte)'\236', (byte)'\237',
- (byte)'\240', (byte)'\241', (byte)'\242', (byte)'\243', (byte)'\244', (byte)'\245', (byte)'\246', (byte)'\247',
- (byte)'\250', (byte)'\251', (byte)'\252', (byte)'\253', (byte)'\254', (byte)'\255', (byte)'\256', (byte)'\257',
- (byte)'\260', (byte)'\261', (byte)'\262', (byte)'\263', (byte)'\264', (byte)'\265', (byte)'\266', (byte)'\267',
- (byte)'\270', (byte)'\271', (byte)'\272', (byte)'\273', (byte)'\274', (byte)'\275', (byte)'\276', (byte)'\277',
- (byte)'\300', (byte)'\301', (byte)'\302', (byte)'\303', (byte)'\304', (byte)'\305', (byte)'\306', (byte)'\307',
- (byte)'\310', (byte)'\311', (byte)'\312', (byte)'\313', (byte)'\314', (byte)'\315', (byte)'\316', (byte)'\317',
- (byte)'\320', (byte)'\321', (byte)'\322', (byte)'\323', (byte)'\324', (byte)'\325', (byte)'\326', (byte)'\327',
- (byte)'\330', (byte)'\331', (byte)'\332', (byte)'\333', (byte)'\334', (byte)'\335', (byte)'\336', (byte)'\337',
- (byte)'\340', (byte)'\341', (byte)'\342', (byte)'\343', (byte)'\344', (byte)'\345', (byte)'\346', (byte)'\347',
- (byte)'\350', (byte)'\351', (byte)'\352', (byte)'\353', (byte)'\354', (byte)'\355', (byte)'\356', (byte)'\357',
- (byte)'\360', (byte)'\361', (byte)'\362', (byte)'\363', (byte)'\364', (byte)'\365', (byte)'\366', (byte)'\367',
- (byte)'\370', (byte)'\371', (byte)'\372', (byte)'\373', (byte)'\374', (byte)'\375', (byte)'\376', (byte)'\377',
- };
-
- public static final int LowerMap[][] = {
- {0x41, 0x61},
- {0x42, 0x62},
- {0x43, 0x63},
- {0x44, 0x64},
- {0x45, 0x65},
-