Mercurial > people > rkennke > jdk9-shenandoah-final > nashorn
changeset 279:e955e64fd15d
Merge
author | lana |
---|---|
date | Wed, 22 May 2013 09:59:15 -0700 |
parents | 1fd18f40ab52 (diff) 6b9f41203800 (current diff) |
children | 8af550dee961 |
files | |
diffstat | 110 files changed, 3178 insertions(+), 4495 deletions(-) [+] |
line wrap: on
line diff
--- a/docs/JavaScriptingProgrammersGuide.html Fri May 17 10:14:03 2013 -0700 +++ b/docs/JavaScriptingProgrammersGuide.html Wed May 22 09:59:15 2013 -0700 @@ -71,9 +71,20 @@ 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 @@ </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 @@ <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 @@ <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 @@ </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 @@ </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 @@ 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 @@ 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 – passing an implementation JavaScript object +or function to a constructor, or using <code>Java.extend</code> with <code>new</code> – 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> – aside from being able to take any number of type parameters +denoting a class to extend and interfaces to implement – 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 – 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 – 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 – 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 – 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. – 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>
--- a/docs/source/javaarray.js Fri May 17 10:14:03 2013 -0700 +++ b/docs/source/javaarray.js Wed May 22 09:59:15 2013 -0700 @@ -40,7 +40,7 @@ // 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 @@ // 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);
--- a/make/build.xml Fri May 17 10:14:03 2013 -0700 +++ b/make/build.xml Wed May 22 09:59:15 2013 -0700 @@ -212,7 +212,9 @@ target="${javac.target}" debug="${javac.debug}" encoding="${javac.encoding}" - includeantruntime="false"/> + includeantruntime="false"> + <compilerarg line="-extdirs """/> + </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>
--- a/make/code_coverage.xml Fri May 17 10:14:03 2013 -0700 +++ b/make/code_coverage.xml Wed May 22 09:59:15 2013 -0700 @@ -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}"/>
--- a/make/project.properties Fri May 17 10:14:03 2013 -0700 +++ b/make/project.properties Wed May 22 09:59:15 2013 -0700 @@ -216,7 +216,7 @@ # -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 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/api/scripting/JSObject.java Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,87 @@ +/* + * 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.api.scripting; + +/** + * netscape.javascript.JSObject-like interface for nashorn script objects. + */ +public abstract class JSObject { + /** + * Call a JavaScript method + * + * @param methodName name of method + * @param args arguments to method + * @return result of call + */ + public abstract Object call(String methodName, Object args[]); + + /** + * Evaluate a JavaScript expression + * + * @param s JavaScript expression to evaluate + * @return evaluation result + */ + public abstract Object eval(String s); + + /** + * Retrieves a named member of a JavaScript object. + * + * @param name of member + * @return member + */ + public abstract Object getMember(String name); + + /** + * Retrieves an indexed member of a JavaScript object. + * + * @param index index of member slot + * @return member + */ + public abstract Object getSlot(int index); + + /** + * Remove a named member from a JavaScript object + * + * @param name name of member + */ + public abstract void removeMember(String name); + + /** + * Set a named member in a JavaScript object + * + * @param name name of member + * @param value value of member + */ + public abstract void setMember(String name, Object value); + + /** + * Set an indexed member in a JavaScript object + * + * @param index index of member slot + * @param value value of member + */ + public abstract void setSlot(int index, Object value); +}
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed May 22 09:59:15 2013 -0700 @@ -42,7 +42,6 @@ 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
--- a/src/jdk/nashorn/api/scripting/resources/engine.js Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/api/scripting/resources/engine.js Wed May 22 09:59:15 2013 -0700 @@ -88,7 +88,7 @@ } } - array = Java.toJavaArray(array); + array = Java.to(array); return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array); } });
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed May 22 09:59:15 2013 -0700 @@ -2028,6 +2028,13 @@ 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(); @@ -2096,13 +2103,16 @@ } @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);
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Wed May 22 09:59:15 2013 -0700 @@ -11,13 +11,21 @@ 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.ReturnNode; +import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.Node; @@ -174,7 +182,7 @@ 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; @@ -208,6 +216,89 @@ }, /* + * 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() { + 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(getLexicalContext(), 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("[", getLexicalContext().getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange()); + return node.setSymbol(getLexicalContext(), 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 +309,6 @@ 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;
--- a/src/jdk/nashorn/internal/codegen/Compiler.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Wed May 22 09:59:15 2013 -0700 @@ -99,7 +99,7 @@ private boolean strict; - private CodeInstaller<ScriptEnvironment> installer; + private final CodeInstaller<ScriptEnvironment> installer; private final TemporarySymbols temporarySymbols = new TemporarySymbols(); @@ -219,6 +219,7 @@ 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 @@ 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 @@ } if (sb != null) { - LOG.info(sb); + LOG.fine(sb); } return rootClass;
--- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java Wed May 22 09:59:15 2013 -0700 @@ -262,7 +262,7 @@ * @return the internal descriptor for this type */ public static String typeDescriptor(final Class<?> clazz) { - return Type.getDescriptor(clazz); + return Type.typeFor(clazz).getDescriptor(); } /**
--- a/src/jdk/nashorn/internal/codegen/Lower.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Wed May 22 09:59:15 2013 -0700 @@ -261,19 +261,25 @@ return throwNode; } - private static Node ensureUniqueLabelsIn(final Node node) { + private static Node ensureUniqueNamesIn(final LexicalContext lc, final Node node) { return node.accept(new NodeVisitor() { - @Override - public Node leaveDefault(final Node labelledNode) { - return labelledNode.ensureUniqueLabels(getLexicalContext()); - } + @Override + public Node leaveFunctionNode(final FunctionNode functionNode) { + final String name = functionNode.getName(); + return functionNode.setName(getLexicalContext(), lc.getCurrentFunction().uniqueName(name)); + } + + @Override + public Node leaveDefault(final Node labelledNode) { + return labelledNode.ensureUniqueLabels(getLexicalContext()); + } }); } - 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; } @@ -288,10 +294,10 @@ final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all")); - final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))). + final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)). setIsTerminal(getLexicalContext(), 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 @@ -316,9 +322,9 @@ * @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 LexicalContext lc = getLexicalContext(); final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor() { final List<Node> insideTry = new ArrayList<>(); @@ -338,7 +344,7 @@ @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); } @@ -372,7 +378,7 @@ resultNode = null; } - newStatements.addAll(copyFinally(finallyBody)); + newStatements.addAll(copyFinally(lc, finallyBody)); if (!isTerminal(newStatements)) { newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); } @@ -382,7 +388,7 @@ 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); } @@ -548,7 +554,7 @@ final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); return callNode.setEvalArgs( new CallNode.EvalArgs( - ensureUniqueLabelsIn(args.get(0)).accept(this), + ensureUniqueNamesIn(getLexicalContext(), args.get(0)).accept(this), compilerConstant(THIS), evalLocation(callee), currentFunction.isStrict()));
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed May 22 09:59:15 2013 -0700 @@ -2081,7 +2081,9 @@ * @param args debug information to print */ private void debug(final Object... args) { - debug(30, args); + if (DEBUG) { + debug(30, args); + } } /** @@ -2091,7 +2093,9 @@ * @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 @@ new Throwable().printStackTrace(LOG.getOutputStream()); } } - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,474 @@ +/* + * 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.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 { + 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() { + } + + @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 (getLexicalContext().inLoop() && !isLoopCounter(getLexicalContext().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() { + 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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/codegen/types/Range.java Wed May 22 09:59:15 2013 -0700 @@ -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); + } +}
--- a/src/jdk/nashorn/internal/codegen/types/Type.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Wed May 22 09:59:15 2013 -0700 @@ -106,23 +106,13 @@ 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 */
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Wed May 22 09:59:15 2013 -0700 @@ -59,6 +59,23 @@ 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
--- a/src/jdk/nashorn/internal/ir/CatchNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java Wed May 22 09:59:15 2013 -0700 @@ -42,6 +42,11 @@ /** 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 @@ * @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; } /** @@ -124,7 +132,7 @@ 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 @@ 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; + } + }
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Wed May 22 09:59:15 2013 -0700 @@ -250,6 +250,7 @@ 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 @@ super(functionNode); this.flags = flags; + this.name = name; this.returnType = returnType; this.compileUnit = compileUnit; this.lastToken = lastToken; @@ -271,7 +273,6 @@ // 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; @@ -315,7 +316,7 @@ 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 @@ 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 @@ * @return true if specialization is possible */ public boolean canSpecialize() { - return getFlag(CAN_SPECIALIZE); + return snapshot != null && getFlag(CAN_SPECIALIZE); } /** @@ -389,7 +390,7 @@ } 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 @@ 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 @@ 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 @@ } /** - * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ this, lastToken, flags, + name, Type.widest(this.returnType, returnType.isObject() ? Type.OBJECT : returnType), @@ -801,7 +817,7 @@ 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)); } /**
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java Wed May 22 09:59:15 2013 -0700 @@ -440,6 +440,23 @@ } /** + * 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 @@ } private LoopNode getContinueTo() { - final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction()); - return iter.hasNext() ? iter.next() : null; + return getCurrentLoop(); } /**
--- a/src/jdk/nashorn/internal/ir/Node.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Node.java Wed May 22 09:59:15 2013 -0700 @@ -153,6 +153,14 @@ } /** + * 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
--- a/src/jdk/nashorn/internal/ir/Symbol.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Wed May 22 09:59:15 2013 -0700 @@ -29,6 +29,8 @@ 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 @@ /** 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 @@ this.type = type; this.slot = slot; this.fieldIndex = -1; + this.range = Range.createUnknownRange(); trace("CREATE SYMBOL"); } @@ -157,12 +163,13 @@ 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 @@ @Override public String toString() { - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append(name). append(' '). @@ -410,6 +417,22 @@ } /** + * 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
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/ir/ThrowNode.java Wed May 22 09:59:15 2013 -0700 @@ -36,6 +36,11 @@ /** 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 @@ * @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 @@ -98,7 +106,17 @@ 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; } }
--- a/src/jdk/nashorn/internal/objects/NativeJava.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeJava.java Wed May 22 09:59:15 2013 -0700 @@ -240,39 +240,52 @@ } /** - * 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 only + * performs shallow creation of Java arrays, but might be extended for other types in the future. 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 objArray 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. + * type. Returns null if scriptObject 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); - + public static Object to(final Object self, final Object objArray, final Object objType) throws ClassNotFoundException { if (objArray == null) { return null; } + final Class<?> componentType; + if(objType == UNDEFINED) { + componentType = Object.class; + } else { + final StaticClass arrayType; + if(objType instanceof StaticClass) { + arrayType = (StaticClass)objType; + } else { + arrayType = type(objType); + } + final Class<?> arrayClass = arrayType.getRepresentedClass(); + if(!arrayClass.isArray()) { + throw typeError("to.expects.array.type", arrayClass.getName()); + } + componentType = arrayClass.getComponentType(); + } + Global.checkObject(objArray); - return ((ScriptObject)objArray).getArray().asArrayOfType(componentType.getRepresentedClass()); + return ((ScriptObject)objArray).getArray().asArrayOfType(componentType); } /** @@ -283,7 +296,7 @@ * <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 +307,7 @@ * 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) {
--- a/src/jdk/nashorn/internal/parser/Parser.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/parser/Parser.java Wed May 22 09:59:15 2013 -0700 @@ -1537,7 +1537,7 @@ endOfLine(); - appendStatement(new ThrowNode(throwLine, throwToken, finish, expression)); + appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, 0)); } /** @@ -1597,7 +1597,7 @@ 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);
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java Wed May 22 09:59:15 2013 -0700 @@ -35,21 +35,27 @@ */ 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 @@ } MethodType type() { - return invoker.type(); + return type; } @Override @@ -103,8 +109,8 @@ 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 @@ * 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; }
--- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Wed May 22 09:59:15 2013 -0700 @@ -78,9 +78,9 @@ //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)); } }
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed May 22 09:59:15 2013 -0700 @@ -30,6 +30,8 @@ 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 @@ */ 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 @@ 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 @@ 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 @@ 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, final MethodHandle guard, final MethodHandle fallback) { - final MethodHandle target = + private MethodHandle addCode(final FunctionNode fn) { + return addCode(fn, null, null, null); + } + + 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()); - 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(); + 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); } } - final CompiledFunction cf = new CompiledFunction(mh); + MethodHandle mh = target; + if (guard != null) { + mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback); + } + + final CompiledFunction cf = new CompiledFunction(runtimeType == null ? targetType : runtimeType, mh); code.add(cf); return cf.getInvoker(); @@ -212,69 +247,162 @@ 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) {
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed May 22 09:59:15 2013 -0700 @@ -54,7 +54,7 @@ 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 @@ /** 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; @@ -219,6 +222,7 @@ _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");
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed May 22 09:59:15 2013 -0700 @@ -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 @@ 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 @@ 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 @@ // "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) {
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed May 22 09:59:15 2013 -0700 @@ -38,7 +38,7 @@ 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
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Wed May 22 09:59:15 2013 -0700 @@ -310,7 +310,34 @@ 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 @@ 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);
--- a/src/jdk/nashorn/internal/runtime/options/Option.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/options/Option.java Wed May 22 09:59:15 2013 -0700 @@ -42,10 +42,6 @@ this.value = value; } - void setValue(final T value) { - this.value = value; - } - /** * Return the value of an option * @return the option value
--- a/src/jdk/nashorn/internal/runtime/options/Options.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/options/Options.java Wed May 22 09:59:15 2013 -0700 @@ -501,8 +501,6 @@ return new Option<>(TimeZone.getTimeZone(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());
--- a/src/jdk/nashorn/internal/runtime/options/ValueOption.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * 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.runtime.options; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; - -/** - * This option represents a collection of comma separated values - */ -public class ValueOption extends Option<String> { - - private Collection<String> values; - - ValueOption(final String value) { - super(value); - if (value != null) { - values = new LinkedHashSet<>(); - final StringTokenizer st = new StringTokenizer(getValue(), ","); - while (st.hasMoreElements()) { - values.add(st.nextToken()); - } - } - } - - /** - * Get the values in the option - * @return collection of strings - */ - public Collection<String> getValues() { - return Collections.unmodifiableCollection(values); - } - -}
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * 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.runtime.regexp; - -import jdk.nashorn.internal.runtime.ParserException; - -import static java.util.regex.Pattern.CASE_INSENSITIVE; -import static java.util.regex.Pattern.MULTILINE; -import static java.util.regex.Pattern.UNICODE_CASE; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * Default regular expression implementation based on java.util.regex package. - * - * 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 { - - /** Java regexp pattern to use for match. We compile to one of these */ - private Pattern pattern; - - /** The matcher */ - private RegExpMatcher matcher; - - /** - * Construct a Regular expression from the given {@code source} and {@code flags} strings. - * - * @param source RegExp source string - * @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 { - super(source, flags); - - int intFlags = 0; - - if (isIgnoreCase()) { - intFlags |= CASE_INSENSITIVE | UNICODE_CASE; - } - if (isMultiline()) { - intFlags |= MULTILINE; - } - - try { - RegExpScanner parsed; - - try { - parsed = RegExpScanner.scan(source); - } catch (final PatternSyntaxException e) { - // refine the exception with a better syntax error, if this - // passes, just rethrow what we have - Pattern.compile(source, intFlags); - throw e; - } - - if (parsed != null) { - this.pattern = Pattern.compile(parsed.getJavaPattern(), intFlags); - this.groupsInNegativeLookahead = parsed.getGroupsInNegativeLookahead(); - } - } catch (final PatternSyntaxException e2) { - throwParserException("syntax", e2.getMessage()); - } - } - - @Override - public RegExpMatcher match(final String str) { - if (pattern == null) { - return null; // never matches or similar, e.g. a[] - } - - RegExpMatcher currentMatcher = this.matcher; - - if (currentMatcher == null || matcher.getInput() != str) { - currentMatcher = new DefaultMatcher(str); - this.matcher = currentMatcher; - } - - return currentMatcher; - } - - class DefaultMatcher implements RegExpMatcher { - final String input; - final Matcher defaultMatcher; - - DefaultMatcher(final String input) { - this.input = input; - this.defaultMatcher = pattern.matcher(input); - } - - @Override - public boolean search(final int start) { - return defaultMatcher.find(start); - } - - @Override - public String getInput() { - return input; - } - - @Override - public int start() { - return defaultMatcher.start(); - } - - @Override - public int start(final int group) { - return defaultMatcher.start(group); - } - - @Override - public int end() { - return defaultMatcher.end(); - } - - @Override - public int end(final int group) { - return defaultMatcher.end(group); - } - - @Override - public String group() { - return defaultMatcher.group(); - } - - @Override - public String group(final int group) { - return defaultMatcher.group(group); - } - - @Override - public int groupCount() { - return defaultMatcher.groupCount(); - } - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,163 @@ +/* + * 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.runtime.regexp; + +import jdk.nashorn.internal.runtime.ParserException; + +import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static java.util.regex.Pattern.MULTILINE; +import static java.util.regex.Pattern.UNICODE_CASE; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Default regular expression implementation based on java.util.regex package. + * + * 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 JdkRegExp extends RegExp { + + /** Java regexp pattern to use for match. We compile to one of these */ + private Pattern pattern; + + /** The matcher */ + private RegExpMatcher matcher; + + /** + * Construct a Regular expression from the given {@code source} and {@code flags} strings. + * + * @param source RegExp source string + * @param flags RegExp flag string + * @throws ParserException if flags is invalid or source string has syntax error. + */ + public JdkRegExp(final String source, final String flags) throws ParserException { + super(source, flags); + + int intFlags = 0; + + if (isIgnoreCase()) { + intFlags |= CASE_INSENSITIVE | UNICODE_CASE; + } + if (isMultiline()) { + intFlags |= MULTILINE; + } + + try { + RegExpScanner parsed; + + try { + parsed = RegExpScanner.scan(source); + } catch (final PatternSyntaxException e) { + // refine the exception with a better syntax error, if this + // passes, just rethrow what we have + Pattern.compile(source, intFlags); + throw e; + } + + if (parsed != null) { + this.pattern = Pattern.compile(parsed.getJavaPattern(), intFlags); + this.groupsInNegativeLookahead = parsed.getGroupsInNegativeLookahead(); + } + } catch (final PatternSyntaxException e2) { + throwParserException("syntax", e2.getMessage()); + } + } + + @Override + public RegExpMatcher match(final String str) { + if (pattern == null) { + return null; // never matches or similar, e.g. a[] + } + + RegExpMatcher currentMatcher = this.matcher; + + if (currentMatcher == null || matcher.getInput() != str) { + currentMatcher = new DefaultMatcher(str); + this.matcher = currentMatcher; + } + + return currentMatcher; + } + + class DefaultMatcher implements RegExpMatcher { + final String input; + final Matcher defaultMatcher; + + DefaultMatcher(final String input) { + this.input = input; + this.defaultMatcher = pattern.matcher(input); + } + + @Override + public boolean search(final int start) { + return defaultMatcher.find(start); + } + + @Override + public String getInput() { + return input; + } + + @Override + public int start() { + return defaultMatcher.start(); + } + + @Override + public int start(final int group) { + return defaultMatcher.start(group); + } + + @Override + public int end() { + return defaultMatcher.end(); + } + + @Override + public int end(final int group) { + return defaultMatcher.end(group); + } + + @Override + public String group() { + return defaultMatcher.group(); + } + + @Override + public String group(final int group) { + return defaultMatcher.group(group); + } + + @Override + public int groupCount() { + return defaultMatcher.groupCount(); + } + } + +}
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Wed May 22 09:59:15 2013 -0700 @@ -113,7 +113,7 @@ 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); }
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Wed May 22 09:59:15 2013 -0700 @@ -29,7 +29,7 @@ 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 @@ * @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); } /**
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java Wed May 22 09:59:15 2013 -0700 @@ -21,10 +21,7 @@ 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 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.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 @@ //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 @@ 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 @@ } 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 @@ 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 @@ } 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 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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;
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java Wed May 22 09:59:15 2013 -0700 @@ -28,8 +28,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } - 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 @@ 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 @@ addInt(p); addTemplate(chars); } else { - addChars(chars, p, mbLength * strLength); + addChars(chars, p, strLength); } } @@ -242,14 +214,14 @@ 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 @@ } @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 @@ } @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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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:
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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) { - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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)); - } - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java Wed May 22 09:59:15 2013 -0700 @@ -51,10 +51,6 @@ 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 @@ 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]; }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java Wed May 22 09:59:15 2013 -0700 @@ -25,12 +25,15 @@ 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 @@ } 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) {
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java Wed May 22 09:59:15 2013 -0700 @@ -53,56 +53,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } - if (Config.USE_CAPTURE_HISTORY) { - if (regex.captureHistory != 0) checkCaptureHistory(region); - } } else { msaBegin = sstart - str; msaEnd = s - str; @@ -437,125 +366,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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() {
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java Wed May 22 09:59:15 2013 -0700 @@ -34,6 +34,239 @@ 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 @@ 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++;
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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; - } - - -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java Wed May 22 09:59:15 2013 -0700 @@ -22,8 +22,6 @@ 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 @@ 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 @@ 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 @@ compileCClassNode((CClassNode)node); break; - case NodeType.CTYPE: - compileCTypeNode((CTypeNode)node); - break; - case NodeType.CANY: compileAnyCharNode(); break; @@ -130,19 +121,8 @@ 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:
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java Wed May 22 09:59:15 2013 -0700 @@ -31,10 +31,6 @@ 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 @@ 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 @@ 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 @@ 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; }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Wed May 22 09:59:15 2013 -0700 @@ -95,20 +95,6 @@ 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++) {
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java Wed May 22 09:59:15 2013 -0700 @@ -27,10 +27,7 @@ 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 @@ \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 @@ } 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 @@ 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 @@ } } - 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 @@ 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 @@ 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 @@ token.setBackrefNum(1); token.setBackrefRef1(num); token.setBackrefByName(false); - if (Config.USE_BACKREF_WITH_LEVEL) token.setBackrefExistLevel(false); return; } @@ -845,76 +591,6 @@ } } - 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 @@ } } - 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 @@ 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 @@ } } - 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))); }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java Wed May 22 09:59:15 2013 -0700 @@ -58,17 +58,10 @@ // 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 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 @@ 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 @@ } 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 */
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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(); - } - -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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); - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java Wed May 22 09:59:15 2013 -0700 @@ -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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ } // inner switch break; - case CHAR_PROPERTY: - node = parseCharProperty(); - break; - case CC_CC_OPEN: CClassNode cc = parseCharClass(); node = cc; @@ -735,20 +560,6 @@ 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:
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java Wed May 22 09:59:15 2013 -0700 @@ -23,9 +23,11 @@ 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 @@ 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 @@ WarnCallback warnings; MatcherFactory factory; - private Analyser analyser; + protected Analyser analyser; int options; int userOptions; @@ -65,8 +66,6 @@ //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 @@ 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 @@ 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 @@ 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; - } }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java Wed May 22 09:59:15 2013 -0700 @@ -25,7 +25,6 @@ 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 @@ 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 @@ return sb.toString(); } - CaptureTreeNode getCaptureTree() { - return historyRoot; - } - void clear() { for (int i=0; i<beg.length; i++) { beg[i] = end[i] = REGION_NOTPOS;
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ScanEnvironment.java Wed May 22 09:59:15 2013 -0700 @@ -40,16 +40,10 @@ 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 @@ numCall = 0; numMem = 0; - numNamed = 0; - memNodes = null; - numCombExpCheck = 0; - combExpMaxRegNum = 0; currMaxRegNum = 0; hasRecursion = false; }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ScannerSupport.java Wed May 22 09:59:15 2013 -0700 @@ -37,6 +37,8 @@ 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 @@ return end; } - private final int INT_SIGN_BIT = 1 << 31; - protected final int scanUnsignedNumber() { int last = c; int num = 0; // long ???
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java Wed May 22 09:59:15 2013 -0700 @@ -22,7 +22,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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(); } } }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java Wed May 22 09:59:15 2013 -0700 @@ -609,7 +609,7 @@ 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 ),
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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(); - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java Wed May 22 09:59:15 2013 -0700 @@ -22,7 +22,6 @@ 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 @@ 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 @@ 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;
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CTypeNode.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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(); - } - -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CallNode.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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(); - } - -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java Wed May 22 09:59:15 2013 -0700 @@ -25,7 +25,7 @@ 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 @@ } // 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 @@ 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; }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java Wed May 22 09:59:15 2013 -0700 @@ -21,9 +21,10 @@ 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 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 @@ 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 @@ headExact = other.headExact; nextHeadExact = other.nextHeadExact; isRefered = other.isRefered; - combExpCheckNum = other.combExpCheckNum; } public void reduceNestedQuantifier(QuantifierNode other) { @@ -143,7 +167,7 @@ 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 @@ 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 @@ 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
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java Wed May 22 09:59:15 2013 -0700 @@ -40,7 +40,6 @@ 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 @@ state |= NST_MIN_FIXED; } - public void clearMinFixed() { - state &= ~NST_MIN_FIXED; - } - public boolean isMaxFixed() { return (state & NST_MAX_FIXED) != 0; } @@ -69,10 +64,6 @@ state |= NST_MAX_FIXED; } - public void clearMaxFixed() { - state &= ~NST_MAX_FIXED; - } - public boolean isCLenFixed() { return (state & NST_CLEN_FIXED) != 0; } @@ -81,10 +72,6 @@ state |= NST_CLEN_FIXED; } - public void clearCLenFixed() { - state &= ~NST_CLEN_FIXED; - } - public boolean isMark1() { return (state & NST_MARK1) != 0; } @@ -93,10 +80,6 @@ state |= NST_MARK1; } - public void clearMark1() { - state &= ~NST_MARK1; - } - public boolean isMark2() { return (state & NST_MARK2) != 0; } @@ -117,10 +100,6 @@ 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 @@ 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 @@ state |= NST_RECURSION; } - public void clearRecursion() { - state &= ~NST_RECURSION; - } - public boolean isCalled() { return (state & NST_CALLED) != 0; } @@ -153,10 +124,6 @@ state |= NST_CALLED; } - public void clearCAlled() { - state &= ~NST_CALLED; - } - public boolean isAddrFixed() { return (state & NST_ADDR_FIXED) != 0; } @@ -165,22 +132,6 @@ 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 @@ state |= NST_NAME_REF; } - public void clearNameRef() { - state &= ~NST_NAME_REF; - } - public boolean isInRepeat() { return (state & NST_IN_REPEAT) != 0; } @@ -201,10 +148,6 @@ state |= NST_IN_REPEAT; } - public void clearInRepeat() { - state &= ~NST_IN_REPEAT; - } - public boolean isNestLevel() { return (state & NST_NEST_LEVEL) != 0; } @@ -213,10 +156,6 @@ state |= NST_NEST_LEVEL; } - public void clearNestLevel() { - state &= ~NST_NEST_LEVEL; - } - public boolean isByNumber() { return (state & NST_BY_NUMBER) != 0; } @@ -225,8 +164,4 @@ state |= NST_BY_NUMBER; } - public void clearByNumber() { - state &= ~NST_BY_NUMBER; - } - }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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"); - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchGreedyBacktrack.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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); - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchRailsRegs.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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); - } - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/bench/BenchSeveralRegexps.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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); - } -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/constants/OPCode.java Wed May 22 09:59:15 2013 -0700 @@ -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 @@ 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; }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/constants/Reduce.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 ?" - }; - -} -
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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}, - {0x46, 0x66}, - {0x47, 0x67}, - {0x48, 0x68}, - {0x49, 0x69}, - {0x4a, 0x6a}, - {0x4b, 0x6b}, - {0x4c, 0x6c}, - {0x4d, 0x6d}, - {0x4e, 0x6e}, - {0x4f, 0x6f}, - {0x50, 0x70}, - {0x51, 0x71}, - {0x52, 0x72}, - {0x53, 0x73}, - {0x54, 0x74}, - {0x55, 0x75}, - {0x56, 0x76}, - {0x57, 0x77}, - {0x58, 0x78}, - {0x59, 0x79}, - {0x5a, 0x7a} - }; -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/ObjPtr.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/ObjPtr.java Wed May 22 09:59:15 2013 -0700 @@ -30,6 +30,5 @@ public T p; - static final ObjPtr<Void> NULL = new ObjPtr<Void>(); }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/PosixBracket.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +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".toCharArray(), 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; - -import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; -import jdk.nashorn.internal.runtime.regexp.joni.exception.JOniException; - -import java.util.HashMap; - -public class PosixBracket { - - public static final char[][] PBSNamesLower = { - "alnum".toCharArray(), - "alpha".toCharArray(), - "blank".toCharArray(), - "cntrl".toCharArray(), - "digit".toCharArray(), - "graph".toCharArray(), - "lower".toCharArray(), - "print".toCharArray(), - "punct".toCharArray(), - "space".toCharArray(), - "upper".toCharArray(), - "xdigit".toCharArray(), - "ascii".toCharArray(), - "word".toCharArray() - }; - - public static final int PBSValues[] = { - CharacterType.ALNUM, - CharacterType.ALPHA, - CharacterType.BLANK, - CharacterType.CNTRL, - CharacterType.DIGIT, - CharacterType.GRAPH, - CharacterType.LOWER, - CharacterType.PRINT, - CharacterType.PUNCT, - CharacterType.SPACE, - CharacterType.UPPER, - CharacterType.XDIGIT, - CharacterType.ASCII, - CharacterType.WORD, - }; - - public static int propertyNameToCType(String name) { - name = name.toLowerCase(); - if (!PBSTableUpper.containsKey(name)) { - throw new JOniException(ErrorMessages.ERR_INVALID_CHAR_PROPERTY_NAME.replaceAll("%n", name)); - } - return PBSTableUpper.get(name); - } - - private static final HashMap<String,Integer> PBSTableUpper = new HashMap<String,Integer>(); - - static { - for (int i=0; i<PBSValues.length; i++) PBSTableUpper.put(new String(PBSNamesLower[i]), PBSValues[i]); - } - -}
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/Ptr.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +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 final class Ptr { - public Ptr() { - this(0); - } - - public Ptr(int p) { - this.p = p; - } - - public int p; - - public static final Ptr NULL = new Ptr(0); -} -
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java Wed May 22 09:59:15 2013 -0700 @@ -22,28 +22,16 @@ import jdk.nashorn.internal.runtime.regexp.joni.Config; public interface ErrorMessages { - final String MISMATCH = "mismatch"; - final String NO_SUPPORT_CONFIG = "no support in this configuration"; /* from jcodings */ - final String ERR_INVALID_CHAR_PROPERTY_NAME = "invalid character property name <%n>"; final String ERR_INVALID_CODE_POINT_VALUE = "invalid code point value"; final String ERR_TOO_BIG_WIDE_CHAR_VALUE = "too big wide-char value"; final String ERR_TOO_LONG_WIDE_CHAR_VALUE = "too long wide-char value"; /* internal error */ - final String ERR_MEMORY = "fail to memory allocation"; - final String ERR_MATCH_STACK_LIMIT_OVER = "match-stack limit over"; - final String ERR_TYPE_BUG = "undefined type (bug)"; final String ERR_PARSER_BUG = "internal parser error (bug)"; - final String ERR_STACK_BUG = "stack error (bug)"; final String ERR_UNDEFINED_BYTECODE = "undefined bytecode (bug)"; final String ERR_UNEXPECTED_BYTECODE = "unexpected bytecode (bug)"; - final String ERR_DEFAULT_ENCODING_IS_NOT_SETTED = "default multibyte-encoding is not setted"; - final String ERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR = "can't convert to wide-char on specified multibyte-encoding"; - - /* general error */ - final String ERR_INVALID_ARGUMENT = "invalid argument"; /* syntax error */ final String ERR_END_PATTERN_AT_LEFT_BRACE = "end pattern at left brace"; @@ -56,11 +44,9 @@ final String ERR_META_CODE_SYNTAX = "invalid meta-code syntax"; final String ERR_CONTROL_CODE_SYNTAX = "invalid control-code syntax"; final String ERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE = "char-class value at end of range"; - final String ERR_CHAR_CLASS_VALUE_AT_START_OF_RANGE = "char-class value at start of range"; final String ERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS = "unmatched range specifier in char-class"; final String ERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED = "target of repeat operator is not specified"; final String ERR_TARGET_OF_REPEAT_OPERATOR_INVALID = "target of repeat operator is invalid"; - final String ERR_NESTED_REPEAT_OPERATOR = "nested repeat operator"; final String ERR_UNMATCHED_CLOSE_PARENTHESIS = "unmatched close parenthesis"; final String ERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS = "end pattern with unmatched parenthesis"; final String ERR_END_PATTERN_IN_GROUP = "end pattern in group"; @@ -74,25 +60,14 @@ final String ERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE = "too big number for repeat range"; final String ERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE = "upper is smaller than lower in repeat range"; final String ERR_EMPTY_RANGE_IN_CHAR_CLASS = "empty range in char class"; - final String ERR_MISMATCH_CODE_LENGTH_IN_CLASS_RANGE = "mismatch multibyte code length in char-class range"; final String ERR_TOO_MANY_MULTI_BYTE_RANGES = "too many multibyte code ranges are specified"; final String ERR_TOO_SHORT_MULTI_BYTE_STRING = "too short multibyte code string"; - final String ERR_TOO_BIG_BACKREF_NUMBER = "too big backref number"; - final String ERR_INVALID_BACKREF = Config.USE_NAMED_GROUP ? "invalid backref number/name" : "invalid backref number"; + final String ERR_INVALID_BACKREF = "invalid backref number"; final String ERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED = "numbered backref/call is not allowed. (use name)"; - final String ERR_INVALID_WIDE_CHAR_VALUE = "invalid wide-char value"; final String ERR_EMPTY_GROUP_NAME = "group name is empty"; final String ERR_INVALID_GROUP_NAME = "invalid group name <%n>"; - final String ERR_INVALID_CHAR_IN_GROUP_NAME = Config.USE_NAMED_GROUP ? "invalid char in group name <%n>" : "invalid char in group number <%n>"; - final String ERR_UNDEFINED_NAME_REFERENCE = "undefined name <%n> reference"; - final String ERR_UNDEFINED_GROUP_REFERENCE = "undefined group <%n> reference"; - final String ERR_MULTIPLEX_DEFINED_NAME = "multiplex defined name <%n>"; - final String ERR_MULTIPLEX_DEFINITION_NAME_CALL = "multiplex definition name <%n> call"; - final String ERR_NEVER_ENDING_RECURSION = "never ending recursion"; + final String ERR_INVALID_CHAR_IN_GROUP_NAME = "invalid char in group number <%n>"; final String ERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY = "group number is too big for capture history"; - final String ERR_NOT_SUPPORTED_ENCODING_COMBINATION = "not supported encoding combination"; final String ERR_INVALID_COMBINATION_OF_OPTIONS = "invalid combination of options"; - final String ERR_OVER_THREAD_PASS_LIMIT_COUNT = "over thread pass limit count"; - final String ERR_TOO_BIG_SB_CHAR_VALUE = "too big singlebyte char value"; }
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java Wed May 22 09:59:15 2013 -0700 @@ -30,8 +30,4 @@ super(message.replaceAll("%n", str)); } - public ValueException(String message, byte[]bytes, int p, int end) { - this(message, new String(bytes, p, end - p)); - } - }
--- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed May 22 09:59:15 2013 -0700 @@ -125,6 +125,7 @@ type.error.no.method.matches.args=Can not invoke method {0} with the passed arguments; they do not match any of its method signatures. type.error.method.not.constructor=Java method {0} can't be used as a constructor. type.error.env.not.object=$ENV must be an Object. +type.error.to.expects.array.type=Java.to() expects an array target type. {0} is not an array type. range.error.inappropriate.array.length=inappropriate array length: {0} range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20] range.error.invalid.precision=precision argument toPrecision() must be in [1, 21]
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri May 17 10:14:03 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties Wed May 22 09:59:15 2013 -0700 @@ -277,6 +277,12 @@ desc="Print the symbol table." \ } +nashorn.option.range.analysis = { \ + name="--range-analysis", \ + is_undocumented=true, \ + desc="Do range analysis using known compile time types, and try to narrow number types" \ +} + nashorn.option.D = { \ name="-D", \ desc="-Dname=value. Set a system property. This option can be repeated.", \
--- a/src/netscape/javascript/JSObject.java Fri May 17 10:14:03 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * 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 netscape.javascript; - -import java.applet.Applet; - -/** - * Stub for JSObject to get compilation going. - */ -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 - * - * @param methodName name of method - * @param args arguments to method - * @return result of call - */ - public abstract Object call(String methodName, Object args[]); - - /** - * Evaluate a JavaScript expression - * - * @param s JavaScript expression to evaluate - * @return evaluation result - */ - public abstract Object eval(String s); - - /** - * Retrieves a named member of a JavaScript object. - * - * @param name of member - * @return member - */ - public abstract Object getMember(String name); - - /** - * Retrieves an indexed member of a JavaScript object. - * - * @param index index of member slot - * @return member - */ - public abstract Object getSlot(int index); - - /** - * Remove a named member from a JavaScript object - * - * @param name name of member - */ - public abstract void removeMember(String name); - - /** - * Set a named member in a JavaScript object - * - * @param name name of member - * @param value value of member - */ - public abstract void setMember(String name, Object value); - - /** - * Set an indexed member in a JavaScript object - * - * @param index index of member slot - * @param value value of member - */ - public abstract void setSlot(int index, Object value); -}
--- a/test/script/basic/JDK-8008554.js Fri May 17 10:14:03 2013 -0700 +++ b/test/script/basic/JDK-8008554.js Wed May 22 09:59:15 2013 -0700 @@ -32,5 +32,5 @@ var dir = __DIR__; var file = __FILE__.replace("JDK-8008554", "NASHORN-99"); load(file); -file = "file://" + __DIR__ + "NASHORN-99.js"; +file = "file:///" + __DIR__ + "NASHORN-99.js"; load(file);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8011718.js Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,46 @@ +/* + * 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. + * + * 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. + */ + +/** + * JDK-8011718: binding already bound function with extra arguments fails. + * + * @test + * @run + */ + +var obj = { + hello:"From obj", +}; +var obj2 = { + hello:"From obj2", +}; + +function doit(cb){ + cb(); + var cb2 = cb.bind(obj2, "This one is not acccepted"); + cb2(); +} + +doit(function(){ + print(this.hello); + }.bind(obj));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8011718.js.EXPECTED Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,2 @@ +From obj +From obj
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8012305.js Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,39 @@ +/* + * 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. + * + * 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. + */ + +/** + * JDK-8012305: Function.bind can't be called on prototype function inside constructor + * + * @test + * @run + */ + +function MyObject() { + // If the call to bind is removed, then the function is properly printed. + print("function " + this._process); + this._process = this._process.bind(this); +} + +MyObject.prototype._process = function() { print("Message "); } + +var s = new MyObject();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8012305.js.EXPECTED Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,1 @@ +function function() { print("Message "); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8013919.js Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,39 @@ +/* + * 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. + * + * 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. + */ + +/** + * JDK-8013913: finally cloning of function node declarations caused + * method collissions + * + * @test + * @run + */ + +try { + print("a"); +} finally { + var b = function() { + print("b"); + } + b(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8013919.js.EXPECTED Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,2 @@ +a +b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8014426.js Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,49 @@ +/* + * 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. + * + * 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. + */ + +/** + * Ensure catchall exceptions from finally inlining are rethrown as is + * + * @test + * @run + */ + +function runScriptEngine() { + var fac = new Packages.jdk.nashorn.api.scripting.NashornScriptEngineFactory(); + var engine = fac.getScriptEngine(); + engine.eval( +"try {\n\ + doIt();\n\ +} finally { \n\ + var x = 17;\n\ +}\n\ +function doIt() {\n\ + throw new TypeError('en stor graa noshoerning!');\n\ +}\n"); +} + +try { + runScriptEngine(); +} catch(e) { + print(e); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8014426.js.EXPECTED Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,1 @@ +javax.script.ScriptException: TypeError: en stor graa noshoerning! in <eval> at line number 7 at column number 2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8014647.js Wed May 22 09:59:15 2013 -0700 @@ -0,0 +1,40 @@ +/* + * 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. + * + * 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. + */ + +/** + * JDK-8014647: Allow class-based overrides to be initialized with a ScriptFunction + * + * @test + * @run + */ + +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() +var r3 = new RunnableImpl2(function() { print("I'm runnable 3!") }) +r1.run() +r2.run() +r3.run() +print("r1.class === r2.class: " + (r1.class === r2.class)) +print("r2.class === r3.class: " + (r2.class === r3.class))