# HG changeset patch # User lana # Date 1369871995 25200 # Node ID bf497a99ac5c975ca199d8f7244b0e14f9ae9cc5 # Parent 2fd6acba737b01e705e1f7c33588c922a3787f13# Parent 1d40bf1412e0090745e3556ca13572be508be0c5 Merge diff -r 2fd6acba737b -r bf497a99ac5c nashorn/.hgignore --- a/nashorn/.hgignore Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/.hgignore Wed May 29 16:59:55 2013 -0700 @@ -24,3 +24,4 @@ .idea/* test/lib/testng.jar test/script/external/* +.project diff -r 2fd6acba737b -r bf497a99ac5c nashorn/docs/JavaScriptingProgrammersGuide.html --- a/nashorn/docs/JavaScriptingProgrammersGuide.html Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/docs/JavaScriptingProgrammersGuide.html Wed May 29 16:59:55 2013 -0700 @@ -71,9 +71,20 @@ Arrays
  • Implementing Java Interfaces
  • -
  • Extending Java classes +
  • Extending Abstract Java Classes +
  • +
  • Extending Concrete Java Classes +
  • +
  • Implementing Multiple Java Interfaces +
  • +
  • Class-Bound Implementations
  • Overload Resolution
  • +
  • Mapping of Data Types Between Java +and JavaScript
  • + + +
  • Implementing Your Own Script @@ -466,10 +477,10 @@ -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.:
    
    - var anArrayList = new Java.type("java.util.ArrayList")
    + var anArrayList = new (Java.type("java.util.ArrayList"))
     
    or @@ -496,6 +507,37 @@

    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.

    +

    +In addition to creating new instances, the type objects returned from Java.type calls can also be used to access the +static fields and methods of the classes: +

    
    + var File = Java.type("java.io.File")
    + File.createTempFile("nashorn", ".tmp")
    +
    +

    +Methods with names of the form isXxx(), getXxx(), and setXxx() can also be used as properties, for both instances and statics. +

    +

    +A type object returned from Java.type is distinct from a java.lang.Class object. You can obtain one from the other using properties class and static on them. +

    
    + 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))
    +
    +

    +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 new and instanceof operators and as the namespace for the static fields +and methods, but they are different than the runtime Class objects returned by getClass() 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 static +property on a Class object since compile-time class expressions are never reified as objects). +


    Importing Java Packages, Classes

    @@ -558,10 +600,7 @@

    Creating, Converting and Using Java Arrays

    -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.

    +Array element access or length access is the same as in Java.

    
     // javaarray.js
     
    @@ -577,27 +616,31 @@
     

    It is also possible to convert between JavaScript and Java arrays. -Given a JavaScript array and a Java type, Java.toJavaArray returns a Java array with the same initial contents, and with the specified component type. +Given a JavaScript array and a Java type, Java.to returns a Java array with the same initial contents, and with the specified array type.

    
      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
     

    -Given a Java array or Collection, Java.toJavaScriptArray 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 Java.type() to specify the type of the array. +You can also omit the array type, in which case a Object[] will be created. +

    +

    +Given a Java array or Collection, Java.from 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.

    
     var File = Java.type("java.io.File");
     var listCurDir = new File(".").listFiles();
    -var jsList = Java.toJavaScriptArray(listCurDir);
    +var jsList = Java.from(listCurDir);
     print(jsList);
     

    -

    Implementing Java Interfaces

    +

    Implementing Java interfaces

    A Java interface can be implemented in JavaScript by using a Java anonymous class-like syntax:

    
    @@ -631,8 +674,8 @@
     
     

    - -

    Extending Java classes

    + +

    Extending Abstract Java Classes

    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.:

    @@ -671,6 +714,9 @@ Here, Timer.schedule() expects a TimerTask 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. +
    + +

    Extending Concrete Java Classes

    To extend a concrete Java class, you have to use Java.extend function. Java.extend 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); +

    +The reason you must use Java.extend() with concrete classes is that with concrete classes, there can be a +syntactic ambiguity if you just invoke their constructor. Consider this example: +

    +
    
    +var t = new java.lang.Thread({ run: function() { print("Hello!") } })
    +
    +

    +If we allowed subclassing of concrete classes with constructor syntax, Nashorn couldn't tell if you're creating a new +Thread and passing it a Runnable at this point, or you are subclassing Thread and +passing it a new implementation for its own run() method. +

    +
    + +

    Implementing Multiple Interfaces

    +

    +Java.extend 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 java.lang.Object). +


    + +

    Class-Bound Implementations

    +

    +The methods shown so far for extending Java classes and implementing interfaces – passing an implementation JavaScript object +or function to a constructor, or using Java.extend with new – 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 new, 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, Runnable have the same class regardless of them having +different JavaScript implementation objects: +

    +
    
    +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))
    +
    +

    +prints: +

    +
    
    +I'm runnable 1!
    +I'm runnable 2!
    +We share the same class: true
    +
    +

    +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. +

    +

    +Fortunately, there's a solution for that: Java.extend() – 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, Java.extend() 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: +

    +
    
    +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))
    +
    +

    +prints: +

    +
    
    +I'm runnable 1!
    +I'm runnable 2!
    +We share the same class: false
    +
    +

    +As you can see, the major difference here is that we moved the implementation object into the invocation of Java.extend +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 Java.extend() with a class-specific implementation object triggers +the creation of a new Java adapter class. +

    +

    +Finally, the adapter classes with class-bound implementations can still 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 Java.extend, 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. +

    +
    
    +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))
    +
    +

    +prints: +

    +
    
    +I'm runnable 1!
    +I'm runnable 2!
    +We share the same class: true
    +

    Overload Resolution

    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.

    +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:

    
     // overload.js
     
     var out = java.lang.System.out;
     
     // select a particular print function 
    -out["println(java.lang.Object)"]("hello");
    +out["println(Object)"]("hello");
     
     
    +

    +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. +

    +
    + +

    Mapping of Data Types Between Java and JavaScript

    +

    +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. +

    +

    +Every JavaScript object is also a java.util.Map so APIs receiving maps will receive them directly. +

    +

    +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 Number or Object, you can only +count on them being a Number, and have to test specifically for whether it's a boxed Double, +Integer, Long, 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 +ToNumber conversion algorithm will be applied to the value. +

    +

    +In a similar vein, if a Java method expects a String or a Boolean, the values will be +converted using all conversions allowed by the JavaScript specification's ToString and ToBoolean +conversions. +

    +

    +Finally, a word of caution about strings. Due to internal performance optimizations of string operations, JavaScript strings are +not always necessarily of type java.lang.String, but they will always be of type java.lang.CharSequence. +If you pass them to a Java method that expects a java.lang.String parameter, then you will naturally receive a Java +String, but if the signature of your method is more generic, i.e. it receives a java.lang.Object parameter, you can +end up with an object of private engine implementation class that implements CharSequence but is not a Java String. +


    Implementing Your Own Script Engine

    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/docs/source/javaarray.js --- a/nashorn/docs/source/javaarray.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/docs/source/javaarray.js Wed May 29 16:59:55 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); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/make/build-benchmark.xml --- a/nashorn/make/build-benchmark.xml Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/make/build-benchmark.xml Wed May 29 16:59:55 2013 -0700 @@ -24,258 +24,270 @@ - - - - + + + + + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + @@ -307,7 +319,7 @@ - + diff -r 2fd6acba737b -r bf497a99ac5c nashorn/make/build.xml --- a/nashorn/make/build.xml Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/make/build.xml Wed May 29 16:59:55 2013 -0700 @@ -212,7 +212,9 @@ target="${javac.target}" debug="${javac.debug}" encoding="${javac.encoding}" - includeantruntime="false"/> + includeantruntime="false"> + + @@ -305,6 +307,8 @@ + + diff -r 2fd6acba737b -r bf497a99ac5c nashorn/make/code_coverage.xml --- a/nashorn/make/code_coverage.xml Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/make/code_coverage.xml Wed May 29 16:59:55 2013 -0700 @@ -139,6 +139,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 2fd6acba737b -r bf497a99ac5c nashorn/make/project.properties --- a/nashorn/make/project.properties Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/make/project.properties Wed May 29 16:59:55 2013 -0700 @@ -87,6 +87,7 @@ testng.listeners=\ org.testng.reporters.SuiteHTMLReporter, \ + org.testng.reporters.TestHTMLReporter, \ org.testng.reporters.jq.Main, \ org.testng.reporters.FailedReporter, \ org.testng.reporters.XMLReporter \ @@ -214,9 +215,13 @@ run.test.xmx=3G run.test.xms=2G +run.test.user.language=tr +run.test.user.country=TR + # -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods # add '-Dtest.js.outofprocess' to run each test in a new sub-process -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 +run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} + #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/api/scripting/JSObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/api/scripting/JSObject.java Wed May 29 16:59:55 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); +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed May 29 16:59:55 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 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/api/scripting/resources/engine.js --- a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js Wed May 29 16:59:55 2013 -0700 @@ -88,7 +88,7 @@ } } - array = Java.toJavaArray(array); + array = Java.to(array); return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array); } }); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/Attr.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Wed May 29 16:59:55 2013 -0700 @@ -84,8 +84,8 @@ import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.WithNode; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; 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.Context; import jdk.nashorn.internal.runtime.Debug; @@ -111,7 +111,7 @@ * computed. */ -final class Attr extends NodeOperatorVisitor { +final class Attr extends NodeOperatorVisitor { /** * Local definitions in current block (to discriminate from function @@ -138,6 +138,7 @@ * Constructor. */ Attr(final TemporarySymbols temporarySymbols) { + super(new LexicalContext()); this.temporarySymbols = temporarySymbols; this.localDefs = new ArrayDeque<>(); this.localUses = new ArrayDeque<>(); @@ -202,7 +203,7 @@ private void acceptDeclarations(final FunctionNode functionNode, final Block body) { // This visitor will assign symbol to all declared variables, except function declarations (which are taken care // in a separate step above) and "var" declarations in for loop initializers. - body.accept(new NodeOperatorVisitor() { + body.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterFunctionNode(final FunctionNode nestedFn) { return false; @@ -218,7 +219,7 @@ if (varNode.isFunctionDeclaration()) { newType(symbol, FunctionNode.FUNCTION_TYPE); } - return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol)); + return varNode.setName((IdentNode)ident.setSymbol(lc, symbol)); } return varNode; } @@ -227,8 +228,8 @@ private void enterFunctionBody() { - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); - final Block body = getLexicalContext().getCurrentBlock(); + final FunctionNode functionNode = lc.getCurrentFunction(); + final Block body = lc.getCurrentBlock(); initFunctionWideVariables(functionNode, body); @@ -256,7 +257,7 @@ //the symbols in the block should really be stateless block.clearSymbols(); - if (getLexicalContext().isFunctionBody()) { + if (lc.isFunctionBody()) { enterFunctionBody(); } pushLocalsBlock(); @@ -283,7 +284,7 @@ @Override public boolean enterCatchNode(final CatchNode catchNode) { final IdentNode exception = catchNode.getException(); - final Block block = getLexicalContext().getCurrentBlock(); + final Block block = lc.getCurrentBlock(); start(catchNode); @@ -298,10 +299,10 @@ @Override public Node leaveCatchNode(final CatchNode catchNode) { final IdentNode exception = catchNode.getException(); - final Block block = getLexicalContext().getCurrentBlock(); + final Block block = lc.getCurrentBlock(); final Symbol symbol = findSymbol(block, exception.getName()); assert symbol != null; - return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol))); + return end(catchNode.setException((IdentNode)exception.setSymbol(lc, symbol))); } /** @@ -320,7 +321,7 @@ flags |= IS_SCOPE; } - final FunctionNode function = getLexicalContext().getFunction(block); + final FunctionNode function = lc.getFunction(block); if (symbol != null) { // Symbol was already defined. Check if it needs to be redefined. if ((flags & KINDMASK) == IS_PARAM) { @@ -353,12 +354,12 @@ if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { symbolBlock = block; //internal vars are always defined in the block closest to them } else { - symbolBlock = getLexicalContext().getFunctionBody(function); + symbolBlock = lc.getFunctionBody(function); } // Create and add to appropriate block. symbol = new Symbol(name, flags); - symbolBlock.putSymbol(getLexicalContext(), symbol); + symbolBlock.putSymbol(lc, symbol); if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { symbol.setNeedsSlot(true); @@ -381,7 +382,7 @@ //an outermost function in our lexical context that is not a program (runScript) //is possible - it is a function being compiled lazily if (functionNode.isDeclared()) { - final Iterator blocks = getLexicalContext().getBlocks(); + final Iterator blocks = lc.getBlocks(); if (blocks.hasNext()) { defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR); } @@ -397,13 +398,11 @@ public Node leaveFunctionNode(final FunctionNode functionNode) { FunctionNode newFunctionNode = functionNode; - final LexicalContext lc = getLexicalContext(); - final Block body = newFunctionNode.getBody(); //look for this function in the parent block if (functionNode.isDeclared()) { - final Iterator blocks = getLexicalContext().getBlocks(); + final Iterator blocks = lc.getBlocks(); if (blocks.hasNext()) { newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName())); } @@ -411,7 +410,7 @@ final boolean anonymous = functionNode.isAnonymous(); final String name = anonymous ? null : functionNode.getIdent().getName(); if (anonymous || body.getExistingSymbol(name) != null) { - newFunctionNode = (FunctionNode)ensureSymbol(lc, FunctionNode.FUNCTION_TYPE, newFunctionNode); + newFunctionNode = (FunctionNode)ensureSymbol(FunctionNode.FUNCTION_TYPE, newFunctionNode); } else { assert name != null; final Symbol self = body.getExistingSymbol(name); @@ -490,8 +489,6 @@ start(identNode); - final LexicalContext lc = getLexicalContext(); - if (identNode.isPropertyName()) { // assign a pseudo symbol to property name final Symbol pseudoSymbol = pseudoSymbol(name); @@ -549,7 +546,7 @@ */ private void maybeForceScope(final Symbol symbol) { if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) { - Symbol.setSymbolIsScope(getLexicalContext(), symbol); + Symbol.setSymbolIsScope(lc, symbol); } } @@ -558,7 +555,7 @@ return false; } boolean previousWasBlock = false; - for(final Iterator it = getLexicalContext().getAllNodes(); it.hasNext();) { + for(final Iterator it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if(node instanceof FunctionNode) { // We reached the function boundary without seeing a definition for the symbol - it needs to be in @@ -594,10 +591,8 @@ } if (symbol.isScope()) { - final LexicalContext lc = getLexicalContext(); - Block scopeBlock = null; - for (final Iterator contextNodeIter = getLexicalContext().getAllNodes(); contextNodeIter.hasNext(); ) { + for (final Iterator contextNodeIter = lc.getAllNodes(); contextNodeIter.hasNext(); ) { final LexicalContextNode node = contextNodeIter.next(); if (node instanceof Block) { if (((Block)node).getExistingSymbol(name) != null) { @@ -610,7 +605,7 @@ } if (scopeBlock != null) { - assert getLexicalContext().contains(scopeBlock); + assert lc.contains(scopeBlock); lc.setFlag(scopeBlock, Block.NEEDS_SCOPE); } } @@ -622,8 +617,8 @@ * @see #needsParentScope() */ private void setUsesGlobalSymbol() { - for (final Iterator fns = getLexicalContext().getFunctions(); fns.hasNext();) { - getLexicalContext().setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE); + for (final Iterator fns = lc.getFunctions(); fns.hasNext();) { + lc.setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE); } } @@ -635,7 +630,7 @@ private Symbol findSymbol(final Block block, final String name) { // Search up block chain to locate symbol. - for (final Iterator blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { + for (final Iterator blocks = lc.getBlocks(block); blocks.hasNext();) { // Find name. final Symbol symbol = blocks.next().getExistingSymbol(name); // If found then we are good. @@ -656,11 +651,11 @@ public Node leaveLiteralNode(final LiteralNode literalNode) { assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; - final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType()); + final Symbol symbol = new Symbol(lc.getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType()); if (literalNode instanceof ArrayLiteralNode) { ((ArrayLiteralNode)literalNode).analyze(); } - return end(literalNode.setSymbol(getLexicalContext(), symbol)); + return end(literalNode.setSymbol(lc, symbol)); } @Override @@ -676,7 +671,7 @@ @Override public Node leavePropertyNode(final PropertyNode propertyNode) { // assign a pseudo symbol to property name, see NASHORN-710 - return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); + return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); } @Override @@ -734,11 +729,11 @@ type = Type.OBJECT; } - switchNode.setTag(newInternal(getLexicalContext().getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type)); + switchNode.setTag(newInternal(lc.getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type)); end(switchNode); - return switchNode.setCases(getLexicalContext(), newCases); + return switchNode.setCases(lc, newCases); } @Override @@ -761,7 +756,7 @@ final IdentNode ident = varNode.getName(); final String name = ident.getName(); - final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR); + final Symbol symbol = defineSymbol(lc.getCurrentBlock(), name, IS_VAR); assert symbol != null; // NASHORN-467 - use before definition of vars - conservative @@ -781,7 +776,6 @@ final IdentNode ident = newVarNode.getName(); final String name = ident.getName(); - final LexicalContext lc = getLexicalContext(); final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); if (init == null) { @@ -834,7 +828,7 @@ @Override public Node leaveDELETE(final UnaryNode unaryNode) { - final FunctionNode currentFunctionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunctionNode = lc.getCurrentFunction(); final boolean strictMode = currentFunctionNode.isStrict(); final Node rhs = unaryNode.rhs(); final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this); @@ -894,10 +888,10 @@ * @return true if the symbol denoted by the specified name in the current lexical context defined in the program level. */ private boolean isProgramLevelSymbol(final String name) { - for(final Iterator it = getLexicalContext().getBlocks(); it.hasNext();) { + for(final Iterator it = lc.getBlocks(); it.hasNext();) { final Block next = it.next(); if(next.getExistingSymbol(name) != null) { - return next == getLexicalContext().getFunctionBody(getLexicalContext().getOutermostFunction()); + return next == lc.getFunctionBody(lc.getOutermostFunction()); } } throw new AssertionError("Couldn't find symbol " + name + " in the context"); @@ -914,14 +908,14 @@ } private IdentNode compilerConstant(CompilerConstants cc) { - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode functionNode = lc.getCurrentFunction(); return (IdentNode) new IdentNode( functionNode.getToken(), functionNode.getFinish(), cc.symbolName()). setSymbol( - getLexicalContext(), + lc, functionNode.compilerConstant(cc)); } @@ -999,7 +993,7 @@ final Node lhs = binaryNode.lhs(); if (lhs instanceof IdentNode) { - final Block block = getLexicalContext().getCurrentBlock(); + final Block block = lc.getCurrentBlock(); final IdentNode ident = (IdentNode)lhs; final String name = ident.getName(); @@ -1043,7 +1037,7 @@ } private boolean isLocal(FunctionNode function, Symbol symbol) { - final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol); + final FunctionNode definingFn = lc.getDefiningFunction(symbol); // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local return definingFn == null || definingFn == function; } @@ -1329,7 +1323,7 @@ @Override public Node leaveForNode(final ForNode forNode) { if (forNode.isForIn()) { - forNode.setIterator(newInternal(getLexicalContext().getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73 + forNode.setIterator(newInternal(lc.getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73 /* * Iterators return objects, so we need to widen the scope of the * init variable if it, for example, has been assigned double type @@ -1407,7 +1401,7 @@ final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName()); assert paramSymbol != null; assert paramSymbol.isParam(); - newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol)); + newParams.add((IdentNode)param.setSymbol(lc, paramSymbol)); assert paramSymbol != null; Type type = functionNode.getHints().getParameterType(pos); @@ -1439,10 +1433,10 @@ FunctionNode newFunctionNode = functionNode; if (nparams == 0 || (specialize * 2) < nparams) { - newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext()); + newFunctionNode = newFunctionNode.clearSnapshot(lc); } - return newFunctionNode.setParameters(getLexicalContext(), newParams); + return newFunctionNode.setParameters(lc, newParams); } /** @@ -1506,7 +1500,7 @@ } private Symbol exceptionSymbol() { - return newInternal(getLexicalContext().getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class)); + return newInternal(lc.getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class)); } /** @@ -1520,8 +1514,8 @@ * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes */ private Node ensureAssignmentSlots(final Node assignmentDest) { - final LexicalContext attrLexicalContext = getLexicalContext(); - return assignmentDest.accept(new NodeVisitor() { + final LexicalContext attrLexicalContext = lc; + return assignmentDest.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveIndexNode(final IndexNode indexNode) { assert indexNode.getSymbol().isTemp(); @@ -1565,7 +1559,7 @@ FunctionNode currentFunctionNode = functionNode; do { changed.clear(); - final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor() { + final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor(new LexicalContext()) { private Node widen(final Node node, final Type to) { if (node instanceof LiteralNode) { @@ -1579,7 +1573,7 @@ symbol = temporarySymbols.getTypedTemporarySymbol(to); } newType(symbol, to); - final Node newNode = node.setSymbol(getLexicalContext(), symbol); + final Node newNode = node.setSymbol(lc, symbol); changed.add(newNode); return newNode; } @@ -1622,7 +1616,7 @@ return newBinaryNode; } }); - getLexicalContext().replace(currentFunctionNode, newFunctionNode); + lc.replace(currentFunctionNode, newFunctionNode); currentFunctionNode = newFunctionNode; } while (!changed.isEmpty()); return currentFunctionNode; @@ -1643,12 +1637,12 @@ } private Node ensureSymbol(final Type type, final Node node) { - LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type); - return ensureSymbol(getLexicalContext(), type, node); + LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type); + return temporarySymbols.ensureSymbol(lc, type, node); } private Symbol newInternal(final String name, final Type type) { - final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL); + final Symbol iter = defineSymbol(lc.getCurrentBlock(), name, IS_VAR | IS_INTERNAL); iter.setType(type); // NASHORN-73 return iter; } @@ -1705,10 +1699,6 @@ localUses.peek().add(name); } - private Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) { - return temporarySymbols.ensureSymbol(lc, type, node); - } - /** * Pessimistically promote all symbols in current function node to Object types * This is done when the function contains unevaluated black boxes such as @@ -1717,7 +1707,7 @@ * @param body body for the function node we are leaving */ private static void objectifySymbols(final Block body) { - body.accept(new NodeVisitor() { + body.accept(new NodeVisitor(new LexicalContext()) { private void toObject(final Block block) { for (final Symbol symbol : block.getSymbols()) { if (!symbol.isTemp()) { @@ -1761,7 +1751,7 @@ append("] "). append(printNode ? node.toString() : ""). append(" in '"). - append(getLexicalContext().getCurrentFunction().getName()). + append(lc.getCurrentFunction().getName()). append("'"); LOG.info(sb); LOG.indent(); @@ -1787,7 +1777,7 @@ append("] "). append(printNode ? node.toString() : ""). append(" in '"). - append(getLexicalContext().getCurrentFunction().getName()); + append(lc.getCurrentFunction().getName()); if (node.getSymbol() == null) { sb.append(" "); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed May 29 16:59:55 2013 -0700 @@ -52,16 +52,13 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; import java.io.PrintWriter; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; -import java.util.Deque; import java.util.EnumSet; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Map; +import java.util.Locale; import java.util.TreeMap; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; @@ -83,11 +80,11 @@ import jdk.nashorn.internal.ir.ExecuteNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; -import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContextNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; @@ -150,7 +147,7 @@ * The CodeGenerator visits nodes only once, tags them as resolved and emits * bytecode for them. */ -final class CodeGenerator extends NodeOperatorVisitor { +final class CodeGenerator extends NodeOperatorVisitor { /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global"; @@ -168,23 +165,12 @@ /** How many regexp fields have been emitted */ private int regexFieldCount; - /** Map of shared scope call sites */ - private final Map scopeCalls = new HashMap<>(); - - /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */ - private final Deque compileUnits = new ArrayDeque<>(); - - /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */ - private final Deque methodEmitters = new ArrayDeque<>(); - - /** The discard stack - whenever we enter a discard node we keep track of its return value status - - * i.e. should we keep it or throw it away */ - private final Deque discard = new ArrayDeque<>(); - - // A stack tracking the next free local variable slot in the blocks. There's one entry for every block - // currently on the lexical context stack. - private int[] nextFreeSlots = new int[16]; - private int nextFreeSlotsSize = 0; + /** Line number for last statement. If we encounter a new line number, line number bytecode information + * needs to be generated */ + private int lastLineNumber = -1; + + /** When should we stop caching regexp expressions in fields to limit bytecode size? */ + private static final int MAX_REGEX_FIELDS = 2 * 1024; /** Current method emitter */ private MethodEmitter method; @@ -192,20 +178,16 @@ /** Current compile unit */ private CompileUnit unit; - private int lastLineNumber = -1; - - /** When should we stop caching regexp expressions in fields to limit bytecode size? */ - private static final int MAX_REGEX_FIELDS = 2 * 1024; - private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug"); + /** * Constructor. * * @param compiler */ CodeGenerator(final Compiler compiler) { - super(new DynamicScopeTrackingLexicalContext()); + super(new CodeGeneratorLexicalContext()); this.compiler = compiler; this.callSiteFlags = compiler.getEnv()._callsite_flags; } @@ -217,37 +199,7 @@ * @return the correct flags for a call site in the current function */ int getCallSiteFlags() { - return getLexicalContext().getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; - } - - private void pushMethodEmitter(final MethodEmitter newMethod) { - methodEmitters.push(newMethod); - this.method = newMethod; - } - - private void popMethodEmitter(final MethodEmitter oldMethod) { - assert methodEmitters.peek() == oldMethod; - methodEmitters.pop(); - if (!methodEmitters.isEmpty()) { - this.method = methodEmitters.peek(); - } else { - this.method = null; - } - } - - private void push(final CompileUnit newUnit) { - compileUnits.push(newUnit); - this.unit = newUnit; - } - - private void pop(final CompileUnit oldUnit) { - assert compileUnits.peek() == oldUnit; - compileUnits.pop(); - if (!compileUnits.isEmpty()) { - this.unit = compileUnits.peek(); - } else { - this.unit = null; - } + return lc.getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; } /** @@ -265,7 +217,7 @@ } final String name = symbol.getName(); - final Source source = getLexicalContext().getCurrentFunction().getSource(); + final Source source = lc.getCurrentFunction().getSource(); if (CompilerConstants.__FILE__.name().equals(name)) { return method.load(source.getName()); @@ -291,88 +243,43 @@ } /** - * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new - * variables introduced into them at run time - a with block or a function directly containing an eval call. - */ - private static class DynamicScopeTrackingLexicalContext extends LexicalContext { - int dynamicScopeCount = 0; - - @Override - public T push(T node) { - if(isDynamicScopeBoundary(node)) { - ++dynamicScopeCount; - } - return super.push(node); - } - - @Override - public T pop(T node) { - final T popped = super.pop(node); - if(isDynamicScopeBoundary(popped)) { - --dynamicScopeCount; - } - return popped; - } - - private boolean isDynamicScopeBoundary(LexicalContextNode node) { - if(node instanceof Block) { - // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture - // processing of WithNode.expression too, but it should be unaffected. - return !isEmpty() && peek() instanceof WithNode; - } else if(node instanceof FunctionNode) { - // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new - // variable into the function's scope), and it isn't strict (as evals in strict functions get an - // isolated scope). - return isFunctionDynamicScope((FunctionNode)node); - } - return false; - } - } - - boolean inDynamicScope() { - return ((DynamicScopeTrackingLexicalContext)getLexicalContext()).dynamicScopeCount > 0; - } - - static boolean isFunctionDynamicScope(FunctionNode fn) { - return fn.hasEval() && !fn.isStrict(); - } - - /** * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load * * @param function function to check for fast scope * @return true if fast scope */ private boolean isFastScope(final Symbol symbol) { - if(!symbol.isScope()) { + if (!symbol.isScope()) { return false; } - final LexicalContext lc = getLexicalContext(); - if(!inDynamicScope()) { + + if (!lc.inDynamicScope()) { // If there's no with or eval in context, and the symbol is marked as scoped, it is fast scoped. Such a // symbol must either be global, or its defining block must need scope. assert symbol.isGlobal() || lc.getDefiningBlock(symbol).needsScope() : symbol.getName(); return true; } - if(symbol.isGlobal()) { + + if (symbol.isGlobal()) { // Shortcut: if there's a with or eval in context, globals can't be fast scoped return false; } + // Otherwise, check if there's a dynamic scope between use of the symbol and its definition final String name = symbol.getName(); boolean previousWasBlock = false; for (final Iterator it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); - if(node instanceof Block) { + if (node instanceof Block) { // If this block defines the symbol, then we can fast scope the symbol. final Block block = (Block)node; - if(block.getExistingSymbol(name) == symbol) { + if (block.getExistingSymbol(name) == symbol) { assert block.needsScope(); return true; } previousWasBlock = true; } else { - if((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && isFunctionDynamicScope((FunctionNode)node))) { + if ((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node))) { // If we hit a scope that can have symbols introduced into it at run time before finding the defining // block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block // before - its block. Otherwise, we are currently processing the WithNode's expression, and that's @@ -387,16 +294,14 @@ } private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { - method.load(isFastScope(symbol) ? getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol) : -1); - final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); - scopeCall.generateInvoke(method); - return method; + method.load(isFastScope(symbol) ? getScopeProtoDepth(lc.getCurrentBlock(), symbol) : -1); + final SharedScopeCall scopeCall = lc.getScopeGet(unit, valueType, symbol, flags | CALLSITE_FAST_SCOPE); + return scopeCall.generateInvoke(method); } private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { loadFastScopeProto(symbol, false); - method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); - return method; + return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); } private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { @@ -408,7 +313,7 @@ private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { int depth = 0; final String name = symbol.getName(); - for(final Iterator blocks = getLexicalContext().getBlocks(startingBlock); blocks.hasNext();) { + for(final Iterator blocks = lc.getBlocks(startingBlock); blocks.hasNext();) { final Block currentBlock = blocks.next(); if (currentBlock.getExistingSymbol(name) == symbol) { return depth; @@ -421,7 +326,7 @@ } private void loadFastScopeProto(final Symbol symbol, final boolean swap) { - final int depth = getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol); + final int depth = getScopeProtoDepth(lc.getCurrentBlock(), symbol); assert depth != -1; if (depth > 0) { if (swap) { @@ -464,7 +369,7 @@ */ final CodeGenerator codegen = this; - node.accept(new NodeVisitor() { + node.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterIdentNode(final IdentNode identNode) { loadIdent(identNode); @@ -538,7 +443,7 @@ final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined(); if (symbol.hasSlot() && !isInternal) { - assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getLexicalContext().getCurrentFunction(); + assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + lc.getCurrentFunction(); if (symbol.getSymbolType().isNumber()) { numbers.add(symbol); } else if (symbol.getSymbolType().isObject()) { @@ -595,7 +500,6 @@ if (block.needsScope() && !block.isTerminal()) { popBlockScope(block); } - --nextFreeSlotsSize; return block; } @@ -624,11 +528,11 @@ public boolean enterBreakNode(final BreakNode breakNode) { lineNumber(breakNode); - final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel()); - for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) { + final BreakableNode breakFrom = lc.getBreakable(breakNode.getLabel()); + for (int i = 0; i < lc.getScopeNestingLevelTo(breakFrom); i++) { closeWith(); } - method.splitAwareGoto(getLexicalContext(), breakFrom.getBreakLabel()); + method.splitAwareGoto(lc, breakFrom.getBreakLabel()); return false; } @@ -672,11 +576,12 @@ final List args = callNode.getArgs(); final Node function = callNode.getFunction(); - final Block currentBlock = getLexicalContext().getCurrentBlock(); - - function.accept(new NodeVisitor() { - - private void sharedScopeCall(final IdentNode identNode, final int flags) { + final Block currentBlock = lc.getCurrentBlock(); + final CodeGeneratorLexicalContext codegenLexicalContext = lc; + + function.accept(new NodeVisitor(new LexicalContext()) { + + private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) { final Symbol symbol = identNode.getSymbol(); int scopeCallFlags = flags; method.loadCompilerConstant(SCOPE); @@ -688,8 +593,8 @@ } loadArgs(args); final Type[] paramTypes = method.getTypesFromStack(args.size()); - final SharedScopeCall scopeCall = getScopeCall(symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); - scopeCall.generateInvoke(method); + final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); + return scopeCall.generateInvoke(method); } private void scopeCall(final IdentNode node, final int flags) { @@ -756,7 +661,7 @@ evalCall(node, flags); } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) - || CodeGenerator.this.inDynamicScope()) { + || CodeGenerator.this.lc.inDynamicScope()) { scopeCall(node, flags); } else { sharedScopeCall(node, flags); @@ -845,11 +750,11 @@ public boolean enterContinueNode(final ContinueNode continueNode) { lineNumber(continueNode); - final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel()); - for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) { + final LoopNode continueTo = lc.getContinueTo(continueNode.getLabel()); + for (int i = 0; i < lc.getScopeNestingLevelTo(continueTo); i++) { closeWith(); } - method.splitAwareGoto(getLexicalContext(), continueTo.getContinueLabel()); + method.splitAwareGoto(lc, continueTo.getContinueLabel()); return false; } @@ -875,90 +780,89 @@ public boolean enterForNode(final ForNode forNode) { lineNumber(forNode); - final Node test = forNode.getTest(); - final Block body = forNode.getBody(); - final Node modify = forNode.getModify(); - - final Label breakLabel = forNode.getBreakLabel(); - final Label continueLabel = forNode.getContinueLabel(); - final Label loopLabel = new Label("loop"); - - Node init = forNode.getInit(); - if (forNode.isForIn()) { - final Symbol iter = forNode.getIterator(); - - // We have to evaluate the optional initializer expression - // of the iterator variable of the for-in statement. - if (init instanceof VarNode) { - init.accept(this); - init = ((VarNode)init).getName(); - } - - load(modify); - assert modify.getType().isObject(); - method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); - method.store(iter); - method._goto(continueLabel); - method.label(loopLabel); - - new Store(init) { - @Override - protected void storeNonDiscard() { - return; - } - @Override - protected void evaluate() { - method.load(iter); - method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); - } - }.store(); - - body.accept(this); - - method.label(continueLabel); - method.load(iter); - method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); - method.ifne(loopLabel); - method.label(breakLabel); + enterForIn(forNode); } else { - if (init != null) { - init.accept(this); - } - - final Label testLabel = new Label("test"); - - method._goto(testLabel); - method.label(loopLabel); - body.accept(this); - method.label(continueLabel); - - if (!body.isTerminal() && modify != null) { - load(modify); - } - - method.label(testLabel); - if (test != null) { - new BranchOptimizer(this, method).execute(test, loopLabel, true); - } else { - method._goto(loopLabel); - } - - method.label(breakLabel); + enterFor(forNode); } return false; } - private static int assignSlots(final Block block, final int firstSlot) { - int nextSlot = firstSlot; - for (final Symbol symbol : block.getSymbols()) { - if (symbol.hasSlot()) { - symbol.setSlot(nextSlot); - nextSlot += symbol.slotCount(); + private void enterFor(final ForNode forNode) { + final Node init = forNode.getInit(); + final Node test = forNode.getTest(); + final Block body = forNode.getBody(); + final Node modify = forNode.getModify(); + + if (init != null) { + init.accept(this); + } + + final Label loopLabel = new Label("loop"); + final Label testLabel = new Label("test"); + + method._goto(testLabel); + method.label(loopLabel); + body.accept(this); + method.label(forNode.getContinueLabel()); + + if (!body.isTerminal() && modify != null) { + load(modify); + } + + method.label(testLabel); + if (test != null) { + new BranchOptimizer(this, method).execute(test, loopLabel, true); + } else { + method._goto(loopLabel); + } + + method.label(forNode.getBreakLabel()); + } + + private void enterForIn(final ForNode forNode) { + final Block body = forNode.getBody(); + final Node modify = forNode.getModify(); + + final Symbol iter = forNode.getIterator(); + final Label loopLabel = new Label("loop"); + + Node init = forNode.getInit(); + + // We have to evaluate the optional initializer expression + // of the iterator variable of the for-in statement. + if (init instanceof VarNode) { + init.accept(this); + init = ((VarNode)init).getName(); + } + + load(modify); + assert modify.getType().isObject(); + method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); + method.store(iter); + method._goto(forNode.getContinueLabel()); + method.label(loopLabel); + + new Store(init) { + @Override + protected void storeNonDiscard() { + return; } - } - return nextSlot; + @Override + protected void evaluate() { + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); + } + }.store(); + + body.accept(this); + + method.label(forNode.getContinueLabel()); + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); + method.ifne(loopLabel); + method.label(forNode.getBreakLabel()); } /** @@ -967,24 +871,11 @@ * @param block block with local vars. */ private void initLocals(final Block block) { - final boolean isFunctionBody = getLexicalContext().isFunctionBody(); - - final int nextFreeSlot; - if (isFunctionBody) { - // On entry to function, start with slot 0 - nextFreeSlot = 0; - } else { - // Otherwise, continue from previous block's first free slot - nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1]; - } - if(nextFreeSlotsSize == nextFreeSlots.length) { - final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2]; - System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize); - nextFreeSlots = newNextFreeSlots; - } - nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot); - - final FunctionNode function = getLexicalContext().getCurrentFunction(); + lc.nextFreeSlot(block); + + final boolean isFunctionBody = lc.isFunctionBody(); + + final FunctionNode function = lc.getCurrentFunction(); if (isFunctionBody) { /* Fix the predefined slots so they have numbers >= 0, like varargs. */ if (function.needsParentScope()) { @@ -1023,7 +914,7 @@ } if (symbol.isVar()) { - if(varsInScope || symbol.isScope()) { + if (varsInScope || symbol.isScope()) { nameList.add(symbol.getName()); newSymbols.add(symbol); values.add(null); @@ -1062,7 +953,7 @@ @Override protected void loadScope(MethodEmitter m) { - if(function.needsParentScope()) { + if (function.needsParentScope()) { m.loadCompilerConstant(SCOPE); } else { m.loadNull(); @@ -1096,7 +987,7 @@ private void initArguments(final FunctionNode function) { method.loadCompilerConstant(VARARGS); - if(function.needsCallee()) { + if (function.needsCallee()) { method.loadCompilerConstant(CALLEE); } else { // If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the @@ -1126,10 +1017,10 @@ LOG.info("=== BEGIN ", functionNode.getName()); assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode); - push(functionNode.getCompileUnit()); - assert !compileUnits.isEmpty(); - - pushMethodEmitter(unit.getClassEmitter().method(functionNode)); + unit = lc.pushCompileUnit(functionNode.getCompileUnit()); + assert lc.hasCompileUnits(); + + method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode)); // Mark end for variable tables. method.begin(); @@ -1140,11 +1031,11 @@ public Node leaveFunctionNode(final FunctionNode functionNode) { try { method.end(); // wrap up this method - pop(functionNode.getCompileUnit()); - popMethodEmitter(method); + unit = lc.popCompileUnit(functionNode.getCompileUnit()); + method = lc.popMethodEmitter(method); LOG.info("=== END ", functionNode.getName()); - final FunctionNode newFunctionNode = functionNode.setState(getLexicalContext(), CompilationState.EMITTED); + final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED); newFunctionObject(newFunctionNode, functionNode); return newFunctionNode; @@ -1238,16 +1129,16 @@ final MethodEmitter savedMethod = method; for (final ArrayUnit arrayUnit : units) { - push(arrayUnit.getCompileUnit()); + unit = lc.pushCompileUnit(arrayUnit.getCompileUnit()); final String className = unit.getUnitClassName(); - final String name = getLexicalContext().getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName()); + final String name = lc.getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName()); final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); final MethodEmitter me = unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); - pushMethodEmitter(me); - - method.setFunctionNode(getLexicalContext().getCurrentFunction()); + method = lc.pushMethodEmitter(me); + + method.setFunctionNode(lc.getCurrentFunction()); method.begin(); fixScopeSlot(); @@ -1260,7 +1151,7 @@ method._return(); method.end(); - popMethodEmitter(me); + method = lc.popMethodEmitter(me); assert method == savedMethod; method.loadCompilerConstant(THIS); @@ -1271,7 +1162,7 @@ method.swap(); method.invokestatic(className, name, signature); - pop(unit); + unit = lc.popCompileUnit(unit); } return method; @@ -1407,7 +1298,7 @@ return loadRegexToken(regexToken); } // emit field - final String regexName = getLexicalContext().getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName()); + final String regexName = lc.getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName()); final ClassEmitter classEmitter = unit.getClassEmitter(); classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); @@ -1545,7 +1436,7 @@ method.registerReturn(); - final Type returnType = getLexicalContext().getCurrentFunction().getReturnType(); + final Type returnType = lc.getCurrentFunction().getReturnType(); final Node expression = returnNode.getExpression(); if (expression != null) { @@ -1756,7 +1647,7 @@ final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); - final FunctionNode fn = getLexicalContext().getCurrentFunction(); + final FunctionNode fn = lc.getCurrentFunction(); final String className = splitCompileUnit.getUnitClassName(); final String name = splitNode.getName(); @@ -1767,7 +1658,7 @@ new Class[] {ScriptFunction.class, Object.class, ScriptObject.class}; final MethodEmitter caller = method; - push(splitCompileUnit); + unit = lc.pushCompileUnit(splitCompileUnit); final Call splitCall = staticCallNoLookup( className, @@ -1781,8 +1672,7 @@ rtype, ptypes); - pushMethodEmitter(splitEmitter); - + method = lc.pushMethodEmitter(splitEmitter); method.setFunctionNode(fn); if (fn.needsCallee()) { @@ -1809,7 +1699,7 @@ } private void fixScopeSlot() { - if (getLexicalContext().getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) { + if (lc.getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) { // TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method) method.load(Type.typeFor(ScriptObject.class), SCOPE.slot()); method.storeCompilerConstant(SCOPE); @@ -1826,15 +1716,15 @@ // Wrap up this method. method.loadCompilerConstant(RETURN); - method._return(getLexicalContext().getCurrentFunction().getReturnType()); + method._return(lc.getCurrentFunction().getReturnType()); method.end(); - pop(splitNode.getCompileUnit()); - popMethodEmitter(method); + unit = lc.popCompileUnit(splitNode.getCompileUnit()); + method = lc.popMethodEmitter(method); } catch (final Throwable t) { Context.printStackTrace(t); - final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getLexicalContext().getCurrentFunction().getSource().getName()); + final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + lc.getCurrentFunction().getSource().getName()); e.initCause(t); throw e; } @@ -1862,7 +1752,7 @@ //has to be zero caller.label(new Label("split_return")); method.loadCompilerConstant(RETURN); - caller._return(getLexicalContext().getCurrentFunction().getReturnType()); + caller._return(lc.getCurrentFunction().getReturnType()); caller.label(breakLabel); } else { assert !targets.isEmpty(); @@ -1879,14 +1769,14 @@ caller.label(labels[i - low]); if (i == 0) { caller.loadCompilerConstant(RETURN); - caller._return(getLexicalContext().getCurrentFunction().getReturnType()); + caller._return(lc.getCurrentFunction().getReturnType()); } else { // Clear split state. caller.loadCompilerConstant(SCOPE); caller.checkcast(Scope.class); caller.load(-1); caller.invoke(Scope.SET_SPLIT_STATE); - caller.splitAwareGoto(getLexicalContext(), targets.get(i - 1)); + caller.splitAwareGoto(lc, targets.get(i - 1)); } } caller.label(breakLabel); @@ -2028,9 +1918,16 @@ public boolean enterThrowNode(final ThrowNode throwNode) { lineNumber(throwNode); + if (throwNode.isSyntheticRethrow()) { + //do not wrap whatever this is in an ecma exception, just rethrow it + load(throwNode.getExpression()); + method.athrow(); + return false; + } + method._new(ECMAException.class).dup(); - final Source source = getLexicalContext().getCurrentFunction().getSource(); + final Source source = lc.getCurrentFunction().getSource(); final Node expression = throwNode.getExpression(); final int position = throwNode.position(); @@ -2081,7 +1978,7 @@ //TODO this is very ugly - try not to call enter/leave methods directly //better to use the implicit lexical context scoping given by the visitor's //accept method. - getLexicalContext().push(catchBlock); + lc.push(catchBlock); enterBlock(catchBlock); final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); @@ -2094,15 +1991,19 @@ protected void storeNonDiscard() { return; } + @Override protected void evaluate() { + if (catchNode.isSyntheticRethrow()) { + method.load(symbol); + return; + } /* * If caught object is an instance of ECMAException, then * bind obj.thrown to the script catch var. Or else bind the * caught object itself to the script catch var. */ final Label notEcmaException = new Label("no_ecma_exception"); - method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException); method.checkcast(ECMAException.class); //TODO is this necessary? method.getField(ECMAException.THROWN); @@ -2137,7 +2038,7 @@ } leaveBlock(catchBlock); - getLexicalContext().pop(catchBlock); + lc.pop(catchBlock); } method.label(skip); @@ -2234,7 +2135,7 @@ final boolean hasScope = method.hasScope(); final Label tryLabel; - if(hasScope) { + if (hasScope) { tryLabel = new Label("with_try"); method.label(tryLabel); method.loadCompilerConstant(SCOPE); @@ -2245,7 +2146,7 @@ load(expression); assert expression.getType().isObject() : "with expression needs to be object: " + expression; - if(hasScope) { + if (hasScope) { // Construct a WithObject if we have a scope method.invoke(ScriptRuntime.OPEN_WITH); method.storeCompilerConstant(SCOPE); @@ -2285,7 +2186,7 @@ @Override public boolean enterADD(final UnaryNode unaryNode) { load(unaryNode.rhs()); - assert unaryNode.rhs().getType().isNumber(); + assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol(); method.store(unaryNode.getSymbol()); return false; @@ -2320,7 +2221,7 @@ } method.convert(Type.OBJECT); } else if (value instanceof Boolean) { - method.getField(staticField(Boolean.class, value.toString().toUpperCase(), Boolean.class)); + method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class)); } else { load(rhs); method.convert(unaryNode.getType()); @@ -2387,13 +2288,13 @@ public boolean enterDISCARD(final UnaryNode unaryNode) { final Node rhs = unaryNode.rhs(); - discard.push(rhs); + lc.pushDiscard(rhs); load(rhs); - if (discard.peek() == rhs) { + if (lc.getCurrentDiscard() == rhs) { assert !rhs.isAssignment(); method.pop(); - discard.pop(); + lc.popDiscard(); } return false; @@ -2445,7 +2346,7 @@ assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs); load(lhs); load(rhs); - method.add(); + method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack? method.store(symbol); return null; } @@ -2989,53 +2890,12 @@ * Generate all shared scope calls generated during codegen. */ protected void generateScopeCalls() { - for (final SharedScopeCall scopeAccess : scopeCalls.values()) { + for (final SharedScopeCall scopeAccess : lc.getScopeCalls()) { scopeAccess.generateScopeCall(); } } /** - * Get a shared static method representing a dynamic scope callsite. - * - * @param symbol the symbol - * @param valueType the value type of the symbol - * @param returnType the return type - * @param paramTypes the parameter types - * @param flags the callsite flags - * @return an object representing a shared scope call - */ - private SharedScopeCall getScopeCall(final Symbol symbol, final Type valueType, final Type returnType, - final Type[] paramTypes, final int flags) { - - final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags); - if (scopeCalls.containsKey(scopeCall)) { - return scopeCalls.get(scopeCall); - } - scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall")); - scopeCalls.put(scopeCall, scopeCall); - return scopeCall; - } - - /** - * Get a shared static method representing a dynamic scope get access. - * - * @param type the type of the variable - * @param symbol the symbol - * @param flags the callsite flags - * @return an object representing a shared scope call - */ - private SharedScopeCall getScopeGet(final Type type, final Symbol symbol, final int flags) { - - final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags); - if (scopeCalls.containsKey(scopeCall)) { - return scopeCalls.get(scopeCall); - } - scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall")); - scopeCalls.put(scopeCall, scopeCall); - return scopeCall; - } - - /** * Debug code used to print symbols * * @param block the block we are in @@ -3129,14 +2989,14 @@ private void prologue() { final Symbol targetSymbol = target.getSymbol(); - final Symbol scopeSymbol = getLexicalContext().getCurrentFunction().compilerConstant(SCOPE); + final Symbol scopeSymbol = lc.getCurrentFunction().compilerConstant(SCOPE); /** * This loads the parts of the target, e.g base and index. they are kept * on the stack throughout the store and used at the end to execute it */ - target.accept(new NodeVisitor() { + target.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterIdentNode(final IdentNode node) { if (targetSymbol.isScope()) { @@ -3203,22 +3063,21 @@ * @return the quick symbol */ private Symbol quickSymbol(final Type type, final String prefix) { - final String name = getLexicalContext().getCurrentFunction().uniqueName(prefix); + final String name = lc.getCurrentFunction().uniqueName(prefix); final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL); symbol.setType(type); - final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1]; - nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount(); - symbol.setSlot(quickSlot); + + symbol.setSlot(lc.quickSlot(symbol)); return symbol; } // store the result that "lives on" after the op, e.g. "i" in i++ postfix. protected void storeNonDiscard() { - if (discard.peek() == assignNode) { + if (lc.getCurrentDiscard() == assignNode) { assert assignNode.isAssignment(); - discard.pop(); + lc.popDiscard(); return; } @@ -3246,7 +3105,7 @@ */ method.convert(target.getType()); - target.accept(new NodeVisitor() { + target.accept(new NodeVisitor(new LexicalContext()) { @Override protected boolean enterDefault(Node node) { throw new AssertionError("Unexpected node " + node + " in store epilogue"); @@ -3308,7 +3167,6 @@ } private void newFunctionObject(final FunctionNode functionNode, final FunctionNode originalFunctionNode) { - final LexicalContext lc = getLexicalContext(); assert lc.peek() == functionNode; // We don't emit a ScriptFunction on stack for: // 1. the outermost compiled function (as there's no code being generated in its outer context that'd need it diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.codegen; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; + +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.LexicalContext; +import jdk.nashorn.internal.ir.LexicalContextNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.WithNode; + +/** + * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new + * variables introduced into them at run time - a with block or a function directly containing an eval call. + * Furthermore, this class keeps track of current discard state, which the current method emitter being used is, + * the current compile unit, and local variable indexes + */ +final class CodeGeneratorLexicalContext extends LexicalContext { + private int dynamicScopeCount; + + /** Map of shared scope call sites */ + private final Map scopeCalls = new HashMap<>(); + + /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */ + private final Deque compileUnits = new ArrayDeque<>(); + + /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */ + private final Deque methodEmitters = new ArrayDeque<>(); + + /** The discard stack - whenever we enter a discard node we keep track of its return value status - + * i.e. should we keep it or throw it away */ + private final Deque discard = new ArrayDeque<>(); + + /** A stack tracking the next free local variable slot in the blocks. There's one entry for every block + * currently on the lexical context stack. */ + private int[] nextFreeSlots = new int[16]; + + /** size of next free slot vector */ + private int nextFreeSlotsSize; + + @Override + public T push(final T node) { + if (isDynamicScopeBoundary(node)) { + ++dynamicScopeCount; + } + return super.push(node); + } + + @Override + public T pop(final T node) { + final T popped = super.pop(node); + if (isDynamicScopeBoundary(popped)) { + --dynamicScopeCount; + } + if (node instanceof Block) { + --nextFreeSlotsSize; + } + return popped; + } + + private boolean isDynamicScopeBoundary(final LexicalContextNode node) { + if (node instanceof Block) { + // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture + // processing of WithNode.expression too, but it should be unaffected. + return !isEmpty() && peek() instanceof WithNode; + } else if (node instanceof FunctionNode) { + // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new + // variable into the function's scope), and it isn't strict (as evals in strict functions get an + // isolated scope). + return isFunctionDynamicScope((FunctionNode)node); + } + return false; + } + + boolean inDynamicScope() { + return dynamicScopeCount > 0; + } + + static boolean isFunctionDynamicScope(FunctionNode fn) { + return fn.hasEval() && !fn.isStrict(); + } + + MethodEmitter pushMethodEmitter(final MethodEmitter newMethod) { + methodEmitters.push(newMethod); + return newMethod; + } + + MethodEmitter popMethodEmitter(final MethodEmitter oldMethod) { + assert methodEmitters.peek() == oldMethod; + methodEmitters.pop(); + return methodEmitters.isEmpty() ? null : methodEmitters.peek(); + } + + CompileUnit pushCompileUnit(final CompileUnit newUnit) { + compileUnits.push(newUnit); + return newUnit; + } + + CompileUnit popCompileUnit(final CompileUnit oldUnit) { + assert compileUnits.peek() == oldUnit; + compileUnits.pop(); + return compileUnits.isEmpty() ? null : compileUnits.peek(); + } + + boolean hasCompileUnits() { + return !compileUnits.isEmpty(); + } + + Collection getScopeCalls() { + return Collections.unmodifiableCollection(scopeCalls.values()); + } + + /** + * Get a shared static method representing a dynamic scope callsite. + * + * @param unit current compile unit + * @param symbol the symbol + * @param valueType the value type of the symbol + * @param returnType the return type + * @param paramTypes the parameter types + * @param flags the callsite flags + * @return an object representing a shared scope call + */ + SharedScopeCall getScopeCall(final CompileUnit unit, final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) { + final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags); + if (scopeCalls.containsKey(scopeCall)) { + return scopeCalls.get(scopeCall); + } + scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName("scopeCall")); + scopeCalls.put(scopeCall, scopeCall); + return scopeCall; + } + + /** + * Get a shared static method representing a dynamic scope get access. + * + * @param unit current compile unit + * @param type the type of the variable + * @param symbol the symbol + * @param flags the callsite flags + * @return an object representing a shared scope call + */ + SharedScopeCall getScopeGet(final CompileUnit unit, final Type type, final Symbol symbol, final int flags) { + final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags); + if (scopeCalls.containsKey(scopeCall)) { + return scopeCalls.get(scopeCall); + } + scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName("scopeCall")); + scopeCalls.put(scopeCall, scopeCall); + return scopeCall; + } + + + void nextFreeSlot(final Block block) { + final boolean isFunctionBody = isFunctionBody(); + + final int nextFreeSlot; + if (isFunctionBody) { + // On entry to function, start with slot 0 + nextFreeSlot = 0; + } else { + // Otherwise, continue from previous block's first free slot + nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1]; + } + if (nextFreeSlotsSize == nextFreeSlots.length) { + final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2]; + System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize); + nextFreeSlots = newNextFreeSlots; + } + nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot); + } + + private static int assignSlots(final Block block, final int firstSlot) { + int nextSlot = firstSlot; + for (final Symbol symbol : block.getSymbols()) { + if (symbol.hasSlot()) { + symbol.setSlot(nextSlot); + nextSlot += symbol.slotCount(); + } + } + return nextSlot; + } + + void pushDiscard(final Node node) { + discard.push(node); + } + + Node popDiscard() { + return discard.pop(); + } + + Node getCurrentDiscard() { + return discard.peek(); + } + + int quickSlot(final Symbol symbol) { + final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1]; + nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount(); + return quickSlot; + } + +} + diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Wed May 29 16:59:55 2013 -0700 @@ -11,20 +11,27 @@ 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.LexicalContext; +import jdk.nashorn.internal.ir.ReturnNode; +import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; -import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.TemporarySymbols; import jdk.nashorn.internal.ir.debug.ASTWriter; import jdk.nashorn.internal.ir.debug.PrintVisitor; -import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.ScriptEnvironment; @@ -66,7 +73,7 @@ FunctionNode newFunctionNode = outermostFunctionNode; - newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() { + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor(new LexicalContext()) { // self references are done with invokestatic and thus cannot // have trampolines - never lazy @Override @@ -99,10 +106,9 @@ lazy.remove(node); } - newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeOperatorVisitor() { + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveFunctionNode(final FunctionNode functionNode) { - final LexicalContext lc = getLexicalContext(); if (lazy.contains(functionNode)) { Compiler.LOG.fine( "Marking ", @@ -174,7 +180,7 @@ FunctionNode transform(final Compiler compiler, final FunctionNode fn) { final TemporarySymbols ts = compiler.getTemporarySymbols(); final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts)); - if(compiler.getEnv()._print_mem_usage) { + if (compiler.getEnv()._print_mem_usage) { Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount()); } return newFunctionNode; @@ -186,12 +192,11 @@ * @param functionNode node where to start iterating */ private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) { - return (FunctionNode)functionNode.accept(new NodeVisitor() { + return (FunctionNode)functionNode.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveFunctionNode(final FunctionNode node) { - final LexicalContext lc = getLexicalContext(); if (node.isLazy()) { - FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT); + FunctionNode newNode = node.setReturnType(lc, Type.OBJECT); return ts.ensureSymbol(lc, Type.OBJECT, newNode); } //node may have a reference here that needs to be nulled if it was referred to by @@ -208,6 +213,89 @@ }, /* + * 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 returns = new ArrayList<>(); + + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor(new LexicalContext()) { + private final Deque> returnStack = new ArrayDeque<>(); + + @Override + public boolean enterFunctionNode(final FunctionNode functionNode) { + returnStack.push(new ArrayList()); + return true; + } + + @Override + public Node leaveFunctionNode(final FunctionNode functionNode) { + Type returnType = Type.UNKNOWN; + for (final ReturnNode ret : returnStack.pop()) { + if (ret.getExpression() == null) { + returnType = Type.OBJECT; + break; + } + returnType = Type.widest(returnType, ret.getExpression().getType()); + } + return functionNode.setReturnType(lc, returnType); + } + + @Override + public Node leaveReturnNode(final ReturnNode returnNode) { + final ReturnNode result = (ReturnNode)leaveDefault(returnNode); + returns.add(result); + return result; + } + + @Override + public Node leaveDefault(final Node node) { + final Symbol symbol = node.getSymbol(); + if (symbol != null) { + final Range range = symbol.getRange(); + final Type symbolType = symbol.getSymbolType(); + if (!symbolType.isNumeric()) { + return node; + } + final Type rangeType = range.getType(); + if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range + RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange()); + return node.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols())); + } + } + return node; + } + }); + + Type returnType = Type.UNKNOWN; + for (final ReturnNode node : returns) { + if (node.getExpression() != null) { + returnType = Type.widest(returnType, node.getExpression().getType()); + } else { + returnType = Type.OBJECT; + break; + } + } + + return newFunctionNode.setReturnType(null, returnType); + } + + @Override + public String toString() { + return "[Range Analysis]"; + } + }, + + + /* * Splitter Split the AST into several compile units based on a size * heuristic Splitter needs attributed AST for weight calculations (e.g. is * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less). @@ -218,7 +306,6 @@ FunctionNode transform(final Compiler compiler, final FunctionNode fn) { final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); -// assert fn.isProgram() ; final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/Compiler.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Wed May 29 16:59:55 2013 -0700 @@ -99,7 +99,7 @@ private boolean strict; - private CodeInstaller installer; + private final CodeInstaller 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; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Wed May 29 16:59:55 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(); } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java --- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Wed May 29 16:59:55 2013 -0700 @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.Assignment; @@ -84,13 +85,14 @@ * and frame optimizations */ -final class FinalizeTypes extends NodeOperatorVisitor { +final class FinalizeTypes extends NodeOperatorVisitor { private static final DebugLogger LOG = new DebugLogger("finalize"); private final TemporarySymbols temporarySymbols; FinalizeTypes(final TemporarySymbols temporarySymbols) { + super(new LexicalContext()); this.temporarySymbols = temporarySymbols; } @@ -233,7 +235,7 @@ private boolean symbolIsInteger(Node node) { final Symbol symbol = node.getSymbol(); - assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource(); + assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource(); return true; } @@ -382,12 +384,10 @@ final Node test = forNode.getTest(); final Node modify = forNode.getModify(); - final LexicalContext lc = getLexicalContext(); - if (forNode.isForIn()) { return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400 } - assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getLexicalContext().getCurrentFunction(); + assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction(); return forNode. setInit(lc, init == null ? null : discard(init)). @@ -419,7 +419,7 @@ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { - return functionNode.setState(getLexicalContext(), CompilationState.FINALIZED); + return functionNode.setState(lc, CompilationState.FINALIZED); } @Override @@ -450,7 +450,7 @@ public Node leaveReturnNode(final ReturnNode returnNode) { final Node expr = returnNode.getExpression(); if (expr != null) { - return returnNode.setExpression(convert(expr, getLexicalContext().getCurrentFunction().getReturnType())); + return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType())); } return returnNode; } @@ -482,8 +482,8 @@ } return switchNode. - setExpression(getLexicalContext(), convert(expression, Type.OBJECT)). - setCases(getLexicalContext(), newCases); + setExpression(lc, convert(expression, Type.OBJECT)). + setCases(lc, newCases); } @Override @@ -519,14 +519,14 @@ public Node leaveWhileNode(final WhileNode whileNode) { final Node test = whileNode.getTest(); if (test != null) { - return whileNode.setTest(getLexicalContext(), convert(test, Type.BOOLEAN)); + return whileNode.setTest(lc, convert(test, Type.BOOLEAN)); } return whileNode; } @Override public Node leaveWithNode(final WithNode withNode) { - return withNode.setExpression(getLexicalContext(), convert(withNode.getExpression(), Type.OBJECT)); + return withNode.setExpression(lc, convert(withNode.getExpression(), Type.OBJECT)); } private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) { @@ -550,7 +550,6 @@ return; // nothing to do } - final LexicalContext lc = getLexicalContext(); final FunctionNode functionNode = lc.getFunction(block); final boolean allVarsInScope = functionNode.allVarsInScope(); final boolean isVarArg = functionNode.isVarArg(); @@ -652,7 +651,7 @@ private static void setCanBePrimitive(final Node node, final Type to) { final HashSet exclude = new HashSet<>(); - node.accept(new NodeVisitor() { + node.accept(new NodeVisitor(new LexicalContext()) { private void setCanBePrimitive(final Symbol symbol) { LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol)); symbol.setCanBePrimitive(to); @@ -762,7 +761,7 @@ } } LOG.info("Type override for lhs in '", node, "' => ", to); - return ((TypeOverride)node).setType(temporarySymbols, getLexicalContext(), to); + return ((TypeOverride)node).setType(temporarySymbols, lc, to); } /** @@ -785,8 +784,8 @@ private Node convert(final Node node, final Type to) { assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass(); assert node != null : "node is null"; - assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction(); - assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction(); + assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction(); + assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + lc.getCurrentFunction(); final Type from = node.getType(); @@ -800,7 +799,7 @@ Node resultNode = node; - if (node instanceof LiteralNode && !to.isObject()) { + if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) { final LiteralNode newNode = new LiteralNodeConstantEvaluator((LiteralNode)node, to).eval(); if (newNode != null) { resultNode = newNode; @@ -817,7 +816,6 @@ assert !node.isTerminal(); - final LexicalContext lc = getLexicalContext(); //This is the only place in this file that can create new temporaries //FinalizeTypes may not introduce ANY node that is not a conversion. return temporarySymbols.ensureSymbol(lc, to, resultNode); @@ -854,7 +852,7 @@ symbol = symbol.setTypeOverrideShared(to, temporarySymbols); LOG.info("Type override for temporary in '", node, "' => ", to); } - return node.setSymbol(getLexicalContext(), symbol); + return node.setSymbol(lc, symbol); } /** @@ -907,7 +905,7 @@ if (literalNode != null) { //inherit literal symbol for attr. - literalNode = (LiteralNode)literalNode.setSymbol(getLexicalContext(), parent.getSymbol()); + literalNode = (LiteralNode)literalNode.setSymbol(lc, parent.getSymbol()); } return literalNode; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java --- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Wed May 29 16:59:55 2013 -0700 @@ -33,7 +33,9 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IfNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.UnaryNode; @@ -45,11 +47,12 @@ /** * Simple constant folding pass, executed before IR is starting to be lowered. */ -final class FoldConstants extends NodeVisitor { +final class FoldConstants extends NodeVisitor { private static final DebugLogger LOG = new DebugLogger("fold"); FoldConstants() { + super(new LexicalContext()); } @Override @@ -79,7 +82,7 @@ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { - return functionNode.setState(getLexicalContext(), CompilationState.CONSTANT_FOLDED); + return functionNode.setState(lc, CompilationState.CONSTANT_FOLDED); } @Override @@ -141,6 +144,10 @@ return null; } + if (rhsNode instanceof ArrayLiteralNode) { + return null; + } + final LiteralNode rhs = (LiteralNode)rhsNode; final boolean rhsInteger = rhs.getType().isInteger(); @@ -212,6 +219,10 @@ final LiteralNode lhs = (LiteralNode)parent.lhs(); final LiteralNode rhs = (LiteralNode)parent.rhs(); + if (lhs instanceof ArrayLiteralNode || rhs instanceof ArrayLiteralNode) { + return null; + } + final Type widest = Type.widest(lhs.getType(), rhs.getType()); boolean isInteger = widest.isInteger(); @@ -279,9 +290,9 @@ isLong &= value != 0.0 && JSType.isRepresentableAsLong(value); if (isInteger) { - return LiteralNode.newInstance(token, finish, JSType.toInt32(value)); + return LiteralNode.newInstance(token, finish, (int)value); } else if (isLong) { - return LiteralNode.newInstance(token, finish, JSType.toLong(value)); + return LiteralNode.newInstance(token, finish, (long)value); } return LiteralNode.newInstance(token, finish, value); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/Lower.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Wed May 29 16:59:55 2013 -0700 @@ -80,7 +80,7 @@ * finalized. */ -final class Lower extends NodeOperatorVisitor { +final class Lower extends NodeOperatorVisitor { private static final DebugLogger LOG = new DebugLogger("lower"); @@ -105,7 +105,7 @@ terminated = true; } } else { - statement.accept(new NodeVisitor() { + statement.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterVarNode(final VarNode varNode) { newStatements.add(varNode.setInit(null)); @@ -121,7 +121,6 @@ @Override public boolean enterBlock(final Block block) { - final LexicalContext lc = getLexicalContext(); final FunctionNode function = lc.getCurrentFunction(); if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) { new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); @@ -134,12 +133,10 @@ //now we have committed the entire statement list to the block, but we need to truncate //whatever is after the last terminal. block append won't append past it - final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext(); - Statement last = lc.getLastStatement(); if (lc.isFunctionBody()) { - final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunction = lc.getCurrentFunction(); final boolean isProgram = currentFunction.isProgram(); final ReturnNode returnNode = new ReturnNode( last == null ? block.getLineNumber() : last.getLineNumber(), //TODO? @@ -191,7 +188,7 @@ final Node expr = executeNode.getExpression(); ExecuteNode node = executeNode; - final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunction = lc.getCurrentFunction(); if (currentFunction.isProgram()) { if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function @@ -216,7 +213,7 @@ final Node test = forNode.getTest(); if (!forNode.isForIn() && conservativeAlwaysTrue(test)) { - newForNode = forNode.setTest(getLexicalContext(), null); + newForNode = forNode.setTest(lc, null); } return addStatement(checkEscape(newForNode)); @@ -230,7 +227,7 @@ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { LOG.info("END FunctionNode: ", functionNode.getName()); - return functionNode.setState(getLexicalContext(), CompilationState.LOWERED); + return functionNode.setState(lc, CompilationState.LOWERED); } @Override @@ -261,19 +258,25 @@ return throwNode; } - private static Node ensureUniqueLabelsIn(final Node node) { - return node.accept(new NodeVisitor() { - @Override - public Node leaveDefault(final Node labelledNode) { - return labelledNode.ensureUniqueLabels(getLexicalContext()); - } + private static Node ensureUniqueNamesIn(final LexicalContext lc, final Node node) { + return node.accept(new NodeVisitor(new LexicalContext()) { + @Override + public Node leaveFunctionNode(final FunctionNode functionNode) { + final String name = functionNode.getName(); + return functionNode.setName(lc, lc.getCurrentFunction().uniqueName(name)); + } + + @Override + public Node leaveDefault(final Node labelledNode) { + return labelledNode.ensureUniqueLabels(lc); + } }); } - private static List copyFinally(final Block finallyBody) { + private static List copyFinally(final LexicalContext lc, final Block finallyBody) { final List newStatements = new ArrayList<>(); for (final Statement statement : finallyBody.getStatements()) { - newStatements.add((Statement)ensureUniqueLabelsIn(statement)); + newStatements.add((Statement)ensureUniqueNamesIn(lc, statement)); if (statement.hasTerminalFlags()) { return newStatements; } @@ -286,12 +289,12 @@ final long token = tryNode.getToken(); final int finish = tryNode.getFinish(); - final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all")); + final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all")); - final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))). - setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal + final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)). + setIsTerminal(lc, true); //ends with throw, so terminal - final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody); + final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW); final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode); //catchallblock -> catchallnode (catchnode) -> exception -> throw @@ -300,7 +303,7 @@ } private IdentNode compilerConstant(final CompilerConstants cc) { - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode functionNode = lc.getCurrentFunction(); return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); } @@ -316,11 +319,10 @@ * @return new try node after splicing finally code (same if nop) */ private Node spliceFinally(final TryNode tryNode, final List rethrows, final Block finallyBody) { - final int finish = tryNode.getFinish(); + assert tryNode.getFinallyBody() == null; + final int finish = tryNode.getFinish(); - assert tryNode.getFinallyBody() == null; - - final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor() { + final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor(new LexicalContext()) { final List insideTry = new ArrayList<>(); @Override @@ -338,7 +340,7 @@ @Override public Node leaveThrowNode(final ThrowNode throwNode) { if (rethrows.contains(throwNode)) { - final List newStatements = copyFinally(finallyBody); + final List newStatements = copyFinally(lc, finallyBody); if (!isTerminal(newStatements)) { newStatements.add(throwNode); } @@ -349,12 +351,12 @@ @Override public Node leaveBreakNode(final BreakNode breakNode) { - return copy(breakNode, Lower.this.getLexicalContext().getBreakable(breakNode.getLabel())); + return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel())); } @Override public Node leaveContinueNode(final ContinueNode continueNode) { - return copy(continueNode, Lower.this.getLexicalContext().getContinueTo(continueNode.getLabel())); + return copy(continueNode, Lower.this.lc.getContinueTo(continueNode.getLabel())); } @Override @@ -372,17 +374,17 @@ resultNode = null; } - newStatements.addAll(copyFinally(finallyBody)); + newStatements.addAll(copyFinally(lc, finallyBody)); if (!isTerminal(newStatements)) { newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); } - return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements)); + return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements)); } private Node copy(final Statement endpoint, final Node targetNode) { if (!insideTry.contains(targetNode)) { - final List newStatements = copyFinally(finallyBody); + final List newStatements = copyFinally(lc, finallyBody); if (!isTerminal(newStatements)) { newStatements.add(endpoint); } @@ -436,7 +438,7 @@ final Block catchAll = catchAllBlock(tryNode); final List rethrows = new ArrayList<>(); - catchAll.accept(new NodeVisitor() { + catchAll.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterThrowNode(final ThrowNode throwNode) { rethrows.add(throwNode); @@ -464,7 +466,7 @@ @Override public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); - if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) { + if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) { new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); } return varNode; @@ -478,7 +480,7 @@ if (conservativeAlwaysTrue(test)) { //turn it into a for node without a test. final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this); - getLexicalContext().replace(whileNode, forNode); + lc.replace(whileNode, forNode); return forNode; } @@ -513,7 +515,7 @@ * @return eval location */ private String evalLocation(final IdentNode node) { - final Source source = getLexicalContext().getCurrentFunction().getSource(); + final Source source = lc.getCurrentFunction().getSource(); return new StringBuilder(). append(source.getName()). append('#'). @@ -545,10 +547,10 @@ // 'eval' call with at least one argument if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) { - final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunction = lc.getCurrentFunction(); return callNode.setEvalArgs( new CallNode.EvalArgs( - ensureUniqueLabelsIn(args.get(0)).accept(this), + ensureUniqueNamesIn(lc, args.get(0)).accept(this), compilerConstant(THIS), evalLocation(callee), currentFunction.isStrict())); @@ -574,7 +576,7 @@ private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) { final List escapes = new ArrayList<>(); - loopBody.accept(new NodeVisitor() { + loopBody.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveBreakNode(final BreakNode node) { escapes.add(node); @@ -595,7 +597,6 @@ } private LoopNode checkEscape(final LoopNode loopNode) { - final LexicalContext lc = getLexicalContext(); final boolean escapes = controlFlowEscapes(lc, loopNode.getBody()); if (escapes) { return loopNode. @@ -607,7 +608,7 @@ private Node addStatement(final Statement statement) { - ((BlockLexicalContext)getLexicalContext()).appendStatement(statement); + lc.appendStatement(statement); return statement; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java --- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed May 29 16:59:55 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()); } } - } } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.codegen; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import jdk.nashorn.internal.codegen.types.Range; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.Assignment; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.ForNode; +import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.LexicalContext; +import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; +import jdk.nashorn.internal.ir.LoopNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.RuntimeNode; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.ir.VarNode; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.DebugLogger; + +/** + * Range analysis and narrowing of type where it can be proven + * that there is no spillover, e.g. + * + * function func(c) { + * var v = c & 0xfff; + * var w = c & 0xeee; + * var x = v * w; + * return x; + * } + * + * Proves that the multiplication never exceeds 24 bits and can thus be an int + */ +final class RangeAnalyzer extends NodeOperatorVisitor { + static final DebugLogger LOG = new DebugLogger("ranges"); + + private static final Range.Functionality RANGE = new Range.Functionality(LOG); + + private final Map loopCounters = new HashMap<>(); + + RangeAnalyzer() { + super(new LexicalContext()); + } + + @Override + public boolean enterForNode(final ForNode forNode) { + //conservatively attempt to identify the loop counter. Null means that it wasn't + //properly identified and that no optimizations can be made with it - its range is + //simply unknown in that case, if it is assigned in the loop + final Symbol counter = findLoopCounter(forNode); + LOG.fine("Entering forNode " + forNode + " counter = " + counter); + if (counter != null && !assignedInLoop(forNode, counter)) { + loopCounters.put(forNode, counter); + } + return true; + } + + //destination visited + private Symbol setRange(final Node dest, final Range range) { + if (range.isUnknown()) { + return null; + } + + final Symbol symbol = dest.getSymbol(); + assert symbol != null : dest + " " + dest.getClass() + " has no symbol"; + assert symbol.getRange() != null : symbol + " has no range"; + final Range symRange = RANGE.join(symbol.getRange(), range); + + //anything assigned in the loop, not being the safe loop counter(s) invalidates its entire range + if (lc.inLoop() && !isLoopCounter(lc.getCurrentLoop(), symbol)) { + symbol.setRange(Range.createGenericRange()); + return symbol; + } + + if (!symRange.equals(symbol.getRange())) { + LOG.fine("Modify range for " + dest + " " + symbol + " from " + symbol.getRange() + " to " + symRange + " (in node = " + dest + ")" ); + symbol.setRange(symRange); + } + + return null; + } + + @Override + public Node leaveADD(final BinaryNode node) { + setRange(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSUB(final BinaryNode node) { + setRange(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveMUL(final BinaryNode node) { + setRange(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveDIV(final BinaryNode node) { + setRange(node, RANGE.div(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveMOD(final BinaryNode node) { + setRange(node, RANGE.mod(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveBIT_AND(final BinaryNode node) { + setRange(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveBIT_OR(final BinaryNode node) { + setRange(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveBIT_XOR(final BinaryNode node) { + setRange(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSAR(final BinaryNode node) { + setRange(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSHL(final BinaryNode node) { + setRange(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSHR(final BinaryNode node) { + setRange(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + private Node leaveCmp(final BinaryNode node) { + setRange(node, Range.createTypeRange(Type.BOOLEAN)); + return node; + } + + @Override + public Node leaveEQ(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveEQ_STRICT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveNE(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveNE_STRICT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveLT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveLE(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveGT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveGE(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveASSIGN(final BinaryNode node) { + Range range = node.rhs().getSymbol().getRange(); + if (range.isUnknown()) { + range = Range.createGenericRange(); + } + + setRange(node.lhs(), range); + setRange(node, range); + + return node; + } + + private Node leaveSelfModifyingAssign(final BinaryNode node, final Range range) { + setRange(node.lhs(), range); + setRange(node, range); + return node; + } + + private Node leaveSelfModifyingAssign(final UnaryNode node, final Range range) { + setRange(node.rhs(), range); + setRange(node, range); + return node; + } + + @Override + public Node leaveASSIGN_ADD(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SUB(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_MUL(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_DIV(final BinaryNode node) { + return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER)); + } + + @Override + public Node leaveASSIGN_MOD(final BinaryNode node) { + return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER)); + } + + @Override + public Node leaveASSIGN_BIT_AND(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_BIT_OR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_BIT_XOR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SAR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SHR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SHL(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveDECINC(final UnaryNode node) { + switch (node.tokenType()) { + case DECPREFIX: + case DECPOSTFIX: + return leaveSelfModifyingAssign(node, RANGE.sub(node.rhs().getSymbol().getRange(), Range.createRange(1))); + case INCPREFIX: + case INCPOSTFIX: + return leaveSelfModifyingAssign(node, RANGE.add(node.rhs().getSymbol().getRange(), Range.createRange(1))); + default: + assert false; + return node; + } + } + + @Override + public Node leaveADD(final UnaryNode node) { + Range range = node.rhs().getSymbol().getRange(); + if (!range.getType().isNumeric()) { + range = Range.createTypeRange(Type.NUMBER); + } + setRange(node, range); + return node; + } + + @Override + public Node leaveBIT_NOT(final UnaryNode node) { + setRange(node, Range.createTypeRange(Type.INT)); + return node; + } + + @Override + public Node leaveNOT(final UnaryNode node) { + setRange(node, Range.createTypeRange(Type.BOOLEAN)); + return node; + } + + @Override + public Node leaveSUB(final UnaryNode node) { + setRange(node, RANGE.neg(node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveVarNode(final VarNode node) { + if (node.isAssignment()) { + Range range = node.getInit().getSymbol().getRange(); + range = range.isUnknown() ? Range.createGenericRange() : range; + + setRange(node.getName(), range); + setRange(node, range); + } + + return node; + } + + @SuppressWarnings("rawtypes") + @Override + public boolean enterLiteralNode(final LiteralNode node) { + // ignore array literals + return !(node instanceof ArrayLiteralNode); + } + + @Override + public Node leaveLiteralNode(@SuppressWarnings("rawtypes") final LiteralNode node) { + if (node.getType().isInteger()) { + setRange(node, Range.createRange(node.getInt32())); + } else if (node.getType().isNumber()) { + setRange(node, Range.createRange(node.getNumber())); + } else if (node.getType().isLong()) { + setRange(node, Range.createRange(node.getLong())); + } else if (node.getType().isBoolean()) { + setRange(node, Range.createTypeRange(Type.BOOLEAN)); + } else { + setRange(node, Range.createGenericRange()); + } + return node; + } + + @Override + public boolean enterRuntimeNode(final RuntimeNode node) { + // a runtime node that cannot be specialized is no point entering + return node.getRequest().canSpecialize(); + } + + /** + * Check whether a symbol is unsafely assigned in a loop - i.e. repeteadly assigned and + * not being identified as the loop counter. That means we don't really know anything + * about its range. + * @param loopNode loop node + * @param symbol symbol + * @return true if assigned in loop + */ + // TODO - this currently checks for nodes only - needs to be augmented for while nodes + // assignment analysis is also very conservative + private static boolean assignedInLoop(final LoopNode loopNode, final Symbol symbol) { + final HashSet skip = new HashSet<>(); + final HashSet assignmentsInLoop = new HashSet<>(); + + loopNode.accept(new NodeVisitor(new LexicalContext()) { + private boolean assigns(final Node node, final Symbol s) { + return node.isAssignment() && ((Assignment)node).getAssignmentDest().getSymbol() == s; + } + + @Override + public boolean enterForNode(final ForNode forNode) { + if (forNode.getInit() != null) { + skip.add(forNode.getInit()); + } + if (forNode.getModify() != null) { + skip.add(forNode.getModify()); + } + return true; + } + + @Override + public Node leaveDefault(final Node node) { + //if this is an assignment to symbol + if (!skip.contains(node) && assigns(node, symbol)) { + assignmentsInLoop.add(node); + } + return node; + } + }); + + return !assignmentsInLoop.isEmpty(); + } + + /** + * Check for a loop counter. This is currently quite conservative, in that it only handles + * x <= counter and x < counter. + * + * @param node loop node to check + * @return + */ + private static Symbol findLoopCounter(final LoopNode node) { + final Node test = node.getTest(); + + if (test != null && test.isComparison()) { + final BinaryNode binaryNode = (BinaryNode)test; + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + //detect ident cmp int_literal + if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode)rhs).getType().isInteger()) { + final Symbol symbol = lhs.getSymbol(); + final int margin = ((LiteralNode)rhs).getInt32(); + final TokenType op = test.tokenType(); + + switch (op) { + case LT: + case LE: + symbol.setRange(RANGE.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin))); + return symbol; + case GT: + case GE: + //setRange(lhs, Range.createRange(op == TokenType.GT ? margin + 1 : margin)); + //return symbol; + default: + break; + } + } + } + + return null; + } + + private boolean isLoopCounter(final LoopNode loopNode, final Symbol symbol) { + //this only works if loop nodes aren't replaced by other ones during this transform, but they are not + return loopCounters.get(loopNode) == symbol; + } +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java --- a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java Wed May 29 16:59:55 2013 -0700 @@ -116,9 +116,10 @@ /** * Generate the invoke instruction for this shared scope call. * @param method the method emitter + * @return the method emitter */ - public void generateInvoke(final MethodEmitter method) { - method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); + public MethodEmitter generateInvoke(final MethodEmitter method) { + return method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/Splitter.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Wed May 29 16:59:55 2013 -0700 @@ -49,12 +49,12 @@ /** * Split the IR into smaller compile units. */ -final class Splitter extends NodeVisitor { +final class Splitter extends NodeVisitor { /** Current compiler. */ private final Compiler compiler; /** IR to be broken down. */ - private FunctionNode outermost; + private final FunctionNode outermost; /** Compile unit for the main script. */ private final CompileUnit outermostCompileUnit; @@ -75,6 +75,7 @@ * @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit */ public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { + super(new LexicalContext()); this.compiler = compiler; this.outermost = functionNode; this.outermostCompileUnit = outermostCompileUnit; @@ -93,8 +94,6 @@ LOG.finest("Initiating split of '", functionNode.getName(), "'"); - final LexicalContext lc = getLexicalContext(); - long weight = WeighNodes.weigh(functionNode); final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost; @@ -127,7 +126,7 @@ final Block body = functionNode.getBody(); final List dc = directChildren(functionNode); - final Block newBody = (Block)body.accept(new NodeVisitor() { + final Block newBody = (Block)body.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterFunctionNode(final FunctionNode nestedFunction) { return dc.contains(nestedFunction); @@ -136,7 +135,7 @@ @Override public Node leaveFunctionNode(final FunctionNode nestedFunction) { FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction); - getLexicalContext().replace(nestedFunction, split); + lc.replace(nestedFunction, split); return split; } }); @@ -149,13 +148,13 @@ private static List directChildren(final FunctionNode functionNode) { final List dc = new ArrayList<>(); - functionNode.accept(new NodeVisitor() { + functionNode.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterFunctionNode(final FunctionNode child) { if (child == functionNode) { return true; } - if (getLexicalContext().getParentFunction(child) == functionNode) { + if (lc.getParentFunction(child) == functionNode) { dc.add(child); } return false; @@ -181,7 +180,7 @@ * @return new weight for the resulting block. */ private Block splitBlock(final Block block, final FunctionNode function) { - getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); + lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_SPLIT); final List splits = new ArrayList<>(); List statements = new ArrayList<>(); @@ -210,7 +209,7 @@ splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); } - return block.setStatements(getLexicalContext(), splits); + return block.setStatements(lc, splits); } /** @@ -258,7 +257,7 @@ // been split already, so weigh again before splitting. long weight = WeighNodes.weigh(block, weightCache); if (weight >= SPLIT_THRESHOLD) { - newBlock = splitBlock(block, getLexicalContext().getFunction(block)); + newBlock = splitBlock(block, lc.getFunction(block)); weight = WeighNodes.weigh(newBlock, weightCache); } weightCache.put(newBlock, weight); @@ -274,9 +273,9 @@ return literal; } - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode functionNode = lc.getCurrentFunction(); - getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT); + lc.setFlag(functionNode, FunctionNode.IS_SPLIT); if (literal instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java --- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Wed May 29 16:59:55 2013 -0700 @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; @@ -41,6 +42,7 @@ import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; @@ -63,7 +65,7 @@ * Computes the "byte code" weight of an AST segment. This is used * for Splitting too large class files */ -final class WeighNodes extends NodeOperatorVisitor { +final class WeighNodes extends NodeOperatorVisitor { /* * Weight constants. */ @@ -100,7 +102,7 @@ * @param weightCache cache of already calculated block weights */ private WeighNodes(FunctionNode topFunction, final Map weightCache) { - super(); + super(new LexicalContext()); this.topFunction = topFunction; this.weightCache = weightCache; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/types/Range.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Range.java Wed May 29 16:59:55 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 results = + Arrays.asList( + lhs.getMin() * rhs.getMin(), + lhs.getMin() * rhs.getMax(), + lhs.getMax() * rhs.getMin(), + lhs.getMax() * rhs.getMax()); + return createIntegerRange(Collections.min(results), Collections.max(results)); + } + } + + if (a.getType().isNumeric() && b.getType().isNumeric()) { + return createNumberRange(); + } + + return createGenericRange(); + } + + /** + * Neg operation + * @param a range of value symbol to be negated + * @return resulting range representing the value range after neg + */ + public Range neg(final Range a) { + if (a.isIntegerType()) { + final IntegerRange rhs = (IntegerRange)a; + if (rhs.getMin() != Long.MIN_VALUE && rhs.getMax() != Long.MIN_VALUE) { + return createIntegerRange(-rhs.getMax(), -rhs.getMin()); + } + } + + if (a.getType().isNumeric()) { + return createNumberRange(); + } + + return createGenericRange(); + } + + /** + * Bitwise and operation + * @param a range of first symbol to be and:ed + * @param b range of second symbol to be and:ed + * @return resulting range representing the value range after and + */ + public Range and(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final int resultMask = (int) (((IntegerRange)a).getBitMask() & ((IntegerRange)b).getBitMask()); + if (resultMask >= 0) { + return createIntegerRange(0, resultMask); + } + } else if (a.isUnknown() && b.isIntegerType()) { + final long operandMask = ((IntegerRange)b).getBitMask(); + if (operandMask >= 0) { + return createIntegerRange(0, operandMask); + } + } else if (a.isIntegerType() && b.isUnknown()) { + final long operandMask = ((IntegerRange)a).getBitMask(); + if (operandMask >= 0) { + return createIntegerRange(0, operandMask); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise or operation + * @param a range of first symbol to be or:ed + * @param b range of second symbol to be or:ed + * @return resulting range representing the value range after or + */ + public Range or(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask()); + if (resultMask >= 0) { + return createIntegerRange(0, resultMask); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise xor operation + * @param a range of first symbol to be xor:ed + * @param b range of second symbol to be xor:ed + * @return resulting range representing the value range after and + */ + public Range xor(final Range a, final Range b) { + if (a.isIntegerConst() && b.isIntegerConst()) { + return createRange(((IntegerRange)a).getMin() ^ ((IntegerRange)b).getMin()); + } + + if (a.isIntegerType() && b.isIntegerType()) { + final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask()); + if (resultMask >= 0) { + return createIntegerRange(0, createIntegerRange(0, resultMask).getBitMask()); + } + } + return createTypeRange(Type.INT); + } + + /** + * Bitwise shl operation + * @param a range of first symbol to be shl:ed + * @param b range of second symbol to be shl:ed + * @return resulting range representing the value range after shl + */ + public Range shl(final Range a, final Range b) { + if (b.isIntegerType() && b.isIntegerConst()) { + final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); + final int shift = (int)((IntegerRange) b).getMin() & 0x1f; + final int min = (int)left.getMin() << shift; + final int max = (int)left.getMax() << shift; + if (min >> shift == left.getMin() && max >> shift == left.getMax()) { + return createIntegerRange(min, max); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise shr operation + * @param a range of first symbol to be shr:ed + * @param b range of second symbol to be shr:ed + * @return resulting range representing the value range after shr + */ + public Range shr(final Range a, final Range b) { + if (b.isIntegerType() && b.isIntegerConst()) { + final long shift = ((IntegerRange) b).getMin() & 0x1f; + final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); + if (left.getMin() >= 0) { + long min = left.getMin() >>> shift; + long max = left.getMax() >>> shift; + return createIntegerRange(min, max); + } else if (shift >= 1) { + return createIntegerRange(0, JSType.MAX_UINT >>> shift); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise sar operation + * @param a range of first symbol to be sar:ed + * @param b range of second symbol to be sar:ed + * @return resulting range representing the value range after sar + */ + public Range sar(final Range a, final Range b) { + if (b.isIntegerType() && b.isIntegerConst()) { + final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); + final long shift = ((IntegerRange) b).getMin() & 0x1f; + final long min = left.getMin() >> shift; + final long max = left.getMax() >> shift; + return createIntegerRange(min, max); + } + + return createTypeRange(Type.INT); + } + + /** + * Modulo operation + * @param a range of first symbol to the mod operation + * @param b range of second symbol to be mod operation + * @return resulting range representing the value range after mod + */ + public Range mod(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final IntegerRange rhs = (IntegerRange) b; + if (rhs.getMin() > 0 || rhs.getMax() < 0) { // divisor range must not include 0 + final long absmax = Math.max(Math.abs(rhs.getMin()), Math.abs(rhs.getMax())) - 1; + return createIntegerRange(rhs.getMin() > 0 ? 0 : -absmax, rhs.getMax() < 0 ? 0 : +absmax); + } + } + return createTypeRange(Type.NUMBER); + } + + /** + * Division operation + * @param a range of first symbol to the division + * @param b range of second symbol to be division + * @return resulting range representing the value range after division + */ + public Range div(final Range a, final Range b) { + // TODO + return createTypeRange(Type.NUMBER); + } + } + + /** + * Simple trace functionality that will log range creation + */ + public static class TraceFunctionality extends Functionality { + TraceFunctionality(final DebugLogger log) { + super(log); + } + + private Range trace(final Range result, final String operation, final Range... operands) { + log.fine("range::" + operation + Arrays.toString(operands) + " => " + result); + return result; + } + + @Override + public Range join(final Range a, final Range b) { + final Range result = super.join(a, b); + if (!a.equals(b)) { + trace(result, "join", a, b); + } + return result; + } + + @Override + public Range add(final Range a, final Range b) { + return trace(super.add(a, b), "add", a, b); + } + + @Override + public Range sub(final Range a, final Range b) { + return trace(super.sub(a, b), "sub", a, b); + } + + @Override + public Range mul(final Range a, final Range b) { + return trace(super.mul(a, b), "mul", a, b); + } + + @Override + public Range neg(final Range a) { + return trace(super.neg(a), "neg", a); + } + + @Override + public Range and(final Range a, final Range b) { + return trace(super.and(a, b), "and", a, b); + } + + @Override + public Range or(final Range a, final Range b) { + return trace(super.or(a, b), "or", a, b); + } + + @Override + public Range xor(final Range a, final Range b) { + return trace(super.xor(a, b), "xor", a, b); + } + + @Override + public Range shl(final Range a, final Range b) { + return trace(super.shl(a, b), "shl", a, b); + } + + @Override + public Range shr(final Range a, final Range b) { + return trace(super.shr(a, b), "shr", a, b); + } + + @Override + public Range sar(final Range a, final Range b) { + return trace(super.sar(a, b), "sar", a, b); + } + + @Override + public Range mod(final Range a, final Range b) { + return trace(super.mod(a, b), "mod", a, b); + } + + @Override + public Range div(final Range a, final Range b) { + return trace(super.div(a, b), "div", a, b); + } + } + + @Override + public String toString() { + return String.valueOf(getType()); + } + + @SuppressWarnings("unused") + private static boolean isRepresentableAsInt(final double number) { + return (int)number == number && !isNegativeZero(number); + } + + private static boolean isRepresentableAsLong(final double number) { + return (long)number == number && !isNegativeZero(number); + } + + private static boolean isNegativeZero(final double number) { + return Double.doubleToLongBits(number) == Double.doubleToLongBits(-0.0); + } +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/codegen/types/Type.java --- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java Wed May 29 16:59:55 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 */ diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/AccessNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Wed May 29 16:59:55 2013 -0700 @@ -60,7 +60,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterAccessNode(this)) { return visitor.leaveAccessNode( setBase(base.accept(visitor)). @@ -110,7 +110,6 @@ return new AccessNode(this, base, property, isFunction(), hasCallSiteType()); } - private AccessNode setProperty(final IdentNode property) { if (this.property == property) { return this; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Wed May 29 16:59:55 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 @@ -143,7 +160,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterBinaryNode(this)) { return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/Block.java --- a/nashorn/src/jdk/nashorn/internal/ir/Block.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java Wed May 29 16:59:55 2013 -0700 @@ -131,7 +131,7 @@ * @return new or same node */ @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterBlock(this)) { return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/BreakNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java Wed May 29 16:59:55 2013 -0700 @@ -59,7 +59,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterBreakNode(this)) { return visitor.leaveBreakNode(this); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/CallNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Wed May 29 16:59:55 2013 -0700 @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -194,7 +195,7 @@ * @return node or replacement */ @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterCallNode(this)) { final CallNode newCallNode = (CallNode)visitor.leaveCallNode( setFunction(function.accept(visitor)). diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/CaseNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java Wed May 29 16:59:55 2013 -0700 @@ -78,7 +78,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterCaseNode(this)) { final Node newTest = test == null ? null : test.accept(visitor); final Block newBody = body == null ? null : (Block)body.accept(visitor); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/CatchNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Wed May 29 16:59:55 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; } /** @@ -71,7 +79,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterCatchNode(this)) { return visitor.leaveCatchNode( setException((IdentNode)exception.accept(visitor)). @@ -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; + } + } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java Wed May 29 16:59:55 2013 -0700 @@ -55,7 +55,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterContinueNode(this)) { return visitor.leaveContinueNode(this); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java Wed May 29 16:59:55 2013 -0700 @@ -56,7 +56,7 @@ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterEmptyNode(this)) { return visitor.leaveEmptyNode(this); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java Wed May 29 16:59:55 2013 -0700 @@ -62,7 +62,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterExecuteNode(this)) { return visitor.leaveExecuteNode(setExpression(expression.accept(visitor))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/ForNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java Wed May 29 16:59:55 2013 -0700 @@ -86,7 +86,7 @@ } @Override - protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { + protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterForNode(this)) { return visitor.leaveForNode( setInit(lc, init == null ? null : init.accept(visitor)). diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Wed May 29 16:59:55 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, @@ -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; @@ -280,7 +281,7 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterFunctionNode(this)) { return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor))); } @@ -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 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)); } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/IdentNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Wed May 29 16:59:55 2013 -0700 @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__; import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; - import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -119,7 +118,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterIdentNode(this)) { return visitor.leaveIdentNode(this); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/IfNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/IfNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/IfNode.java Wed May 29 16:59:55 2013 -0700 @@ -72,7 +72,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterIfNode(this)) { return visitor.leaveIfNode( setTest(test.accept(visitor)). diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/IndexNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Wed May 29 16:59:55 2013 -0700 @@ -56,19 +56,12 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterIndexNode(this)) { - final Node newBase = base.accept(visitor); - final Node newIndex = index.accept(visitor); - final IndexNode newNode; - if (newBase != base || newIndex != index) { - newNode = new IndexNode(this, newBase, newIndex, isFunction(), hasCallSiteType()); - } else { - newNode = this; - } - return visitor.leaveIndexNode(newNode); + return visitor.leaveIndexNode( + setBase(base.accept(visitor)). + setIndex(index.accept(visitor))); } - return this; } @@ -106,6 +99,13 @@ return index; } + private IndexNode setBase(final Node base) { + if (this.base == base) { + return this; + } + return new IndexNode(this, base, index, isFunction(), hasCallSiteType()); + } + /** * Set the index expression for this node * @param index new index expression diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/LabelNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java Wed May 29 16:59:55 2013 -0700 @@ -67,11 +67,11 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterLabelNode(this)) { return visitor.leaveLabelNode( - setLabel(visitor.getLexicalContext(), (IdentNode)label.accept(visitor)). - setBody(visitor.getLexicalContext(), (Block)body.accept(visitor))); + setLabel(lc, (IdentNode)label.accept(visitor)). + setBody(lc, (Block)body.accept(visitor))); } return this; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java --- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Wed May 29 16:59:55 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 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 iter = new NodeIterator<>(LoopNode.class, getCurrentFunction()); - return iter.hasNext() ? iter.next() : null; + return getCurrentLoop(); } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java Wed May 29 16:59:55 2013 -0700 @@ -60,10 +60,10 @@ * * @return new node or same node depending on state change */ - protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor); + protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor); @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { final LexicalContext lc = visitor.getLexicalContext(); lc.push(this); final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Wed May 29 16:59:55 2013 -0700 @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; + import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -208,7 +209,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { return visitor.leaveLiteralNode(this); } @@ -514,7 +515,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { if (value != null) { final Node newValue = value.accept(visitor); @@ -840,7 +841,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { final List oldValue = Arrays.asList(value); final List newValue = Node.accept(visitor, Node.class, oldValue); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/Node.java --- a/nashorn/src/jdk/nashorn/internal/ir/Node.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java Wed May 29 16:59:55 2013 -0700 @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Token; @@ -153,6 +154,14 @@ } /** + * Returns true if this node represents a comparison operator + * @return true if comparison + */ + public boolean isComparison() { + return false; + } + + /** * For reference copies - ensure that labels in the copy node are unique * using an appropriate copy constructor * @param lc lexical context @@ -167,7 +176,7 @@ * @param visitor Node visitor. * @return node the node or its replacement after visitation, null if no further visitations are required */ - public abstract Node accept(NodeVisitor visitor); + public abstract Node accept(NodeVisitor visitor); @Override public String toString() { @@ -329,7 +338,7 @@ } //on change, we have to replace the entire list, that's we can't simple do ListIterator.set - static List accept(final NodeVisitor visitor, final Class clazz, final List list) { + static List accept(final NodeVisitor visitor, final Class clazz, final List list) { boolean changed = false; final List newList = new ArrayList<>(); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java Wed May 29 16:59:55 2013 -0700 @@ -58,7 +58,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterObjectNode(this)) { return visitor.leaveObjectNode(setElements(Node.accept(visitor, Node.class, elements))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java Wed May 29 16:59:55 2013 -0700 @@ -81,7 +81,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterPropertyNode(this)) { return visitor.leavePropertyNode( setKey((PropertyKey)((Node)key).accept(visitor)). diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java Wed May 29 16:59:55 2013 -0700 @@ -86,7 +86,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterReturnNode(this)) { if (expression != null) { return visitor.leaveReturnNode(setExpression(expression.accept(visitor))); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed May 29 16:59:55 2013 -0700 @@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; @@ -407,7 +408,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterRuntimeNode(this)) { final List newArgs = new ArrayList<>(); for (final Node arg : args) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/SplitNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java Wed May 29 16:59:55 2013 -0700 @@ -81,7 +81,7 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterSplitNode(this)) { return visitor.leaveSplitNode(setBody(lc, body.accept(visitor))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java Wed May 29 16:59:55 2013 -0700 @@ -100,11 +100,11 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterSwitchNode(this)) { return visitor.leaveSwitchNode( - setExpression(visitor.getLexicalContext(), expression.accept(visitor)). - setCases(visitor.getLexicalContext(), Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex)); + setExpression(lc, expression.accept(visitor)). + setCases(lc, Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex)); } return this; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/Symbol.java --- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Wed May 29 16:59:55 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 TRACE_SYMBOLS; private static final Set 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 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java Wed May 29 16:59:55 2013 -0700 @@ -63,7 +63,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterTernaryNode(this)) { final Node newLhs = lhs().accept(visitor); final Node newRhs = rhs().accept(visitor); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java Wed May 29 16:59:55 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 @@ -64,7 +72,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterThrowNode(this)) { return visitor.leaveThrowNode(setExpression(expression.accept(visitor))); } @@ -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; } } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/TryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/TryNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java Wed May 29 16:59:55 2013 -0700 @@ -106,7 +106,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterTryNode(this)) { // Need to do finallybody first for termination analysis. TODO still necessary? final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Wed May 29 16:59:55 2013 -0700 @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.parser.TokenType.CONVERT; import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; @@ -121,7 +120,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterUnaryNode(this)) { return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/VarNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Wed May 29 16:59:55 2013 -0700 @@ -121,7 +121,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterVarNode(this)) { final IdentNode newName = (IdentNode)name.accept(visitor); final Node newInit = init == null ? null : init.accept(visitor); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/WhileNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java Wed May 29 16:59:55 2013 -0700 @@ -75,7 +75,7 @@ } @Override - protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { + protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterWhileNode(this)) { if (isDoWhile()) { return visitor.leaveWhileNode( diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/WithNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/WithNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/WithNode.java Wed May 29 16:59:55 2013 -0700 @@ -64,7 +64,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterWithNode(this)) { return visitor.leaveWithNode( setExpression(lc, expression.accept(visitor)). diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java --- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Wed May 29 16:59:55 2013 -0700 @@ -45,6 +45,7 @@ import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.LabelNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; @@ -74,7 +75,8 @@ /** * This IR writer produces a JSON string that represents AST as a JSON string. */ -public final class JSONWriter extends NodeVisitor { +public final class JSONWriter extends NodeVisitor { + /** * Returns AST as JSON compatible string. * @@ -867,7 +869,8 @@ // Internals below private JSONWriter(final boolean includeLocation) { - this.buf = new StringBuilder(); + super(new LexicalContext()); + this.buf = new StringBuilder(); this.includeLocation = includeLocation; } @@ -963,7 +966,7 @@ objectStart("loc"); // source name - final Source src = getLexicalContext().getCurrentFunction().getSource(); + final Source src = lc.getCurrentFunction().getSource(); property("source", src.getName()); comma(); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Wed May 29 16:59:55 2013 -0700 @@ -36,6 +36,7 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.LabelNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.Statement; @@ -53,7 +54,7 @@ * * see the flags --print-parse and --print-lower-parse */ -public final class PrintVisitor extends NodeVisitor { +public final class PrintVisitor extends NodeVisitor { /** Tab width */ private static final int TABWIDTH = 4; @@ -84,6 +85,7 @@ * @param printLineNumbers should line number nodes be included in the output? */ public PrintVisitor(final boolean printLineNumbers) { + super(new LexicalContext()); this.EOLN = System.lineSeparator(); this.sb = new StringBuilder(); this.printLineNumbers = printLineNumbers; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Wed May 29 16:59:55 2013 -0700 @@ -32,21 +32,15 @@ /** * Like NodeVisitor but navigating further into operators. + * @param Lexical context class for this NodeOperatorVisitor */ -public class NodeOperatorVisitor extends NodeVisitor { - /** - * Constructor - */ - public NodeOperatorVisitor() { - super(); - } - +public class NodeOperatorVisitor extends NodeVisitor { /** * Constructor * * @param lc a custom lexical context */ - public NodeOperatorVisitor(final LexicalContext lc) { + public NodeOperatorVisitor(final T lc) { super(lc); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Wed May 29 16:59:55 2013 -0700 @@ -60,23 +60,18 @@ /** * Visitor used to navigate the IR. + * @param lexical context class used by this visitor */ -public abstract class NodeVisitor { - private final LexicalContext lc; - - /** - * Constructor - */ - public NodeVisitor() { - this(new LexicalContext()); - } +public abstract class NodeVisitor { + /** lexical context in use */ + protected final T lc; /** * Constructor * * @param lc a custom lexical context */ - public NodeVisitor(final LexicalContext lc) { + public NodeVisitor(final T lc) { this.lc = lc; } @@ -84,7 +79,7 @@ * Get the lexical context of this node visitor * @return lexical context */ - public LexicalContext getLexicalContext() { + public T getLexicalContext() { return lc; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java --- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java Wed May 29 16:59:55 2013 -0700 @@ -59,11 +59,6 @@ } @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) - public static Object BYTES_PER_ELEMENT(final Object self) { - return ((ArrayBufferView)self).bytesPerElement(); - } - - @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) public static Object buffer(final Object self) { return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).buffer; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/DateParser.java --- a/nashorn/src/jdk/nashorn/internal/objects/DateParser.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/DateParser.java Wed May 29 16:59:55 2013 -0700 @@ -32,6 +32,7 @@ import static java.lang.Character.UPPERCASE_LETTER; import java.util.HashMap; +import java.util.Locale; /** * JavaScript date parser. This class first tries to parse a date string @@ -486,7 +487,7 @@ while (pos < limit && isAsciiLetter(string.charAt(pos))) { pos++; } - final String key = string.substring(start, pos).toLowerCase(); + final String key = string.substring(start, pos).toLowerCase(Locale.ENGLISH); final Name name = names.get(key); // then advance to end of name while (pos < length && isAsciiLetter(string.charAt(pos))) { @@ -683,7 +684,7 @@ Name(final String name, final int type, final int value) { assert name != null; - assert name.equals(name.toLowerCase()); + assert name.equals(name.toLowerCase(Locale.ENGLISH)); this.name = name; // use first three characters as lookup key diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java Wed May 29 16:59:55 2013 -0700 @@ -603,6 +603,11 @@ } } + @Override + public Object getLength() { + return length; + } + private Object getArgumentsLength() { return length; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeArray.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Wed May 29 16:59:55 2013 -0700 @@ -754,25 +754,11 @@ final Object obj = Global.toObject(self); final ScriptObject sobj = (ScriptObject)obj; final long len = JSType.toUint32(sobj.getLength()); - final double startNum = JSType.toNumber(start); - final long relativeStartUint32 = JSType.toUint32(startNum); - final long relativeStart = JSType.toInteger(startNum); - - long k = relativeStart < 0 ? - Math.max(len + relativeStart, 0) : - Math.min( - Math.max(relativeStartUint32, relativeStart), - len); + final long relativeStart = JSType.toLong(start); + final long relativeEnd = (end == ScriptRuntime.UNDEFINED) ? len : JSType.toLong(end); - final double endNum = (end == ScriptRuntime.UNDEFINED)? Double.NaN : JSType.toNumber(end); - final long relativeEndUint32 = (end == ScriptRuntime.UNDEFINED)? len : JSType.toUint32(endNum); - final long relativeEnd = (end == ScriptRuntime.UNDEFINED)? len : JSType.toInteger(endNum); - - final long finale = relativeEnd < 0 ? - Math.max(len + relativeEnd, 0) : - Math.min( - Math.max(relativeEndUint32, relativeEnd), - len); + long k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); + final long finale = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); if (k >= finale) { return new NativeArray(0); @@ -909,21 +895,10 @@ final ScriptObject sobj = (ScriptObject)obj; final boolean strict = Global.isStrict(); final long len = JSType.toUint32(sobj.getLength()); - final double startNum = JSType.toNumber(start); - final long relativeStartUint32 = JSType.toUint32(startNum); - final long relativeStart = JSType.toInteger(startNum); + final long relativeStart = JSType.toLong(start); - //TODO: workaround overflow of relativeStart for start > Integer.MAX_VALUE - final long actualStart = relativeStart < 0 ? - Math.max(len + relativeStart, 0) : - Math.min( - Math.max(relativeStartUint32, relativeStart), - len); - - final long actualDeleteCount = - Math.min( - Math.max(JSType.toInteger(deleteCount), 0), - len - actualStart); + final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); + final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart); final NativeArray array = new NativeArray(actualDeleteCount); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeDate.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java Wed May 29 16:59:55 2013 -0700 @@ -770,7 +770,7 @@ nd.setTime(NaN); return nd.getTime(); } - int yearInt = JSType.toInteger(yearNum); + int yearInt = (int)yearNum; if (0 <= yearInt && yearInt <= 99) { yearInt += 1900; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Wed May 29 16:59:55 2013 -0700 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -38,7 +40,12 @@ */ @ScriptClass("Float32Array") public final class NativeFloat32Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 4; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 4; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Wed May 29 16:59:55 2013 -0700 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -38,7 +40,12 @@ */ @ScriptClass("Float64Array") public final class NativeFloat64Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 8; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 8; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java Wed May 29 16:59:55 2013 -0700 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -37,7 +39,12 @@ */ @ScriptClass("Int16Array") public final class NativeInt16Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 2; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 2; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java Wed May 29 16:59:55 2013 -0700 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -37,7 +39,12 @@ */ @ScriptClass("Int32Array") public final class NativeInt32Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 4; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 4; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java Wed May 29 16:59:55 2013 -0700 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -37,7 +39,12 @@ */ @ScriptClass("Int8Array") public final class NativeInt8Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 1; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 1; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeJava.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Wed May 29 16:59:55 2013 -0700 @@ -30,6 +30,8 @@ import java.lang.reflect.Array; import java.util.Collection; +import java.util.Deque; +import java.util.List; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.internal.objects.annotations.Attribute; @@ -37,6 +39,7 @@ import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.ListAdapter; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; @@ -240,39 +243,56 @@ } /** - * Given a JavaScript array and a Java type, returns a Java array with the same initial contents, and with the - * specified component type. Example: + * Given a script object and a Java type, converts the script object into the desired Java type. Currently it + * performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example: *
          * 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
          * 
    * @param self not used - * @param objArray the JavaScript array. Can be null. - * @param objType either a {@link #type(Object, Object) type object} or a String describing the component type of - * the Java array to create. Can not be null. If undefined, Object is assumed (allowing the argument to be omitted). - * @return a Java array with the copy of JavaScript array's contents, converted to the appropriate Java component - * type. Returns null if objArray is null. + * @param obj the script object. Can be null. + * @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java + * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be + * omitted). + * @return a Java object whose value corresponds to the original script object's value. Specifically, for array + * target types, returns a Java array of the same type with contents converted to the array's component type. Does + * not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper + * around the object, see {@link ListAdapter} for details. Returns null if obj is null. * @throws ClassNotFoundException if the class described by objType is not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object toJavaArray(final Object self, final Object objArray, final Object objType) throws ClassNotFoundException { - final StaticClass componentType = - objType instanceof StaticClass ? - (StaticClass)objType : - objType == UNDEFINED ? - StaticClass.forClass(Object.class) : - type(objType); - - if (objArray == null) { + public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException { + if (obj == null) { return null; } - Global.checkObject(objArray); + Global.checkObject(obj); - return ((ScriptObject)objArray).getArray().asArrayOfType(componentType.getRepresentedClass()); + final Class targetClass; + if(objType == UNDEFINED) { + targetClass = Object[].class; + } else { + final StaticClass targetType; + if(objType instanceof StaticClass) { + targetType = (StaticClass)objType; + } else { + targetType = type(objType); + } + targetClass = targetType.getRepresentedClass(); + } + + if(targetClass.isArray()) { + return ((ScriptObject)obj).getArray().asArrayOfType(targetClass.getComponentType()); + } + + if(targetClass == List.class || targetClass == Deque.class) { + return new ListAdapter((ScriptObject)obj); + } + + throw typeError("unsupported.java.to.type", targetClass.getName()); } /** @@ -283,7 +303,7 @@ *
          * var File = Java.type("java.io.File")
          * var listHomeDir = new File("~").listFiles()
    -     * var jsListHome = Java.toJavaScriptArray(listHomeDir)
    +     * var jsListHome = Java.from(listHomeDir)
          * var jpegModifiedDates = jsListHome
          *     .filter(function(val) { return val.getName().endsWith(".jpg") })
          *     .map(function(val) { return val.lastModified() })
    @@ -294,7 +314,7 @@
          * null.
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    -    public static Object toJavaScriptArray(final Object self, final Object objArray) {
    +    public static Object from(final Object self, final Object objArray) {
             if (objArray == null) {
                 return null;
             } else if (objArray instanceof Collection) {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeMath.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java	Wed May 29 16:59:55 2013 -0700
    @@ -611,13 +611,11 @@
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
         public static Object round(final Object self, final Object x) {
    -        if (GlobalFunctions.isNaN(self, x)) {
    -            return Double.NaN;
    -        } else if (!GlobalFunctions.isFinite(self, x)) {
    -            return x;
    +        final double d = JSType.toNumber(x);
    +        if (Math.getExponent(d) >= 52) {
    +            return d;
             }
    -
    -        return Math.round(JSType.toNumber(x));
    +        return Math.copySign(Math.floor(d + 0.5), d);
         }
     
         /**
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeString.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Wed May 29 16:59:55 2013 -0700
    @@ -38,6 +38,7 @@
     import java.util.Arrays;
     import java.util.LinkedList;
     import java.util.List;
    +import java.util.Locale;
     import jdk.internal.dynalink.CallSiteDescriptor;
     import jdk.internal.dynalink.linker.GuardedInvocation;
     import jdk.internal.dynalink.linker.LinkRequest;
    @@ -630,17 +631,24 @@
     
             final String str       = checkObjectToString(self);
             final String searchStr = JSType.toString(search);
    +        final int length       = str.length();
     
    -        int from;
    +        int end;
     
             if (pos == UNDEFINED) {
    -            from = str.length();
    +            end = length;
             } else {
                 final double numPos = JSType.toNumber(pos);
    -            from = !Double.isNaN(numPos) ? (int)numPos : (int)Double.POSITIVE_INFINITY;
    +            end = Double.isNaN(numPos) ? length : (int)numPos;
    +            if (end < 0) {
    +                end = 0;
    +            } else if (end > length) {
    +                end = length;
    +            }
             }
     
    -        return str.lastIndexOf(searchStr, from);
    +
    +        return str.lastIndexOf(searchStr, end);
         }
     
         /**
    @@ -997,7 +1005,7 @@
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE)
         public static Object toLowerCase(final Object self) {
    -        return checkObjectToString(self).toLowerCase();
    +        return checkObjectToString(self).toLowerCase(Locale.ROOT);
         }
     
         /**
    @@ -1017,7 +1025,7 @@
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE)
         public static Object toUpperCase(final Object self) {
    -        return checkObjectToString(self).toUpperCase();
    +        return checkObjectToString(self).toUpperCase(Locale.ROOT);
         }
     
         /**
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Wed May 29 16:59:55 2013 -0700
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
     
    @@ -37,7 +39,12 @@
      */
     @ScriptClass("Uint16Array")
     public final class NativeUint16Array extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 2;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 2;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Wed May 29 16:59:55 2013 -0700
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.JSType;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
    @@ -38,7 +40,12 @@
      */
     @ScriptClass("Uint32Array")
     public final class NativeUint32Array extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 4;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 4;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteBegin, final int length) {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Wed May 29 16:59:55 2013 -0700
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
     
    @@ -37,7 +39,12 @@
      */
     @ScriptClass("Uint8Array")
     public final class NativeUint8Array extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 1;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 1;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed May 29 16:59:55 2013 -0700
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.JSType;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
    @@ -38,7 +40,12 @@
      */
     @ScriptClass("Uint8ClampedArray")
     public final class NativeUint8ClampedArray extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 1;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 1;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/parser/Parser.java
    --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Wed May 29 16:59:55 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);
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/parser/TokenType.java
    --- a/nashorn/src/jdk/nashorn/internal/parser/TokenType.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/parser/TokenType.java	Wed May 29 16:59:55 2013 -0700
    @@ -25,6 +25,7 @@
     
     package jdk.nashorn.internal.parser;
     
    +import java.util.Locale;
     import static jdk.nashorn.internal.parser.TokenKind.BINARY;
     import static jdk.nashorn.internal.parser.TokenKind.BRACKET;
     import static jdk.nashorn.internal.parser.TokenKind.FUTURE;
    @@ -249,7 +250,7 @@
         }
     
         public String getNameOrType() {
    -        return name == null ? super.name().toLowerCase() : name;
    +        return name == null ? super.name().toLowerCase(Locale.ENGLISH) : name;
         }
     
         public TokenType getNext() {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed May 29 16:59:55 2013 -0700
    @@ -75,7 +75,23 @@
     
         private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
         private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
    -    private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
    +    private static final MethodHandle SPILL_ELEMENT_GETTER;
    +    private static final MethodHandle SPILL_ELEMENT_SETTER;
    +
    +    private static final int SPILL_CACHE_SIZE = 8;
    +    private static final MethodHandle[] SPILL_ACCESSORS = new MethodHandle[SPILL_CACHE_SIZE * 2];
    +
    +    static {
    +        for (int i = 0; i < NOOF_TYPES; i++) {
    +            final Type type = ACCESSOR_TYPES.get(i);
    +            ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
    +            ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
    +        }
    +
    +        final MethodHandle spillGetter = MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class);
    +        SPILL_ELEMENT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, spillGetter);
    +        SPILL_ELEMENT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, spillGetter);
    +    }
     
         /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
         private MethodHandle primitiveGetter;
    @@ -96,14 +112,6 @@
          */
         private Class currentType;
     
    -    static {
    -        for (int i = 0; i < NOOF_TYPES; i++) {
    -            final Type type = ACCESSOR_TYPES.get(i);
    -            ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
    -            ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
    -        }
    -    }
    -
         /**
          * Delegate constructor. This is used when adding properties to the Global scope, which
          * is necessary for outermost levels in a script (the ScriptObject is represented by
    @@ -114,19 +122,31 @@
          * @param delegate  delegate script object to rebind receiver to
          */
         public AccessorProperty(final AccessorProperty property, final ScriptObject delegate) {
    -        this(property);
    -
    -        this.getters = new MethodHandle[NOOF_TYPES];
    +        super(property);
     
    -        this.primitiveGetter = bindTo(primitiveGetter, delegate);
    -        this.primitiveSetter = bindTo(primitiveSetter, delegate);
    -        this.objectGetter    = bindTo(objectGetter, delegate);
    -        this.objectSetter    = bindTo(objectSetter, delegate);
    +        this.primitiveGetter = bindTo(property.primitiveGetter, delegate);
    +        this.primitiveSetter = bindTo(property.primitiveSetter, delegate);
    +        this.objectGetter    = bindTo(property.objectGetter, delegate);
    +        this.objectSetter    = bindTo(property.objectSetter, delegate);
     
             setCurrentType(property.getCurrentType());
         }
     
         /**
    +     * Constructor for spill properties. Array getters and setters will be created on demand.
    +     *
    +     * @param key    the property key
    +     * @param flags  the property flags
    +     * @param slot   spill slot
    +     */
    +    public AccessorProperty(final String key, final int flags, final int slot) {
    +        super(key, flags, slot);
    +        assert (flags & IS_SPILL) == IS_SPILL;
    +
    +        setCurrentType(Object.class);
    +    }
    +
    +    /**
          * Constructor. Similar to the constructor with both primitive getters and setters, the difference
          * here being that only one getter and setter (setter is optional for non writable fields) is given
          * to the constructor, and the rest are created from those. Used e.g. by Nasgen classes
    @@ -268,7 +288,40 @@
         }
     
         @Override
    +    protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict)  {
    +        if (isSpill()) {
    +            self.spill[getSlot()] = value;
    +        } else {
    +            try {
    +                getSetter(Object.class, self.getMap()).invokeExact((Object)self, value);
    +            } catch (final Error|RuntimeException e) {
    +                throw e;
    +            } catch (final Throwable e) {
    +                throw new RuntimeException(e);
    +            }
    +        }
    +    }
    +
    +    @Override
    +    protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
    +        if (isSpill()) {
    +            return self.spill[getSlot()];
    +        }
    +
    +        try {
    +            return getGetter(Object.class).invokeExact((Object)self);
    +        } catch (final Error|RuntimeException e) {
    +            throw e;
    +        } catch (final Throwable e) {
    +            throw new RuntimeException(e);
    +        }
    +    }
    +
    +    @Override
         public MethodHandle getGetter(final Class type) {
    +        if (isSpill() && objectGetter == null) {
    +            objectGetter = getSpillGetter();
    +        }
             final int i = getAccessorTypeIndex(type);
             if (getters[i] == null) {
                 getters[i] = debug(
    @@ -284,7 +337,7 @@
                     "get");
             }
     
    -        return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i];
    +        return getters[i];
         }
     
         private Property getWiderProperty(final Class type) {
    @@ -313,6 +366,9 @@
         }
     
         private MethodHandle generateSetter(final Class forType, final Class type) {
    +        if (isSpill() && objectSetter == null) {
    +            objectSetter = getSpillSetter();
    +        }
             MethodHandle mh = createSetter(forType, type, primitiveSetter, objectSetter);
             mh = MH.asType(mh, ACCESSOR_SETTER_TYPES[getAccessorTypeIndex(type)]); //has to be the case for invokeexact to work in ScriptObject
             mh = debug(mh, currentType, type, "set");
    @@ -343,7 +399,7 @@
                 mh = generateSetter(forType, type);
             }
     
    -        return isSpill() ? MH.filterArguments(mh, 0, SPILLGETTER) : mh;
    +        return mh;
         }
     
         @Override
    @@ -363,6 +419,30 @@
             setCurrentType(newType);
         }
     
    +    private MethodHandle getSpillGetter() {
    +        final int slot = getSlot();
    +        MethodHandle getter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2] : null;
    +        if (getter == null) {
    +            getter = MH.asType(MH.insertArguments(SPILL_ELEMENT_GETTER, 1, slot), Lookup.GET_OBJECT_TYPE);
    +            if (slot < SPILL_CACHE_SIZE) {
    +                SPILL_ACCESSORS[slot * 2] = getter;
    +            }
    +        }
    +        return getter;
    +    }
    +
    +    private MethodHandle getSpillSetter() {
    +        final int slot = getSlot();
    +        MethodHandle setter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2 + 1] : null;
    +        if (setter == null) {
    +            setter = MH.asType(MH.insertArguments(SPILL_ELEMENT_SETTER, 1, slot), Lookup.SET_OBJECT_TYPE);
    +            if (slot < SPILL_CACHE_SIZE) {
    +                SPILL_ACCESSORS[slot * 2 + 1] = setter;
    +            }
    +        }
    +        return setter;
    +    }
    +
         private static void finest(final String str) {
             if (DEBUG_FIELDS) {
                 LOG.finest(str);
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed May 29 16:59:55 2013 -0700
    @@ -35,21 +35,27 @@
      */
     final class CompiledFunction implements Comparable {
     
    +    /** 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 "";
    +        return "";
         }
     
         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;
             }
     
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Wed May 29 16:59:55 2013 -0700
    @@ -35,7 +35,6 @@
      */
     
     public final class DebugLogger {
    -    @SuppressWarnings("NonConstantLogger")
         private final Logger  logger;
         private final boolean isEnabled;
     
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed May 29 16:59:55 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));
             }
         }
     
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java	Wed May 29 16:59:55 2013 -0700
    @@ -153,5 +153,24 @@
             return prototype.isScope();
         }
     
    +    /**
    +     * Get the property value from self as object.
    +     *
    +     * @return the property value
    +     */
    +    public Object getObjectValue() {
    +        return property.getObjectValue(getGetterReceiver(), getOwner());
    +    }
    +
    +    /**
    +     * Set the property value in self.
    +     *
    +     * @param value the new value
    +     * @param strict strict flag
    +     */
    +    public void setObjectValue(final Object value, final boolean strict) {
    +        property.setObjectValue(getSetterReceiver(), getOwner(), value, strict);
    +    }
    +
     }
     
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Wed May 29 16:59:55 2013 -0700
    @@ -30,6 +30,7 @@
     
     import java.lang.invoke.MethodHandle;
     import java.lang.invoke.MethodHandles;
    +import java.util.Locale;
     
     /**
      * Utilities used by Global class.
    @@ -373,10 +374,10 @@
                 } else if (ch < 256) {
                     sb.append('%');
                     final byte b = (byte)ch;
    -                sb.append(Integer.toHexString(b & 0xFF).toUpperCase());
    +                sb.append(Integer.toHexString(b & 0xFF).toUpperCase(Locale.ENGLISH));
                 } else {
                     sb.append("%u");
    -                sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase());
    +                sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase(Locale.ENGLISH));
                 }
             }
     
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Wed May 29 16:59:55 2013 -0700
    @@ -36,6 +36,8 @@
     import jdk.nashorn.internal.parser.JSONParser;
     import jdk.nashorn.internal.parser.TokenType;
     import jdk.nashorn.internal.runtime.linker.Bootstrap;
    +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
    +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
     
     /**
      * Utilities used by "JSON" object implementation.
    @@ -94,7 +96,7 @@
             if (reviver instanceof ScriptFunction) {
                 assert global instanceof GlobalObject;
                 final ScriptObject root = ((GlobalObject)global).newObject();
    -            root.set("", unfiltered, root.isStrictContext());
    +            root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered);
                 return walk(root, "", (ScriptFunction)reviver);
             }
             return unfiltered;
    @@ -115,7 +117,7 @@
                     if (newElement == ScriptRuntime.UNDEFINED) {
                         valueObj.delete(key, strict);
                     } else {
    -                    valueObj.set(key, newElement, strict);
    +                    setPropertyValue(valueObj, key, newElement, strict);
                     }
                 }
             }
    @@ -175,7 +177,9 @@
                     final PropertyNode pNode     = (PropertyNode) elem;
                     final Node         valueNode = pNode.getValue();
     
    -                object.set(pNode.getKeyName(), convertNode(global, valueNode), strict);
    +                final String name = pNode.getKeyName();
    +                final Object value = convertNode(global, valueNode);
    +                setPropertyValue(object, name, value, strict);
                 }
     
                 return object;
    @@ -188,6 +192,21 @@
             }
         }
     
    +    // add a new property if does not exist already, or else set old property
    +    private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value, final boolean strict) {
    +        final int index = getArrayIndexNoThrow(name);
    +        if (isValidArrayIndex(index)) {
    +            // array index key
    +            sobj.defineOwnProperty(index, value);
    +        } else if (sobj.getMap().findProperty(name) != null) {
    +            // pre-existing non-inherited property, call set
    +            sobj.set(name, value, strict);
    +        } else {
    +            // add new property
    +            sobj.addOwnProperty(name, Property.WRITABLE_ENUMERABLE_CONFIGURABLE, value);
    +        }
    +    }
    +
         // does the given IR node represent a numeric array?
         private static boolean isNumericArray(final Node[] values) {
             for (final Node node : values) {
    diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/JSType.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Wed Jul 05 18:57:05 2017 +0200
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Wed May 29 16:59:55 2013 -0700
    @@ -28,6 +28,7 @@
     import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
     import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
     
    +import java.util.Locale;
     import jdk.internal.dynalink.beans.StaticClass;
     import jdk.nashorn.internal.codegen.CompilerConstants.Call;
     import jdk.nashorn.internal.parser.Lexer;
    @@ -111,7 +112,7 @@
          */
         public final String typeName() {
             // For NULL, "object" has to be returned!
    -        return ((this == NULL) ? OBJECT : this).name().toLowerCase();
    +        return ((this == NULL) ? OBJECT : this).name().toLowerCase(Locale.ENGLISH);
         }
     
         /**
    @@ -565,8 +566,11 @@
         }
     
         /**
    -     * JavaScript compliant Object to integer conversion
    -     * See ECMA 9.4 ToInteger
    +     * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
    +     *
    +     * 

    Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE} + * for double values that exceed the int range, including positive and negative Infinity. It is the + * caller's responsibility to handle such values correctly.

    * * @param obj an object * @return an integer @@ -576,8 +580,11 @@ } /** - * JavaScript compliant Object to long conversion - * See ECMA 9.4 ToInteger + * JavaScript compliant Object to long conversion. See ECMA 9.4 ToInteger + * + *

    Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE} + * for double values that exceed the long range, including positive and negative Infinity. It is the + * caller's responsibility to handle such values correctly.

    * * @param obj an object * @return a long diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,337 @@ +package jdk.nashorn.internal.runtime; + +import java.util.AbstractList; +import java.util.Deque; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.RandomAccess; +import jdk.nashorn.internal.runtime.linker.InvokeByName; + +/** + * An adapter that can wrap any ECMAScript Array-like object (that adheres to the array rules for the property + * {@code length} and having conforming {@code push}, {@code pop}, {@code shift}, {@code unshift}, and {@code splice} + * methods) and expose it as both a Java list and double-ended queue. While script arrays aren't necessarily efficient + * as dequeues, it's still slightly more efficient to be able to translate dequeue operations into pushes, pops, shifts, + * and unshifts, than to blindly translate all list's add/remove operations into splices. Also, it is conceivable that a + * custom script object that implements an Array-like API can have a background data representation that is optimized + * for dequeue-like access. Note that with ECMAScript arrays, {@code push} and {@pop} operate at the end of the array, + * while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue {@link #push(Object)} + * and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script operations respectively, + * while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and {@code pop}. + */ +public class ListAdapter extends AbstractList implements RandomAccess, Deque { + // These add to the back and front of the list + private static final InvokeByName PUSH = new InvokeByName("push", ScriptObject.class, void.class, Object.class); + private static final InvokeByName UNSHIFT = new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); + + // These remove from the back and front of the list + private static final InvokeByName POP = new InvokeByName("pop", ScriptObject.class, Object.class); + private static final InvokeByName SHIFT = new InvokeByName("shift", ScriptObject.class, Object.class); + + // These insert and remove in the middle of the list + private static final InvokeByName SPLICE_ADD = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class); + private static final InvokeByName SPLICE_REMOVE = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); + + private final ScriptObject obj; + + /** + * Creates a new list wrapper for the specified script object. + * @param obj script the object to wrap + */ + public ListAdapter(ScriptObject obj) { + this.obj = obj; + } + + @Override + public int size() { + return JSType.toInt32(obj.getLength()); + } + + @Override + public Object get(int index) { + checkRange(index); + return obj.get(index); + } + + @Override + public Object set(int index, Object element) { + checkRange(index); + final Object prevValue = get(index); + obj.set(index, element, false); + return prevValue; + } + + private void checkRange(int index) { + if(index < 0 || index >= size()) { + throw invalidIndex(index); + } + } + + @Override + public void push(Object e) { + addFirst(e); + } + + @Override + public boolean add(Object e) { + addLast(e); + return true; + } + + @Override + public void addFirst(Object e) { + try { + final Object fn = UNSHIFT.getGetter().invokeExact(obj); + checkFunction(fn, UNSHIFT); + UNSHIFT.getInvoker().invokeExact(fn, obj, e); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public void addLast(Object e) { + try { + final Object fn = PUSH.getGetter().invokeExact(obj); + checkFunction(fn, PUSH); + PUSH.getInvoker().invokeExact(fn, obj, e); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public void add(int index, Object e) { + try { + if(index < 0) { + throw invalidIndex(index); + } else if(index == 0) { + addFirst(e); + } else { + final int size = size(); + if(index < size) { + final Object fn = SPLICE_ADD.getGetter().invokeExact(obj); + checkFunction(fn, SPLICE_ADD); + SPLICE_ADD.getInvoker().invokeExact(fn, obj, index, 0, e); + } else if(index == size) { + addLast(e); + } else { + throw invalidIndex(index); + } + } + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + private static void checkFunction(Object fn, InvokeByName invoke) { + if(!(fn instanceof ScriptFunction)) { + throw new UnsupportedOperationException("The script object doesn't have a function named " + invoke.getName()); + } + } + + private static IndexOutOfBoundsException invalidIndex(int index) { + return new IndexOutOfBoundsException(String.valueOf(index)); + } + + @Override + public boolean offer(Object e) { + return offerLast(e); + } + + @Override + public boolean offerFirst(Object e) { + addFirst(e); + return true; + } + + @Override + public boolean offerLast(Object e) { + addLast(e); + return true; + } + + @Override + public Object pop() { + return removeFirst(); + } + + @Override + public Object remove() { + return removeFirst(); + } + + @Override + public Object removeFirst() { + checkNonEmpty(); + return invokeShift(); + } + + @Override + public Object removeLast() { + checkNonEmpty(); + return invokePop(); + } + + private void checkNonEmpty() { + if(isEmpty()) { + throw new NoSuchElementException(); + } + } + + @Override + public Object remove(int index) { + if(index < 0) { + throw invalidIndex(index); + } else if (index == 0) { + return invokeShift(); + } else { + final int maxIndex = size() - 1; + if(index < maxIndex) { + final Object prevValue = get(index); + invokeSpliceRemove(index, 1); + return prevValue; + } else if(index == maxIndex) { + return invokePop(); + } else { + throw invalidIndex(index); + } + } + } + + private Object invokeShift() { + try { + final Object fn = SHIFT.getGetter().invokeExact(obj); + checkFunction(fn, SHIFT); + return SHIFT.getInvoker().invokeExact(fn, obj); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + private Object invokePop() { + try { + final Object fn = POP.getGetter().invokeExact(obj); + checkFunction(fn, POP); + return POP.getInvoker().invokeExact(fn, obj); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + protected void removeRange(int fromIndex, int toIndex) { + invokeSpliceRemove(fromIndex, toIndex - fromIndex); + } + + private void invokeSpliceRemove(int fromIndex, int count) { + try { + final Object fn = SPLICE_REMOVE.getGetter().invokeExact(obj); + checkFunction(fn, SPLICE_REMOVE); + SPLICE_REMOVE.getInvoker().invokeExact(fn, obj, fromIndex, count); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public Object poll() { + return pollFirst(); + } + + @Override + public Object pollFirst() { + return isEmpty() ? null : invokeShift(); + } + + @Override + public Object pollLast() { + return isEmpty() ? null : invokePop(); + } + + @Override + public Object peek() { + return peekFirst(); + } + + @Override + public Object peekFirst() { + return isEmpty() ? null : get(0); + } + + @Override + public Object peekLast() { + return isEmpty() ? null : get(size() - 1); + } + + @Override + public Object element() { + return getFirst(); + } + + @Override + public Object getFirst() { + checkNonEmpty(); + return get(0); + } + + @Override + public Object getLast() { + checkNonEmpty(); + return get(size() - 1); + } + + @Override + public Iterator descendingIterator() { + final ListIterator it = listIterator(size()); + return new Iterator() { + @Override + public boolean hasNext() { + return it.hasPrevious(); + } + + @Override + public Object next() { + return it.previous(); + } + + @Override + public void remove() { + it.remove(); + } + }; + } + + @Override + public boolean removeFirstOccurrence(Object o) { + return removeOccurrence(o, iterator()); + } + + @Override + public boolean removeLastOccurrence(Object o) { + return removeOccurrence(o, descendingIterator()); + } + + private static boolean removeOccurrence(Object o, Iterator it) { + while(it.hasNext()) { + final Object e = it.next(); + if(o == null ? e == null : o.equals(e)) { + it.remove(); + return true; + } + } + return false; + } +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/Logging.java --- a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java Wed May 29 16:59:55 2013 -0700 @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.logging.ConsoleHandler; @@ -117,7 +118,7 @@ if ("".equals(value)) { level = Level.INFO; } else { - level = Level.parse(value.toUpperCase()); + level = Level.parse(value.toUpperCase(Locale.ENGLISH)); } final String name = Logging.lastPart(key); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java --- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Wed May 29 16:59:55 2013 -0700 @@ -25,10 +25,16 @@ package jdk.nashorn.internal.runtime; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.Guards; +import jdk.nashorn.internal.lookup.MethodHandleFactory; +import jdk.nashorn.internal.lookup.MethodHandleFunctionality; import jdk.nashorn.internal.objects.NativeJava; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; @@ -65,6 +71,10 @@ * */ public final class NativeJavaPackage extends ScriptObject { + private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality(); + private static final MethodHandle CLASS_NOT_FOUND = findOwnMH("classNotFound", Void.TYPE, NativeJavaPackage.class); + private static final MethodHandle TYPE_GUARD = Guards.getClassGuard(NativeJavaPackage.class); + /** Full name of package (includes path.) */ private final String name; @@ -123,6 +133,30 @@ return super.getDefaultValue(hint); } + @Override + protected GuardedInvocation findNewMethod(CallSiteDescriptor desc) { + return createClassNotFoundInvocation(desc); + } + + @Override + protected GuardedInvocation findCallMethod(CallSiteDescriptor desc, LinkRequest request) { + return createClassNotFoundInvocation(desc); + } + + private static GuardedInvocation createClassNotFoundInvocation(final CallSiteDescriptor desc) { + // If NativeJavaPackage is invoked either as a constructor or as a function, throw a ClassNotFoundException as + // we can assume the user attempted to instantiate a non-existent class. + final MethodType type = desc.getMethodType(); + return new GuardedInvocation( + MH.dropArguments(CLASS_NOT_FOUND, 1, type.parameterList().subList(1, type.parameterCount())), + type.parameterType(0) == NativeJavaPackage.class ? null : TYPE_GUARD); + } + + @SuppressWarnings("unused") + private static void classNotFound(final NativeJavaPackage pkg) throws ClassNotFoundException { + throw new ClassNotFoundException(pkg.name); + } + /** * "No such property" call placeholder. * @@ -188,4 +222,7 @@ return noSuchProperty(desc, request); } + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { + return MH.findStatic(MethodHandles.lookup(), NativeJavaPackage.class, name, MH.type(rtype, types)); + } } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/Property.java --- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java Wed May 29 16:59:55 2013 -0700 @@ -52,6 +52,9 @@ * we can use leave flag byte initialized with (the default) zero value. */ + /** Mask for property being both writable, enumerable and configurable */ + public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000; + /** ECMA 8.6.1 - Is this property not writable? */ public static final int NOT_WRITABLE = 0b0000_0000_0001; @@ -352,6 +355,27 @@ } /** + * Set the value of this property in {@code owner}. This allows to bypass creation of the + * setter MethodHandle for spill and user accessor properties. + * + * @param self the this object + * @param owner the owner object + * @param value the new property value + * @param strict is this a strict setter? + */ + protected abstract void setObjectValue(ScriptObject self, ScriptObject owner, Object value, boolean strict); + + /** + * Set the Object value of this property from {@code owner}. This allows to bypass creation of the + * getter MethodHandle for spill and user accessor properties. + * + * @param self the this object + * @param owner the owner object + * @return the property value + */ + protected abstract Object getObjectValue(ScriptObject self, ScriptObject owner); + + /** * Abstract method for retrieving the setter for the property. We do not know * anything about the internal representation when we request the setter, we only * know that the setter will take the property as a parameter of the given type. diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed May 29 16:59:55 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 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 runtimeType(final MethodType mt) { + final ArrayList 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 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 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 runtimeParamTypes = runtimeType(runtimeType); + while (runtimeParamTypes.size() > functionNode.getParameters().size()) { + runtimeParamTypes.remove(0); + } for (i = 0; i < compileTimeArgs.size(); i++) { - final Type runtimeType = runtimeArgs.get(i); - final Type compileType = compileTimeArgs.get(i); + final Type rparam = Type.typeFor(runtimeType.parameterType(i)); + final Type cparam = compileTimeArgs.get(i); - if (compileType.isObject() && !runtimeType.isObject()) { + if (cparam.isObject() && !rparam.isObject()) { + //check that the runtime object is still coercible to the runtime type, because compiler can't prove it's always primitive if (guard == null) { - guard = PARAM_TYPE_GUARD; - guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()])); + guard = MH.insertArguments(PARAM_TYPE_GUARD, 0, (Object)runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()])); } } } - //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs); + Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args)); assert snapshot != null; assert snapshot != functionNode; final Compiler compiler = new Compiler(installer); - final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()])))); + + final FunctionNode compiledSnapshot = compiler.compile( + snapshot.setHints( + null, + new Compiler.Hints(runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()])))); + /* + * No matter how narrow your types were, they can never be narrower than Attr during recompile made them. I.e. you + * can put an int into the function here, if you see it as a runtime type, but if the function uses a multiplication + * on it, it will still need to be a double. At least until we have overflow checks. Similarly, if an int is + * passed but it is used as a string, it makes no sense to make the parameter narrower than Object. At least until + * the "different types for one symbol in difference places" work is done + */ compiler.install(compiledSnapshot); - final MethodHandle nmh = addCode(compiledSnapshot, guard, mh); - - return nmh; + return addCode(compiledSnapshot, runtimeType, guard, mh); } private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed May 29 16:59:55 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; @@ -183,7 +186,7 @@ * @param out output print writer * @param err error print writer */ - ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { + public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { this.out = out; this.err = err; this.namespace = new Namespace(); @@ -219,6 +222,7 @@ _print_parse = options.getBoolean("print.parse"); _print_lower_parse = options.getBoolean("print.lower.parse"); _print_symbols = options.getBoolean("print.symbols"); + _range_analysis = options.getBoolean("range.analysis"); _scripting = options.getBoolean("scripting"); _strict = options.getBoolean("strict"); _version = options.getBoolean("version"); @@ -258,14 +262,19 @@ } this._callsite_flags = callSiteFlags; - final Option option = options.get("timezone"); - if (option != null) { - this._timezone = (TimeZone)option.getValue(); + final Option timezoneOption = options.get("timezone"); + if (timezoneOption != null) { + this._timezone = (TimeZone)timezoneOption.getValue(); } else { this._timezone = TimeZone.getDefault(); } - this._locale = Locale.getDefault(); + final Option localeOption = options.get("locale"); + if (localeOption != null) { + this._locale = (Locale)localeOption.getValue(); + } else { + this._locale = Locale.getDefault(); + } } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed May 29 16:59:55 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) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed May 29 16:59:55 2013 -0700 @@ -25,7 +25,6 @@ package jdk.nashorn.internal.runtime; -import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall; import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; import static jdk.nashorn.internal.lookup.Lookup.MH; @@ -151,17 +150,6 @@ /** Method handle for setting the user accessors of a ScriptObject */ public static final Call SET_USER_ACCESSORS = virtualCall(ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); - /** Method handle for getter for {@link UserAccessorProperty}, given a slot */ - static final Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), ScriptObject.class, "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class); - - /** Method handle for setter for {@link UserAccessorProperty}, given a slot */ - static final Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), ScriptObject.class, "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class); - - private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Object.class); - private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class, - Object.class, Object.class, Object.class); - /** * Constructor */ @@ -699,17 +687,9 @@ * @return New property. */ public final Property addOwnProperty(final String key, final int propertyFlags, final Object value) { - final MethodHandle setter = addSpill(key, propertyFlags); - - try { - setter.invokeExact((Object)this, value); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } - - return getMap().findProperty(key); + final Property property = addSpillProperty(key, propertyFlags); + property.setObjectValue(this, this, value, false); + return property; } /** @@ -744,15 +724,7 @@ // Erase the property field value with undefined. If the property is defined // by user-defined accessors, we don't want to call the setter!! if (!(property instanceof UserAccessorProperty)) { - try { - // make the property value to be undefined - //TODO specproperties - property.getSetter(Object.class, getMap()).invokeExact((Object)this, (Object)UNDEFINED); - } catch (final RuntimeException | Error e) { - throw e; - } catch (final Throwable t) { - throw new RuntimeException(t); - } + property.setObjectValue(this, this, UNDEFINED, false); } } @@ -948,18 +920,7 @@ * @return the value of the property */ protected static Object getObjectValue(final FindProperty find) { - final MethodHandle getter = find.getGetter(Object.class); - if (getter != null) { - try { - return getter.invokeExact((Object)find.getGetterReceiver()); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } - } - - return UNDEFINED; + return find.getObjectValue(); } /** @@ -2087,11 +2048,7 @@ property = addOwnProperty(property); } else { int i = getMap().getSpillLength(); - MethodHandle getter = MH.arrayElementGetter(Object[].class); - MethodHandle setter = MH.arrayElementSetter(Object[].class); - getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE); - setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE); - property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter); + property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i); notifyPropertyAdded(this, property); property = addOwnProperty(property); i = property.getSlot(); @@ -2115,20 +2072,15 @@ /** * Add a spill entry for the given key. - * @param key Property key. - * @param propertyFlags Property flags. + * @param key Property key. * @return Setter method handle. */ - private MethodHandle addSpill(final String key, final int propertyFlags) { - final Property spillProperty = addSpillProperty(key, propertyFlags); + MethodHandle addSpill(final String key) { + final Property spillProperty = addSpillProperty(key, 0); final Class type = Object.class; return spillProperty.getSetter(type, getMap()); //TODO specfields } - MethodHandle addSpill(final String key) { - return addSpill(key, 0); - } - /** * Make sure arguments are paired correctly, with respect to more parameters than declared, * fewer parameters than declared and other things that JavaScript allows. This might involve @@ -2659,14 +2611,8 @@ return; } - try { - final MethodHandle setter = f.getSetter(Object.class, strict); //TODO specfields - setter.invokeExact((Object)f.getSetterReceiver(), value); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } + f.setObjectValue(value, strict); + } else if (!isExtensible()) { if (strict) { throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this)); @@ -2677,13 +2623,7 @@ } private void spill(final String key, final Object value) { - try { - addSpill(key).invokeExact((Object)this, value); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } + addSpillProperty(key, 0).setObjectValue(this, this, value, false); } @@ -3217,46 +3157,6 @@ return (index < 0 || (index >= spill.length)) ? null : spill[index]; } - // User defined getter and setter are always called by "dyn:call". Note that the user - // getter/setter may be inherited. If so, proto is bound during lookup. In either - // inherited or self case, slot is also bound during lookup. Actual ScriptFunction - // to be called is retrieved everytime and applied. - @SuppressWarnings("unused") - private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) { - final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; - final Object func = container.getSpill(slot); - - if (func instanceof ScriptFunction) { - try { - return INVOKE_UA_GETTER.invokeExact(func, self); - } catch(final Error|RuntimeException t) { - throw t; - } catch(final Throwable t) { - throw new RuntimeException(t); - } - } - - return UNDEFINED; - } - - @SuppressWarnings("unused") - private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) { - final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; - final Object func = container.getSpill(slot); - - if (func instanceof ScriptFunction) { - try { - INVOKE_UA_SETTER.invokeExact(func, self, value); - } catch(final Error|RuntimeException t) { - throw t; - } catch(final Throwable t) { - throw new RuntimeException(t); - } - } else if (name != null) { - throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); - } - } - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { final Class own = ScriptObject.class; final MethodType mt = MH.type(rtype, types); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed May 29 16:59:55 2013 -0700 @@ -36,6 +36,7 @@ import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; +import java.util.Locale; import java.util.NoSuchElementException; import java.util.Objects; import jdk.internal.dynalink.beans.StaticClass; @@ -788,7 +789,7 @@ return false; } - throw typeError("in.with.non.object", rvalType.toString().toLowerCase()); + throw typeError("in.with.non.object", rvalType.toString().toLowerCase(Locale.ENGLISH)); } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed May 29 16:59:55 2013 -0700 @@ -46,7 +46,7 @@ public final class ScriptingFunctions { /** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */ - public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class); + public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class, Object.class); /** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */ public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); @@ -78,13 +78,17 @@ * Nashorn extension: global.readLine (scripting-mode-only) * Read one line of input from the standard input. * - * @param self self reference + * @param self self reference + * @param prompt String used as input prompt * * @return line that was read * * @throws IOException if an exception occurs */ - public static Object readLine(final Object self) throws IOException { + public static Object readLine(final Object self, final Object prompt) throws IOException { + if (prompt != UNDEFINED) { + System.out.print(JSType.toString(prompt)); + } final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); return reader.readLine(); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java --- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed May 29 16:59:55 2013 -0700 @@ -183,17 +183,10 @@ private SetMethod createNewSpillPropertySetter() { final int nextSpill = getMap().getSpillLength(); - final Property property = createSpillProperty(nextSpill); + final Property property = new AccessorProperty(getName(), Property.IS_SPILL, nextSpill); return new SetMethod(createSpillMethodHandle(nextSpill, property), property); } - private Property createSpillProperty(final int nextSpill) { - final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE); - final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE); - - return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter); - } - private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) { final PropertyMap oldMap = getMap(); final PropertyMap newMap = getNewMap(property); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed May 29 16:59:55 2013 -0700 @@ -26,7 +26,15 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.lookup.Lookup; +import jdk.nashorn.internal.runtime.linker.Bootstrap; + +import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; /** * Property with user defined getters/setters. Actual getter and setter @@ -51,6 +59,22 @@ /** User defined setter function slot. */ private final int setterSlot; + /** Getter method handle */ + private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class, + "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class); + + /** Setter method handle */ + private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class, + "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class); + + /** Dynamic invoker for getter */ + private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, + Object.class, Object.class); + + /** Dynamic invoker for setter */ + private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class, + Object.class, Object.class, Object.class); + /** * Constructor * @@ -134,8 +158,18 @@ } @Override + protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) { + return userAccessorGetter(owner, getGetterSlot(), self); + } + + @Override + protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) { + userAccessorSetter(owner, getSetterSlot(), strict ? getKey() : null, self, value); + } + + @Override public MethodHandle getGetter(final Class type) { - return Lookup.filterReturnType(ScriptObject.USER_ACCESSOR_GETTER.methodHandle(), type); + return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type); } @Override @@ -146,7 +180,7 @@ @Override public MethodHandle getSetter(final Class type, final PropertyMap currentMap) { - return ScriptObject.USER_ACCESSOR_SETTER.methodHandle(); + return USER_ACCESSOR_SETTER.methodHandle(); } @Override @@ -155,4 +189,42 @@ return (value instanceof ScriptFunction) ? (ScriptFunction) value : null; } + // User defined getter and setter are always called by "dyn:call". Note that the user + // getter/setter may be inherited. If so, proto is bound during lookup. In either + // inherited or self case, slot is also bound during lookup. Actual ScriptFunction + // to be called is retrieved everytime and applied. + static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) { + final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; + final Object func = container.getSpill(slot); + + if (func instanceof ScriptFunction) { + try { + return INVOKE_UA_GETTER.invokeExact(func, self); + } catch(final Error|RuntimeException t) { + throw t; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } + + return UNDEFINED; + } + + static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) { + final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; + final Object func = container.getSpill(slot); + + if (func instanceof ScriptFunction) { + try { + INVOKE_UA_SETTER.invokeExact(func, self, value); + } catch(final Error|RuntimeException t) { + throw t; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } else if (name != null) { + throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); + } + } + } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java Wed May 29 16:59:55 2013 -0700 @@ -40,7 +40,7 @@ * private static final InvokeByName TO_JSON = new InvokeByName("toJSON", Object.class, Object.class, Object.class); * ... * final Object toJSONFn = TO_JSON.getGetter().invokeExact(obj); - * value = TO_JSON.getInvoker().invokeExact(toJSON, obj, key); + * value = TO_JSON.getInvoker().invokeExact(toJSONFn, obj, key); * * In practice, you can have stronger type assumptions if it makes sense for your code, just remember that you must use * the same parameter types as the formal types of the arguments for {@code invokeExact} to work: @@ -50,7 +50,7 @@ * final ScriptObject sobj = (ScriptObject)obj; * final Object toJSONFn = TO_JSON.getGetter().invokeExact(sobj); * if(toJSONFn instanceof ScriptFunction) { - * value = TO_JSON.getInvoker().invokeExact(toJSON, sobj, key); + * value = TO_JSON.getInvoker().invokeExact(toJSONFn, sobj, key); * } * * Note that in general you will not want to reuse a single instance of this class for implementing more than one call @@ -59,6 +59,7 @@ * separate instance of this class for every place. */ public class InvokeByName { + private final String name; private final MethodHandle getter; private final MethodHandle invoker; @@ -81,6 +82,7 @@ * @param ptypes the parameter types of the function. */ public InvokeByName(final String name, final Class targetClass, final Class rtype, final Class... ptypes) { + this.name = name; getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getItem:" + name, Object.class, targetClass); final Class[] finalPtypes; @@ -97,6 +99,14 @@ } /** + * Returns the name of the function retrieved through this invoker. + * @return the name of the function retrieved through this invoker. + */ + public String getName() { + return name; + } + + /** * Returns the property getter that can be invoked on an object to retrieve the function object that will be * subsequently invoked by the invoker returned by {@link #getInvoker()}. * @return the property getter method handle for the function. diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed May 29 16:59:55 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 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Wed May 29 16:59:55 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); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Wed May 29 16:59:55 2013 -0700 @@ -43,6 +43,7 @@ import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.SecureClassLoader; + import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; @@ -58,6 +59,7 @@ * "class loader", it does not, in fact, extend {@code ClassLoader}, but rather uses them internally. Instances of this * class are normally created by {@link JavaAdapterBytecodeGenerator}. */ +@SuppressWarnings("javadoc") class JavaAdapterClassLoader extends JavaAdapterGeneratorBase { private static final Type PRIVILEGED_ACTION_TYPE = Type.getType(PrivilegedAction.class); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed May 29 16:59:55 2013 -0700 @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.support.LinkRequestImpl; import jdk.nashorn.internal.objects.NativeJava; @@ -66,6 +67,7 @@ *

    */ +@SuppressWarnings("javadoc") public final class JavaAdapterFactory { /** * A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents. diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java Wed May 29 16:59:55 2013 -0700 @@ -33,6 +33,7 @@ * Base class for both {@link JavaAdapterBytecodeGenerator} and {@link JavaAdapterClassLoader}, containing those * bytecode types, type names and method descriptor that are used by both. */ +@SuppressWarnings("javadoc") abstract class JavaAdapterGeneratorBase { static final Type CONTEXT_TYPE = Type.getType(Context.class); static final Type OBJECT_TYPE = Type.getType(Object.class); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/options/Option.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Option.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Option.java Wed May 29 16:59:55 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 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Wed May 29 16:59:55 2013 -0700 @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime.options; +import java.util.Locale; import java.util.TimeZone; import jdk.nashorn.internal.runtime.QuotedStringTokenizer; @@ -151,6 +152,9 @@ case "timezone": this.defaultValue = TimeZone.getDefault().getID(); break; + case "locale": + this.defaultValue = Locale.getDefault().toLanguageTag(); + break; default: break; } @@ -263,7 +267,7 @@ this.params = arg; break; case "type": - this.type = arg.toLowerCase(); + this.type = arg.toLowerCase(Locale.ENGLISH); break; case "default": this.defaultValue = arg; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/options/Options.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java Wed May 29 16:59:55 2013 -0700 @@ -499,10 +499,10 @@ case "timezone": // default value "TimeZone.getDefault()" return new Option<>(TimeZone.getTimeZone(value)); + case "locale": + return new Option<>(Locale.forLanguageTag(value)); case "keyvalues": return new KeyValueOption(value); - case "values": - return new ValueOption(value); case "log": final KeyValueOption kv = new KeyValueOption(value); Logging.initialize(kv.getValues()); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/options/ValueOption.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/ValueOption.java Wed Jul 05 18:57:05 2017 +0200 +++ /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 { - - private Collection 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 getValues() { - return Collections.unmodifiableCollection(values); - } - -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Wed Jul 05 18:57:05 2017 +0200 +++ /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(); - } - } - -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java Wed May 29 16:59:55 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(); + } + } + +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Wed May 29 16:59:55 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); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Wed May 29 16:59:55 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); } /** diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Wed May 29 16:59:55 2013 -0700 @@ -868,6 +868,9 @@ * \ ClassEscape */ private boolean classAtomNoDash() { + if (atEOF()) { + return false; + } final int startIn = position; final int startOut = sb.length(); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java Wed May 29 16:59:55 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(""); 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; ic)/ - 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 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) (? (?= 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 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 MAX_NODE_OPT_INFO_REF_COUNT) { + if (++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) { int min = 0; int max = MinMaxLen.INFINITE_DISTANCE; if (en.isMinFixed()) min = en.minLength; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java Wed May 29 16:59:55 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) { /* /(?..){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) { /* /(?..){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: diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java Wed Jul 05 18:57:05 2017 +0200 +++ /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) { - } -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java Wed Jul 05 18:57:05 2017 +0200 +++ /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, "", "(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, "", "()V", null, null); - factoryInit.visitVarInsn(ALOAD, 0); - factoryInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", "", "()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, "", "(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", "", "(Lorg/joni/Regex;[BII)V"); - } - - protected final void setupMachineInit() { - if (bitsets + ranges + templates > 0) { // ok, some of these are in use, we'd like to cache the factory - machine.visitField(ACC_PRIVATE + ACC_FINAL, "factory", "L" + factoryName + ";", null, null); - machineInit.visitVarInsn(ALOAD, THIS); // this - machineInit.visitVarInsn(ALOAD, 1); // this, Regex - machineInit.visitFieldInsn(GETFIELD, "jdk/nashorn/internal/runtime/regexp/joni/Regex", "factory", "Lorg/joni/MatcherFactory;"); // this, factory - machineInit.visitTypeInsn(CHECKCAST, factoryName); - machineInit.visitFieldInsn(PUTFIELD, machineName, "factory", "L" + factoryName + ";"); // [] - } - - machineInit.visitInsn(RETURN); - machineInit.visitMaxs(0, 0); - //init.visitMaxs(5, 5); - machineInit.visitEnd(); - } - - protected final void prepareMachineMatch() { - match = machine.visitMethod(ACC_SYNTHETIC, "matchAt", "(III)I", null, null); - move(S, SSTART); // s = sstart - load("bytes", "[B"); // - astore(BYTES); // byte[]bytes = this.bytes - } - - protected final void setupMachineMatch() { - match.visitInsn(ICONST_M1); - match.visitInsn(IRETURN); - - match.visitMaxs(maxStack, maxVars); - match.visitEnd(); - } - - protected final void setupClasses() { - byte[]factoryCode = factory.toByteArray(); - byte[]machineCode = machine.toByteArray(); - - if (Config.DEBUG_ASM) { - try { - FileOutputStream fos; - fos = new FileOutputStream(factoryName.substring(factoryName.lastIndexOf('/') + 1) + ".class"); - fos.write(factoryCode); - fos.close(); - fos = new FileOutputStream(machineName.substring(machineName.lastIndexOf('/') + 1) + ".class"); - fos.write(machineCode); - fos.close(); - } catch (IOException ioe) { - ioe.printStackTrace(Config.err); - } - } - - loader.defineClass(machineName.replace('/', '.'), machineCode); - Class cls = loader.defineClass(factoryName.replace('/', '.'), factoryCode); - try { - regex.factory = (MatcherFactory)cls.newInstance(); - } catch(Exception e) { - e.printStackTrace(Config.err); - } - } - - protected final void aload(int var) { - match.visitVarInsn(ALOAD, var); - } - - protected final void astore(int var) { - match.visitVarInsn(ASTORE, var); - } - - protected final void loadThis() { - match.visitVarInsn(ALOAD, THIS); - } - - protected final void load(int var) { - match.visitVarInsn(ILOAD, var); - } - - protected final void store(int var) { - match.visitVarInsn(ISTORE, var); - } - - protected final void move(int to, int from) { - load(from); - store(to); - } - - protected final void load(String field, String singature) { - loadThis(); - match.visitFieldInsn(GETFIELD, machineName, field, singature); - } - - protected final void load(String field) { - load(field, "I"); - } - - protected final void store(String field, String singature) { - loadThis(); - match.visitFieldInsn(PUTFIELD, machineName, field, singature); - } - - protected final void store(String field) { - store(field, "I"); - } - - protected final String installTemplate(char[] arr, int p, int length) { - String templateName = TEMPLATE + ++templates; - installArray(templateName, arr, p, length); - return templateName; - } - - protected final String installCodeRange(int[]arr) { - String coreRangeName = CODERANGE + ++ranges; - installArray(coreRangeName, arr); - return coreRangeName; - } - - protected final String installBitSet(int[]arr) { - String bitsetName = BITSET + ++bitsets; - installArray(bitsetName, arr); - return bitsetName; - } - - private void installArray(String name, int[]arr) { - factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[I", null, null); - factoryInit.visitVarInsn(ALOAD, THIS); // this; - loadInt(factoryInit, arr.length); // this, length - factoryInit.visitIntInsn(NEWARRAY, T_INT); // this, arr - for (int i=0;i < arr.length; i++) buildArray(i, arr[i], IASTORE); - factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[I"); - } - - private void installArray(String name, char[]arr, int p, int length) { - factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[B", null, null); - factoryInit.visitVarInsn(ALOAD, THIS); // this; - loadInt(factoryInit, arr.length); // this, length - factoryInit.visitIntInsn(NEWARRAY, T_BYTE); // this, arr - for (int i=p, j=0; i < p + length; i++, j++) buildArray(j, arr[i] & 0xff, BASTORE); - factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[B"); - } - - private void buildArray(int index, int value, int type) { - factoryInit.visitInsn(DUP); // ... arr, arr - loadInt(factoryInit, index); // ... arr, arr, index - loadInt(factoryInit, value); // ... arr, arr, index, value - factoryInit.visitInsn(type); // ... arr - } - - private void loadInt(MethodVisitor mv, int value) { - if (value >= -1 && value <= 5) { - mv.visitInsn(value + ICONST_0); // ICONST_0 == 3 - } else if (value >= 6 && value <= 127 || value >= -128 && value <= -2) { - mv.visitIntInsn(BIPUSH, value); - } else if (value >= 128 && value <= 32767 || value >= -32768 && value <= -129) { - mv.visitIntInsn(SIPUSH, value); - } else { - mv.visitLdcInsn(new Integer(value)); - } - } -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java Wed May 29 16:59:55 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 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() { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java Wed May 29 16:59:55 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++; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java Wed Jul 05 18:57:05 2017 +0200 +++ /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, \k */ - 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; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Wed May 29 16:59:55 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++) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java Wed May 29 16:59:55 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 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))); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java Wed May 29 16:59:55 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 */ diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java Wed Jul 05 18:57:05 2017 +0200 +++ /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 0) buff.append(", "); - buff.append(backRefs[i]); - } - } - return buff.toString(); - } - -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java Wed Jul 05 18:57:05 2017 +0200 +++ /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); - } -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java Wed May 29 16:59:55 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 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 (?<=...), (?...) */ - } - 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) { - 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: diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java Wed May 29 16:59:55 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 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(); // 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 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; - } } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java Wed May 29 16:59:55 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 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(); } } } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java Wed May 29 16:59:55 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 ), diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java Wed Jul 05 18:57:05 2017 +0200 +++ /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 0) { - for (int i=0; i set, WarnCallback warnings) { - if (target == null || target.parent == this) - warnings.warn(this.getAddressName() + " doesn't point to a target or the target has been stolen"); - // do not recurse here - } - - @Override - public String toString(int level) { - StringBuilder value = new StringBuilder(super.toString(level)); - value.append("\n name: " + new String(name, nameP, nameEnd - nameP)); - value.append("\n groupNum: " + groupNum); - value.append("\n target: " + pad(target.getAddressName(), level + 1)); - value.append("\n unsetAddrList: " + pad(unsetAddrList, level + 1)); - - return value.toString(); - } - -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java Wed May 29 16:59:55 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; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java Wed May 29 16:59:55 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 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java Wed May 29 16:59:55 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; - } - } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java Wed Jul 05 18:57:05 2017 +0200 +++ /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 NULL = new ObjPtr(); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/PosixBracket.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/PosixBracket.java Wed Jul 05 18:57:05 2017 +0200 +++ /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 PBSTableUpper = new HashMap(); - - static { - for (int i=0; i" : "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"; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java Wed May 29 16:59:55 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)); - } - } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed May 29 16:59:55 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.unsupported.java.to.type=Unsupported Java.to target type {0}. 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] diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Wed May 29 16:59:55 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.", \ @@ -326,6 +332,15 @@ type=TimeZone \ } +nashorn.option.locale = { \ + name="--locale", \ + short_name="-l", \ + is_undocumented=true, \ + params="", \ + desc="Set Locale for script execution.", \ + type=Locale \ +} + nashorn.option.trace.callsites = { \ name="--trace-callsites", \ short_name="-tcs", \ diff -r 2fd6acba737b -r bf497a99ac5c nashorn/src/netscape/javascript/JSObject.java --- a/nashorn/src/netscape/javascript/JSObject.java Wed Jul 05 18:57:05 2017 +0200 +++ /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); -} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8008554.js --- a/nashorn/test/script/basic/JDK-8008554.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8008554.js Wed May 29 16:59:55 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); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8010804.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8010804.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,86 @@ +/* + * 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-8010804: Review long and integer usage conventions + * + * @test + * @run + */ + +var x = []; +print(x.length); +x[4294967294] = 1; +print(x.length); +x[4294967295] = 1; +print(x.length); +print(x.slice(4294967293).length); +print(x.slice(4294967294).length); +print(x.slice(4294967295).length); +print(x.slice(4294967296).length); + +print(x.slice(-4294967293).length); +print(x.slice(-4294967294).length); +print(x.slice(-4294967295).length); +print(x.slice(-4294967296).length); + +print(x.slice(0, 4294967293).length); +print(x.slice(0, 4294967294).length); +print(x.slice(0, 4294967295).length); +print(x.slice(0, 4294967296).length); + +print(x.slice(0, -4294967293).length); +print(x.slice(0, -4294967294).length); +print(x.slice(0, -4294967295).length); +print(x.slice(0, -4294967296).length); + +print(x.slice(9223371036854775807).length); +print(x.slice(9223372036854775807).length); +print(x.slice(9223373036854775807).length); +print(x.slice(9223374036854775807).length); + +print(x.slice(-9223371036854775807).length); +print(x.slice(-9223372036854775807).length); +print(x.slice(-9223373036854775807).length); +print(x.slice(-9223374036854775807).length); + +print(x.slice(-9223371036854775807, 1).length); +print(x.slice(-9223372036854775807, 1).length); +print(x.slice(-9223373036854775807, 1).length); +print(x.slice(-9223374036854775807, 1).length); + +print(x.slice(-9223371036854775807, -1).length); +print(x.slice(-9223372036854775807, -1).length); +print(x.slice(-9223373036854775807, -1).length); +print(x.slice(-9223374036854775807, -1).length); + +print(x.slice(Infinity).length); +print(x.slice(Infinity, Infinity).length); +print(x.slice(Infinity, -Infinity).length); +print(x.slice(-Infinity).length); +print(x.slice(-Infinity, Infinity).length); +print(x.slice(-Infinity, -Infinity).length); + +var d = new Date(); +d.setYear(Infinity); +print(d); \ No newline at end of file diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8010804.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8010804.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,42 @@ +0 +4294967295 +4294967295 +2 +1 +0 +0 +4294967293 +4294967294 +4294967295 +4294967295 +4294967293 +4294967294 +4294967295 +4294967295 +2 +1 +0 +0 +0 +0 +0 +0 +4294967295 +4294967295 +4294967295 +4294967295 +1 +1 +1 +1 +4294967294 +4294967294 +4294967294 +4294967294 +0 +0 +0 +4294967295 +4294967295 +0 +Invalid Date diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8011023.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011023.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** + * Round should be ecma compliant + * + * @test + * @run + */ + +print(1/Math.round(-0.5)); +print(Math.round(9007199254740991)); +print(Math.round(9223372036854775807*2)); + diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8011023.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011023.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,3 @@ +-Infinity +9007199254740991 +18446744073709552000 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8011718.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011718.js Wed May 29 16:59:55 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)); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8011718.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011718.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,2 @@ +From obj +From obj diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8012083.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012083.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,70 @@ +/* + * 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-8012093 - array literals can only be subject to constant evaluation under very special + * circumstances. + * + * @test + * @run + */ + + +var w00t = 17; +print(+[w00t]); + +var empty = []; +print(empty == false); + +print([] == false); +print([] === false); +print(!![]); + +print(~[]); +print(![]); +print(![17]); +print(![17,1,2]); + +var one = 1; +var two = 2; +var a1 = [one]; +var a2 = [two]; +print(+a1 + +a2); //3 + +var x = 1; +print(+["apa"]); +print(+[]); //0 +print(+[1]); //1 +print(+[x]); //1 +print(+[1,2,3]); //NaN +var a = []; +var b = [1]; +print(a/b); +print(++[[]][+[]]+[+[]]); //10 +print(+[] == 0); + +var first = [![]+[]][+[]][+[]]+[![]+[]][+[]][+!+[]]+[!+[]+[]][+![]][+![]]+[![]+[]][+[]][+!+[]]+[![]+[]][+[]][+!+[]+!+[]]; +var second =(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]; + +print(first + " " + second); + diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8012083.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012083.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,19 @@ +17 +true +true +false +true +-1 +false +false +false +3 +NaN +0 +1 +1 +NaN +0 +10 +true +fatal fail diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8012305.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012305.js Wed May 29 16:59:55 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(); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8012305.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012305.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,1 @@ +function function() { print("Message "); } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8013919.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8013919.js Wed May 29 16:59:55 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(); +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8013919.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8013919.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,2 @@ +a +b diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014426.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014426.js Wed May 29 16:59:55 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); +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014426.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014426.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,1 @@ +javax.script.ScriptException: TypeError: en stor graa noshoerning! in at line number 7 at column number 2 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014647.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014647.js Wed May 29 16:59:55 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)) diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014647.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014647.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,5 @@ +I'm runnable 1! +I'm runnable 2! +I'm runnable 3! +r1.class === r2.class: false +r2.class === r3.class: true diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014735.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014735.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,43 @@ +/* + * 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-8014735: Typed Array, BYTES_PER_ELEMENT should be a class property + * + * @test + * @run + */ + +function bytesPerElement(func) { + print(func.name + ".BYTES_PER_ELEMENT = " + func.BYTES_PER_ELEMENT); +} + +bytesPerElement(Int8Array); +bytesPerElement(Int16Array); +bytesPerElement(Int32Array); +bytesPerElement(Uint8Array); +bytesPerElement(Uint8ClampedArray); +bytesPerElement(Uint16Array); +bytesPerElement(Uint32Array); +bytesPerElement(Float32Array); +bytesPerElement(Float64Array); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014735.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014735.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,9 @@ +Int8Array.BYTES_PER_ELEMENT = 1 +Int16Array.BYTES_PER_ELEMENT = 2 +Int32Array.BYTES_PER_ELEMENT = 4 +Uint8Array.BYTES_PER_ELEMENT = 1 +Uint8ClampedArray.BYTES_PER_ELEMENT = 1 +Uint16Array.BYTES_PER_ELEMENT = 2 +Uint32Array.BYTES_PER_ELEMENT = 4 +Float32Array.BYTES_PER_ELEMENT = 4 +Float64Array.BYTES_PER_ELEMENT = 8 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014953.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014953.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,45 @@ +/* + * 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-8014953: Have NativeJavaPackage throw a ClassNotFoundException when invoked with "new" + * + * @test + * @run + */ + +try { + new java.util.ArrrayList(16) +} catch(e) { + print("Invoked as constructor"); + print("e.class=" + e.class) + print("e.message=" + e.message); +} + +try { + java.util.ArrrayList(16) +} catch(e) { + print("Invoked as method"); + print("e.class=" + e.class) + print("e.message=" + e.message); +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8014953.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014953.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,6 @@ +Invoked as constructor +e.class=class java.lang.ClassNotFoundException +e.message=java.util.ArrrayList +Invoked as method +e.class=class java.lang.ClassNotFoundException +e.message=java.util.ArrrayList diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015267.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015267.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,109 @@ +/* + * 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-8015267: have a List/Deque adapter for JS array-like objects + * + * @test + * @run + */ + +var a = ['a', 'b', 'c', 'd'] + +var l = Java.to(a, java.util.List) +print(l instanceof java.util.List) +print(l instanceof java.util.Deque) + +print(l[0]) +print(l[1]) +print(l[2]) +print(l[3]) + +print(l.size()) + +l.push('x') +print(a) + +l.addLast('y') +print(a) + +print(l.pop()) +print(l.removeLast()) +print(a) + +l.add('e') +l.add(5, 'f') +print(a) + +l.add(0, 'z') +print(a) + +l.add(2, 'x') +print(a) + +l[7] = 'g' +print(a) + +try { l.add(15, '') } catch(e) { print(e.class) } +try { l.remove(15) } catch(e) { print(e.class) } +try { l.add(-1, '') } catch(e) { print(e.class) } +try { l.remove(-1) } catch(e) { print(e.class) } + +l.remove(7) +l.remove(2) +l.remove(0) +print(a) + +print(l.peek()) +print(l.peekFirst()) +print(l.peekLast()) + +print(l.element()) +print(l.getFirst()) +print(l.getLast()) + +l.offer('1') +l.offerFirst('2') +l.offerLast('3') +print(a) + +a = ['1', '2', 'x', '3', '4', 'x', '5', '6', 'x', '7', '8'] +print(a) +var l = Java.to(a, java.util.List) +l.removeFirstOccurrence('x') +print(a) +l.removeLastOccurrence('x') +print(a) + +var empty = Java.to([], java.util.List) +try { empty.pop() } catch(e) { print(e.class) } +try { empty.removeFirst() } catch(e) { print(e.class) } +try { empty.removeLast() } catch(e) { print(e.class) } + +try { empty.element() } catch(e) { print(e.class) } +try { empty.getFirst() } catch(e) { print(e.class) } +try { empty.getLast() } catch(e) { print(e.class) } + +print(empty.peek()) +print(empty.peekFirst()) +print(empty.peekLast()) diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015267.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015267.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,40 @@ +true +true +a +b +c +d +4 +x,a,b,c,d +x,a,b,c,d,y +x +y +a,b,c,d +a,b,c,d,e,f +z,a,b,c,d,e,f +z,a,x,b,c,d,e,f +z,a,x,b,c,d,e,g +class java.lang.IndexOutOfBoundsException +class java.lang.IndexOutOfBoundsException +class java.lang.IndexOutOfBoundsException +class java.lang.IndexOutOfBoundsException +a,b,c,d,e +a +a +e +a +a +e +2,a,b,c,d,e,1,3 +1,2,x,3,4,x,5,6,x,7,8 +1,2,3,4,x,5,6,x,7,8 +1,2,3,4,x,5,6,7,8 +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +null +null +null diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015348.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015348.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,35 @@ +/* + * 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-8015348: RegExp("[") results in StackOverflowError + * + * @test + * @run + */ + +try { + new RegExp('['); +} catch (error) { + print(error.name); +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015348.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015348.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,1 @@ +SyntaxError diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015349.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015349.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,43 @@ +/* + * 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-8015349: "abc".lastIndexOf("a",-1) should evaluate to 0 and not -1 + * + * @test + * @run + */ + +function printEval(code) { + print(code + " = " + eval(code)); +} + +printEval("'abc'.lastIndexOf('a', 4)"); +printEval("'abc'.lastIndexOf('b', Infinity)"); +printEval("'abc'.lastIndexOf('a', -1)"); +printEval("'abc'.lastIndexOf('a', -Infinity)"); +printEval("'oracle'.lastIndexOf('u')"); +printEval("'hello'.lastIndexOf('l')"); +printEval("'hello'.lastIndexOf('l', 2)"); +printEval("'hello'.lastIndexOf('l', 3)"); +printEval("'hello'.lastIndexOf('l', 1)"); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015349.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015349.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,9 @@ +'abc'.lastIndexOf('a', 4) = 0 +'abc'.lastIndexOf('b', Infinity) = 1 +'abc'.lastIndexOf('a', -1) = 0 +'abc'.lastIndexOf('a', -Infinity) = 0 +'oracle'.lastIndexOf('u') = -1 +'hello'.lastIndexOf('l') = 3 +'hello'.lastIndexOf('l', 2) = 2 +'hello'.lastIndexOf('l', 3) = 3 +'hello'.lastIndexOf('l', 1) = -1 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015352.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015352.js Wed May 29 16:59:55 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-8015352: "i".toUpperCase() => currently returns "İ", but should be "I" (with Turkish locale) + * + * @test + * @option --locale=tr-TR + * @run + */ + +if ("i".toUpperCase() != "I") { + fail("'i'.toUpperCase() is not 'I'"); +} + +if ("i".toUpperCase() == "i".toLocaleUpperCase()) { + fail("'i'.toUpperCase() == 'i'.toLocaleUpperCase()"); +} + +if ("I".toLowerCase() != "i") { + fail("'I'.toLowerCase() is not 'i'"); +} + +if ("I".toLowerCase() == "I".toLocaleLowerCase()) { + fail("'i'.toLowerCase() == 'i'.toLocaleLowerCase()"); +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/JDK-8015354.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015354.js Wed May 29 16:59:55 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-8015354: JSON.parse should not use [[Put]] but use [[DefineOwnProperty]] instead + * + * @test + * @run + */ + +Object.defineProperty(Object.prototype, + "", { + set: function(v) { + throw "set called"; + } +}); + +JSON.parse('{}',function(){}); + +Object.defineProperty(Object.prototype, + "foo",{ + set: function(v) { + throw "set called"; + } +}); +JSON.parse('{"foo": 1}'); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/NASHORN-377.js --- a/nashorn/test/script/basic/NASHORN-377.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/NASHORN-377.js Wed May 29 16:59:55 2013 -0700 @@ -43,7 +43,7 @@ function arrstr(a, n, w) { var s = ""; if (typeof n == "undefined") n = a.length; - if (typeof w == "undefined") w = a.BYTES_PER_ELEMENT * 2; + if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2; for (var i = 0; i < n; i++) { s += tohex(a[i], w); } @@ -96,7 +96,7 @@ var b = new ArrayBuffer(8); for (var i in types) { var x = new types[i](b); - print(x.byteOffset, x.byteLength, x.length, x.BYTES_PER_ELEMENT); + print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT); assertTrue(function(){ return x.constructor === types[i] }); } })(); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/NASHORN-556.js --- a/nashorn/test/script/basic/NASHORN-556.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/NASHORN-556.js Wed May 29 16:59:55 2013 -0700 @@ -47,7 +47,7 @@ // (NoTypeArrayData) var empty = {}; empty.length = 10; - Java.toJavaArray(empty); + Java.to(empty); delete empty[0]; Array.prototype.slice.call(empty, 0, 1); Array.prototype.pop.call(empty); @@ -63,7 +63,7 @@ function f2() { // DeletedArrayFilter var deleted = [,1,,2,,3,,4,,]; - assertEq(2, Java.toJavaArray(deleted)[3]); + assertEq(2, Java.to(deleted)[3]); assertEq(undefined, deleted.pop()); assertEq(4, deleted.pop()); deleted.unshift(5); @@ -78,7 +78,7 @@ function f3() { // DeletedRangeArrayFilter var delrange = [1,2,3,,,,,,,,,,]; - Java.toJavaArray(delrange); + Java.to(delrange); delrange.unshift(4); p.apply(null, delrange); print(delrange.slice(1,3), delrange.slice(2,6)); @@ -88,7 +88,7 @@ function f4() { // NumberArrayData var num = [1.1,2.2,3.3,4.4,5.5]; - Java.toJavaArray(num); + Java.to(num); assertEq(2, num[3] >>> 1); assertEq(5, num[4] | 0); assertEq(5.5, num.pop()); @@ -104,7 +104,7 @@ function f5() { // ObjectArrayData var obj = [2,"two",3.14,"pi",14,"fourteen"]; - Java.toJavaArray(obj); + Java.to(obj); assertEq(-12.86, obj[2] - 16); assertEq(7, obj[4] >>> 1); obj.unshift("one"); @@ -131,14 +131,14 @@ sparse.length = 1024*1024; sparse.push(sparse.length); delete sparse[sparse.length-1]; - //print(Java.toJavaArray(sparse).length); + //print(Java.to(sparse).length); (function(){}).apply(null, sparse); } function f7() { // UndefinedArrayFilter var undef = [1,2,3,4,5,undefined,7,8,9,19]; - Java.toJavaArray(undef); + Java.to(undef); assertEq(4, undef[8] >>> 1); var tmp = undef[9] >>> 1; undef[8] = tmp; @@ -154,8 +154,8 @@ function f8() { // LongArrayData - var j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); - Java.toJavaArray(j); + var j = Java.from(Java.to([23,37,42,86,47], "long[]")); + Java.to(j); p.apply(null, j); assertEq(43, j[3] >>> 1); assertEq(36, j[4] - 11); @@ -164,12 +164,12 @@ assertEq(7, j.shift()); assertEq(47, j.pop()); j.push("asdf"); - j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); + j = Java.from(Java.to([23,37,42,86,47], "long[]")); j.length = 3; j[0] = 13; - j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); + j = Java.from(Java.to([23,37,42,86,47], "long[]")); delete j[0]; - j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); + j = Java.from(Java.to([23,37,42,86,47], "long[]")); j.length = 20; j[0] = 13.37; } diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/allgettersetters.js --- a/nashorn/test/script/basic/allgettersetters.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/allgettersetters.js Wed May 29 16:59:55 2013 -0700 @@ -34,6 +34,9 @@ for (var i in properties) { var prop = properties[i]; try { + if (!/\d.*/.test(prop)) { + eval("obj." + prop + " = " + "obj." + prop + ";"); + } obj[prop] = obj[prop]; } catch (e) { if (!expectError || !(e instanceof TypeError)) { diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/compile-octane.js.EXPECTED --- a/nashorn/test/script/basic/compile-octane.js.EXPECTED Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/compile-octane.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -1,39 +1,13 @@ -Compiling... box2d.js -Compiled OK: box2d.js - -Compiling... code-load.js -Compiled OK: code-load.js - -Compiling... crypto.js -Compiled OK: crypto.js - -Compiling... deltablue.js -Compiled OK: deltablue.js - -Compiling... earley-boyer.js -Compiled OK: earley-boyer.js - -Compiling... gbemu.js -Compiled OK: gbemu.js - -Compiling... mandreel.js -Compiled OK: mandreel.js - -Compiling... navier-stokes.js -Compiled OK: navier-stokes.js - -Compiling... pdfjs.js -Compiled OK: pdfjs.js - -Compiling... raytrace.js -Compiled OK: raytrace.js - -Compiling... regexp.js -Compiled OK: regexp.js - -Compiling... richards.js -Compiled OK: richards.js - -Compiling... splay.js -Compiled OK: splay.js - +Compiled OK: box2d +Compiled OK: code-load +Compiled OK: crypto +Compiled OK: deltablue +Compiled OK: earley-boyer +Compiled OK: gbemu +Compiled OK: mandreel +Compiled OK: navier-stokes +Compiled OK: pdfjs +Compiled OK: raytrace +Compiled OK: regexp +Compiled OK: richards +Compiled OK: splay diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/javaarrayconversion.js --- a/nashorn/test/script/basic/javaarrayconversion.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/javaarrayconversion.js Wed May 29 16:59:55 2013 -0700 @@ -34,7 +34,7 @@ var testCount = 0; function testF(inputValue, type, testFn) { - var x = Java.toJavaArray([inputValue], type)[0]; + var x = Java.to([inputValue], type + "[]")[0]; if(!testFn(x)) { throw ("unexpected value: " + x) } @@ -130,7 +130,7 @@ function assertCantConvert(sourceType, targetType) { try { - Java.toJavaArray([new Java.type(sourceType)()], targetType) + Java.to([new Java.type(sourceType)()], targetType + "[]") throw "no TypeError encountered" } catch(e) { if(!(e instanceof TypeError)) { @@ -164,7 +164,7 @@ intArray[0] = 1234; intArray[1] = 42; intArray[2] = 5; -var jsIntArray = Java.toJavaScriptArray(intArray) +var jsIntArray = Java.from(intArray) assert(jsIntArray instanceof Array); assert(jsIntArray[0] === 1234); assert(jsIntArray[1] === 42); @@ -179,7 +179,7 @@ var byteArray = new (Java.type("byte[]"))(2) byteArray[0] = -128; byteArray[1] = 127; -var jsByteArray = Java.toJavaScriptArray(byteArray) +var jsByteArray = Java.from(byteArray) assert(jsByteArray instanceof Array); assert(jsByteArray[0] === -128); assert(jsByteArray[1] === 127); @@ -187,7 +187,7 @@ var shortArray = new (Java.type("short[]"))(2) shortArray[0] = -32768; shortArray[1] = 32767; -var jsShortArray = Java.toJavaScriptArray(shortArray) +var jsShortArray = Java.from(shortArray) assert(jsShortArray instanceof Array); assert(jsShortArray[0] === -32768); assert(jsShortArray[1] === 32767); @@ -195,7 +195,7 @@ var floatArray = new (Java.type("float[]"))(2) floatArray[0] = java.lang.Float.MIN_VALUE; floatArray[1] = java.lang.Float.MAX_VALUE; -var jsFloatArray = Java.toJavaScriptArray(floatArray) +var jsFloatArray = Java.from(floatArray) assert(jsFloatArray instanceof Array); assert(jsFloatArray[0] == java.lang.Float.MIN_VALUE); assert(jsFloatArray[1] == java.lang.Float.MAX_VALUE); @@ -204,7 +204,7 @@ charArray[0] = "a"; charArray[1] = "b"; charArray[2] = "1"; -var jsCharArray = Java.toJavaScriptArray(charArray) +var jsCharArray = Java.from(charArray) assert(jsCharArray instanceof Array); assert(jsCharArray[0] === 97); assert(jsCharArray[1] === 98); @@ -213,7 +213,7 @@ var booleanArray = new (Java.type("boolean[]"))(2) booleanArray[0] = true; booleanArray[1] = false; -var jsBooleanArray = Java.toJavaScriptArray(booleanArray) +var jsBooleanArray = Java.from(booleanArray) assert(jsBooleanArray instanceof Array); assert(jsBooleanArray[0] === true); assert(jsBooleanArray[1] === false); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/ranges_disabled.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_disabled.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** + * range analysis test. check that computation return values are correct + * both with and without range analysis + * + * @test + * @run + */ + +load(__DIR__ + "ranges_payload.js"); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/ranges_disabled.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_disabled.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,4 @@ +289 +11094405 +4294967293 +-4722 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/ranges_enabled.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_enabled.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * range analysis test. check that computation return values are correct + * both with and without range analysis + * + * @test + * @option --range-analysis + * @run + */ + +load(__DIR__ + "ranges_payload.js"); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/ranges_enabled.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_enabled.js.EXPECTED Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,4 @@ +289 +11094405 +4294967293 +-4722 diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/ranges_payload.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_payload.js Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,74 @@ +/* + * 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. + */ + +/** + * range analysis test. check that computation return values are correct + * both with and without range analysis + * + * @subtest + */ + +function f(c) { + var v = c & 0xffff; + var w = v & 0xfff; + var x = v * w; + return x; +} + +function g() { + var sum = 0; + for (var x = 0; x < 4711; x++) { + sum += x; + } + return sum; +} + +function g2() { + var sum = 0; + //make sure we overflow + var displacement = 0x7ffffffe; + for (var x = displacement; x < (displacement + 2); x++) { + sum += x; + } + return sum; +} + +//mostly provide code coverage for all the range operations +function h() { + var sum = 0; + sum += 4711; + sum &= 0xffff; + sum /= 2; + sum *= 2; + sum -= 4; + sum |= 2; + sum ^= 17; + sum = sum % 10000; + sum = -sum; + return sum +} + +print(f(17)); +print(g()); +print(g2()); +print(h()); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/basic/run-octane.js --- a/nashorn/test/script/basic/run-octane.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/basic/run-octane.js Wed May 29 16:59:55 2013 -0700 @@ -26,36 +26,20 @@ */ var tests = [ - "box2d.js", - "code-load.js", - "crypto.js", - "deltablue.js", - "earley-boyer.js", - "gbemu.js", - "mandreel.js", - "navier-stokes.js", - "pdfjs.js", - "raytrace.js", - "regexp.js", - "richards.js", - "splay.js" + {file:"box2d",suite:"Box2DBenchmark"}, + {file:"code-load",suite:"CodeLoad"}, + {file:"crypto",suite:"Crypto"}, + {file:"deltablue",suite:"DeltaBlue"}, + {file:"earley-boyer", suite:"EarleyBoyer"}, + {file:"gbemu", suite:"GameboyBenchmark"}, + {file:"mandreel", suite:"MandreelBenchmark"}, + {file:"navier-stokes", suite:"NavierStokes"}, + {file:"pdfjs", suite:"PdfJS"}, + {file:"raytrace", suite:"RayTrace"}, + {file:"regexp", suite:"RegExpSuite"}, + {file:"richards", suite:"Richards"}, + {file:"splay", suite:"Splay"} ]; - -// hack, teardown breaks things defined in the global space, making it impossible -// to do multiple consecutive benchmark runs with the same harness. I think it's a bug -// that the setup and teardown aren't each others constructor and destructor but rather -// that the benchmarks rely on partial global state. For shame, Octane! -var ignoreTeardown = [ - { name: "box2d.js" }, - { name: "gbemu.js" }, -]; - - -//TODO mandreel can be compiled as a test, but not run multiple times unless modified to not have global state -var compileOnly = { - "mandreel.js" : true -}; - var dir = (typeof(__DIR__) == 'undefined') ? "test/script/basic/" : __DIR__; // TODO: why is this path hard coded when it's defined in project properties? @@ -71,110 +55,106 @@ } function should_compile_only(name) { - return (typeof compile_only !== 'undefined') || compileOnly[name] === true; + return (typeof compile_only !== 'undefined') } function run_one_benchmark(arg, iters) { - var file_name; - var file = arg.split('/'); - if (file.length == 1) { - file = arg.split('\\'); - } - - //trim off trailing path separators - while (file[file.length - 1].indexOf(".js") == -1) { - file.pop(); - } - file_name = file[file.length - 1]; - + var file = (arg.file + ".js").split('/'); + + file_name = path + file[file.length - 1]; + var compile_and_return = should_compile_only(file_name); if (compile_and_return) { if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them return; } - print("Compiling... " + file_name); } - - load(path + 'base.js'); - load(arg); + + print_verbose("Loading... " + file_name); + load(file_name); if (compile_and_return) { - print("Compiled OK: " + file_name); - print(""); + print_always("Compiled OK: " + arg.file); return; } var success = true; - var hiscore = 0; - var loscore = 10e8; var current_name; - function PrintResult(name, result) { - current_name = name; - } - - function PrintError(name, error) { - current_name = name; - PrintResult(name, error); - success = false; - } - - function PrintScore(score) { - if (success) { - if (+score >= hiscore) { - hiscore = +score; - } - if (+score <= loscore) { - loscore = +score; - } - } - - if (verbose) { - print("Score: " + score); - } - } - if (iters == undefined) { iters = numberOfIterations; } else { numberOfIterations = iters; } - - print(runtime + ": running " + file_name + "..."); - - for (var i = 0; i < numberOfIterations; i++) { - var callbacks = - { NotifyResult: PrintResult, - NotifyError: PrintError, - NotifyScore: PrintScore }; - - for (j in ignoreTeardown) { - var ignore = ignoreTeardown[j]; - if (endsWith(arg, ignore.name)) { - var teardownOverride = ignore.teardown; - if (!teardownOverride) { - teardownOverride = function() {}; - } + + var benchmarks = eval(arg.suite + ".benchmarks"); + var min_score = 1e9; + var max_score = 0; + var mean_score = 0; - for (k in BenchmarkSuite.suites) { - var benchmarks = BenchmarkSuite.suites[k].benchmarks; - for (l in benchmarks) { - benchmarks[l].TearDown = teardownOverride; - } - } - break; - } + try { + for (var x = 0; x < benchmarks.length ; x++) { + benchmarks[x].Setup(); + } + print_verbose("Running '" + arg.file + "' for " + iters + " iterations of no less than " + min_time + " seconds (" + runtime + ")"); + + var scores = []; + + var min_time_ms = min_time * 1000; + var len = benchmarks.length; + + for (var it = 0; it < iters + 1; it++) { + //every iteration must take a minimum of 10 secs + var ops = 0; + var elapsed = 0; + var start = new Date; + do { + for (var i = 0; i < len; i++) { + benchmarks[i].run(); + } + ops += len; + elapsed = new Date - start; + } while (elapsed < min_time * 1000); + + var score = ops / elapsed * 1000 * 60; + scores.push(score); + var name = it == 0 ? "warmup" : "iteration " + it; + print_verbose("[" + arg.file + "] " + name + " finished " + score.toFixed(0) + " ops/minute"); } - - BenchmarkSuite.RunSuites(callbacks); + + for (var x = 0; x < benchmarks.length ; x++) { + benchmarks[x].TearDown(); + } + + for (var x = 1; x < iters + 1 ; x++) { + mean_score += scores[x]; + min_score = Math.min(min_score, scores[x]); + max_score = Math.max(max_score, scores[x]); + } + mean_score /= iters; + + } catch (e) { + print_always("*** Aborted and setting score to zero. Reason: " + e); + mean_score = min_score = max_score = 0; + scores = [0]; } - - var start = "Score: "; - if (runtime != "") { - start = runtime + ": "; - } - print(start + current_name + ' (version ' + BenchmarkSuite.version + '): ' + loscore + '-' + hiscore); + + var res = "[" + arg.file + "] " + mean_score.toFixed(0); + if (verbose) { + res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0); + } + print_always(res); +} + +function print_always(x) { + print(x); +} + +function print_verbose(x) { + if (verbose) { + print(x); + } } function run_suite(tests, iters) { @@ -186,6 +166,7 @@ runtime = "command line"; var args = []; + if (typeof $ARGS !== 'undefined') { args = $ARGS; } else if (typeof arguments !== 'undefined' && arguments.length != 0) { @@ -211,6 +192,7 @@ var tests_found = []; var iters = undefined; +var min_time = 5; for (var i = 0; i < args.length; i++) { arg = args[i]; @@ -220,21 +202,41 @@ runtime = args[++i]; } else if (arg == "--verbose") { verbose = true; + } else if (arg == "--min-time") { + min_time = +args[++i]; } else if (arg == "") { continue; //skip } else { - tests_found.push(arg); + var found = false; + for (j in tests) { + if (tests[j].file === arg) { + tests_found.push(tests[j]); + found = true; + break; + } + } + if (!found) { + var str = "unknown test name: '" + arg + "' -- valid names are: "; + for (j in tests) { + if (j != 0) { + str += ", "; + } + str += "'" + tests[j].file + "'"; + } + throw str; + } } } if (tests_found.length == 0) { for (i in tests) { - tests_found.push(path + tests[i]); + tests_found.push(tests[i]); } } tests_found.sort(); +load(path + 'base.js'); run_suite(tests_found, iters); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/currently-failing/logcoverage.js --- a/nashorn/test/script/currently-failing/logcoverage.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/currently-failing/logcoverage.js Wed May 29 16:59:55 2013 -0700 @@ -53,8 +53,7 @@ // set new standard err System.setErr(newErr); System.setOut(newOut); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]")); var reader = new java.io.FileReader(name); engine.eval(reader); newErr.flush(); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/trusted/NASHORN-638.js --- a/nashorn/test/script/trusted/NASHORN-638.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/trusted/NASHORN-638.js Wed May 29 16:59:55 2013 -0700 @@ -47,8 +47,7 @@ try { // set new standard err System.setErr(newErr); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]")); engine.eval(code); newErr.flush(); return new java.lang.String(baos.toByteArray()); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/script/trusted/NASHORN-653.js --- a/nashorn/test/script/trusted/NASHORN-653.js Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/script/trusted/NASHORN-653.js Wed May 29 16:59:55 2013 -0700 @@ -85,8 +85,7 @@ try { // set new standard err System.setErr(newErr); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]")); engine.eval(code); newErr.flush(); return new java.lang.String(baos.toByteArray()); diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed Jul 05 18:57:05 2017 +0200 +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed May 29 16:59:55 2013 -0700 @@ -47,7 +47,6 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleScriptContext; -import netscape.javascript.JSObject; import org.testng.Assert; import org.testng.annotations.Test; diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/src/jdk/nashorn/internal/runtime/regexp/JdkRegExpTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/regexp/JdkRegExpTest.java Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,61 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import jdk.nashorn.internal.runtime.ParserException; +import org.testng.annotations.Test; + +/** + * Basic tests for the JDK based RegExp implementation. + * + * @test + * @run testng jdk.nashorn.internal.runtime.regexp.JdkRegExpTest + */ +public class JdkRegExpTest { + + /** + * Compile a regular expression using the JDK implementation + */ + @Test + public void testMatcher() { + RegExp regexp = new RegExpFactory().compile("f(o)o", ""); + RegExpMatcher matcher = regexp.match("foo"); + assertNotNull(matcher); + assertTrue(matcher.search(0)); + assertEquals(matcher.getInput(), "foo"); + assertEquals(matcher.groupCount(), 1); + assertEquals(matcher.group(), "foo"); + assertEquals(matcher.start(), 0); + assertEquals(matcher.end(), 3); + assertEquals(matcher.group(1), "o"); + assertEquals(matcher.start(1), 1); + assertEquals(matcher.end(1), 2); + } +} diff -r 2fd6acba737b -r bf497a99ac5c nashorn/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java Wed May 29 16:59:55 2013 -0700 @@ -0,0 +1,52 @@ +/* + * 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.joni; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.Test; + +/** + * Joni coverage tests + * + * @test + * @run testng jdk.nashorn.internal.runtime.regexp.joni.JoniTest + */ +public class JoniTest { + + @Test + public void testDump() { + new Regex("^a{3,}(.*)[z]++\\s\\1x$").dumpTree(); + new Regex("^a{3,}(.*)[z]++\\s\\1x$").dumpByteCode(); + new Regex("(abc){4,}{2,5}").dumpTree(); + new Regex("(abc){4,}{2,5}").dumpByteCode(); + new Regex("aaa|aa|bbbb|ccc").dumpTree(); + new Regex("aaa|aa|bbbb|ccc").dumpByteCode(); + new Regex("(?:ZFVR.(\\d+\\.\\d+))|(?:(?:Sversbk|TenaCnenqvfb|Vprjrnfry).(\\d+\\.\\d+))|(?:Bcren.(\\d+\\.\\d+))|(?:NccyrJroXvg.(\\d+(?:\\.\\d+)?))").dumpTree(); + new Regex("(?:ZFVR.(\\d+\\.\\d+))|(?:(?:Sversbk|TenaCnenqvfb|Vprjrnfry).(\\d+\\.\\d+))|(?:Bcren.(\\d+\\.\\d+))|(?:NccyrJroXvg.(\\d+(?:\\.\\d+)?))").dumpByteCode(); + } +}