This commit is contained in:
Lana Steuck 2014-11-06 15:13:08 -08:00
commit f0dc68f1aa
201 changed files with 3297 additions and 1225 deletions

View File

@ -29,14 +29,16 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class EvalFile { public class EvalFile {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
// create a script engine manager // create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager(); final ScriptEngineManager factory = new ScriptEngineManager();
// create JavaScript engine // create JavaScript engine
ScriptEngine engine = factory.getEngineByName("nashorn"); final ScriptEngine engine = factory.getEngineByName("nashorn");
// evaluate JavaScript code from given file - specified by first argument // evaluate JavaScript code from given file - specified by first argument
engine.eval(new java.io.FileReader(args[0])); engine.eval(new java.io.FileReader(args[0]));
} }

View File

@ -29,14 +29,16 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class EvalScript { public class EvalScript {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
// create a script engine manager // create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager(); final ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine // create a JavaScript engine
ScriptEngine engine = factory.getEngineByName("nashorn"); final ScriptEngine engine = factory.getEngineByName("nashorn");
// evaluate JavaScript code from String // evaluate JavaScript code from String
engine.eval("print('Hello, World')"); engine.eval("print('Hello, World')");
} }

View File

@ -29,22 +29,25 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class InvokeScriptFunction { public class InvokeScriptFunction {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); final ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn"); final ScriptEngine engine = manager.getEngineByName("nashorn");
// JavaScript code in a String // JavaScript code in a String
String script = "function hello(name) { print('Hello, ' + name); }"; final String script = "function hello(name) { print('Hello, ' + name); }";
// evaluate script // evaluate script
engine.eval(script); engine.eval(script);
// javax.script.Invocable is an optional interface. // javax.script.Invocable is an optional interface.
// Check whether your script engine implements or not! // Check whether your script engine implements or not!
// Note that the JavaScript engine implements Invocable interface. // Note that the JavaScript engine implements Invocable interface.
Invocable inv = (Invocable) engine; final Invocable inv = (Invocable) engine;
// invoke the global function named "hello" // invoke the global function named "hello"
inv.invokeFunction("hello", "Scripting!!" ); inv.invokeFunction("hello", "Scripting!!" );

View File

@ -29,26 +29,29 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class InvokeScriptMethod { public class InvokeScriptMethod {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); final ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn"); final ScriptEngine engine = manager.getEngineByName("nashorn");
// JavaScript code in a String. This code defines a script object 'obj' // JavaScript code in a String. This code defines a script object 'obj'
// with one method called 'hello'. // with one method called 'hello'.
String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; final String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
// evaluate script // evaluate script
engine.eval(script); engine.eval(script);
// javax.script.Invocable is an optional interface. // javax.script.Invocable is an optional interface.
// Check whether your script engine implements or not! // Check whether your script engine implements or not!
// Note that the JavaScript engine implements Invocable interface. // Note that the JavaScript engine implements Invocable interface.
Invocable inv = (Invocable) engine; final Invocable inv = (Invocable) engine;
// get script object on which we want to call the method // get script object on which we want to call the method
Object obj = engine.get("obj"); final Object obj = engine.get("obj");
// invoke the method named "hello" on the script object "obj" // invoke the method named "hello" on the script object "obj"
inv.invokeMethod(obj, "hello", "Script Method !!" ); inv.invokeMethod(obj, "hello", "Script Method !!" );

View File

@ -29,12 +29,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
@SuppressWarnings("javadoc")
public class MultiScopes { public class MultiScopes {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); final ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn"); final ScriptEngine engine = manager.getEngineByName("nashorn");
engine.put("x", "hello"); engine.put("x", "hello");
// print global variable "x" // print global variable "x"
@ -42,9 +47,9 @@ public class MultiScopes {
// the above line prints "hello" // the above line prints "hello"
// Now, pass a different script context // Now, pass a different script context
ScriptContext newContext = new SimpleScriptContext(); final ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); final Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
// add new variable "x" to the new engineScope // add new variable "x" to the new engineScope
engineScope.put("x", "world"); engineScope.put("x", "world");

View File

@ -29,28 +29,31 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class RunnableImpl { public class RunnableImpl {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); final ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn"); final ScriptEngine engine = manager.getEngineByName("nashorn");
// JavaScript code in a String // JavaScript code in a String
String script = "function run() { print('run called'); }"; final String script = "function run() { print('run called'); }";
// evaluate script // evaluate script
engine.eval(script); engine.eval(script);
Invocable inv = (Invocable) engine; final Invocable inv = (Invocable) engine;
// get Runnable interface object from engine. This interface methods // get Runnable interface object from engine. This interface methods
// are implemented by script functions with the matching name. // are implemented by script functions with the matching name.
Runnable r = inv.getInterface(Runnable.class); final Runnable r = inv.getInterface(Runnable.class);
// start a new thread that runs the script implemented // start a new thread that runs the script implemented
// runnable interface // runnable interface
Thread th = new Thread(r); final Thread th = new Thread(r);
th.start(); th.start();
th.join(); th.join();
} }

View File

@ -29,31 +29,34 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class RunnableImplObject { public class RunnableImplObject {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); final ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn"); final ScriptEngine engine = manager.getEngineByName("nashorn");
// JavaScript code in a String // JavaScript code in a String
String script = "var obj = new Object(); obj.run = function() { print('run method called'); }"; final String script = "var obj = new Object(); obj.run = function() { print('run method called'); }";
// evaluate script // evaluate script
engine.eval(script); engine.eval(script);
// get script object on which we want to implement the interface with // get script object on which we want to implement the interface with
Object obj = engine.get("obj"); final Object obj = engine.get("obj");
Invocable inv = (Invocable) engine; final Invocable inv = (Invocable) engine;
// get Runnable interface object from engine. This interface methods // get Runnable interface object from engine. This interface methods
// are implemented by script methods of object 'obj' // are implemented by script methods of object 'obj'
Runnable r = inv.getInterface(obj, Runnable.class); final Runnable r = inv.getInterface(obj, Runnable.class);
// start a new thread that runs the script implemented // start a new thread that runs the script implemented
// runnable interface // runnable interface
Thread th = new Thread(r); final Thread th = new Thread(r);
th.start(); th.start();
th.join(); th.join();
} }

View File

@ -29,15 +29,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import javax.script.*; import java.io.File;
import java.io.*; import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@SuppressWarnings("javadoc")
public class ScriptVars { public class ScriptVars {
public static void main(String[] args) throws Exception { public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); final ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn"); final ScriptEngine engine = manager.getEngineByName("nashorn");
File f = new File("test.txt"); final File f = new File("test.txt");
// expose File object as variable to script // expose File object as variable to script
engine.put("file", f); engine.put("file", f);

View File

@ -97,6 +97,7 @@ import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
import jdk.internal.dynalink.support.AutoDiscovery; import jdk.internal.dynalink.support.AutoDiscovery;
import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; import jdk.internal.dynalink.support.BottomGuardingDynamicLinker;
import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider; import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider;
@ -105,6 +106,7 @@ import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.DefaultPrelinkFilter; import jdk.internal.dynalink.support.DefaultPrelinkFilter;
import jdk.internal.dynalink.support.LinkerServicesImpl; import jdk.internal.dynalink.support.LinkerServicesImpl;
import jdk.internal.dynalink.support.TypeConverterFactory; import jdk.internal.dynalink.support.TypeConverterFactory;
import jdk.internal.dynalink.support.TypeUtilities;
/** /**
* A factory class for creating {@link DynamicLinker}s. The most usual dynamic linker is a linker that is a composition * A factory class for creating {@link DynamicLinker}s. The most usual dynamic linker is a linker that is a composition
@ -115,7 +117,6 @@ import jdk.internal.dynalink.support.TypeConverterFactory;
* @author Attila Szegedi * @author Attila Szegedi
*/ */
public class DynamicLinkerFactory { public class DynamicLinkerFactory {
/** /**
* Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}. * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}.
*/ */
@ -130,6 +131,7 @@ public class DynamicLinkerFactory {
private boolean syncOnRelink = false; private boolean syncOnRelink = false;
private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD;
private GuardedInvocationFilter prelinkFilter; private GuardedInvocationFilter prelinkFilter;
private MethodTypeConversionStrategy autoConversionStrategy;
/** /**
* Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread
@ -258,6 +260,29 @@ public class DynamicLinkerFactory {
this.prelinkFilter = prelinkFilter; this.prelinkFilter = prelinkFilter;
} }
/**
* Sets an object representing the conversion strategy for automatic type conversions. After
* {@link TypeConverterFactory#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has
* applied all custom conversions to a method handle, it still needs to effect
* {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
* can usually be automatically applied as per
* {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}.
* However, sometimes language runtimes will want to customize even those conversions for their own call
* sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
* ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
* automatic conversion strategy, that can deal with null values. Note that when the strategy's
* {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)}
* is invoked, the custom language conversions will already have been applied to the method handle, so by
* design the difference between the handle's current method type and the desired final type will always
* only be ones that can be subjected to method invocation conversions. The strategy also doesn't need to
* invoke a final {@code MethodHandle.asType()} as the converter factory will do that as the final step.
* @param autoConversionStrategy the strategy for applying method invocation conversions for the linker
* created by this factory.
*/
public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) {
this.autoConversionStrategy = autoConversionStrategy;
}
/** /**
* Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as
* the pre-link filter. * the pre-link filter.
@ -324,8 +349,9 @@ public class DynamicLinkerFactory {
prelinkFilter = new DefaultPrelinkFilter(); prelinkFilter = new DefaultPrelinkFilter();
} }
return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters), composite), return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters,
prelinkFilter, runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); autoConversionStrategy), composite), prelinkFilter, runtimeContextArgCount, syncOnRelink,
unstableRelinkThreshold);
} }
private static ClassLoader getThreadContextClassLoader() { private static ClassLoader getThreadContextClassLoader() {

View File

@ -287,10 +287,21 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
*/ */
private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) { private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) {
if(CallerSensitiveDetector.isCallerSensitive(m)) { if(CallerSensitiveDetector.isCallerSensitive(m)) {
// Method has @CallerSensitive annotation
return new CallerSensitiveDynamicMethod(m); return new CallerSensitiveDynamicMethod(m);
} }
// Method has no @CallerSensitive annotation
final MethodHandle mh;
try {
mh = unreflectSafely(m);
} catch (final IllegalAccessError e) {
// java.lang.invoke can in some case conservatively treat as caller sensitive methods that aren't
// marked with the annotation. In this case, we'll fall back to treating it as caller sensitive.
return new CallerSensitiveDynamicMethod(m);
}
// Proceed with non-caller sensitive
final Member member = (Member)m; final Member member = (Member)m;
return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName(), m instanceof Constructor); return new SimpleDynamicMethod(mh, member.getDeclaringClass(), member.getName(), m instanceof Constructor);
} }
/** /**

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2014, 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file, and Oracle licenses the original version of this file under the BSD
* license:
*/
/*
Copyright 2014 Attila Szegedi
Licensed under both the Apache License, Version 2.0 (the "Apache License")
and the BSD License (the "BSD License"), with licensee being free to
choose either of the two at their discretion.
You may not use this file except in compliance with either the Apache
License or the BSD License.
If you choose to use this file in compliance with the Apache License, the
following notice applies to you:
You may obtain a copy of the Apache License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
If you choose to use this file in compliance with the BSD License, the
following notice applies to you:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.linker;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
/**
* Interface for objects representing a strategy for converting a method handle to a new type.
*/
public interface MethodTypeConversionStrategy {
/**
* Converts a method handle to a new type.
* @param target target method handle
* @param newType new type
* @return target converted to the new type.
*/
public MethodHandle asType(final MethodHandle target, final MethodType newType);
}

View File

@ -97,6 +97,7 @@ import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardedTypeConversion; import jdk.internal.dynalink.linker.GuardedTypeConversion;
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
/** /**
* A factory for type converters. This class is the main implementation behind the * A factory for type converters. This class is the main implementation behind the
@ -109,6 +110,7 @@ public class TypeConverterFactory {
private final GuardingTypeConverterFactory[] factories; private final GuardingTypeConverterFactory[] factories;
private final ConversionComparator[] comparators; private final ConversionComparator[] comparators;
private final MethodTypeConversionStrategy autoConversionStrategy;
private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() { private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
@Override @Override
@ -177,8 +179,24 @@ public class TypeConverterFactory {
* Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
* *
* @param factories the {@link GuardingTypeConverterFactory} instances to compose. * @param factories the {@link GuardingTypeConverterFactory} instances to compose.
* @param autoConversionStrategy conversion strategy for automatic type conversions. After
* {@link #asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has applied all custom
* conversions to a method handle, it still needs to effect
* {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
* can usually be automatically applied as per
* {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}.
* However, sometimes language runtimes will want to customize even those conversions for their own call
* sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
* ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
* automatic conversion strategy, that can deal with null values. Note that when the strategy's
* {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)}
* is invoked, the custom language conversions will already have been applied to the method handle, so by
* design the difference between the handle's current method type and the desired final type will always
* only be ones that can be subjected to method invocation conversions. Can be null, in which case no
* custom strategy is employed.
*/ */
public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories) { public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories,
final MethodTypeConversionStrategy autoConversionStrategy) {
final List<GuardingTypeConverterFactory> l = new LinkedList<>(); final List<GuardingTypeConverterFactory> l = new LinkedList<>();
final List<ConversionComparator> c = new LinkedList<>(); final List<ConversionComparator> c = new LinkedList<>();
for(final GuardingTypeConverterFactory factory: factories) { for(final GuardingTypeConverterFactory factory: factories) {
@ -189,20 +207,24 @@ public class TypeConverterFactory {
} }
this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]); this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]);
this.comparators = c.toArray(new ConversionComparator[c.size()]); this.comparators = c.toArray(new ConversionComparator[c.size()]);
this.autoConversionStrategy = autoConversionStrategy;
} }
/** /**
* Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
* {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
* parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive, * parameters. For all conversions that are not a JLS method invocation conversion it'll insert
* wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions, * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
* it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters * provided by {@link GuardingTypeConverterFactory} implementations. For the remaining JLS method invocation
* provided by {@link GuardingTypeConverterFactory} implementations. * conversions, it will invoke {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} first
* if an automatic conversion strategy was specified in the
* {@link #TypeConverterFactory(Iterable, MethodTypeConversionStrategy) constructor}, and finally apply
* {@link MethodHandle#asType(MethodType)} for any remaining conversions.
* *
* @param handle target method handle * @param handle target method handle
* @param fromType the types of source arguments * @param fromType the types of source arguments
* @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)},
* {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}, and
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
* {@link GuardingTypeConverterFactory} produced type converters as filters. * {@link GuardingTypeConverterFactory} produced type converters as filters.
*/ */
@ -246,8 +268,12 @@ public class TypeConverterFactory {
} }
} }
// Take care of automatic conversions // Give change to automatic conversion strategy, if one is present.
return newHandle.asType(fromType); final MethodHandle autoConvertedHandle =
autoConversionStrategy != null ? autoConversionStrategy.asType(newHandle, fromType) : newHandle;
// Do a final asType for any conversions that remain.
return autoConvertedHandle.asType(fromType);
} }
private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List<MethodHandle> converters) { private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List<MethodHandle> converters) {

View File

@ -520,4 +520,13 @@ public class TypeUtilities {
public static Class<?> getWrapperType(final Class<?> primitiveType) { public static Class<?> getWrapperType(final Class<?> primitiveType) {
return WRAPPER_TYPES.get(primitiveType); return WRAPPER_TYPES.get(primitiveType);
} }
/**
* Returns true if the passed type is a wrapper for a primitive type.
* @param type the examined type
* @return true if the passed type is a wrapper for a primitive type.
*/
public static boolean isWrapperType(final Class<?> type) {
return PRIMITIVE_TYPES.containsKey(type);
}
} }

View File

@ -27,8 +27,8 @@ package jdk.nashorn.internal;
/** /**
* Class that exposes the current state of asserts. * Class that exposes the current state of asserts.
*
*/ */
@SuppressWarnings("all")
public final class AssertsEnabled { public final class AssertsEnabled {
private static boolean assertsEnabled = false; private static boolean assertsEnabled = false;
static { static {

View File

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.net.URL;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque; import java.util.Deque;
@ -93,6 +94,8 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
private final Deque<List<IdentNode>> explodedArguments = new ArrayDeque<>(); private final Deque<List<IdentNode>> explodedArguments = new ArrayDeque<>();
private final Deque<MethodType> callSiteTypes = new ArrayDeque<>();
private static final String ARGUMENTS = ARGUMENTS_VAR.symbolName(); private static final String ARGUMENTS = ARGUMENTS_VAR.symbolName();
/** /**
@ -118,86 +121,108 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
return context.getLogger(this.getClass()); return context.getLogger(this.getClass());
} }
@SuppressWarnings("serial")
private static class TransformFailedException extends RuntimeException {
TransformFailedException(final FunctionNode fn, final String message) {
super(massageURL(fn.getSource().getURL()) + '.' + fn.getName() + " => " + message, null, false, false);
}
}
@SuppressWarnings("serial")
private static class AppliesFoundException extends RuntimeException {
AppliesFoundException() {
super("applies_found", null, false, false);
}
}
private static final AppliesFoundException HAS_APPLIES = new AppliesFoundException();
private boolean hasApplies(final FunctionNode functionNode) {
try {
functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterCallNode(final CallNode callNode) {
if (isApply(callNode)) {
throw HAS_APPLIES;
}
return true;
}
});
} catch (final AppliesFoundException e) {
return true;
}
log.fine("There are no applies in ", DebugLogger.quote(functionNode.getName()), " - nothing to do.");
return false; // no applies
}
/** /**
* Arguments may only be used as args to the apply. Everything else is disqualified * Arguments may only be used as args to the apply. Everything else is disqualified
* We cannot control arguments if they escape from the method and go into an unknown * We cannot control arguments if they escape from the method and go into an unknown
* scope, thus we are conservative and treat any access to arguments outside the * scope, thus we are conservative and treat any access to arguments outside the
* apply call as a case of "we cannot apply the optimization". * apply call as a case of "we cannot apply the optimization".
*
* @return true if arguments escape
*/ */
private boolean argumentsEscape(final FunctionNode functionNode) { private void checkValidTransform(final FunctionNode functionNode) {
@SuppressWarnings("serial")
final UnsupportedOperationException uoe = new UnsupportedOperationException() {
@Override
public synchronized Throwable fillInStackTrace() {
return null;
}
};
final Set<Expression> argumentsFound = new HashSet<>(); final Set<Expression> argumentsFound = new HashSet<>();
final Deque<Set<Expression>> stack = new ArrayDeque<>(); final Deque<Set<Expression>> stack = new ArrayDeque<>();
//ensure that arguments is only passed as arg to apply
try {
functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
private boolean isCurrentArg(final Expression expr) {
return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call
}
private boolean isArguments(final Expression expr) { //ensure that arguments is only passed as arg to apply
if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) { functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
argumentsFound.add(expr);
private boolean isCurrentArg(final Expression expr) {
return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call
}
private boolean isArguments(final Expression expr) {
if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) {
argumentsFound.add(expr);
return true;
}
return false;
}
private boolean isParam(final String name) {
for (final IdentNode param : functionNode.getParameters()) {
if (param.getName().equals(name)) {
return true; return true;
} }
return false;
} }
return false;
private boolean isParam(final String name) {
for (final IdentNode param : functionNode.getParameters()) {
if (param.getName().equals(name)) {
return true;
}
}
return false;
}
@Override
public Node leaveIdentNode(final IdentNode identNode) {
if (isParam(identNode.getName()) || isArguments(identNode) && !isCurrentArg(identNode)) {
throw uoe; //avoid filling in stack trace
}
return identNode;
}
@Override
public boolean enterCallNode(final CallNode callNode) {
final Set<Expression> callArgs = new HashSet<>();
if (isApply(callNode)) {
final List<Expression> argList = callNode.getArgs();
if (argList.size() != 2 || !isArguments(argList.get(argList.size() - 1))) {
throw new UnsupportedOperationException();
}
callArgs.addAll(callNode.getArgs());
}
stack.push(callArgs);
return true;
}
@Override
public Node leaveCallNode(final CallNode callNode) {
stack.pop();
return callNode;
}
});
} catch (final UnsupportedOperationException e) {
if (!argumentsFound.isEmpty()) {
log.fine("'arguments' is used but escapes, or is reassigned in '" + functionNode.getName() + "'. Aborting");
} }
return true; //bad
}
return false; @Override
public Node leaveIdentNode(final IdentNode identNode) {
if (isParam(identNode.getName())) {
throw new TransformFailedException(lc.getCurrentFunction(), "parameter: " + identNode.getName());
}
// it's OK if 'argument' occurs as the current argument of an apply
if (isArguments(identNode) && !isCurrentArg(identNode)) {
throw new TransformFailedException(lc.getCurrentFunction(), "is 'arguments': " + identNode.getName());
}
return identNode;
}
@Override
public boolean enterCallNode(final CallNode callNode) {
final Set<Expression> callArgs = new HashSet<>();
if (isApply(callNode)) {
final List<Expression> argList = callNode.getArgs();
if (argList.size() != 2 || !isArguments(argList.get(argList.size() - 1))) {
throw new TransformFailedException(lc.getCurrentFunction(), "argument pattern not matched: " + argList);
}
callArgs.addAll(callNode.getArgs());
}
stack.push(callArgs);
return true;
}
@Override
public Node leaveCallNode(final CallNode callNode) {
stack.pop();
return callNode;
}
});
} }
@Override @Override
@ -224,12 +249,14 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
final CallNode newCallNode = callNode.setArgs(newArgs).setIsApplyToCall(); final CallNode newCallNode = callNode.setArgs(newArgs).setIsApplyToCall();
log.fine("Transformed ", if (log.isEnabled()) {
callNode, log.fine("Transformed ",
" from apply to call => ", callNode,
newCallNode, " from apply to call => ",
" in ", newCallNode,
DebugLogger.quote(lc.getCurrentFunction().getName())); " in ",
DebugLogger.quote(lc.getCurrentFunction().getName()));
}
return newCallNode; return newCallNode;
} }
@ -237,12 +264,12 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
return callNode; return callNode;
} }
private boolean pushExplodedArgs(final FunctionNode functionNode) { private void pushExplodedArgs(final FunctionNode functionNode) {
int start = 0; int start = 0;
final MethodType actualCallSiteType = compiler.getCallSiteType(functionNode); final MethodType actualCallSiteType = compiler.getCallSiteType(functionNode);
if (actualCallSiteType == null) { if (actualCallSiteType == null) {
return false; throw new TransformFailedException(lc.getCurrentFunction(), "No callsite type");
} }
assert actualCallSiteType.parameterType(actualCallSiteType.parameterCount() - 1) != Object[].class : "error vararg callsite passed to apply2call " + functionNode.getName() + " " + actualCallSiteType; assert actualCallSiteType.parameterType(actualCallSiteType.parameterCount() - 1) != Object[].class : "error vararg callsite passed to apply2call " + functionNode.getName() + " " + actualCallSiteType;
@ -264,8 +291,8 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
} }
} }
callSiteTypes.push(actualCallSiteType);
explodedArguments.push(newParams); explodedArguments.push(newParams);
return true;
} }
@Override @Override
@ -288,11 +315,30 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
return false; return false;
} }
if (argumentsEscape(functionNode)) { if (!hasApplies(functionNode)) {
return false; return false;
} }
return pushExplodedArgs(functionNode); if (log.isEnabled()) {
log.info("Trying to specialize apply to call in '",
functionNode.getName(),
"' params=",
functionNode.getParameters(),
" id=",
functionNode.getId(),
" source=",
massageURL(functionNode.getSource().getURL()));
}
try {
checkValidTransform(functionNode);
pushExplodedArgs(functionNode);
} catch (final TransformFailedException e) {
log.info("Failure: ", e.getMessage());
return false;
}
return true;
} }
/** /**
@ -300,8 +346,8 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
* @return true if successful, false otherwise * @return true if successful, false otherwise
*/ */
@Override @Override
public Node leaveFunctionNode(final FunctionNode functionNode0) { public Node leaveFunctionNode(final FunctionNode functionNode) {
FunctionNode newFunctionNode = functionNode0; FunctionNode newFunctionNode = functionNode;
final String functionName = newFunctionNode.getName(); final String functionName = newFunctionNode.getName();
if (changed.contains(newFunctionNode.getId())) { if (changed.contains(newFunctionNode.getId())) {
@ -310,17 +356,18 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
setParameters(lc, explodedArguments.peek()); setParameters(lc, explodedArguments.peek());
if (log.isEnabled()) { if (log.isEnabled()) {
log.info("Successfully specialized apply to call in '", log.info("Success: ",
massageURL(newFunctionNode.getSource().getURL()),
'.',
functionName, functionName,
" params=",
explodedArguments.peek(),
"' id=", "' id=",
newFunctionNode.getId(), newFunctionNode.getId(),
" source=", " params=",
newFunctionNode.getSource().getURL()); callSiteTypes.peek());
} }
} }
callSiteTypes.pop();
explodedArguments.pop(); explodedArguments.pop();
return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED); return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED);
@ -331,4 +378,15 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
return f instanceof AccessNode && "apply".equals(((AccessNode)f).getProperty()); return f instanceof AccessNode && "apply".equals(((AccessNode)f).getProperty());
} }
private static String massageURL(final URL url) {
if (url == null) {
return "<null>";
}
final String str = url.toString();
final int slash = str.lastIndexOf('/');
if (slash == -1) {
return str;
}
return str.substring(slash + 1);
}
} }

View File

@ -615,7 +615,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
static final TypeBounds UNBOUNDED = new TypeBounds(Type.UNKNOWN, Type.OBJECT); static final TypeBounds UNBOUNDED = new TypeBounds(Type.UNKNOWN, Type.OBJECT);
static final TypeBounds INT = exact(Type.INT); static final TypeBounds INT = exact(Type.INT);
static final TypeBounds NUMBER = exact(Type.NUMBER);
static final TypeBounds OBJECT = exact(Type.OBJECT); static final TypeBounds OBJECT = exact(Type.OBJECT);
static final TypeBounds BOOLEAN = exact(Type.BOOLEAN); static final TypeBounds BOOLEAN = exact(Type.BOOLEAN);
@ -3569,7 +3568,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT); operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT);
} else { } else {
// Non-optimistic, non-FP +. Allow it to overflow. // Non-optimistic, non-FP +. Allow it to overflow.
operandBounds = new TypeBounds(binaryNode.getWidestOperandType(), Type.OBJECT); operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest),
Type.OBJECT);
forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest); forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest);
} }
loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation); loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation);
@ -3856,12 +3856,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
operandBounds = numericBounds; operandBounds = numericBounds;
} else { } else {
final boolean isOptimistic = isValid(getProgramPoint()); final boolean isOptimistic = isValid(getProgramPoint());
if(isOptimistic) { if(isOptimistic || node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) {
operandBounds = new TypeBounds(node.getType(), Type.NUMBER); operandBounds = new TypeBounds(node.getType(), Type.NUMBER);
} else if(node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) {
// Non-optimistic division must always take double arguments as its result must also be
// double.
operandBounds = TypeBounds.NUMBER;
} else { } else {
// Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow. // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(), operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
@ -3897,7 +3893,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private static boolean isRhsZero(final BinaryNode binaryNode) { private static boolean isRhsZero(final BinaryNode binaryNode) {
final Expression rhs = binaryNode.rhs(); final Expression rhs = binaryNode.rhs();
return rhs instanceof LiteralNode && INT_ZERO.equals(((LiteralNode)rhs).getValue()); return rhs instanceof LiteralNode && INT_ZERO.equals(((LiteralNode<?>)rhs).getValue());
} }
private void loadBIT_XOR(final BinaryNode binaryNode) { private void loadBIT_XOR(final BinaryNode binaryNode) {

View File

@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.Deque; import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import jdk.nashorn.internal.IntDeque; import jdk.nashorn.internal.IntDeque;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.Block;
@ -250,7 +249,7 @@ final class CodeGeneratorLexicalContext extends LexicalContext {
static Type getTypeForSlotDescriptor(final char typeDesc) { static Type getTypeForSlotDescriptor(final char typeDesc) {
// Recognizing both lowercase and uppercase as we're using both to signify symbol boundaries; see // Recognizing both lowercase and uppercase as we're using both to signify symbol boundaries; see
// MethodEmitter.markSymbolBoundariesInLvarTypesDescriptor(). // MethodEmitter.markSymbolBoundariesInLvarTypesDescriptor().
switch(typeDesc) { switch (typeDesc) {
case 'I': case 'I':
case 'i': case 'i':
return Type.INT; return Type.INT;

View File

@ -389,6 +389,7 @@ public final class Compiler implements Loggable {
* @param continuationEntryPoints continuation entry points for restof method * @param continuationEntryPoints continuation entry points for restof method
* @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator}
*/ */
@SuppressWarnings("unused")
public Compiler( public Compiler(
final Context context, final Context context,
final ScriptEnvironment env, final ScriptEnvironment env,

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse; import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse;
import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue; import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -236,12 +235,12 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
private byte conversions; private byte conversions;
void recordConversion(final LvarType from, final LvarType to) { void recordConversion(final LvarType from, final LvarType to) {
switch(from) { switch (from) {
case UNDEFINED: case UNDEFINED:
return; return;
case INT: case INT:
case BOOLEAN: case BOOLEAN:
switch(to) { switch (to) {
case LONG: case LONG:
recordConversion(I2L); recordConversion(I2L);
return; return;
@ -256,7 +255,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
return; return;
} }
case LONG: case LONG:
switch(to) { switch (to) {
case DOUBLE: case DOUBLE:
recordConversion(L2D); recordConversion(L2D);
return; return;
@ -1425,6 +1424,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
* @param symbol the symbol representing the variable * @param symbol the symbol representing the variable
* @param type the type * @param type the type
*/ */
@SuppressWarnings("unused")
private void setType(final Symbol symbol, final LvarType type) { private void setType(final Symbol symbol, final LvarType type) {
if(getLocalVariableTypeOrNull(symbol) == type) { if(getLocalVariableTypeOrNull(symbol) == type) {
return; return;

View File

@ -1591,7 +1591,7 @@ public class MethodEmitter implements Emitter {
/** /**
* Abstraction for performing a conditional jump of any type * Abstraction for performing a conditional jump of any type
* *
* @see MethodEmitter.Condition * @see Condition
* *
* @param cond the condition to test * @param cond the condition to test
* @param trueLabel the destination label is condition is true * @param trueLabel the destination label is condition is true
@ -2217,6 +2217,10 @@ public class MethodEmitter implements Emitter {
* @return the method emitter * @return the method emitter
*/ */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) { MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names
return load(name).dynamicGetIndex(valueType, flags, isMethod);
}
debug("dynamic_get", name, valueType, getProgramPoint(flags)); debug("dynamic_get", name, valueType, getProgramPoint(flags));
Type type = valueType; Type type = valueType;
@ -2240,9 +2244,14 @@ public class MethodEmitter implements Emitter {
* @param name name of property * @param name name of property
* @param flags call site flags * @param flags call site flags
*/ */
void dynamicSet(final String name, final int flags) { void dynamicSet(final String name, final int flags) {
assert !isOptimistic(flags); if (name.length() > LARGE_STRING_THRESHOLD) { // use setIndex for extremely long names
debug("dynamic_set", name, peekType()); load(name).swap().dynamicSetIndex(flags);
return;
}
assert !isOptimistic(flags);
debug("dynamic_set", name, peekType());
Type type = peekType(); Type type = peekType();
if (type.isObject() || type.isBoolean()) { //promote strings to objects etc if (type.isObject() || type.isBoolean()) { //promote strings to objects etc

View File

@ -25,6 +25,8 @@
package jdk.nashorn.internal.codegen; package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.MethodEmitter.LARGE_STRING_THRESHOLD;
import java.util.HashMap; import java.util.HashMap;
/** /**
@ -66,27 +68,28 @@ public class Namespace {
} }
/** /**
* Create a uniqueName name in the namespace in the form base$n where n varies * Create a uniqueName name in the namespace in the form base$n where n varies.
* . * Also truncates very long names that would otherwise break ASM.
* @param base Base of name. Base will be returned if uniqueName.
* *
* @param base Base of name. Base will be returned if uniqueName.
* @return Generated uniqueName name. * @return Generated uniqueName name.
*/ */
public String uniqueName(final String base) { public String uniqueName(final String base) {
final String truncatedBase = base.length() > LARGE_STRING_THRESHOLD ? base.substring(0, LARGE_STRING_THRESHOLD) : base;
for (Namespace namespace = this; namespace != null; namespace = namespace.getParent()) { for (Namespace namespace = this; namespace != null; namespace = namespace.getParent()) {
final HashMap<String, Integer> namespaceDirectory = namespace.directory; final HashMap<String, Integer> namespaceDirectory = namespace.directory;
final Integer counter = namespaceDirectory.get(base); final Integer counter = namespaceDirectory.get(truncatedBase);
if (counter != null) { if (counter != null) {
final int count = counter + 1; final int count = counter + 1;
namespaceDirectory.put(base, count); namespaceDirectory.put(truncatedBase, count);
return base + '-' + count; return truncatedBase + '-' + count;
} }
} }
directory.put(base, 0); directory.put(truncatedBase, 0);
return base; return truncatedBase;
} }
@Override @Override

View File

@ -323,9 +323,11 @@ public final class OptimisticTypesPersistence {
* per-code-version directory. Normally, this will create the SHA-1 digest of the nashorn.jar. In case the classpath * per-code-version directory. Normally, this will create the SHA-1 digest of the nashorn.jar. In case the classpath
* for nashorn is local directory (e.g. during development), this will create the string "dev-" followed by the * for nashorn is local directory (e.g. during development), this will create the string "dev-" followed by the
* timestamp of the most recent .class file. * timestamp of the most recent .class file.
* @return *
* @return digest of currently running nashorn
* @throws Exception if digest could not be created
*/ */
private static String getVersionDirName() throws Exception { public static String getVersionDirName() throws Exception {
final URL url = OptimisticTypesPersistence.class.getResource(""); final URL url = OptimisticTypesPersistence.class.getResource("");
final String protocol = url.getProtocol(); final String protocol = url.getProtocol();
if (protocol.equals("jar")) { if (protocol.equals("jar")) {

View File

@ -55,6 +55,7 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.runtime.JSType;
/** /**
* Type class: INT * Type class: INT
@ -230,19 +231,21 @@ class IntType extends BitwiseType {
@Override @Override
public Type div(final MethodVisitor method, final int programPoint) { public Type div(final MethodVisitor method, final int programPoint) {
// Never perform non-optimistic integer division in JavaScript. if (programPoint == INVALID_PROGRAM_POINT) {
assert programPoint != INVALID_PROGRAM_POINT; JSType.DIV_ZERO.invoke(method);
} else {
method.visitInvokeDynamicInsn("idiv", "(II)I", MATHBOOTSTRAP, programPoint); method.visitInvokeDynamicInsn("idiv", "(II)I", MATHBOOTSTRAP, programPoint);
}
return INT; return INT;
} }
@Override @Override
public Type rem(final MethodVisitor method, final int programPoint) { public Type rem(final MethodVisitor method, final int programPoint) {
// Never perform non-optimistic integer remainder in JavaScript. if (programPoint == INVALID_PROGRAM_POINT) {
assert programPoint != INVALID_PROGRAM_POINT; JSType.REM_ZERO.invoke(method);
} else {
method.visitInvokeDynamicInsn("irem", "(II)I", MATHBOOTSTRAP, programPoint); method.visitInvokeDynamicInsn("irem", "(II)I", MATHBOOTSTRAP, programPoint);
}
return INT; return INT;
} }

View File

@ -170,19 +170,21 @@ class LongType extends BitwiseType {
@Override @Override
public Type div(final MethodVisitor method, final int programPoint) { public Type div(final MethodVisitor method, final int programPoint) {
// Never perform non-optimistic integer division in JavaScript. if (programPoint == INVALID_PROGRAM_POINT) {
assert programPoint != INVALID_PROGRAM_POINT; JSType.DIV_ZERO_LONG.invoke(method);
} else {
method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint); method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint);
}
return LONG; return LONG;
} }
@Override @Override
public Type rem(final MethodVisitor method, final int programPoint) { public Type rem(final MethodVisitor method, final int programPoint) {
// Never perform non-optimistic integer remainder in JavaScript. if (programPoint == INVALID_PROGRAM_POINT) {
assert programPoint != INVALID_PROGRAM_POINT; JSType.REM_ZERO_LONG.invoke(method);
} else {
method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint); method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint);
}
return LONG; return LONG;
} }

View File

@ -356,7 +356,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps, Serializabl
final int pp = input.readInt(); final int pp = input.readInt();
final int typeChar = input.readByte(); final int typeChar = input.readByte();
final Type type; final Type type;
switch(typeChar) { switch (typeChar) {
case 'L': type = Type.OBJECT; break; case 'L': type = Type.OBJECT; break;
case 'D': type = Type.NUMBER; break; case 'D': type = Type.NUMBER; break;
case 'J': type = Type.LONG; break; case 'J': type = Type.LONG; break;
@ -376,13 +376,13 @@ public abstract class Type implements Comparable<Type>, BytecodeOps, Serializabl
} }
private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) { private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) {
final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> cache = INTERNAL_TYPE_CACHE; final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> c = INTERNAL_TYPE_CACHE;
jdk.internal.org.objectweb.asm.Type itype = cache.get(type); jdk.internal.org.objectweb.asm.Type itype = c.get(type);
if (itype != null) { if (itype != null) {
return itype; return itype;
} }
itype = jdk.internal.org.objectweb.asm.Type.getType(type); itype = jdk.internal.org.objectweb.asm.Type.getType(type);
cache.put(type, itype); c.put(type, itype);
return itype; return itype;
} }
@ -1155,6 +1155,10 @@ public abstract class Type implements Comparable<Type>, BytecodeOps, Serializabl
return type; return type;
} }
/**
* Read resolve
* @return resolved type
*/
protected final Object readResolve() { protected final Object readResolve() {
return Type.typeFor(clazz); return Type.typeFor(clazz);
} }

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.CallSiteDescriptor;
@ -44,6 +43,9 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.TypedArrayData; import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* ArrayBufferView, es6 class or TypedArray implementation
*/
@ScriptClass("ArrayBufferView") @ScriptClass("ArrayBufferView")
public abstract class ArrayBufferView extends ScriptObject { public abstract class ArrayBufferView extends ScriptObject {
private final NativeArrayBuffer buffer; private final NativeArrayBuffer buffer;
@ -71,6 +73,13 @@ public abstract class ArrayBufferView extends ScriptObject {
setArray(data); setArray(data);
} }
/**
* Constructor
*
* @param buffer underlying NativeArrayBuffer
* @param byteOffset byte offset for buffer
* @param elementLength element length in bytes
*/
protected ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) { protected ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
this(buffer, byteOffset, elementLength, Global.instance()); this(buffer, byteOffset, elementLength, Global.instance());
} }
@ -89,22 +98,42 @@ public abstract class ArrayBufferView extends ScriptObject {
return factory().bytesPerElement; return factory().bytesPerElement;
} }
/**
* Buffer getter as per spec
* @param self ArrayBufferView instance
* @return buffer
*/
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static Object buffer(final Object self) { public static Object buffer(final Object self) {
return ((ArrayBufferView)self).buffer; return ((ArrayBufferView)self).buffer;
} }
/**
* Buffer offset getter as per spec
* @param self ArrayBufferView instance
* @return buffer offset
*/
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static int byteOffset(final Object self) { public static int byteOffset(final Object self) {
return ((ArrayBufferView)self).byteOffset; return ((ArrayBufferView)self).byteOffset;
} }
/**
* Byte length getter as per spec
* @param self ArrayBufferView instance
* @return array buffer view length in bytes
*/
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static int byteLength(final Object self) { public static int byteLength(final Object self) {
final ArrayBufferView view = (ArrayBufferView)self; final ArrayBufferView view = (ArrayBufferView)self;
return ((TypedArrayData<?>)view.getArray()).getElementLength() * view.bytesPerElement(); return ((TypedArrayData<?>)view.getArray()).getElementLength() * view.bytesPerElement();
} }
/**
* Length getter as per spec
* @param self ArrayBufferView instance
* @return length in elements
*/
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static int length(final Object self) { public static int length(final Object self) {
return ((ArrayBufferView)self).elementLength(); return ((ArrayBufferView)self).elementLength();
@ -119,15 +148,29 @@ public abstract class ArrayBufferView extends ScriptObject {
return ((TypedArrayData<?>)getArray()).getElementLength(); return ((TypedArrayData<?>)getArray()).getElementLength();
} }
/**
* Factory class for byte ArrayBufferViews
*/
protected static abstract class Factory { protected static abstract class Factory {
final int bytesPerElement; final int bytesPerElement;
final int maxElementLength; final int maxElementLength;
/**
* Constructor
*
* @param bytesPerElement number of bytes per element for this buffer
*/
public Factory(final int bytesPerElement) { public Factory(final int bytesPerElement) {
this.bytesPerElement = bytesPerElement; this.bytesPerElement = bytesPerElement;
this.maxElementLength = Integer.MAX_VALUE / bytesPerElement; this.maxElementLength = Integer.MAX_VALUE / bytesPerElement;
} }
/**
* Factory method
*
* @param elementLength number of elements
* @return new ArrayBufferView
*/
public final ArrayBufferView construct(final int elementLength) { public final ArrayBufferView construct(final int elementLength) {
if (elementLength > maxElementLength) { if (elementLength > maxElementLength) {
throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength)); throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength));
@ -135,15 +178,47 @@ public abstract class ArrayBufferView extends ScriptObject {
return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength); return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength);
} }
public abstract ArrayBufferView construct(NativeArrayBuffer buffer, int byteOffset, int elementLength); /**
* Factory method
*
* @param buffer underlying buffer
* @param byteOffset byte offset
* @param elementLength number of elements
*
* @return new ArrayBufferView
*/
public abstract ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength);
public abstract TypedArrayData<?> createArrayData(ByteBuffer nb, int start, int end); /**
* Factory method for array data
*
* @param nb underlying nativebuffer
* @param start start element
* @param end end element
*
* @return new array data
*/
public abstract TypedArrayData<?> createArrayData(final ByteBuffer nb, final int start, final int end);
/**
* Get the class name for this type of buffer
*
* @return class name
*/
public abstract String getClassName(); public abstract String getClassName();
} }
/**
* Get the factor for this kind of buffer
* @return Factory
*/
protected abstract Factory factory(); protected abstract Factory factory();
/**
* Get the prototype for this ArrayBufferView
* @param global global instance
* @return prototype
*/
protected abstract ScriptObject getPrototype(final Global global); protected abstract ScriptObject getPrototype(final Global global);
@Override @Override
@ -151,10 +226,23 @@ public abstract class ArrayBufferView extends ScriptObject {
return factory().getClassName(); return factory().getClassName();
} }
/**
* Check if this array contains floats
* @return true if float array (or double)
*/
protected boolean isFloatArray() { protected boolean isFloatArray() {
return false; return false;
} }
/**
* Inheritable constructor implementation
*
* @param newObj is this a new constructor
* @param args arguments
* @param factory factory
*
* @return new ArrayBufferView
*/
protected static ArrayBufferView constructorImpl(final boolean newObj, final Object[] args, final Factory factory) { protected static ArrayBufferView constructorImpl(final boolean newObj, final Object[] args, final Factory factory) {
final Object arg0 = args.length != 0 ? args[0] : 0; final Object arg0 = args.length != 0 ? args[0] : 0;
final ArrayBufferView dest; final ArrayBufferView dest;
@ -200,6 +288,15 @@ public abstract class ArrayBufferView extends ScriptObject {
return dest; return dest;
} }
/**
* Inheritable implementation of set, if no efficient implementation is available
*
* @param self ArrayBufferView instance
* @param array array
* @param offset0 array offset
*
* @return result of setter
*/
protected static Object setImpl(final Object self, final Object array, final Object offset0) { protected static Object setImpl(final Object self, final Object array, final Object offset0) {
final ArrayBufferView dest = (ArrayBufferView)self; final ArrayBufferView dest = (ArrayBufferView)self;
final int length; final int length;
@ -244,6 +341,15 @@ public abstract class ArrayBufferView extends ScriptObject {
return (int)(length & Integer.MAX_VALUE); return (int)(length & Integer.MAX_VALUE);
} }
/**
* Implementation of subarray if no efficient override exists
*
* @param self ArrayBufferView instance
* @param begin0 begin index
* @param end0 end index
*
* @return sub array
*/
protected static ScriptObject subarrayImpl(final Object self, final Object begin0, final Object end0) { protected static ScriptObject subarrayImpl(final Object self, final Object begin0, final Object end0) {
final ArrayBufferView arrayView = (ArrayBufferView)self; final ArrayBufferView arrayView = (ArrayBufferView)self;
final int byteOffset = arrayView.byteOffset; final int byteOffset = arrayView.byteOffset;

View File

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
@ -41,7 +42,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import javax.script.ScriptContext; import javax.script.ScriptContext;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedInvocation;
@ -54,7 +54,6 @@ import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.GlobalConstants;
import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage; import jdk.nashorn.internal.runtime.NativeJavaPackage;
@ -438,9 +437,6 @@ public final class Global extends ScriptObject implements Scope {
this.scontext = scontext; this.scontext = scontext;
} }
// global constants for this global - they can be replaced with MethodHandle.constant until invalidated
private static AtomicReference<GlobalConstants> gcsInstance = new AtomicReference<>();
@Override @Override
protected Context getContext() { protected Context getContext() {
return context; return context;
@ -470,11 +466,6 @@ public final class Global extends ScriptObject implements Scope {
super(checkAndGetMap(context)); super(checkAndGetMap(context));
this.context = context; this.context = context;
this.setIsScope(); this.setIsScope();
//we can only share one instance of Global constants between globals, or we consume way too much
//memory - this is good enough for most programs
while (gcsInstance.get() == null) {
gcsInstance.compareAndSet(null, new GlobalConstants(context.getLogger(GlobalConstants.class)));
}
} }
/** /**
@ -492,15 +483,6 @@ public final class Global extends ScriptObject implements Scope {
return self instanceof Global? (Global)self : instance(); return self instanceof Global? (Global)self : instance();
} }
/**
* Return the global constants map for fields that
* can be accessed as MethodHandle.constant
* @return constant map
*/
public static GlobalConstants getConstants() {
return gcsInstance.get();
}
/** /**
* Check if we have a Global instance * Check if we have a Global instance
* @return true if one exists * @return true if one exists
@ -559,16 +541,16 @@ public final class Global extends ScriptObject implements Scope {
* as well as our extension builtin objects like "Java", "JSAdapter" as properties * as well as our extension builtin objects like "Java", "JSAdapter" as properties
* of the global scope object. * of the global scope object.
* *
* @param engine ScriptEngine to initialize * @param eng ScriptEngine to initialize
*/ */
public void initBuiltinObjects(final ScriptEngine engine) { public void initBuiltinObjects(final ScriptEngine eng) {
if (this.builtinObject != null) { if (this.builtinObject != null) {
// already initialized, just return // already initialized, just return
return; return;
} }
this.engine = engine; this.engine = eng;
init(engine); init(eng);
} }
/** /**
@ -1717,7 +1699,7 @@ public final class Global extends ScriptObject implements Scope {
return func; return func;
} }
private void init(final ScriptEngine engine) { private void init(final ScriptEngine eng) {
assert Context.getGlobal() == this : "this global is not set as current"; assert Context.getGlobal() == this : "this global is not set as current";
final ScriptEnvironment env = getContext().getEnv(); final ScriptEnvironment env = getContext().getEnv();
@ -1835,7 +1817,7 @@ public final class Global extends ScriptObject implements Scope {
addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
} }
if (engine != null) { if (eng != null) {
// default file name // default file name
addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
// __noSuchProperty__ hook for ScriptContext search of missing variables // __noSuchProperty__ hook for ScriptContext search of missing variables

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects; package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Constructor;
@ -34,6 +33,7 @@ import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter; import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction; import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptObject;
@ -137,6 +137,19 @@ public final class NativeArrayBuffer extends ScriptObject {
return ((NativeArrayBuffer)self).getByteLength(); return ((NativeArrayBuffer)self).getByteLength();
} }
/**
* Returns true if an object is an ArrayBufferView
*
* @param self self
* @param obj object to check
*
* @return true if obj is an ArrayBufferView
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static boolean isView(final Object self, final Object obj) {
return obj instanceof ArrayBufferView;
}
/** /**
* Slice function * Slice function
* @param self native array buffer * @param self native array buffer

View File

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt; import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
@ -572,7 +573,7 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
try { try {
return ((CharSequence)self).charAt(pos); return ((CharSequence)self).charAt(pos);
} catch (final IndexOutOfBoundsException e) { } catch (final IndexOutOfBoundsException e) {
throw new ClassCastException(); throw new ClassCastException(); //invalid char, out of bounds, force relink
} }
} }
@ -1380,7 +1381,6 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
* sequence and that we are in range * sequence and that we are in range
*/ */
private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic { private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic {
private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic(); private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic();
@Override @Override
@ -1389,7 +1389,7 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
//check that it's a char sequence or throw cce //check that it's a char sequence or throw cce
final CharSequence cs = (CharSequence)self; final CharSequence cs = (CharSequence)self;
//check that the index, representable as an int, is inside the array //check that the index, representable as an int, is inside the array
final int intIndex = JSType.toInteger(request.getArguments()[1]); final int intIndex = JSType.toInteger(request.getArguments()[2]);
return intIndex >= 0 && intIndex < cs.length(); //can link return intIndex >= 0 && intIndex < cs.length(); //can link
} catch (final ClassCastException | IndexOutOfBoundsException e) { } catch (final ClassCastException | IndexOutOfBoundsException e) {
//fallthru //fallthru

View File

@ -141,9 +141,8 @@ class ParserContext {
return breakable; return breakable;
} }
return null; return null;
} else {
return getBreakable();
} }
return getBreakable();
} }
/** /**

View File

@ -56,7 +56,7 @@ abstract class ParserContextBaseNode implements ParserContextNode {
/** /**
* Returns a single flag * Returns a single flag
* @param flag * @param flag flag
* @return A single flag * @return A single flag
*/ */
protected int getFlag(final int flag) { protected int getFlag(final int flag) {
@ -64,7 +64,7 @@ abstract class ParserContextBaseNode implements ParserContextNode {
} }
/** /**
* @param flag * @param flag flag
* @return the new flags * @return the new flags
*/ */
@Override @Override
@ -82,7 +82,7 @@ abstract class ParserContextBaseNode implements ParserContextNode {
} }
/** /**
* @param statements * @param statements statements
*/ */
@Override @Override
public void setStatements(final List<Statement> statements) { public void setStatements(final List<Statement> statements) {

View File

@ -41,6 +41,7 @@ import java.security.PrivilegedExceptionAction;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.logging.DebugLogger; import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable; import jdk.nashorn.internal.runtime.logging.Loggable;
@ -102,7 +103,7 @@ public abstract class CodeStore implements Loggable {
} catch (final AccessControlException e) { } catch (final AccessControlException e) {
context.getLogger(CodeStore.class).warning("failed to load code store provider ", e); context.getLogger(CodeStore.class).warning("failed to load code store provider ", e);
} }
final CodeStore store = new DirectoryCodeStore(); final CodeStore store = new DirectoryCodeStore(context);
store.initLogger(context); store.initLogger(context);
return store; return store;
} }
@ -210,32 +211,34 @@ public abstract class CodeStore implements Loggable {
/** /**
* Constructor * Constructor
* *
* @param context the current context
* @throws IOException if there are read/write problems with the cache and cache directory * @throws IOException if there are read/write problems with the cache and cache directory
*/ */
public DirectoryCodeStore() throws IOException { public DirectoryCodeStore(final Context context) throws IOException {
this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE); this(context, Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE);
} }
/** /**
* Constructor * Constructor
* *
* @param context the current context
* @param path directory to store code in * @param path directory to store code in
* @param readOnly is this a read only code store * @param readOnly is this a read only code store
* @param minSize minimum file size for caching scripts * @param minSize minimum file size for caching scripts
* @throws IOException if there are read/write problems with the cache and cache directory * @throws IOException if there are read/write problems with the cache and cache directory
*/ */
public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException { public DirectoryCodeStore(final Context context, final String path, final boolean readOnly, final int minSize) throws IOException {
this.dir = checkDirectory(path, readOnly); this.dir = checkDirectory(path, context.getEnv(), readOnly);
this.readOnly = readOnly; this.readOnly = readOnly;
this.minSize = minSize; this.minSize = minSize;
} }
private static File checkDirectory(final String path, final boolean readOnly) throws IOException { private static File checkDirectory(final String path, final ScriptEnvironment env, final boolean readOnly) throws IOException {
try { try {
return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() {
@Override @Override
public File run() throws IOException { public File run() throws IOException {
final File dir = new File(path).getAbsoluteFile(); final File dir = new File(path, getVersionDir(env)).getAbsoluteFile();
if (readOnly) { if (readOnly) {
if (!dir.exists() || !dir.isDirectory()) { if (!dir.exists() || !dir.isDirectory()) {
throw new IOException("Not a directory: " + dir.getPath()); throw new IOException("Not a directory: " + dir.getPath());
@ -257,6 +260,15 @@ public abstract class CodeStore implements Loggable {
} }
} }
private static String getVersionDir(final ScriptEnvironment env) throws IOException {
try {
final String versionDir = OptimisticTypesPersistence.getVersionDirName();
return env._optimistic_types ? versionDir + "_opt" : versionDir;
} catch (final Exception e) {
throw new IOException(e);
}
}
@Override @Override
public StoredScript load(final Source source, final String functionKey) { public StoredScript load(final Source source, final String functionKey) {
if (source.getLength() < minSize) { if (source.getLength() < minSize) {

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import java.lang.invoke.CallSite; import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@ -777,7 +776,7 @@ final class CompiledFunction {
// Compiler needs a call site type as its input, which always has a callee parameter, so we must add it if // Compiler needs a call site type as its input, which always has a callee parameter, so we must add it if
// this function doesn't have a callee parameter. // this function doesn't have a callee parameter.
final MethodType callSiteType = type.parameterType(0) == ScriptFunction.class ? final MethodType ct = type.parameterType(0) == ScriptFunction.class ?
type : type :
type.insertParameterTypes(0, ScriptFunction.class); type.insertParameterTypes(0, ScriptFunction.class);
final OptimismInfo currentOptInfo = optimismInfo; final OptimismInfo currentOptInfo = optimismInfo;
@ -788,29 +787,29 @@ final class CompiledFunction {
final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo; final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
FunctionNode fn = effectiveOptInfo.reparse(); FunctionNode fn = effectiveOptInfo.reparse();
final boolean serialized = effectiveOptInfo.isSerialized(); final boolean serialized = effectiveOptInfo.isSerialized();
final Compiler compiler = effectiveOptInfo.getCompiler(fn, callSiteType, re); //set to non rest-of final Compiler compiler = effectiveOptInfo.getCompiler(fn, ct, re); //set to non rest-of
if (!shouldRecompile) { if (!shouldRecompile) {
// It didn't necessarily recompile, e.g. for an outer invocation of a recursive function if we already // It didn't necessarily recompile, e.g. for an outer invocation of a recursive function if we already
// recompiled a deoptimized version for an inner invocation. // recompiled a deoptimized version for an inner invocation.
// We still need to do the rest of from the beginning // We still need to do the rest of from the beginning
logRecompile("Rest-of compilation [STANDALONE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints); logRecompile("Rest-of compilation [STANDALONE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null); return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
} }
logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints); logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE); fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
log.info("Reusable IR generated"); log.info("Reusable IR generated");
// compile the rest of the function, and install it // compile the rest of the function, and install it
log.info("Generating and installing bytecode from reusable IR..."); log.info("Generating and installing bytecode from reusable IR...");
logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints); logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL); final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL);
if (effectiveOptInfo.data.usePersistentCodeCache()) { if (effectiveOptInfo.data.usePersistentCodeCache()) {
final RecompilableScriptFunctionData data = effectiveOptInfo.data; final RecompilableScriptFunctionData data = effectiveOptInfo.data;
final int functionNodeId = data.getFunctionNodeId(); final int functionNodeId = data.getFunctionNodeId();
final TypeMap typeMap = data.typeMap(callSiteType); final TypeMap typeMap = data.typeMap(ct);
final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId); final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
final String cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes); final String cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
compiler.persistClassInfo(cacheKey, normalFn); compiler.persistClassInfo(cacheKey, normalFn);
@ -871,6 +870,7 @@ final class CompiledFunction {
private SwitchPoint optimisticAssumptions; private SwitchPoint optimisticAssumptions;
private final DebugLogger log; private final DebugLogger log;
@SuppressWarnings("unused")
OptimismInfo(final RecompilableScriptFunctionData data, final Map<Integer, Type> invalidatedProgramPoints) { OptimismInfo(final RecompilableScriptFunctionData data, final Map<Integer, Type> invalidatedProgramPoints) {
this.data = data; this.data = data;
this.log = data.getLogger(); this.log = data.getLogger();

View File

@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.Source.sourceFor; import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -60,6 +61,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.logging.Level; import java.util.logging.Level;
@ -262,6 +264,10 @@ public final class Context {
// persistent code store // persistent code store
private CodeStore codeStore; private CodeStore codeStore;
// A factory for linking global properties as constant method handles. It is created when the first Global
// is created, and invalidated forever once the second global is created.
private final AtomicReference<GlobalConstants> globalConstantsRef = new AtomicReference<>();
/** /**
* Get the current global scope * Get the current global scope
* @return the current global scope * @return the current global scope
@ -293,7 +299,10 @@ public final class Context {
assert getGlobal() != global; assert getGlobal() != global;
//same code can be cached between globals, then we need to invalidate method handle constants //same code can be cached between globals, then we need to invalidate method handle constants
if (global != null) { if (global != null) {
Global.getConstants().invalidateAll(); final GlobalConstants globalConstants = getContext(global).getGlobalConstants();
if (globalConstants != null) {
globalConstants.invalidateAll();
}
} }
currentGlobal.set(global); currentGlobal.set(global);
} }
@ -528,6 +537,15 @@ public final class Context {
return classFilter; return classFilter;
} }
/**
* Returns the factory for constant method handles for global properties. The returned factory can be
* invalidated if this Context has more than one Global.
* @return the factory for constant method handles for global properties.
*/
GlobalConstants getGlobalConstants() {
return globalConstantsRef.get();
}
/** /**
* Get the error manager for this context * Get the error manager for this context
* @return error manger * @return error manger
@ -1016,9 +1034,32 @@ public final class Context {
* @return the global script object * @return the global script object
*/ */
public Global newGlobal() { public Global newGlobal() {
createOrInvalidateGlobalConstants();
return new Global(this); return new Global(this);
} }
private void createOrInvalidateGlobalConstants() {
for (;;) {
final GlobalConstants currentGlobalConstants = getGlobalConstants();
if (currentGlobalConstants != null) {
// Subsequent invocation; we're creating our second or later Global. GlobalConstants is not safe to use
// with more than one Global, as the constant method handle linkages it creates create a coupling
// between the Global and the call sites in the compiled code.
currentGlobalConstants.invalidateForever();
return;
}
final GlobalConstants newGlobalConstants = new GlobalConstants(getLogger(GlobalConstants.class));
if (globalConstantsRef.compareAndSet(null, newGlobalConstants)) {
// First invocation; we're creating the first Global in this Context. Create the GlobalConstants object
// for this Context.
return;
}
// If we reach here, then we started out as the first invocation, but another concurrent invocation won the
// CAS race. We'll just let the loop repeat and invalidate the CAS race winner.
}
}
/** /**
* Initialize given global scope object. * Initialize given global scope object.
* *
@ -1057,12 +1098,19 @@ public final class Context {
* @return current global's context * @return current global's context
*/ */
static Context getContextTrusted() { static Context getContextTrusted() {
return ((ScriptObject)Context.getGlobal()).getContext(); return getContext(getGlobal());
} }
static Context getContextTrustedOrNull() { static Context getContextTrustedOrNull() {
final Global global = Context.getGlobal(); final Global global = Context.getGlobal();
return global == null ? null : ((ScriptObject)global).getContext(); return global == null ? null : getContext(global);
}
private static Context getContext(final Global global) {
// We can't invoke Global.getContext() directly, as it's a protected override, and Global isn't in our package.
// In order to access the method, we must cast it to ScriptObject first (which is in our package) and then let
// virtual invocation do its thing.
return ((ScriptObject)global).getContext();
} }
/** /**
@ -1150,9 +1198,8 @@ public final class Context {
StoredScript storedScript = null; StoredScript storedScript = null;
FunctionNode functionNode = null; FunctionNode functionNode = null;
// We only use the code store here if optimistic types are disabled. With optimistic types, // We only use the code store here if optimistic types are disabled. With optimistic types, initial compilation
// code is stored per function in RecompilableScriptFunctionData. // just creates a thin wrapper, and actual code is stored per function in RecompilableScriptFunctionData.
// TODO: This should really be triggered by lazy compilation, not optimistic types.
final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types; final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null; final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;

View File

@ -96,15 +96,17 @@ public final class ECMAException extends NashornException {
// If thrown object is an Error or sub-object like TypeError, then // If thrown object is an Error or sub-object like TypeError, then
// an ECMAException object has been already initialized at constructor. // an ECMAException object has been already initialized at constructor.
if (thrown instanceof ScriptObject) { if (thrown instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject)thrown; final Object exception = getException((ScriptObject)thrown);
final Object exception = getException(sobj);
if (exception instanceof ECMAException) { if (exception instanceof ECMAException) {
// copy over file name, line number and column number.
final ECMAException ee = (ECMAException)exception; final ECMAException ee = (ECMAException)exception;
ee.setFileName(fileName); // Make sure exception has correct thrown reference because that's what will end up getting caught.
ee.setLineNumber(line); if (ee.getThrown() == thrown) {
ee.setColumnNumber(column); // copy over file name, line number and column number.
return ee; ee.setFileName(fileName);
ee.setLineNumber(line);
ee.setColumnNumber(column);
return ee;
}
} }
} }
@ -154,7 +156,11 @@ public final class ECMAException extends NashornException {
* @return a {@link ECMAException} * @return a {@link ECMAException}
*/ */
public static Object getException(final ScriptObject errObj) { public static Object getException(final ScriptObject errObj) {
return errObj.get(ECMAException.EXCEPTION_PROPERTY); // Exclude inherited properties that may belong to errors in the prototype chain.
if (errObj.hasOwnProperty(ECMAException.EXCEPTION_PROPERTY)) {
return errObj.get(ECMAException.EXCEPTION_PROPERTY);
}
return null;
} }
/** /**

View File

@ -31,12 +31,14 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint; import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint;
import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote; import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.SwitchPoint; import java.lang.invoke.SwitchPoint;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinker; import jdk.internal.dynalink.DynamicLinker;
@ -50,7 +52,7 @@ import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger; import jdk.nashorn.internal.runtime.logging.Logger;
/** /**
* Each global owns one of these. This is basically table of accessors * Each context owns one of these. This is basically table of accessors
* for global properties. A global constant is evaluated to a MethodHandle.constant * for global properties. A global constant is evaluated to a MethodHandle.constant
* for faster access and to avoid walking to proto chain looking for it. * for faster access and to avoid walking to proto chain looking for it.
* *
@ -67,12 +69,19 @@ import jdk.nashorn.internal.runtime.logging.Logger;
* reregister the switchpoint. Set twice or more - don't try again forever, or we'd * reregister the switchpoint. Set twice or more - don't try again forever, or we'd
* just end up relinking our way into megamorphisism. * just end up relinking our way into megamorphisism.
* *
* Also it has to be noted that this kind of linking creates a coupling between a Global
* and the call sites in compiled code belonging to the Context. For this reason, the
* linkage becomes incorrect as soon as the Context has more than one Global. The
* {@link #invalidateForever()} is invoked by the Context to invalidate all linkages and
* turn off the functionality of this object as soon as the Context's {@link Context#newGlobal()} is invoked
* for second time.
*
* We can extend this to ScriptObjects in general (GLOBAL_ONLY=false), which requires * We can extend this to ScriptObjects in general (GLOBAL_ONLY=false), which requires
* a receiver guard on the constant getter, but it currently leaks memory and its benefits * a receiver guard on the constant getter, but it currently leaks memory and its benefits
* have not yet been investigated property. * have not yet been investigated property.
* *
* As long as all Globals share the same constant instance, we need synchronization * As long as all Globals in a Context share the same GlobalConstants instance, we need synchronization
* whenever we access the instance. * whenever we access it.
*/ */
@Logger(name="const") @Logger(name="const")
public final class GlobalConstants implements Loggable { public final class GlobalConstants implements Loggable {
@ -82,7 +91,7 @@ public final class GlobalConstants implements Loggable {
* Script objects require a receiver guard, which is memory intensive, so this is currently * Script objects require a receiver guard, which is memory intensive, so this is currently
* disabled. We might implement a weak reference based approach to this later. * disabled. We might implement a weak reference based approach to this later.
*/ */
private static final boolean GLOBAL_ONLY = true; public static final boolean GLOBAL_ONLY = true;
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
@ -98,6 +107,8 @@ public final class GlobalConstants implements Loggable {
*/ */
private final Map<String, Access> map = new HashMap<>(); private final Map<String, Access> map = new HashMap<>();
private final AtomicBoolean invalidatedForever = new AtomicBoolean(false);
/** /**
* Constructor - used only by global * Constructor - used only by global
* @param log logger, or null if none * @param log logger, or null if none
@ -216,10 +227,34 @@ public final class GlobalConstants implements Loggable {
* the same class for a new global, but the builtins and global scoped variables * the same class for a new global, but the builtins and global scoped variables
* will have changed. * will have changed.
*/ */
public synchronized void invalidateAll() { public void invalidateAll() {
log.info("New global created - invalidating all constant callsites without increasing invocation count."); if (!invalidatedForever.get()) {
for (final Access acc : map.values()) { log.info("New global created - invalidating all constant callsites without increasing invocation count.");
acc.invalidateUncounted(); synchronized (this) {
for (final Access acc : map.values()) {
acc.invalidateUncounted();
}
}
}
}
/**
* To avoid an expensive global guard "is this the same global", similar to the
* receiver guard on the ScriptObject level, we invalidate all getters when the
* second Global is created by the Context owning this instance. After this
* method is invoked, this GlobalConstants instance will both invalidate all the
* switch points it produced, and it will stop handing out new method handles
* altogether.
*/
public void invalidateForever() {
if (invalidatedForever.compareAndSet(false, true)) {
log.info("New global created - invalidating all constant callsites.");
synchronized (this) {
for (final Access acc : map.values()) {
acc.invalidateForever();
}
map.clear();
}
} }
} }
@ -251,7 +286,7 @@ public final class GlobalConstants implements Loggable {
return obj; return obj;
} }
private synchronized Access getOrCreateSwitchPoint(final String name) { private Access getOrCreateSwitchPoint(final String name) {
Access acc = map.get(name); Access acc = map.get(name);
if (acc != null) { if (acc != null) {
return acc; return acc;
@ -267,9 +302,13 @@ public final class GlobalConstants implements Loggable {
* @param name name of property * @param name name of property
*/ */
void delete(final String name) { void delete(final String name) {
final Access acc = map.get(name); if (!invalidatedForever.get()) {
if (acc != null) { synchronized (this) {
acc.invalidateForever(); final Access acc = map.get(name);
if (acc != null) {
acc.invalidateForever();
}
}
} }
} }
@ -313,45 +352,45 @@ public final class GlobalConstants implements Loggable {
* *
* @return null if failed to set up constant linkage * @return null if failed to set up constant linkage
*/ */
synchronized GuardedInvocation findSetMethod(final FindProperty find, final ScriptObject receiver, final GuardedInvocation inv, final CallSiteDescriptor desc, final LinkRequest request) { GuardedInvocation findSetMethod(final FindProperty find, final ScriptObject receiver, final GuardedInvocation inv, final CallSiteDescriptor desc, final LinkRequest request) {
if (GLOBAL_ONLY && !isGlobalSetter(receiver, find)) { if (invalidatedForever.get() || (GLOBAL_ONLY && !isGlobalSetter(receiver, find))) {
return null; return null;
} }
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final Access acc = getOrCreateSwitchPoint(name); synchronized (this) {
final Access acc = getOrCreateSwitchPoint(name);
if (log.isEnabled()) {
log.fine("Trying to link constant SETTER ", acc);
}
if (!acc.mayRetry()) {
if (log.isEnabled()) { if (log.isEnabled()) {
log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation()); log.fine("Trying to link constant SETTER ", acc);
} }
return null;
if (!acc.mayRetry() || invalidatedForever.get()) {
if (log.isEnabled()) {
log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
}
return null;
}
if (acc.hasBeenInvalidated()) {
log.info("New chance for " + acc);
acc.newSwitchPoint();
}
assert !acc.hasBeenInvalidated();
// if we haven't given up on this symbol, add a switchpoint invalidation filter to the receiver parameter
final MethodHandle target = inv.getInvocation();
final Class<?> receiverType = target.type().parameterType(0);
final MethodHandle boundInvalidator = MH.bindTo(INVALIDATE_SP, this);
final MethodHandle invalidator = MH.asType(boundInvalidator, boundInvalidator.type().changeParameterType(0, receiverType).changeReturnType(receiverType));
final MethodHandle mh = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc));
assert inv.getSwitchPoints() == null : Arrays.asList(inv.getSwitchPoints());
log.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint());
return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException());
} }
assert acc.mayRetry();
if (acc.hasBeenInvalidated()) {
log.info("New chance for " + acc);
acc.newSwitchPoint();
}
assert !acc.hasBeenInvalidated();
// if we haven't given up on this symbol, add a switchpoint invalidation filter to the receiver parameter
final MethodHandle target = inv.getInvocation();
final Class<?> receiverType = target.type().parameterType(0);
final MethodHandle boundInvalidator = MH.bindTo(INVALIDATE_SP, this);
final MethodHandle invalidator = MH.asType(boundInvalidator, boundInvalidator.type().changeParameterType(0, receiverType).changeReturnType(receiverType));
final MethodHandle mh = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc));
assert inv.getSwitchPoints() == null : Arrays.asList(inv.getSwitchPoints());
log.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint());
return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException());
} }
/** /**
@ -380,11 +419,11 @@ public final class GlobalConstants implements Loggable {
* *
* @return resulting getter, or null if failed to create constant * @return resulting getter, or null if failed to create constant
*/ */
synchronized GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc) { GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc) {
// Only use constant getter for fast scope access, because the receiver may change between invocations // Only use constant getter for fast scope access, because the receiver may change between invocations
// for slow-scope and non-scope callsites. // for slow-scope and non-scope callsites.
// Also return null for user accessor properties as they may have side effects. // Also return null for user accessor properties as they may have side effects.
if (!NashornCallSiteDescriptor.isFastScope(desc) if (invalidatedForever.get() || !NashornCallSiteDescriptor.isFastScope(desc)
|| (GLOBAL_ONLY && !find.getOwner().isGlobal()) || (GLOBAL_ONLY && !find.getOwner().isGlobal())
|| find.getProperty() instanceof UserAccessorProperty) { || find.getProperty() instanceof UserAccessorProperty) {
return null; return null;
@ -395,51 +434,53 @@ public final class GlobalConstants implements Loggable {
final Class<?> retType = desc.getMethodType().returnType(); final Class<?> retType = desc.getMethodType().returnType();
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final Access acc = getOrCreateSwitchPoint(name); synchronized (this) {
final Access acc = getOrCreateSwitchPoint(name);
log.fine("Starting to look up object value " + name); log.fine("Starting to look up object value " + name);
final Object c = find.getObjectValue(); final Object c = find.getObjectValue();
if (log.isEnabled()) {
log.fine("Trying to link constant GETTER " + acc + " value = " + c);
}
if (acc.hasBeenInvalidated() || acc.guardFailed()) {
if (log.isEnabled()) { if (log.isEnabled()) {
log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation()); log.fine("Trying to link constant GETTER " + acc + " value = " + c);
} }
return null;
}
final MethodHandle cmh = constantGetter(c); if (acc.hasBeenInvalidated() || acc.guardFailed() || invalidatedForever.get()) {
if (log.isEnabled()) {
log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
}
return null;
}
MethodHandle mh; final MethodHandle cmh = constantGetter(c);
MethodHandle guard;
if (isOptimistic) { MethodHandle mh;
if (JSType.getAccessorTypeIndex(cmh.type().returnType()) <= JSType.getAccessorTypeIndex(retType)) { MethodHandle guard;
//widen return type - this is pessimistic, so it will always work
mh = MH.asType(cmh, cmh.type().changeReturnType(retType)); if (isOptimistic) {
if (JSType.getAccessorTypeIndex(cmh.type().returnType()) <= JSType.getAccessorTypeIndex(retType)) {
//widen return type - this is pessimistic, so it will always work
mh = MH.asType(cmh, cmh.type().changeReturnType(retType));
} else {
//immediately invalidate - we asked for a too wide constant as a narrower one
mh = MH.dropArguments(MH.insertArguments(JSType.THROW_UNWARRANTED.methodHandle(), 0, c, programPoint), 0, Object.class);
}
} else { } else {
//immediately invalidate - we asked for a too wide constant as a narrower one //pessimistic return type filter
mh = MH.dropArguments(MH.insertArguments(JSType.THROW_UNWARRANTED.methodHandle(), 0, c, programPoint), 0, Object.class); mh = Lookup.filterReturnType(cmh, retType);
} }
} else {
//pessimistic return type filter
mh = Lookup.filterReturnType(cmh, retType);
}
if (find.getOwner().isGlobal()) { if (find.getOwner().isGlobal()) {
guard = null; guard = null;
} else { } else {
guard = MH.insertArguments(RECEIVER_GUARD, 0, acc, receiver); guard = MH.insertArguments(RECEIVER_GUARD, 0, acc, receiver);
} }
if (log.isEnabled()) { if (log.isEnabled()) {
log.info("Linked getter " + quote(name) + " as MethodHandle.constant() -> " + c + " " + acc.getSwitchPoint()); log.info("Linked getter " + quote(name) + " as MethodHandle.constant() -> " + c + " " + acc.getSwitchPoint());
mh = MethodHandleFactory.addDebugPrintout(log, Level.FINE, mh, "get const " + acc); mh = MethodHandleFactory.addDebugPrintout(log, Level.FINE, mh, "get const " + acc);
} }
return new GuardedInvocation(mh, guard, acc.getSwitchPoint(), null); return new GuardedInvocation(mh, guard, acc.getSwitchPoint(), null);
}
} }
} }

View File

@ -150,6 +150,12 @@ public enum JSType {
/** Div exact wrapper for potentially integer division that turns into float point */ /** Div exact wrapper for potentially integer division that turns into float point */
public static final Call DIV_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class); public static final Call DIV_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class);
/** Div zero wrapper for integer division that handles (0/0)|0 == 0 */
public static final Call DIV_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class);
/** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */
public static final Call REM_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class);
/** Mod exact wrapper for potentially integer remainders that turns into float point */ /** Mod exact wrapper for potentially integer remainders that turns into float point */
public static final Call REM_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class); public static final Call REM_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class);
@ -174,6 +180,12 @@ public enum JSType {
/** Div exact wrapper for potentially integer division that turns into float point */ /** Div exact wrapper for potentially integer division that turns into float point */
public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class); public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class);
/** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class);
/** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class);
/** Mod exact wrapper for potentially integer remainders that turns into float point */ /** Mod exact wrapper for potentially integer remainders that turns into float point */
public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class); public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class);
@ -1485,6 +1497,28 @@ public enum JSType {
throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
} }
/**
* Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to
* {@code (x / y)|0} JavaScript expression (division of two ints coerced to int).
* @param x the dividend
* @param y the divisor
* @return the result
*/
public static int divZero(final int x, final int y) {
return y == 0 ? 0 : x / y;
}
/**
* Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to
* {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int).
* @param x the dividend
* @param y the divisor
* @return the remainder
*/
public static int remZero(final int x, final int y) {
return y == 0 ? 0 : x % y;
}
/** /**
* Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
* *
@ -1528,6 +1562,28 @@ public enum JSType {
throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); throw new UnwarrantedOptimismException((double)x / (double)y, programPoint);
} }
/**
* Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs
* is coerced to long.
* @param x the dividend
* @param y the divisor
* @return the result
*/
public static long divZero(final long x, final long y) {
return y == 0L ? 0L : x / y;
}
/**
* Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs
* is coerced to long.
* @param x the dividend
* @param y the divisor
* @return the remainder
*/
public static long remZero(final long x, final long y) {
return y == 0L ? 0L : x % y;
}
/** /**
* Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
* *

View File

@ -84,7 +84,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
private transient WeakHashMap<Property, SoftReference<PropertyMap>> history; private transient WeakHashMap<Property, SoftReference<PropertyMap>> history;
/** History of prototypes, used to limit map duplication. */ /** History of prototypes, used to limit map duplication. */
private transient WeakHashMap<PropertyMap, SoftReference<PropertyMap>> protoHistory; private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory;
/** property listeners */ /** property listeners */
private transient PropertyListeners listeners; private transient PropertyListeners listeners;
@ -677,14 +677,14 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/** /**
* Check prototype history for an existing property map with specified prototype. * Check prototype history for an existing property map with specified prototype.
* *
* @param parentMap New prototype object. * @param proto New prototype object.
* *
* @return Existing {@link PropertyMap} or {@code null} if not found. * @return Existing {@link PropertyMap} or {@code null} if not found.
*/ */
private PropertyMap checkProtoHistory(final PropertyMap parentMap) { private PropertyMap checkProtoHistory(final ScriptObject proto) {
final PropertyMap cachedMap; final PropertyMap cachedMap;
if (protoHistory != null) { if (protoHistory != null) {
final SoftReference<PropertyMap> weakMap = protoHistory.get(parentMap); final SoftReference<PropertyMap> weakMap = protoHistory.get(proto);
cachedMap = (weakMap != null ? weakMap.get() : null); cachedMap = (weakMap != null ? weakMap.get() : null);
} else { } else {
cachedMap = null; cachedMap = null;
@ -700,15 +700,15 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/** /**
* Add a map to the prototype history. * Add a map to the prototype history.
* *
* @param parentMap Prototype to add (key.) * @param newProto Prototype to add (key.)
* @param newMap {@link PropertyMap} associated with prototype. * @param newMap {@link PropertyMap} associated with prototype.
*/ */
private void addToProtoHistory(final PropertyMap parentMap, final PropertyMap newMap) { private void addToProtoHistory(final ScriptObject newProto, final PropertyMap newMap) {
if (protoHistory == null) { if (protoHistory == null) {
protoHistory = new WeakHashMap<>(); protoHistory = new WeakHashMap<>();
} }
protoHistory.put(parentMap, new SoftReference<>(newMap)); protoHistory.put(newProto, new SoftReference<>(newMap));
} }
/** /**
@ -883,8 +883,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*/ */
public PropertyMap changeProto(final ScriptObject newProto) { public PropertyMap changeProto(final ScriptObject newProto) {
final PropertyMap parentMap = newProto == null ? null : newProto.getMap(); final PropertyMap nextMap = checkProtoHistory(newProto);
final PropertyMap nextMap = checkProtoHistory(parentMap);
if (nextMap != null) { if (nextMap != null) {
return nextMap; return nextMap;
} }
@ -894,7 +893,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
} }
final PropertyMap newMap = new PropertyMap(this); final PropertyMap newMap = new PropertyMap(this);
addToProtoHistory(parentMap, newMap); addToProtoHistory(newProto, newMap);
return newMap; return newMap;
} }

View File

@ -475,6 +475,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
* @return either the existing map, or a loaded map from the persistent type info cache, or a new empty map if * @return either the existing map, or a loaded map from the persistent type info cache, or a new empty map if
* neither an existing map or a persistent cached type info is available. * neither an existing map or a persistent cached type info is available.
*/ */
@SuppressWarnings("unused")
private static Map<Integer, Type> getEffectiveInvalidatedProgramPoints( private static Map<Integer, Type> getEffectiveInvalidatedProgramPoints(
final Map<Integer, Type> invalidatedProgramPoints, final Object typeInformationFile) { final Map<Integer, Type> invalidatedProgramPoints, final Object typeInformationFile) {
if(invalidatedProgramPoints != null) { if(invalidatedProgramPoints != null) {
@ -727,7 +728,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
assert existingBest != null; assert existingBest != null;
//we are calling a vararg method with real args //we are calling a vararg method with real args
boolean applyToCall = existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType); boolean varArgWithRealArgs = existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType);
//if the best one is an apply to call, it has to match the callsite exactly //if the best one is an apply to call, it has to match the callsite exactly
//or we need to regenerate //or we need to regenerate
@ -736,14 +737,16 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if (best != null) { if (best != null) {
return best; return best;
} }
applyToCall = true; varArgWithRealArgs = true;
} }
if (applyToCall) { if (varArgWithRealArgs) {
// special case: we had an apply to call, but we failed to make it fit.
// Try to generate a specialized one for this callsite. It may
// be another apply to call specialization, or it may not, but whatever
// it is, it is a specialization that is guaranteed to fit
final FunctionInitializer fnInit = compileTypeSpecialization(callSiteType, runtimeScope, false); final FunctionInitializer fnInit = compileTypeSpecialization(callSiteType, runtimeScope, false);
if ((fnInit.getFlags() & FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION) != 0) { //did the specialization work existingBest = addCode(fnInit, callSiteType);
existingBest = addCode(fnInit, callSiteType);
}
} }
return existingBest; return existingBest;

View File

@ -212,6 +212,7 @@ public final class ScriptEnvironment {
* @param out output print writer * @param out output print writer
* @param err error print writer * @param err error print writer
*/ */
@SuppressWarnings("unused")
public 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.out = out;
this.err = err; this.err = err;

View File

@ -47,6 +47,7 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck; import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
@ -922,7 +923,10 @@ public abstract class ScriptObject implements PropertyAccess {
if (property instanceof UserAccessorProperty) { if (property instanceof UserAccessorProperty) {
((UserAccessorProperty)property).setAccessors(this, getMap(), null); ((UserAccessorProperty)property).setAccessors(this, getMap(), null);
} }
Global.getConstants().delete(property.getKey()); final GlobalConstants globalConstants = getGlobalConstants();
if (globalConstants != null) {
globalConstants.delete(property.getKey());
}
return true; return true;
} }
} }
@ -1983,9 +1987,12 @@ public abstract class ScriptObject implements PropertyAccess {
} }
} }
final GuardedInvocation cinv = Global.getConstants().findGetMethod(find, this, desc); final GlobalConstants globalConstants = getGlobalConstants();
if (cinv != null) { if (globalConstants != null) {
return cinv; final GuardedInvocation cinv = globalConstants.findGetMethod(find, this, desc);
if (cinv != null) {
return cinv;
}
} }
final Class<?> returnType = desc.getMethodType().returnType(); final Class<?> returnType = desc.getMethodType().returnType();
@ -2183,14 +2190,22 @@ public abstract class ScriptObject implements PropertyAccess {
final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name)); final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request); final GlobalConstants globalConstants = getGlobalConstants();
if (cinv != null) { if (globalConstants != null) {
return cinv; final GuardedInvocation cinv = globalConstants.findSetMethod(find, this, inv, desc, request);
if (cinv != null) {
return cinv;
}
} }
return inv; return inv;
} }
private GlobalConstants getGlobalConstants() {
// Avoid hitting getContext() which might be costly for a non-Global unless needed.
return GlobalConstants.GLOBAL_ONLY && !isGlobal() ? null : getContext().getGlobalConstants();
}
private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) { private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
if (NashornCallSiteDescriptor.isStrict(desc)) { if (NashornCallSiteDescriptor.isStrict(desc)) {

View File

@ -98,6 +98,10 @@ public abstract class ArrayData {
@Override @Override
public ArrayData ensure(final long safeIndex) { public ArrayData ensure(final long safeIndex) {
if (safeIndex > 0L) { if (safeIndex > 0L) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
return new SparseArrayData(this, safeIndex + 1);
}
//known to fit in int
return toRealArrayData((int)safeIndex).ensure(safeIndex); return toRealArrayData((int)safeIndex).ensure(safeIndex);
} }
return this; return this;

View File

@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* Handle arrays where the index is very large. * Handle arrays where the index is very large.
*/ */
class SparseArrayData extends ArrayData { class SparseArrayData extends ArrayData {
static final long MAX_DENSE_LENGTH = 16 * 512 * 1024; static final int MAX_DENSE_LENGTH = 8 * 1024 * 1024;
/** Underlying array. */ /** Underlying array. */
private ArrayData underlying; private ArrayData underlying;

View File

@ -47,10 +47,9 @@ public final class RecompilationEvent extends RuntimeEvent<RewriteException> {
* @param level logging level * @param level logging level
* @param rewriteException rewriteException wrapped by this RuntimEvent * @param rewriteException rewriteException wrapped by this RuntimEvent
* @param returnValue rewriteException return value - as we don't want to make * @param returnValue rewriteException return value - as we don't want to make
* {@link RewriteException#getReturnValueNonDestructive()} public, we pass it as * {@code RewriteException.getReturnValueNonDestructive()} public, we pass it as
* an extra parameter, rather than querying the getter from another package. * an extra parameter, rather than querying the getter from another package.
*/ */
@SuppressWarnings("javadoc")
public RecompilationEvent(final Level level, final RewriteException rewriteException, final Object returnValue) { public RecompilationEvent(final Level level, final RewriteException rewriteException, final Object returnValue) {
super(level, rewriteException); super(level, rewriteException);
assert Context.getContext().getLogger(RecompilableScriptFunctionData.class).isEnabled() : assert Context.getContext().getLogger(RecompilableScriptFunctionData.class).isEnabled() :

View File

@ -42,6 +42,8 @@ import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.ObjectClassGenerator;
@ -106,6 +108,12 @@ public final class Bootstrap {
return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType()); return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType());
} }
}); });
factory.setAutoConversionStrategy(new MethodTypeConversionStrategy() {
@Override
public MethodHandle asType(final MethodHandle target, final MethodType newType) {
return unboxReturnType(target, newType);
}
});
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD); final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD);
if (relinkThreshold > -1) { if (relinkThreshold > -1) {
factory.setUnstableRelinkThreshold(relinkThreshold); factory.setUnstableRelinkThreshold(relinkThreshold);
@ -420,4 +428,29 @@ public final class Bootstrap {
static GuardedInvocation asTypeSafeReturn(final GuardedInvocation inv, final LinkerServices linkerServices, final CallSiteDescriptor desc) { static GuardedInvocation asTypeSafeReturn(final GuardedInvocation inv, final LinkerServices linkerServices, final CallSiteDescriptor desc) {
return inv == null ? null : inv.asTypeSafeReturn(linkerServices, desc.getMethodType()); return inv == null ? null : inv.asTypeSafeReturn(linkerServices, desc.getMethodType());
} }
/**
* Adapts the return type of the method handle with {@code explicitCastArguments} when it is an unboxing
* conversion. This will ensure that nulls are unwrapped to false or 0.
* @param target the target method handle
* @param newType the desired new type. Note that this method does not adapt the method handle completely to the
* new type, it only adapts the return type; this is allowed as per
* {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)}, which is what this method
* is used for.
* @return the method handle with adapted return type, if it required an unboxing conversion.
*/
private static MethodHandle unboxReturnType(final MethodHandle target, final MethodType newType) {
final MethodType targetType = target.type();
final Class<?> oldReturnType = targetType.returnType();
if (TypeUtilities.isWrapperType(oldReturnType)) {
final Class<?> newReturnType = newType.returnType();
if (newReturnType.isPrimitive()) {
// The contract of setAutoConversionStrategy is such that the difference between newType and targetType
// can only be JLS method invocation conversions.
assert TypeUtilities.isMethodInvocationConvertible(oldReturnType, newReturnType);
return MethodHandles.explicitCastArguments(target, targetType.changeReturnType(newReturnType));
}
}
return target;
}
} }

View File

@ -25,8 +25,10 @@
package jdk.nashorn.internal.runtime.linker; package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.*; import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETMEMBER;
import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETSLOT;
import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETMEMBER;
import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETSLOT;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.CallSiteDescriptor;
@ -114,12 +116,10 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker {
case "getMethod": case "getMethod":
if (c > 2) { if (c > 2) {
return findGetMethod(desc); return findGetMethod(desc);
} else {
// For indexed get, we want GuardedInvocation from beans linker and pass it.
// BrowserJSObjectLinker.get uses this fallback getter for explicit signature method access.
final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices);
return findGetIndexMethod(beanInv);
} }
// For indexed get, we want GuardedInvocation from beans linker and pass it.
// BrowserJSObjectLinker.get uses this fallback getter for explicit signature method access.
return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
case "setProp": case "setProp":
case "setElem": case "setElem":
return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
@ -166,9 +166,8 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker {
final String name = (String)key; final String name = (String)key;
if (name.indexOf('(') != -1) { if (name.indexOf('(') != -1) {
return fallback.invokeExact(jsobj, key); return fallback.invokeExact(jsobj, key);
} else {
return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key);
} }
return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key);
} }
return null; return null;
} }

View File

@ -120,12 +120,10 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy
case "getMethod": case "getMethod":
if (c > 2) { if (c > 2) {
return findGetMethod(desc); return findGetMethod(desc);
} else {
// For indexed get, we want get GuardedInvocation beans linker and pass it.
// JSObjectLinker.get uses this fallback getter for explicit signature method access.
final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices);
return findGetIndexMethod(beanInv);
} }
// For indexed get, we want get GuardedInvocation beans linker and pass it.
// JSObjectLinker.get uses this fallback getter for explicit signature method access.
return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
case "setProp": case "setProp":
case "setElem": case "setElem":
return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
@ -192,9 +190,8 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy
// get with method name and signature. delegate it to beans linker! // get with method name and signature. delegate it to beans linker!
if (name.indexOf('(') != -1) { if (name.indexOf('(') != -1) {
return fallback.invokeExact(jsobj, key); return fallback.invokeExact(jsobj, key);
} else {
return ((JSObject)jsobj).getMember(name);
} }
return ((JSObject)jsobj).getMember(name);
} }
return null; return null;
} }

View File

@ -53,15 +53,34 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
// Object type arguments of Java method calls, field set and array set. // Object type arguments of Java method calls, field set and array set.
private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true); private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class); private static final MethodHandle EXPORT_ARGUMENT;
private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class); private static final MethodHandle EXPORT_NATIVE_ARRAY;
private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class); private static final MethodHandle EXPORT_SCRIPT_OBJECT;
private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class); private static final MethodHandle IMPORT_RESULT;
private static final MethodHandle FILTER_CONSSTRING;
static {
final Lookup lookup = new Lookup(MethodHandles.lookup());
EXPORT_ARGUMENT = lookup.findOwnStatic("exportArgument", Object.class, Object.class);
EXPORT_NATIVE_ARRAY = lookup.findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
EXPORT_SCRIPT_OBJECT = lookup.findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
IMPORT_RESULT = lookup.findOwnStatic("importResult", Object.class, Object.class);
FILTER_CONSSTRING = lookup.findOwnStatic("consStringFilter", Object.class, Object.class);
}
private final BeansLinker beansLinker = new BeansLinker(); private final BeansLinker beansLinker = new BeansLinker();
@Override @Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
if (linkRequest.getReceiver() instanceof ConsString) {
// In order to treat ConsString like a java.lang.String we need a link request with a string receiver.
final Object[] arguments = linkRequest.getArguments();
arguments[0] = "";
final LinkRequest forgedLinkRequest = linkRequest.replaceArguments(linkRequest.getCallSiteDescriptor(), arguments);
final GuardedInvocation invocation = getGuardedInvocation(beansLinker, forgedLinkRequest, linkerServices);
// If an invocation is found we add a filter that makes it work for both Strings and ConsStrings.
return invocation == null ? null : invocation.filterArguments(0, FILTER_CONSSTRING);
}
return getGuardedInvocation(beansLinker, linkRequest, linkerServices); return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
} }
@ -113,6 +132,11 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
return ScriptUtils.unwrap(arg); return ScriptUtils.unwrap(arg);
} }
@SuppressWarnings("unused")
private static Object consStringFilter(final Object arg) {
return arg instanceof ConsString ? arg.toString() : arg;
}
private static class NashornBeansLinkerServices implements LinkerServices { private static class NashornBeansLinkerServices implements LinkerServices {
private final LinkerServices linkerServices; private final LinkerServices linkerServices;

View File

@ -27,7 +27,6 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode.newAltNode; import static jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode.newAltNode;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite;
import java.util.HashSet; import java.util.HashSet;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; 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.BackRefNode;
@ -53,6 +52,7 @@ final class Analyser extends Parser {
super(env, chars, p, end); super(env, chars, p, end);
} }
@SuppressWarnings("unused")
protected final void compile() { protected final void compile() {
if (Config.DEBUG) { if (Config.DEBUG) {
Config.log.println(new String(chars, getBegin(), getEnd())); Config.log.println(new String(chars, getBegin(), getEnd()));
@ -76,7 +76,9 @@ final class Analyser extends Parser {
root = setupTree(root, 0); root = setupTree(root, 0);
if (Config.DEBUG_PARSE_TREE) { if (Config.DEBUG_PARSE_TREE) {
if (Config.DEBUG_PARSE_TREE_RAW) Config.log.println("<TREE>"); if (Config.DEBUG_PARSE_TREE_RAW) {
Config.log.println("<TREE>");
}
root.verifyTree(new HashSet<Node>(), env.reg.warnings); root.verifyTree(new HashSet<Node>(), env.reg.warnings);
Config.log.println(root + "\n"); Config.log.println(root + "\n");
} }
@ -94,7 +96,9 @@ final class Analyser extends Parser {
regex.clearOptimizeInfo(); regex.clearOptimizeInfo();
if (!Config.DONT_OPTIMIZE) setOptimizedInfoFromTree(root); if (!Config.DONT_OPTIMIZE) {
setOptimizedInfoFromTree(root);
}
env.memNodes = null; env.memNodes = null;
@ -110,7 +114,9 @@ final class Analyser extends Parser {
if (Config.DEBUG_COMPILE) { if (Config.DEBUG_COMPILE) {
Config.log.println("stack used: " + regex.stackNeeded); Config.log.println("stack used: " + regex.stackNeeded);
if (Config.USE_STRING_TEMPLATES) Config.log.print("templates: " + regex.templateNum + "\n"); if (Config.USE_STRING_TEMPLATES) {
Config.log.print("templates: " + regex.templateNum + "\n");
}
Config.log.println(new ByteCodePrinter(regex).byteCodeListToString()); Config.log.println(new ByteCodePrinter(regex).byteCodeListToString());
} // DEBUG_COMPILE } // DEBUG_COMPILE
@ -136,7 +142,9 @@ final class Analyser extends Parser {
ConsAltNode can = (ConsAltNode)node; ConsAltNode can = (ConsAltNode)node;
do { do {
final int v = quantifiersMemoryInfo(can.car); final int v = quantifiersMemoryInfo(can.car);
if (v > info) info = v; if (v > info) {
info = v;
}
} while ((can = can.cdr) != null); } while ((can = can.cdr) != null);
break; break;
@ -182,7 +190,9 @@ final class Analyser extends Parser {
switch (node.getType()) { switch (node.getType()) {
case NodeType.BREF: case NodeType.BREF:
final BackRefNode br = (BackRefNode)node; final BackRefNode br = (BackRefNode)node;
if (br.isRecursion()) break; if (br.isRecursion()) {
break;
}
if (br.backRef > env.numMem) { if (br.backRef > env.numMem) {
throw new ValueException(ERR_INVALID_BACKREF); throw new ValueException(ERR_INVALID_BACKREF);
@ -249,6 +259,9 @@ final class Analyser extends Parser {
case EncloseType.STOP_BACKTRACK: case EncloseType.STOP_BACKTRACK:
min = getMinMatchLength(en.target); min = getMinMatchLength(en.target);
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
@ -276,7 +289,9 @@ final class Analyser extends Parser {
ConsAltNode an = (ConsAltNode)node; ConsAltNode an = (ConsAltNode)node;
do { do {
final int tmax = getMaxMatchLength(an.car); final int tmax = getMaxMatchLength(an.car);
if (max < tmax) max = tmax; if (max < tmax) {
max = tmax;
}
} while ((an = an.cdr) != null); } while ((an = an.cdr) != null);
break; break;
@ -304,7 +319,9 @@ final class Analyser extends Parser {
throw new ValueException(ERR_INVALID_BACKREF); throw new ValueException(ERR_INVALID_BACKREF);
} }
final int tmax = getMaxMatchLength(env.memNodes[br.backRef]); final int tmax = getMaxMatchLength(env.memNodes[br.backRef]);
if (max < tmax) max = tmax; if (max < tmax) {
max = tmax;
}
break; break;
case NodeType.QTFR: case NodeType.QTFR:
@ -338,6 +355,9 @@ final class Analyser extends Parser {
case EncloseType.STOP_BACKTRACK: case EncloseType.STOP_BACKTRACK:
max = getMaxMatchLength(en.target); max = getMaxMatchLength(en.target);
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
@ -355,8 +375,8 @@ final class Analyser extends Parser {
return getCharLengthTree(node, 0); return getCharLengthTree(node, 0);
} }
private int getCharLengthTree(final Node node, int level) { private int getCharLengthTree(final Node node, final int levelp) {
level++; final int level = levelp + 1;
int len = 0; int len = 0;
returnCode = 0; returnCode = 0;
@ -366,7 +386,9 @@ final class Analyser extends Parser {
ConsAltNode ln = (ConsAltNode)node; ConsAltNode ln = (ConsAltNode)node;
do { do {
final int tlen = getCharLengthTree(ln.car, level); final int tlen = getCharLengthTree(ln.car, level);
if (returnCode == 0) len = MinMaxLen.distanceAdd(len, tlen); if (returnCode == 0) {
len = MinMaxLen.distanceAdd(len, tlen);
}
} while (returnCode == 0 && (ln = ln.cdr) != null); } while (returnCode == 0 && (ln = ln.cdr) != null);
break; break;
@ -378,7 +400,9 @@ final class Analyser extends Parser {
while (returnCode == 0 && (an = an.cdr) != null) { while (returnCode == 0 && (an = an.cdr) != null) {
final int tlen2 = getCharLengthTree(an.car, level); final int tlen2 = getCharLengthTree(an.car, level);
if (returnCode == 0) { if (returnCode == 0) {
if (tlen != tlen2) varLen = true; if (tlen != tlen2) {
varLen = true;
}
} }
} }
@ -404,7 +428,9 @@ final class Analyser extends Parser {
final QuantifierNode qn = (QuantifierNode)node; final QuantifierNode qn = (QuantifierNode)node;
if (qn.lower == qn.upper) { if (qn.lower == qn.upper) {
tlen = getCharLengthTree(qn.target, level); tlen = getCharLengthTree(qn.target, level);
if (returnCode == 0) len = MinMaxLen.distanceMultiply(tlen, qn.lower); if (returnCode == 0) {
len = MinMaxLen.distanceMultiply(tlen, qn.lower);
}
} else { } else {
returnCode = GET_CHAR_LEN_VARLEN; returnCode = GET_CHAR_LEN_VARLEN;
} }
@ -435,6 +461,9 @@ final class Analyser extends Parser {
case EncloseType.STOP_BACKTRACK: case EncloseType.STOP_BACKTRACK:
len = getCharLengthTree(en.target, level); len = getCharLengthTree(en.target, level);
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
@ -448,7 +477,9 @@ final class Analyser extends Parser {
} }
/* x is not included y ==> 1 : 0 */ /* x is not included y ==> 1 : 0 */
private boolean isNotIncluded(Node x, Node y) { private static boolean isNotIncluded(final Node xn, final Node yn) {
Node x = xn;
Node y = yn;
Node tmp; Node tmp;
// !retry:! // !retry:!
@ -492,10 +523,14 @@ final class Analyser extends Parser {
boolean v = xc.bs.at(i); boolean v = xc.bs.at(i);
if ((v && !xc.isNot()) || (!v && xc.isNot())) { if ((v && !xc.isNot()) || (!v && xc.isNot())) {
v = yc.bs.at(i); v = yc.bs.at(i);
if ((v && !yc.isNot()) || (!v && yc.isNot())) return false; if ((v && !yc.isNot()) || (!v && yc.isNot())) {
return false;
}
} }
} }
if ((xc.mbuf == null && !xc.isNot()) || yc.mbuf == null && !yc.isNot()) return true; if ((xc.mbuf == null && !xc.isNot()) || yc.mbuf == null && !yc.isNot()) {
return true;
}
return false; return false;
// break; not reached // break; not reached
@ -514,7 +549,9 @@ final class Analyser extends Parser {
case NodeType.STR: case NodeType.STR:
final StringNode xs = (StringNode)x; final StringNode xs = (StringNode)x;
if (xs.length() == 0) break; if (xs.length() == 0) {
break;
}
switch (yType) { switch (yType) {
@ -526,13 +563,16 @@ final class Analyser extends Parser {
case NodeType.STR: case NodeType.STR:
final StringNode ys = (StringNode)y; final StringNode ys = (StringNode)y;
int len = xs.length(); int len = xs.length();
if (len > ys.length()) len = ys.length(); if (len > ys.length()) {
len = ys.length();
}
if (xs.isAmbig() || ys.isAmbig()) { if (xs.isAmbig() || ys.isAmbig()) {
/* tiny version */ /* tiny version */
return false; return false;
} else { }
for (int i=0, p=ys.p, q=xs.p; i<len; i++, p++, q++) { for (int i=0, pt=ys.p, q=xs.p; i<len; i++, pt++, q++) {
if (ys.chars[p] != xs.chars[q]) return true; if (ys.chars[pt] != xs.chars[q]) {
return true;
} }
} }
break; break;
@ -542,6 +582,8 @@ final class Analyser extends Parser {
} // inner switch } // inner switch
break; // case NodeType.STR break; // case NodeType.STR
default:
break;
} // switch } // switch
@ -561,7 +603,9 @@ final class Analyser extends Parser {
case NodeType.CTYPE: case NodeType.CTYPE:
case NodeType.CCLASS: case NodeType.CCLASS:
if (!exact) n = node; if (!exact) {
n = node;
}
break; break;
case NodeType.LIST: case NodeType.LIST:
@ -570,7 +614,10 @@ final class Analyser extends Parser {
case NodeType.STR: case NodeType.STR:
final StringNode sn = (StringNode)node; final StringNode sn = (StringNode)node;
if (sn.end <= sn.p) break; // ??? if (sn.end <= sn.p)
{
break; // ???
}
if (exact && !sn.isRaw() && isIgnoreCase(regex.options)){ if (exact && !sn.isRaw() && isIgnoreCase(regex.options)){
// nothing // nothing
@ -605,12 +652,17 @@ final class Analyser extends Parser {
case EncloseType.STOP_BACKTRACK: case EncloseType.STOP_BACKTRACK:
n = getHeadValueNode(en.target, exact); n = getHeadValueNode(en.target, exact);
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
case NodeType.ANCHOR: case NodeType.ANCHOR:
final AnchorNode an = (AnchorNode)node; final AnchorNode an = (AnchorNode)node;
if (an.type == AnchorType.PREC_READ) n = getHeadValueNode(an.target, exact); if (an.type == AnchorType.PREC_READ) {
n = getHeadValueNode(an.target, exact);
}
break; break;
default: default:
@ -622,7 +674,9 @@ final class Analyser extends Parser {
// true: invalid // true: invalid
private boolean checkTypeTree(final Node node, final int typeMask, final int encloseMask, final int anchorMask) { private boolean checkTypeTree(final Node node, final int typeMask, final int encloseMask, final int anchorMask) {
if ((node.getType2Bit() & typeMask) == 0) return true; if ((node.getType2Bit() & typeMask) == 0) {
return true;
}
boolean invalid = false; boolean invalid = false;
@ -641,15 +695,21 @@ final class Analyser extends Parser {
case NodeType.ENCLOSE: case NodeType.ENCLOSE:
final EncloseNode en = (EncloseNode)node; final EncloseNode en = (EncloseNode)node;
if ((en.type & encloseMask) == 0) return true; if ((en.type & encloseMask) == 0) {
return true;
}
invalid = checkTypeTree(en.target, typeMask, encloseMask, anchorMask); invalid = checkTypeTree(en.target, typeMask, encloseMask, anchorMask);
break; break;
case NodeType.ANCHOR: case NodeType.ANCHOR:
final AnchorNode an = (AnchorNode)node; final AnchorNode an = (AnchorNode)node;
if ((an.type & anchorMask) == 0) return true; if ((an.type & anchorMask) == 0) {
return true;
}
if (an.target != null) invalid = checkTypeTree(an.target, typeMask, encloseMask, anchorMask); if (an.target != null) {
invalid = checkTypeTree(an.target, typeMask, encloseMask, anchorMask);
}
break; break;
default: default:
@ -664,7 +724,8 @@ final class Analyser extends Parser {
(?<=A|B) ==> (?<=A)|(?<=B) (?<=A|B) ==> (?<=A)|(?<=B)
(?<!A|B) ==> (?<!A)(?<!B) (?<!A|B) ==> (?<!A)(?<!B)
*/ */
private Node divideLookBehindAlternatives(Node node) { private Node divideLookBehindAlternatives(final Node nodep) {
Node node = nodep;
final AnchorNode an = (AnchorNode)node; final AnchorNode an = (AnchorNode)node;
final int anchorType = an.type; final int anchorType = an.type;
Node head = an.target; Node head = an.target;
@ -699,7 +760,7 @@ final class Analyser extends Parser {
private Node setupLookBehind(final Node node) { private Node setupLookBehind(final Node node) {
final AnchorNode an = (AnchorNode)node; final AnchorNode an = (AnchorNode)node;
final int len = getCharLengthTree(an.target); final int len = getCharLengthTree(an.target);
switch(returnCode) { switch (returnCode) {
case 0: case 0:
an.charLength = len; an.charLength = len;
break; break;
@ -708,14 +769,17 @@ final class Analyser extends Parser {
case GET_CHAR_LEN_TOP_ALT_VARLEN: case GET_CHAR_LEN_TOP_ALT_VARLEN:
if (syntax.differentLengthAltLookBehind()) { if (syntax.differentLengthAltLookBehind()) {
return divideLookBehindAlternatives(node); return divideLookBehindAlternatives(node);
} else {
throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN);
} }
throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN);
default:
break;
} }
return node; return node;
} }
private void nextSetup(Node node, final Node nextNode) { private void nextSetup(final Node nodep, final Node nextNode) {
Node node = nodep;
// retry: // retry:
retry: while(true) { retry: while(true) {
@ -762,7 +826,7 @@ final class Analyser extends Parser {
} }
private void updateStringNodeCaseFoldMultiByte(final StringNode sn) { private void updateStringNodeCaseFoldMultiByte(final StringNode sn) {
final char[] chars = sn.chars; final char[] ch = sn.chars;
final int end = sn.end; final int end = sn.end;
value = sn.p; value = sn.p;
int sp = 0; int sp = 0;
@ -770,15 +834,15 @@ final class Analyser extends Parser {
while (value < end) { while (value < end) {
final int ovalue = value; final int ovalue = value;
buf = EncodingHelper.toLowerCase(chars[value++]); buf = EncodingHelper.toLowerCase(ch[value++]);
if (chars[ovalue] != buf) { if (ch[ovalue] != buf) {
char[] sbuf = new char[sn.length() << 1]; char[] sbuf = new char[sn.length() << 1];
System.arraycopy(chars, sn.p, sbuf, 0, ovalue - sn.p); System.arraycopy(ch, sn.p, sbuf, 0, ovalue - sn.p);
value = ovalue; value = ovalue;
while (value < end) { while (value < end) {
buf = EncodingHelper.toLowerCase(chars[value++]); buf = EncodingHelper.toLowerCase(ch[value++]);
if (sp >= sbuf.length) { if (sp >= sbuf.length) {
final char[]tmp = new char[sbuf.length << 1]; final char[]tmp = new char[sbuf.length << 1];
System.arraycopy(sbuf, 0, tmp, 0, sbuf.length); System.arraycopy(sbuf, 0, tmp, 0, sbuf.length);
@ -798,8 +862,8 @@ final class Analyser extends Parser {
updateStringNodeCaseFoldMultiByte(sn); updateStringNodeCaseFoldMultiByte(sn);
} }
private Node expandCaseFoldMakeRemString(final char[] chars, final int p, final int end) { private Node expandCaseFoldMakeRemString(final char[] ch, final int pp, final int end) {
final StringNode node = new StringNode(chars, p, end); final StringNode node = new StringNode(ch, pp, end);
updateStringNodeCaseFold(node); updateStringNodeCaseFold(node);
node.setAmbig(); node.setAmbig();
@ -807,7 +871,7 @@ final class Analyser extends Parser {
return node; return node;
} }
private boolean expandCaseFoldStringAlt(final int itemNum, final char[] items, private static boolean expandCaseFoldStringAlt(final int itemNum, final char[] items,
final char[] chars, final int p, final int slen, final int end, final ObjPtr<Node> node) { final char[] chars, final int p, final int slen, final int end, final ObjPtr<Node> node) {
ConsAltNode altNode; ConsAltNode altNode;
@ -833,59 +897,68 @@ final class Analyser extends Parser {
private Node expandCaseFoldString(final Node node) { private Node expandCaseFoldString(final Node node) {
final StringNode sn = (StringNode)node; final StringNode sn = (StringNode)node;
if (sn.isAmbig() || sn.length() <= 0) return node; if (sn.isAmbig() || sn.length() <= 0) {
return node;
}
final char[] chars = sn.chars; final char[] chars1 = sn.chars;
int p = sn.p; int pt = sn.p;
final int end = sn.end; final int end = sn.end;
int altNum = 1; int altNum = 1;
ConsAltNode topRoot = null, root = null; ConsAltNode topRoot = null, r = null;
@SuppressWarnings("unused")
final ObjPtr<Node> prevNode = new ObjPtr<Node>(); final ObjPtr<Node> prevNode = new ObjPtr<Node>();
StringNode stringNode = null; StringNode stringNode = null;
while (p < end) { while (pt < end) {
final char[] items = EncodingHelper.caseFoldCodesByString(regex.caseFoldFlag, chars[p]); final char[] items = EncodingHelper.caseFoldCodesByString(regex.caseFoldFlag, chars1[pt]);
if (items.length == 0) { if (items.length == 0) {
if (stringNode == null) { if (stringNode == null) {
if (root == null && prevNode.p != null) { if (r == null && prevNode.p != null) {
topRoot = root = ConsAltNode.listAdd(null, prevNode.p); topRoot = r = ConsAltNode.listAdd(null, prevNode.p);
} }
prevNode.p = stringNode = new StringNode(); // onig_node_new_str(NULL, NULL); prevNode.p = stringNode = new StringNode(); // onig_node_new_str(NULL, NULL);
if (root != null) ConsAltNode.listAdd(root, stringNode); if (r != null) {
ConsAltNode.listAdd(r, stringNode);
}
} }
stringNode.cat(chars, p, p + 1); stringNode.cat(chars1, pt, pt + 1);
} else { } else {
altNum *= (items.length + 1); altNum *= (items.length + 1);
if (altNum > THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION) break; if (altNum > THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION) {
break;
if (root == null && prevNode.p != null) {
topRoot = root = ConsAltNode.listAdd(null, prevNode.p);
} }
expandCaseFoldStringAlt(items.length, items, chars, p, 1, end, prevNode); if (r == null && prevNode.p != null) {
if (root != null) ConsAltNode.listAdd(root, prevNode.p); topRoot = r = ConsAltNode.listAdd(null, prevNode.p);
}
expandCaseFoldStringAlt(items.length, items, chars1, pt, 1, end, prevNode);
if (r != null) {
ConsAltNode.listAdd(r, prevNode.p);
}
stringNode = null; stringNode = null;
} }
p++; pt++;
} }
if (p < end) { if (pt < end) {
final Node srem = expandCaseFoldMakeRemString(chars, p, end); final Node srem = expandCaseFoldMakeRemString(chars1, pt, end);
if (prevNode.p != null && root == null) { if (prevNode.p != null && r == null) {
topRoot = root = ConsAltNode.listAdd(null, prevNode.p); topRoot = r = ConsAltNode.listAdd(null, prevNode.p);
} }
if (root == null) { if (r == null) {
prevNode.p = srem; prevNode.p = srem;
} else { } else {
ConsAltNode.listAdd(root, srem); ConsAltNode.listAdd(r, srem);
} }
} }
/* ending */ /* ending */
@ -909,7 +982,10 @@ final class Analyser extends Parser {
5. find invalid patterns in look-behind. 5. find invalid patterns in look-behind.
6. expand repeated string. 6. expand repeated string.
*/ */
protected final Node setupTree(Node node, int state) { protected final Node setupTree(final Node nodep, final int statep) {
Node node = nodep;
int state = statep;
restart: while (true) { restart: while (true) {
switch (node.getType()) { switch (node.getType()) {
case NodeType.LIST: case NodeType.LIST:
@ -958,7 +1034,9 @@ final class Analyser extends Parser {
final QuantifierNode qn = (QuantifierNode)node; final QuantifierNode qn = (QuantifierNode)node;
Node target = qn.target; Node target = qn.target;
if ((state & IN_REPEAT) != 0) qn.setInRepeat(); if ((state & IN_REPEAT) != 0) {
qn.setInRepeat();
}
if (isRepeatInfinite(qn.upper) || qn.lower >= 1) { if (isRepeatInfinite(qn.upper) || qn.lower >= 1) {
final int d = getMinMatchLength(target); final int d = getMinMatchLength(target);
@ -966,14 +1044,18 @@ final class Analyser extends Parser {
qn.targetEmptyInfo = TargetInfo.IS_EMPTY; qn.targetEmptyInfo = TargetInfo.IS_EMPTY;
if (Config.USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT) { if (Config.USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT) {
final int info = quantifiersMemoryInfo(target); final int info = quantifiersMemoryInfo(target);
if (info > 0) qn.targetEmptyInfo = info; if (info > 0) {
qn.targetEmptyInfo = info;
}
} // USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK } // USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK
// strange stuff here (turned off) // strange stuff here (turned off)
} }
} }
state |= IN_REPEAT; state |= IN_REPEAT;
if (qn.lower != qn.upper) state |= IN_VAR_REPEAT; if (qn.lower != qn.upper) {
state |= IN_VAR_REPEAT;
}
target = setupTree(target, state); target = setupTree(target, state);
@ -1035,11 +1117,16 @@ final class Analyser extends Parser {
final QuantifierNode tqn = (QuantifierNode)en.target; final QuantifierNode tqn = (QuantifierNode)en.target;
if (isRepeatInfinite(tqn.upper) && tqn.lower <= 1 && tqn.greedy) { if (isRepeatInfinite(tqn.upper) && tqn.lower <= 1 && tqn.greedy) {
/* (?>a*), a*+ etc... */ /* (?>a*), a*+ etc... */
if (tqn.target.isSimple()) en.setStopBtSimpleRepeat(); if (tqn.target.isSimple()) {
en.setStopBtSimpleRepeat();
}
} }
} }
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
@ -1059,7 +1146,9 @@ final class Analyser extends Parser {
throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN);
} }
node = setupLookBehind(node); node = setupLookBehind(node);
if (node.getType() != NodeType.ANCHOR) continue restart; if (node.getType() != NodeType.ANCHOR) {
continue restart;
}
setupTree(((AnchorNode)node).target, state); setupTree(((AnchorNode)node).target, state);
break; break;
@ -1068,12 +1157,19 @@ final class Analyser extends Parser {
throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN);
} }
node = setupLookBehind(node); node = setupLookBehind(node);
if (node.getType() != NodeType.ANCHOR) continue restart; if (node.getType() != NodeType.ANCHOR) {
continue restart;
}
setupTree(((AnchorNode)node).target, (state | IN_NOT)); setupTree(((AnchorNode)node).target, (state | IN_NOT));
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
default:
break;
} // switch } // switch
return node; return node;
} // restart: while } // restart: while
@ -1191,7 +1287,9 @@ final class Analyser extends Parser {
opt.expr.copy(nopt.exm); opt.expr.copy(nopt.exm);
} }
opt.expr.reachEnd = false; opt.expr.reachEnd = false;
if (nopt.map.value > 0) opt.map.copy(nopt.map); if (nopt.map.value > 0) {
opt.map.copy(nopt.map);
}
break; break;
case AnchorType.PREC_READ_NOT: case AnchorType.PREC_READ_NOT:
@ -1199,6 +1297,9 @@ final class Analyser extends Parser {
case AnchorType.LOOK_BEHIND_NOT: case AnchorType.LOOK_BEHIND_NOT:
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
} }
@ -1282,8 +1383,12 @@ final class Analyser extends Parser {
if (++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) { if (++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) {
int min = 0; int min = 0;
int max = MinMaxLen.INFINITE_DISTANCE; int max = MinMaxLen.INFINITE_DISTANCE;
if (en.isMinFixed()) min = en.minLength; if (en.isMinFixed()) {
if (en.isMaxFixed()) max = en.maxLength; min = en.minLength;
}
if (en.isMaxFixed()) {
max = en.maxLength;
}
opt.length.set(min, max); opt.length.set(min, max);
} else { // USE_SUBEXP_CALL } else { // USE_SUBEXP_CALL
optimizeNodeLeft(en.target, opt, oenv); optimizeNodeLeft(en.target, opt, oenv);
@ -1298,6 +1403,9 @@ final class Analyser extends Parser {
case EncloseType.STOP_BACKTRACK: case EncloseType.STOP_BACKTRACK:
optimizeNodeLeft(en.target, opt, oenv); optimizeNodeLeft(en.target, opt, oenv);
break; break;
default:
break;
} // inner switch } // inner switch
break; break;
} }
@ -1307,6 +1415,7 @@ final class Analyser extends Parser {
} // switch } // switch
} }
@SuppressWarnings("unused")
protected final void setOptimizedInfoFromTree(final Node node) { protected final void setOptimizedInfoFromTree(final Node node) {
final NodeOptInfo opt = new NodeOptInfo(); final NodeOptInfo opt = new NodeOptInfo();
final OptEnvironment oenv = new OptEnvironment(); final OptEnvironment oenv = new OptEnvironment();
@ -1347,7 +1456,9 @@ final class Analyser extends Parser {
regex.setSubAnchor(opt.map.anchor); regex.setSubAnchor(opt.map.anchor);
} else { } else {
regex.subAnchor |= opt.anchor.leftAnchor & AnchorType.BEGIN_LINE; regex.subAnchor |= opt.anchor.leftAnchor & AnchorType.BEGIN_LINE;
if (opt.length.max == 0) regex.subAnchor |= opt.anchor.rightAnchor & AnchorType.END_LINE; if (opt.length.max == 0) {
regex.subAnchor |= opt.anchor.rightAnchor & AnchorType.END_LINE;
}
} }
if (Config.DEBUG_COMPILE || Config.DEBUG_MATCH) { if (Config.DEBUG_COMPILE || Config.DEBUG_MATCH) {

View File

@ -24,7 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
final class ApplyCaseFold { final class ApplyCaseFold {
// i_apply_case_fold // i_apply_case_fold
public void apply(final int from, final int to, final Object o) { public static void apply(final int from, final int to, final Object o) {
final ApplyCaseFoldArg arg = (ApplyCaseFoldArg)o; final ApplyCaseFoldArg arg = (ApplyCaseFoldArg)o;
final ScanEnvironment env = arg.env; final ScanEnvironment env = arg.env;
@ -45,7 +45,9 @@ final class ApplyCaseFold {
} else { } else {
if (inCC) { if (inCC) {
if (to >= BitSet.SINGLE_BYTE_SIZE) { if (to >= BitSet.SINGLE_BYTE_SIZE) {
if (cc.isNot()) cc.clearNotFlag(); if (cc.isNot()) {
cc.clearNotFlag();
}
cc.addCodeRange(env, to, to); cc.addCodeRange(env, to, to);
} else { } else {
if (cc.isNot()) { if (cc.isNot()) {

View File

@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode;
@SuppressWarnings("javadoc")
public final class ApplyCaseFoldArg { public final class ApplyCaseFoldArg {
final ScanEnvironment env; final ScanEnvironment env;
final CClassNode cc; final CClassNode cc;

View File

@ -24,7 +24,6 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isDynamic;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; 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.BackRefNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
@ -98,15 +97,15 @@ final class ArrayCompiler extends Compiler {
} while ((aln = aln.cdr) != null); } while ((aln = aln.cdr) != null);
} }
private boolean isNeedStrLenOpExact(final int op) { private static boolean isNeedStrLenOpExact(final int op) {
return op == OPCode.EXACTN || op == OPCode.EXACTN_IC; return op == OPCode.EXACTN || op == OPCode.EXACTN_IC;
} }
private boolean opTemplated(final int op) { private static boolean opTemplated(final int op) {
return isNeedStrLenOpExact(op); return isNeedStrLenOpExact(op);
} }
private int selectStrOpcode(final int strLength, final boolean ignoreCase) { private static int selectStrOpcode(final int strLength, final boolean ignoreCase) {
int op; int op;
if (ignoreCase) { if (ignoreCase) {
@ -139,7 +138,7 @@ final class ArrayCompiler extends Compiler {
compileTree(node); compileTree(node);
if (emptyInfo != 0) { if (emptyInfo != 0) {
switch(emptyInfo) { switch (emptyInfo) {
case TargetInfo.IS_EMPTY: case TargetInfo.IS_EMPTY:
addOpcode(OPCode.NULL_CHECK_END); addOpcode(OPCode.NULL_CHECK_END);
break; break;
@ -149,13 +148,15 @@ final class ArrayCompiler extends Compiler {
case TargetInfo.IS_EMPTY_REC: case TargetInfo.IS_EMPTY_REC:
addOpcode(OPCode.NULL_CHECK_END_MEMST_PUSH); addOpcode(OPCode.NULL_CHECK_END_MEMST_PUSH);
break; break;
default:
break;
} // switch } // switch
addMemNum(savedNumNullCheck); /* NULL CHECK ID */ addMemNum(savedNumNullCheck); /* NULL CHECK ID */
} }
} }
private int addCompileStringlength(final char[] chars, final int p, final int strLength, final boolean ignoreCase) { private static int addCompileStringlength(final char[] chars, final int p, final int strLength, final boolean ignoreCase) {
final int op = selectStrOpcode(strLength, ignoreCase); final int op = selectStrOpcode(strLength, ignoreCase);
int len = OPSize.OPCODE; int len = OPSize.OPCODE;
@ -163,7 +164,9 @@ final class ArrayCompiler extends Compiler {
// string length, template index, template string pointer // string length, template index, template string pointer
len += OPSize.LENGTH + OPSize.INDEX + OPSize.INDEX; len += OPSize.LENGTH + OPSize.INDEX + OPSize.INDEX;
} else { } else {
if (isNeedStrLenOpExact(op)) len += OPSize.LENGTH; if (isNeedStrLenOpExact(op)) {
len += OPSize.LENGTH;
}
len += strLength; len += strLength;
} }
return len; return len;
@ -187,9 +190,11 @@ final class ArrayCompiler extends Compiler {
} }
} }
private int compileLengthStringNode(final Node node) { private static int compileLengthStringNode(final Node node) {
final StringNode sn = (StringNode)node; final StringNode sn = (StringNode)node;
if (sn.length() <= 0) return 0; if (sn.length() <= 0) {
return 0;
}
final boolean ambig = sn.isAmbig(); final boolean ambig = sn.isAmbig();
int p, prev; int p, prev;
@ -210,8 +215,10 @@ final class ArrayCompiler extends Compiler {
return rlen; return rlen;
} }
private int compileLengthStringRawNode(final StringNode sn) { private static int compileLengthStringRawNode(final StringNode sn) {
if (sn.length() <= 0) return 0; if (sn.length() <= 0) {
return 0;
}
return addCompileStringlength(sn.chars, sn.p, sn.length(), false); return addCompileStringlength(sn.chars, sn.p, sn.length(), false);
} }
@ -220,8 +227,10 @@ final class ArrayCompiler extends Compiler {
addInts(mbuf.p, mbuf.used); addInts(mbuf.p, mbuf.used);
} }
private int compileLengthCClassNode(final CClassNode cc) { private static int compileLengthCClassNode(final CClassNode cc) {
if (cc.isShare()) return OPSize.OPCODE + OPSize.POINTER; if (cc.isShare()) {
return OPSize.OPCODE + OPSize.POINTER;
}
int len; int len;
if (cc.mbuf == null) { if (cc.mbuf == null) {
@ -360,9 +369,8 @@ final class ArrayCompiler extends Compiler {
if (qn.greedy && infinite) { if (qn.greedy && infinite) {
if (qn.nextHeadExact != null) { if (qn.nextHeadExact != null) {
return OPSize.ANYCHAR_STAR_PEEK_NEXT + tlen * qn.lower; return OPSize.ANYCHAR_STAR_PEEK_NEXT + tlen * qn.lower;
} else {
return OPSize.ANYCHAR_STAR + tlen * qn.lower;
} }
return OPSize.ANYCHAR_STAR + tlen * qn.lower;
} }
} }
@ -425,14 +433,13 @@ final class ArrayCompiler extends Compiler {
final StringNode sn = (StringNode)qn.nextHeadExact; final StringNode sn = (StringNode)qn.nextHeadExact;
addChars(sn.chars, sn.p, 1); addChars(sn.chars, sn.p, 1);
return; return;
} else {
if (isMultiline(regex.options)) {
addOpcode(OPCode.ANYCHAR_ML_STAR);
} else {
addOpcode(OPCode.ANYCHAR_STAR);
}
return;
} }
if (isMultiline(regex.options)) {
addOpcode(OPCode.ANYCHAR_ML_STAR);
} else {
addOpcode(OPCode.ANYCHAR_STAR);
}
return;
} }
int modTLen; int modTLen;
@ -510,9 +517,8 @@ final class ArrayCompiler extends Compiler {
if (isDynamic(prev ^ node.option)) { if (isDynamic(prev ^ node.option)) {
return OPSize.SET_OPTION_PUSH + OPSize.SET_OPTION + OPSize.FAIL + tlen + OPSize.SET_OPTION; return OPSize.SET_OPTION_PUSH + OPSize.SET_OPTION + OPSize.FAIL + tlen + OPSize.SET_OPTION;
} else {
return tlen;
} }
return tlen;
} }
@Override @Override
@ -675,13 +681,15 @@ final class ArrayCompiler extends Compiler {
break; break;
case AnchorType.WORD_BEGIN: case AnchorType.WORD_BEGIN:
if (Config.USE_WORD_BEGIN_END) if (Config.USE_WORD_BEGIN_END) {
addOpcode(OPCode.WORD_BEGIN); addOpcode(OPCode.WORD_BEGIN);
}
break; break;
case AnchorType.WORD_END: case AnchorType.WORD_END:
if (Config.USE_WORD_BEGIN_END) if (Config.USE_WORD_BEGIN_END) {
addOpcode(OPCode.WORD_END); addOpcode(OPCode.WORD_END);
}
break; break;
case AnchorType.PREC_READ: case AnchorType.PREC_READ:
@ -701,7 +709,9 @@ final class ArrayCompiler extends Compiler {
addOpcode(OPCode.LOOK_BEHIND); addOpcode(OPCode.LOOK_BEHIND);
if (node.charLength < 0) { if (node.charLength < 0) {
n = analyser.getCharLengthTree(node.target); n = analyser.getCharLengthTree(node.target);
if (analyser.returnCode != 0) newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); if (analyser.returnCode != 0) {
newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN);
}
} else { } else {
n = node.charLength; n = node.charLength;
} }
@ -714,7 +724,9 @@ final class ArrayCompiler extends Compiler {
addOpcodeRelAddr(OPCode.PUSH_LOOK_BEHIND_NOT, len + OPSize.FAIL_LOOK_BEHIND_NOT); addOpcodeRelAddr(OPCode.PUSH_LOOK_BEHIND_NOT, len + OPSize.FAIL_LOOK_BEHIND_NOT);
if (node.charLength < 0) { if (node.charLength < 0) {
n = analyser.getCharLengthTree(node.target); n = analyser.getCharLengthTree(node.target);
if (analyser.returnCode != 0) newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); if (analyser.returnCode != 0) {
newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN);
}
} else { } else {
n = node.charLength; n = node.charLength;
} }
@ -796,7 +808,9 @@ final class ArrayCompiler extends Compiler {
private void ensure(final int size) { private void ensure(final int size) {
if (size >= code.length) { if (size >= code.length) {
int length = code.length << 1; int length = code.length << 1;
while (length <= size) length <<= 1; while (length <= size) {
length <<= 1;
}
final int[]tmp = new int[length]; final int[]tmp = new int[length];
System.arraycopy(code, 0, tmp, 0, code.length); System.arraycopy(code, 0, tmp, 0, code.length);
code = tmp; code = tmp;
@ -829,11 +843,14 @@ final class ArrayCompiler extends Compiler {
regex.operands[regex.operandLength++] = o; regex.operands[regex.operandLength++] = o;
} }
private void addChars(final char[] chars, int p ,final int length) { private void addChars(final char[] chars, final int pp ,final int length) {
ensure(codeLength + length); ensure(codeLength + length);
int p = pp;
final int end = p + length; final int end = p + length;
while (p < end) code[codeLength++] = chars[p++]; while (p < end) {
code[codeLength++] = chars[p++];
}
} }
private void addInts(final int[]ints, final int length) { private void addInts(final int[]ints, final int length) {
@ -876,6 +893,9 @@ final class ArrayCompiler extends Compiler {
case OPCode.CALL: case OPCode.CALL:
case OPCode.RETURN: // it will appear only with CALL though case OPCode.RETURN: // it will appear only with CALL though
regex.stackNeeded = true; regex.stackNeeded = true;
break;
default:
break;
} }
} }

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public final class BitSet { public final class BitSet {
static final int BITS_PER_BYTE = 8; static final int BITS_PER_BYTE = 8;
public static final int SINGLE_BYTE_SIZE = (1 << BITS_PER_BYTE); public static final int SINGLE_BYTE_SIZE = (1 << BITS_PER_BYTE);
@ -34,7 +35,9 @@ public final class BitSet {
final StringBuilder buffer = new StringBuilder(); final StringBuilder buffer = new StringBuilder();
buffer.append("BitSet"); buffer.append("BitSet");
for (int i=0; i<SINGLE_BYTE_SIZE; i++) { for (int i=0; i<SINGLE_BYTE_SIZE; i++) {
if ((i % (SINGLE_BYTE_SIZE / BITS_TO_STRING_WRAP)) == 0) buffer.append("\n "); if ((i % (SINGLE_BYTE_SIZE / BITS_TO_STRING_WRAP)) == 0) {
buffer.append("\n ");
}
buffer.append(at(i) ? "1" : "0"); buffer.append(at(i) ? "1" : "0");
} }
return buffer.toString(); return buffer.toString();
@ -53,44 +56,62 @@ public final class BitSet {
} }
public void clear() { public void clear() {
for (int i=0; i<BITSET_SIZE; i++) bits[i]=0; for (int i=0; i<BITSET_SIZE; i++) {
bits[i]=0;
}
} }
public boolean isEmpty() { public boolean isEmpty() {
for (int i=0; i<BITSET_SIZE; i++) { for (int i=0; i<BITSET_SIZE; i++) {
if (bits[i] != 0) return false; if (bits[i] != 0) {
return false;
}
} }
return true; return true;
} }
public void setRange(final int from, final int to) { public void setRange(final int from, final int to) {
for (int i=from; i<=to && i < SINGLE_BYTE_SIZE; i++) set(i); for (int i=from; i<=to && i < SINGLE_BYTE_SIZE; i++) {
set(i);
}
} }
public void invert() { public void invert() {
for (int i=0; i<BITSET_SIZE; i++) bits[i] = ~bits[i]; for (int i=0; i<BITSET_SIZE; i++) {
bits[i] = ~bits[i];
}
} }
public void invertTo(final BitSet to) { public void invertTo(final BitSet to) {
for (int i=0; i<BITSET_SIZE; i++) to.bits[i] = ~bits[i]; for (int i=0; i<BITSET_SIZE; i++) {
to.bits[i] = ~bits[i];
}
} }
public void and(final BitSet other) { public void and(final BitSet other) {
for (int i=0; i<BITSET_SIZE; i++) bits[i] &= other.bits[i]; for (int i=0; i<BITSET_SIZE; i++) {
bits[i] &= other.bits[i];
}
} }
public void or(final BitSet other) { public void or(final BitSet other) {
for (int i=0; i<BITSET_SIZE; i++) bits[i] |= other.bits[i]; for (int i=0; i<BITSET_SIZE; i++) {
bits[i] |= other.bits[i];
}
} }
public void copy(final BitSet other) { public void copy(final BitSet other) {
for (int i=0; i<BITSET_SIZE; i++) bits[i] = other.bits[i]; for (int i=0; i<BITSET_SIZE; i++) {
bits[i] = other.bits[i];
}
} }
public int numOn() { public int numOn() {
int num = 0; int num = 0;
for (int i=0; i<SINGLE_BYTE_SIZE; i++) { for (int i=0; i<SINGLE_BYTE_SIZE; i++) {
if (at(i)) num++; if (at(i)) {
num++;
}
} }
return num; return num;
} }
@ -99,9 +120,12 @@ public final class BitSet {
return 1 << (pos % SINGLE_BYTE_SIZE); return 1 << (pos % SINGLE_BYTE_SIZE);
} }
private static int log2(int n){ private static int log2(final int np) {
int log = 0; int log = 0;
while ((n >>>= 1) != 0) log++; int n = np;
while ((n >>>= 1) != 0) {
log++;
}
return log; return log;
} }

View File

@ -34,7 +34,8 @@ final class BitStatus {
return (n < BIT_STATUS_BITS_NUM ? stats & (1 << n) : (stats & 1)) != 0; return (n < BIT_STATUS_BITS_NUM ? stats & (1 << n) : (stats & 1)) != 0;
} }
public static int bsOnAt(int stats, final int n) { public static int bsOnAt(final int statsp, final int n) {
int stats = statsp;
if (n < BIT_STATUS_BITS_NUM) { if (n < BIT_STATUS_BITS_NUM) {
stats |= (1 << n); stats |= (1 << n);
} else { } else {
@ -43,12 +44,7 @@ final class BitStatus {
return stats; return stats;
} }
public static int bsOnOff(int v, final int f, final boolean negative) { public static int bsOnOff(final int v, final int f, final boolean negative) {
if (negative) { return negative ? (v & ~f) : (v | f);
v &= ~f;
} else {
v |= f;
}
return v;
} }
} }

View File

@ -27,10 +27,8 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindNotEmpty;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotBol; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotBol;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotEol; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotEol;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isPosixRegion; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isPosixRegion;
import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
import jdk.nashorn.internal.runtime.regexp.joni.constants.OPCode; import jdk.nashorn.internal.runtime.regexp.joni.constants.OPCode;
import jdk.nashorn.internal.runtime.regexp.joni.constants.OPSize;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder; import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
@ -52,8 +50,8 @@ class ByteCodeMachine extends StackMachine {
this.code = regex.code; this.code = regex.code;
} }
private boolean stringCmpIC(final int caseFlodFlag, int s1, final IntHolder ps2, final int mbLen, final int textEnd) { private boolean stringCmpIC(final int caseFlodFlag, final int s1p, final IntHolder ps2, final int mbLen, final int textEnd) {
int s1 = s1p;
int s2 = ps2.value; int s2 = ps2.value;
final int end1 = s1 + mbLen; final int end1 = s1 + mbLen;
@ -83,12 +81,16 @@ class ByteCodeMachine extends StackMachine {
Config.log.printf("%4d", (s - str)).print("> \""); Config.log.printf("%4d", (s - str)).print("> \"");
int q, i; int q, i;
for (i=0, q=s; i<7 && q<end && s>=0; i++) { for (i=0, q=s; i<7 && q<end && s>=0; i++) {
if (q < end) Config.log.print(new String(new char[]{chars[q++]})); if (q < end) {
Config.log.print(new String(new char[]{chars[q++]}));
}
}
final String string = q < end ? "...\"" : "\"";
q += string.length();
Config.log.print(string);
for (i=0; i<20-(q-s);i++) {
Config.log.print(" ");
} }
final String str = q < end ? "...\"" : "\"";
q += str.length();
Config.log.print(str);
for (i=0; i<20-(q-s);i++) Config.log.print(" ");
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
new ByteCodePrinter(regex).compiledByteCodeToString(sb, ip); new ByteCodePrinter(regex).compiledByteCodeToString(sb, ip);
Config.log.println(sb.toString()); Config.log.println(sb.toString());
@ -96,28 +98,34 @@ class ByteCodeMachine extends StackMachine {
} }
@Override @Override
protected final int matchAt(final int range, final int sstart, final int sprev) { protected final int matchAt(final int r, final int ss, final int sp) {
this.range = range; this.range = r;
this.sstart = sstart; this.sstart = ss;
this.sprev = sprev; this.sprev = sp;
stk = 0; stk = 0;
ip = 0; ip = 0;
if (Config.DEBUG_MATCH) debugMatchBegin(); if (Config.DEBUG_MATCH) {
debugMatchBegin();
}
init(); init();
bestLen = -1; bestLen = -1;
s = sstart; s = ss;
final int[]code = this.code; final int[] c = this.code;
while (true) { while (true) {
if (Config.DEBUG_MATCH) debugMatchLoop(); if (Config.DEBUG_MATCH) {
debugMatchLoop();
}
sbegin = s; sbegin = s;
switch (code[ip++]) { switch (c[ip++]) {
case OPCode.END: if (opEnd()) return finish(); break; case OPCode.END: if (opEnd()) {
return finish();
} break;
case OPCode.EXACT1: opExact1(); break; case OPCode.EXACT1: opExact1(); break;
case OPCode.EXACT2: opExact2(); continue; case OPCode.EXACT2: opExact2(); continue;
case OPCode.EXACT3: opExact3(); continue; case OPCode.EXACT3: opExact3(); continue;
@ -358,10 +366,14 @@ class ByteCodeMachine extends StackMachine {
final char[] bs = regex.templates[code[ip++]]; final char[] bs = regex.templates[code[ip++]];
int ps = code[ip++]; int ps = code[ip++];
while (tlen-- > 0) if (bs[ps++] != chars[s++]) {opFail(); return;} while (tlen-- > 0) {
if (bs[ps++] != chars[s++]) {opFail(); return;}
}
} else { } else {
while (tlen-- > 0) if (code[ip++] != chars[s++]) {opFail(); return;} while (tlen-- > 0) {
if (code[ip++] != chars[s++]) {opFail(); return;}
}
} }
sprev = s - 1; sprev = s - 1;
} }
@ -380,10 +392,14 @@ class ByteCodeMachine extends StackMachine {
final char[] bs = regex.templates[code[ip++]]; final char[] bs = regex.templates[code[ip++]];
int ps = code[ip++]; int ps = code[ip++];
while (tlen-- > 0) if (bs[ps++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} while (tlen-- > 0) {
if (bs[ps++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;}
}
} else { } else {
while (tlen-- > 0) if (code[ip++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} while (tlen-- > 0) {
if (code[ip++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;}
}
} }
sprev = s - 1; sprev = s - 1;
} }
@ -402,11 +418,15 @@ class ByteCodeMachine extends StackMachine {
private boolean isInClassMB() { private boolean isInClassMB() {
final int tlen = code[ip++]; final int tlen = code[ip++];
if (s >= range) return false; if (s >= range) {
return false;
}
final int ss = s; final int ss = s;
s++; s++;
final int c = chars[ss]; final int c = chars[ss];
if (!EncodingHelper.isInCodeRange(code, ip, c)) return false; if (!EncodingHelper.isInCodeRange(code, ip, c)) {
return false;
}
ip += tlen; ip += tlen;
return true; return true;
} }
@ -444,7 +464,9 @@ class ByteCodeMachine extends StackMachine {
final int tlen = code[ip++]; final int tlen = code[ip++];
if (!(s + 1 <= range)) { if (!(s + 1 <= range)) {
if (s >= range) return false; if (s >= range) {
return false;
}
s = end; s = end;
ip += tlen; ip += tlen;
return true; return true;
@ -454,7 +476,9 @@ class ByteCodeMachine extends StackMachine {
s++; s++;
final int c = chars[ss]; final int c = chars[ss];
if (EncodingHelper.isInCodeRange(code, ip, c)) return false; if (EncodingHelper.isInCodeRange(code, ip, c)) {
return false;
}
ip += tlen; ip += tlen;
return true; return true;
} }
@ -511,10 +535,10 @@ class ByteCodeMachine extends StackMachine {
} }
private void opAnyCharStar() { private void opAnyCharStar() {
final char[] chars = this.chars; final char[] ch = this.chars;
while (s < range) { while (s < range) {
pushAlt(ip, s, sprev); pushAlt(ip, s, sprev);
if (isNewLine(chars, s, end)) {opFail(); return;} if (isNewLine(ch, s, end)) {opFail(); return;}
sprev = s; sprev = s;
s++; s++;
} }
@ -532,11 +556,13 @@ class ByteCodeMachine extends StackMachine {
private void opAnyCharStarPeekNext() { private void opAnyCharStarPeekNext() {
final char c = (char)code[ip]; final char c = (char)code[ip];
final char[] chars = this.chars; final char[] ch = this.chars;
while (s < range) { while (s < range) {
final char b = chars[s]; final char b = ch[s];
if (c == b) pushAlt(ip + 1, s, sprev); if (c == b) {
pushAlt(ip + 1, s, sprev);
}
if (isNewLine(b)) {opFail(); return;} if (isNewLine(b)) {opFail(); return;}
sprev = s; sprev = s;
s++; s++;
@ -547,10 +573,12 @@ class ByteCodeMachine extends StackMachine {
private void opAnyCharMLStarPeekNext() { private void opAnyCharMLStarPeekNext() {
final char c = (char)code[ip]; final char c = (char)code[ip];
final char[] chars = this.chars; final char[] ch = this.chars;
while (s < range) { while (s < range) {
if (c == chars[s]) pushAlt(ip + 1, s, sprev); if (c == ch[s]) {
pushAlt(ip + 1, s, sprev);
}
sprev = s; sprev = s;
s++; s++;
} }
@ -592,29 +620,39 @@ class ByteCodeMachine extends StackMachine {
private void opWordBegin() { private void opWordBegin() {
if (s < range && EncodingHelper.isWord(chars[s])) { if (s < range && EncodingHelper.isWord(chars[s])) {
if (s == str || !EncodingHelper.isWord(chars[sprev])) return; if (s == str || !EncodingHelper.isWord(chars[sprev])) {
return;
}
} }
opFail(); opFail();
} }
private void opWordEnd() { private void opWordEnd() {
if (s != str && EncodingHelper.isWord(chars[sprev])) { if (s != str && EncodingHelper.isWord(chars[sprev])) {
if (s == end || !EncodingHelper.isWord(chars[s])) return; if (s == end || !EncodingHelper.isWord(chars[s])) {
return;
}
} }
opFail(); opFail();
} }
private void opBeginBuf() { private void opBeginBuf() {
if (s != str) opFail(); if (s != str) {
opFail();
}
} }
private void opEndBuf() { private void opEndBuf() {
if (s != end) opFail(); if (s != end) {
opFail();
}
} }
private void opBeginLine() { private void opBeginLine() {
if (s == str) { if (s == str) {
if (isNotBol(msaOptions)) opFail(); if (isNotBol(msaOptions)) {
opFail();
}
return; return;
} else if (isNewLine(chars, sprev, end) && s != end) { } else if (isNewLine(chars, sprev, end) && s != end) {
return; return;
@ -626,13 +664,16 @@ class ByteCodeMachine extends StackMachine {
if (s == end) { if (s == end) {
if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
if (str == end || !isNewLine(chars, sprev, end)) { if (str == end || !isNewLine(chars, sprev, end)) {
if (isNotEol(msaOptions)) opFail(); if (isNotEol(msaOptions)) {
opFail();
}
} }
return; return;
} else {
if (isNotEol(msaOptions)) opFail();
return;
} }
if (isNotEol(msaOptions)) {
opFail();
}
return;
} else if (isNewLine(chars, s, end)) { } else if (isNewLine(chars, s, end)) {
return; return;
} }
@ -643,13 +684,16 @@ class ByteCodeMachine extends StackMachine {
if (s == end) { if (s == end) {
if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
if (str == end || !isNewLine(chars, sprev, end)) { if (str == end || !isNewLine(chars, sprev, end)) {
if (isNotEol(msaOptions)) opFail(); if (isNotEol(msaOptions)) {
opFail();
}
} }
return; return;
} else {
if (isNotEol(msaOptions)) opFail();
return;
} }
if (isNotEol(msaOptions)) {
opFail();
}
return;
} else if (isNewLine(chars, s, end) && s + 1 == end) { } else if (isNewLine(chars, s, end) && s + 1 == end) {
return; return;
} }
@ -657,7 +701,9 @@ class ByteCodeMachine extends StackMachine {
} }
private void opBeginPosition() { private void opBeginPosition() {
if (s != msaStart) opFail(); if (s != msaStart) {
opFail();
}
} }
private void opMemoryStartPush() { private void opMemoryStartPush() {
@ -726,11 +772,15 @@ class ByteCodeMachine extends StackMachine {
sprev = s; sprev = s;
// STRING_CMP // STRING_CMP
while(n-- > 0) if (chars[pstart++] != chars[s++]) {opFail(); return;} while(n-- > 0) {
if (chars[pstart++] != chars[s++]) {opFail(); return;}
}
// beyond string check // beyond string check
if (sprev < range) { if (sprev < range) {
while (sprev + 1 < s) sprev++; while (sprev + 1 < s) {
sprev++;
}
} }
} }
@ -764,7 +814,9 @@ class ByteCodeMachine extends StackMachine {
s = value; s = value;
// if (sprev < chars.length) // if (sprev < chars.length)
while (sprev + 1 < s) sprev++; while (sprev + 1 < s) {
sprev++;
}
} }
private void opBackRefMulti() { private void opBackRefMulti() {
@ -773,7 +825,9 @@ class ByteCodeMachine extends StackMachine {
int i; int i;
loop:for (i=0; i<tlen; i++) { loop:for (i=0; i<tlen; i++) {
final int mem = code[ip++]; final int mem = code[ip++];
if (backrefInvalid(mem)) continue; if (backrefInvalid(mem)) {
continue;
}
int pstart = backrefStart(mem); int pstart = backrefStart(mem);
final int pend = backrefEnd(mem); final int pend = backrefEnd(mem);
@ -785,14 +839,18 @@ class ByteCodeMachine extends StackMachine {
int swork = s; int swork = s;
while (n-- > 0) { while (n-- > 0) {
if (chars[pstart++] != chars[swork++]) continue loop; if (chars[pstart++] != chars[swork++]) {
continue loop;
}
} }
s = swork; s = swork;
// beyond string check // beyond string check
if (sprev < range) { if (sprev < range) {
while (sprev + 1 < s) sprev++; while (sprev + 1 < s) {
sprev++;
}
} }
ip += tlen - i - 1; // * SIZE_MEMNUM (1) ip += tlen - i - 1; // * SIZE_MEMNUM (1)
@ -807,7 +865,9 @@ class ByteCodeMachine extends StackMachine {
int i; int i;
loop:for (i=0; i<tlen; i++) { loop:for (i=0; i<tlen; i++) {
final int mem = code[ip++]; final int mem = code[ip++];
if (backrefInvalid(mem)) continue; if (backrefInvalid(mem)) {
continue;
}
final int pstart = backrefStart(mem); final int pstart = backrefStart(mem);
final int pend = backrefEnd(mem); final int pend = backrefEnd(mem);
@ -818,11 +878,16 @@ class ByteCodeMachine extends StackMachine {
sprev = s; sprev = s;
value = s; value = s;
if (!stringCmpIC(regex.caseFoldFlag, pstart, this, n, end)) continue loop; // STRING_CMP_VALUE_IC if (!stringCmpIC(regex.caseFoldFlag, pstart, this, n, end))
{
continue loop; // STRING_CMP_VALUE_IC
}
s = value; s = value;
// if (sprev < chars.length) // if (sprev < chars.length)
while (sprev + 1 < s) sprev++; while (sprev + 1 < s) {
sprev++;
}
ip += tlen - i - 1; // * SIZE_MEMNUM (1) ip += tlen - i - 1; // * SIZE_MEMNUM (1)
break; /* success */ break; /* success */
@ -830,10 +895,12 @@ class ByteCodeMachine extends StackMachine {
if (i == tlen) {opFail(); return;} if (i == tlen) {opFail(); return;}
} }
private boolean memIsInMemp(final int mem, final int num, int memp) { private boolean memIsInMemp(final int mem, final int num, final int mempp) {
for (int i=0; i<num; i++) { for (int i=0, memp = mempp; i<num; i++) {
final int m = code[memp++]; final int m = code[memp++];
if (mem == m) return true; if (mem == m) {
return true;
}
} }
return false; return false;
} }
@ -857,7 +924,9 @@ class ByteCodeMachine extends StackMachine {
if (memIsInMemp(e.getMemNum(), memNum, memp)) { if (memIsInMemp(e.getMemNum(), memNum, memp)) {
final int pstart = e.getMemPStr(); final int pstart = e.getMemPStr();
if (pend != -1) { if (pend != -1) {
if (pend - pstart > end - s) return false; /* or goto next_mem; */ if (pend - pstart > end - s) {
return false; /* or goto next_mem; */
}
int p = pstart; int p = pstart;
value = s; value = s;
@ -867,7 +936,9 @@ class ByteCodeMachine extends StackMachine {
} }
} else { } else {
while (p < pend) { while (p < pend) {
if (chars[p++] != chars[value++]) return false; /* or goto next_mem; */ if (chars[p++] != chars[value++]) {
return false; /* or goto next_mem; */
}
} }
} }
s = value; s = value;
@ -893,24 +964,15 @@ class ByteCodeMachine extends StackMachine {
sprev = s; sprev = s;
if (backrefMatchAtNestedLevel(ic != 0, regex.caseFoldFlag, level, tlen, ip)) { // (s) and (end) implicit if (backrefMatchAtNestedLevel(ic != 0, regex.caseFoldFlag, level, tlen, ip)) { // (s) and (end) implicit
while (sprev + 1 < s) sprev++; while (sprev + 1 < s) {
sprev++;
}
ip += tlen; // * SIZE_MEMNUM ip += tlen; // * SIZE_MEMNUM
} else { } else {
{opFail(); return;} {opFail(); return;}
} }
} }
/* no need: IS_DYNAMIC_OPTION() == 0 */
private void opSetOptionPush() {
// option = code[ip++]; // final for now
pushAlt(ip, s, sprev);
ip += OPSize.SET_OPTION + OPSize.FAIL;
}
private void opSetOption() {
// option = code[ip++]; // final for now
}
private void opNullCheckStart() { private void opNullCheckStart() {
final int mem = code[ip++]; final int mem = code[ip++];
pushNullCheckStart(mem, s); pushNullCheckStart(mem, s);
@ -1142,13 +1204,6 @@ class ByteCodeMachine extends StackMachine {
sprev = EncodingHelper.prevCharHead(str, s); sprev = EncodingHelper.prevCharHead(str, s);
} }
private void opLookBehindSb() {
final int tlen = code[ip++];
s -= tlen;
if (s < str) {opFail(); return;}
sprev = s == str ? -1 : s - 1;
}
private void opPushLookBehindNot() { private void opPushLookBehindNot() {
final int addr = code[ip++]; final int addr = code[ip++];
final int tlen = code[ip++]; final int tlen = code[ip++];

View File

@ -236,16 +236,17 @@ class ByteCodePrinter {
sb.append(new String(code, s, len)); sb.append(new String(code, s, len));
} }
private void pLenStringFromTemplate(final StringBuilder sb, final int len, final char[] tm, final int idx) { private static void pLenStringFromTemplate(final StringBuilder sb, final int len, final char[] tm, final int idx) {
sb.append(":T:").append(len).append(":"); sb.append(":T:").append(len).append(":");
sb.append(tm, idx, len); sb.append(tm, idx, len);
} }
public int compiledByteCodeToString(final StringBuilder sb, int bp) { public int compiledByteCodeToString(final StringBuilder sb, final int bptr) {
int len, n, mem, addr, scn, cod; int len, n, mem, addr, scn, cod;
BitSet bs; BitSet bs;
CClassNode cc; CClassNode cc;
int tm, idx; int tm, idx;
int bp = bptr;
sb.append("[").append(OpCodeNames[code[bp]]); sb.append("[").append(OpCodeNames[code[bp]]);
final int argType = OpCodeArgTypes[code[bp]]; final int argType = OpCodeArgTypes[code[bp]];
@ -253,6 +254,7 @@ class ByteCodePrinter {
if (argType != Arguments.SPECIAL) { if (argType != Arguments.SPECIAL) {
bp++; bp++;
switch (argType) { switch (argType) {
default:
case Arguments.NON: case Arguments.NON:
break; break;
@ -410,7 +412,9 @@ class ByteCodePrinter {
for (int i=0; i<len; i++) { for (int i=0; i<len; i++) {
mem = code[bp]; mem = code[bp];
bp += OPSize.MEMNUM; bp += OPSize.MEMNUM;
if (i > 0) sb.append(", "); if (i > 0) {
sb.append(", ");
}
sb.append(mem); sb.append(mem);
} }
break; break;
@ -428,7 +432,9 @@ class ByteCodePrinter {
for (int i=0; i<len; i++) { for (int i=0; i<len; i++) {
mem = code[bp]; mem = code[bp];
bp += OPSize.MEMNUM; bp += OPSize.MEMNUM;
if (i > 0) sb.append(", "); if (i > 0) {
sb.append(", ");
}
sb.append(mem); sb.append(mem);
} }
break; break;
@ -501,7 +507,9 @@ class ByteCodePrinter {
while (bp < end) { while (bp < end) {
ncode++; ncode++;
if (bp > 0) sb.append(ncode % 5 == 0 ? "\n" : " "); if (bp > 0) {
sb.append(ncode % 5 == 0 ? "\n" : " ");
}
bp = compiledByteCodeToString(sb, bp); bp = compiledByteCodeToString(sb, bp);
} }

View File

@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;
@SuppressWarnings("javadoc")
public final class CodeRangeBuffer implements Cloneable { public final class CodeRangeBuffer implements Cloneable {
private static final int INIT_MULTI_BYTE_RANGE_SIZE = 5; private static final int INIT_MULTI_BYTE_RANGE_SIZE = 5;
private static final int ALL_MULTI_BYTE_RANGE = 0x7fffffff; private static final int ALL_MULTI_BYTE_RANGE = 0x7fffffff;
@ -68,7 +69,9 @@ public final class CodeRangeBuffer implements Cloneable {
for (int i=0; i<p[0]; i++) { for (int i=0; i<p[0]; i++) {
buf.append("[").append(rangeNumToString(p[i * 2 + 1])).append("..").append(rangeNumToString(p[i * 2 + 2])).append("]"); buf.append("[").append(rangeNumToString(p[i * 2 + 1])).append("..").append(rangeNumToString(p[i * 2 + 2])).append("]");
if (i > 0 && i % 6 == 0) buf.append("\n "); if (i > 0 && i % 6 == 0) {
buf.append("\n ");
}
} }
return buf.toString(); return buf.toString();
@ -97,9 +100,13 @@ public final class CodeRangeBuffer implements Cloneable {
} }
private void moveRight(final int from, final int to, final int n) { private void moveRight(final int from, final int to, final int n) {
if (to + n > p.length) expand(to + n); if (to + n > p.length) {
expand(to + n);
}
System.arraycopy(p, from, p, to, n); System.arraycopy(p, from, p, to, n);
if (to + n > used) used = to + n; if (to + n > used) {
used = to + n;
}
} }
protected void moveLeft(final int from, final int to, final int n) { protected void moveLeft(final int from, final int to, final int n) {
@ -113,9 +120,13 @@ public final class CodeRangeBuffer implements Cloneable {
public void writeCodePoint(final int pos, final int b) { public void writeCodePoint(final int pos, final int b) {
final int u = pos + 1; final int u = pos + 1;
if (p.length < u) expand(u); if (p.length < u) {
expand(u);
}
p[pos] = b; p[pos] = b;
if (used < u) used = u; if (used < u) {
used = u;
}
} }
@Override @Override
@ -125,14 +136,19 @@ public final class CodeRangeBuffer implements Cloneable {
// ugly part: these methods should be made OO // ugly part: these methods should be made OO
// add_code_range_to_buf // add_code_range_to_buf
public static CodeRangeBuffer addCodeRangeToBuff(CodeRangeBuffer pbuf, int from, int to) { public static CodeRangeBuffer addCodeRangeToBuff(final CodeRangeBuffer pbufp, final int fromp, final int top) {
int from = fromp, to = top;
CodeRangeBuffer pbuf = pbufp;
if (from > to) { if (from > to) {
final int n = from; final int n = from;
from = to; from = to;
to = n; to = n;
} }
if (pbuf == null) pbuf = new CodeRangeBuffer(); // move to CClassNode if (pbuf == null) {
pbuf = new CodeRangeBuffer(); // move to CClassNode
}
final int[]p = pbuf.p; final int[]p = pbuf.p;
int n = p[0]; int n = p[0];
@ -163,11 +179,17 @@ public final class CodeRangeBuffer implements Cloneable {
final int incN = low + 1 - high; final int incN = low + 1 - high;
if (n + incN > Config.MAX_MULTI_BYTE_RANGES_NUM) throw new ValueException(ErrorMessages.ERR_TOO_MANY_MULTI_BYTE_RANGES); if (n + incN > Config.MAX_MULTI_BYTE_RANGES_NUM) {
throw new ValueException(ErrorMessages.ERR_TOO_MANY_MULTI_BYTE_RANGES);
}
if (incN != 1) { if (incN != 1) {
if (from > p[low * 2 + 1]) from = p[low * 2 + 1]; if (from > p[low * 2 + 1]) {
if (to < p[(high - 1) * 2 + 2]) to = p[(high - 1) * 2 + 2]; from = p[low * 2 + 1];
}
if (to < p[(high - 1) * 2 + 2]) {
to = p[(high - 1) * 2 + 2];
}
} }
if (incN != 0 && high < n) { if (incN != 0 && high < n) {
@ -197,9 +219,8 @@ public final class CodeRangeBuffer implements Cloneable {
if (from > to) { if (from > to) {
if (env.syntax.allowEmptyRangeInCC()) { if (env.syntax.allowEmptyRangeInCC()) {
return pbuf; return pbuf;
} else {
throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS);
} }
throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS);
} }
return addCodeRangeToBuff(pbuf, from, to); return addCodeRangeToBuff(pbuf, from, to);
} }
@ -218,12 +239,16 @@ public final class CodeRangeBuffer implements Cloneable {
public static CodeRangeBuffer notCodeRangeBuff(final CodeRangeBuffer bbuf) { public static CodeRangeBuffer notCodeRangeBuff(final CodeRangeBuffer bbuf) {
CodeRangeBuffer pbuf = null; CodeRangeBuffer pbuf = null;
if (bbuf == null) return setAllMultiByteRange(pbuf); if (bbuf == null) {
return setAllMultiByteRange(pbuf);
}
final int[]p = bbuf.p; final int[]p = bbuf.p;
final int n = p[0]; final int n = p[0];
if (n <= 0) return setAllMultiByteRange(pbuf); if (n <= 0) {
return setAllMultiByteRange(pbuf);
}
int pre = EncodingHelper.mbcodeStartPosition(); int pre = EncodingHelper.mbcodeStartPosition();
@ -235,18 +260,26 @@ public final class CodeRangeBuffer implements Cloneable {
if (pre <= from - 1) { if (pre <= from - 1) {
pbuf = addCodeRangeToBuff(pbuf, pre, from - 1); pbuf = addCodeRangeToBuff(pbuf, pre, from - 1);
} }
if (to == ALL_MULTI_BYTE_RANGE) break; if (to == ALL_MULTI_BYTE_RANGE) {
break;
}
pre = to + 1; pre = to + 1;
} }
if (to < ALL_MULTI_BYTE_RANGE) pbuf = addCodeRangeToBuff(pbuf, to + 1, ALL_MULTI_BYTE_RANGE); if (to < ALL_MULTI_BYTE_RANGE) {
pbuf = addCodeRangeToBuff(pbuf, to + 1, ALL_MULTI_BYTE_RANGE);
}
return pbuf; return pbuf;
} }
// or_code_range_buf // or_code_range_buf
public static CodeRangeBuffer orCodeRangeBuff(CodeRangeBuffer bbuf1, boolean not1, public static CodeRangeBuffer orCodeRangeBuff(final CodeRangeBuffer bbuf1p, final boolean not1p,
CodeRangeBuffer bbuf2, boolean not2) { final CodeRangeBuffer bbuf2p, final boolean not2p) {
CodeRangeBuffer pbuf = null; CodeRangeBuffer pbuf = null;
CodeRangeBuffer bbuf1 = bbuf1p;
CodeRangeBuffer bbuf2 = bbuf2p;
boolean not1 = not1p;
boolean not2 = not2p;
if (bbuf1 == null && bbuf2 == null) { if (bbuf1 == null && bbuf2 == null) {
if (not1 || not2) { if (not1 || not2) {
@ -266,13 +299,11 @@ public final class CodeRangeBuffer implements Cloneable {
if (bbuf1 == null) { if (bbuf1 == null) {
if (not1) { if (not1) {
return setAllMultiByteRange(pbuf); return setAllMultiByteRange(pbuf);
} else {
if (!not2) {
return bbuf2.clone();
} else {
return notCodeRangeBuff(bbuf2);
}
} }
if (!not2) {
return bbuf2.clone();
}
return notCodeRangeBuff(bbuf2);
} }
if (not1) { if (not1) {
@ -302,16 +333,18 @@ public final class CodeRangeBuffer implements Cloneable {
} }
// and_code_range1 // and_code_range1
public static CodeRangeBuffer andCodeRange1(CodeRangeBuffer pbuf, int from1, int to1, final int[]data, final int n) { public static CodeRangeBuffer andCodeRange1(final CodeRangeBuffer pbufp, final int from1p, final int to1p, final int[]data, final int n) {
CodeRangeBuffer pbuf = pbufp;
int from1 = from1p, to1 = to1p;
for (int i=0; i<n; i++) { for (int i=0; i<n; i++) {
final int from2 = data[i * 2 + 1]; final int from2 = data[i * 2 + 1];
final int to2 = data[i * 2 + 2]; final int to2 = data[i * 2 + 2];
if (from2 < from1) { if (from2 < from1) {
if (to2 < from1) { if (to2 < from1) {
continue; continue;
} else {
from1 = to2 + 1;
} }
from1 = to2 + 1;
} else if (from2 <= to1) { } else if (from2 <= to1) {
if (to2 < to1) { if (to2 < to1) {
if (from1 <= from2 - 1) { if (from1 <= from2 - 1) {
@ -324,7 +357,9 @@ public final class CodeRangeBuffer implements Cloneable {
} else { } else {
from1 = from2; from1 = from2;
} }
if (from1 > to1) break; if (from1 > to1) {
break;
}
} }
if (from1 <= to1) { if (from1 <= to1) {
@ -335,15 +370,22 @@ public final class CodeRangeBuffer implements Cloneable {
} }
// and_code_range_buf // and_code_range_buf
public static CodeRangeBuffer andCodeRangeBuff(CodeRangeBuffer bbuf1, boolean not1, public static CodeRangeBuffer andCodeRangeBuff(final CodeRangeBuffer bbuf1p, final boolean not1p,
CodeRangeBuffer bbuf2, boolean not2) { final CodeRangeBuffer bbuf2p, final boolean not2p) {
CodeRangeBuffer pbuf = null; CodeRangeBuffer pbuf = null;
CodeRangeBuffer bbuf1 = bbuf1p;
CodeRangeBuffer bbuf2 = bbuf2p;
boolean not1 = not1p, not2 = not2p;
if (bbuf1 == null) { if (bbuf1 == null) {
if (not1 && bbuf2 != null) return bbuf2.clone(); /* not1 != 0 -> not2 == 0 */ if (not1 && bbuf2 != null) {
return bbuf2.clone(); /* not1 != 0 -> not2 == 0 */
}
return null; return null;
} else if (bbuf2 == null) { } else if (bbuf2 == null) {
if (not2) return bbuf1.clone(); if (not2) {
return bbuf1.clone();
}
return null; return null;
} }
@ -369,8 +411,12 @@ public final class CodeRangeBuffer implements Cloneable {
final int from2 = p2[j * 2 + 1]; final int from2 = p2[j * 2 + 1];
final int to2 = p2[j * 2 + 2]; final int to2 = p2[j * 2 + 2];
if (from2 > to1) break; if (from2 > to1) {
if (to2 < from1) continue; break;
}
if (to2 < from1) {
continue;
}
final int from = from1 > from2 ? from1 : from2; final int from = from1 > from2 ? from1 : from2;
final int to = to1 < to2 ? to1 : to2; final int to = to1 < to2 ? to1 : to2;
pbuf = addCodeRangeToBuff(pbuf, from, to); pbuf = addCodeRangeToBuff(pbuf, from, to);

View File

@ -53,13 +53,17 @@ abstract class Compiler implements ErrorMessages {
protected abstract void compileAltNode(ConsAltNode node); protected abstract void compileAltNode(ConsAltNode node);
private void compileStringRawNode(final StringNode sn) { private void compileStringRawNode(final StringNode sn) {
if (sn.length() <= 0) return; if (sn.length() <= 0) {
return;
}
addCompileString(sn.chars, sn.p, sn.length(), false); addCompileString(sn.chars, sn.p, sn.length(), false);
} }
private void compileStringNode(final StringNode node) { private void compileStringNode(final StringNode node) {
final StringNode sn = node; final StringNode sn = node;
if (sn.length() <= 0) return; if (sn.length() <= 0) {
return;
}
final boolean ambig = sn.isAmbig(); final boolean ambig = sn.isAmbig();
@ -145,7 +149,9 @@ abstract class Compiler implements ErrorMessages {
} }
protected final void compileTreeNTimes(final Node node, final int n) { protected final void compileTreeNTimes(final Node node, final int n) {
for (int i=0; i<n; i++) compileTree(node); for (int i=0; i<n; i++) {
compileTree(node);
}
} }
protected void newSyntaxException(final String message) { protected void newSyntaxException(final String message) {

View File

@ -21,6 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import java.io.PrintStream; import java.io.PrintStream;
@SuppressWarnings("javadoc")
public interface Config { public interface Config {
final int CHAR_TABLE_SIZE = 256; final int CHAR_TABLE_SIZE = 256;

View File

@ -23,6 +23,7 @@ import java.util.Arrays;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType; import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder; import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
@SuppressWarnings("javadoc")
public final class EncodingHelper { public final class EncodingHelper {
final static int NEW_LINE = 0x000a; final static int NEW_LINE = 0x000a;
@ -79,14 +80,19 @@ public final class EncodingHelper {
/* onigenc_get_right_adjust_char_head_with_prev */ /* onigenc_get_right_adjust_char_head_with_prev */
public static int rightAdjustCharHeadWithPrev(final int s, final IntHolder prev) { public static int rightAdjustCharHeadWithPrev(final int s, final IntHolder prev) {
if (prev != null) prev.value = -1; /* Sorry */ if (prev != null) {
prev.value = -1; /* Sorry */
}
return s; return s;
} }
// Encoding.stepBack // Encoding.stepBack
public static int stepBack(final int p, int s, int n) { public static int stepBack(final int p, final int sp, final int np) {
while (s != -1 && n-- > 0) { int s = sp, n = np;
if (s <= p) return -1; while (s != -1 && n-- > 0) {
if (s <= p) {
return -1;
}
s--; s--;
} }
return s; return s;
@ -122,7 +128,7 @@ public final class EncodingHelper {
final int upper = toUpperCase(c); final int upper = toUpperCase(c);
if (upper != c) { if (upper != c) {
fun.apply(c, upper, arg); ApplyCaseFold.apply(c, upper, arg);
} }
} }
} }
@ -133,7 +139,7 @@ public final class EncodingHelper {
final int upper = toUpperCase(c); final int upper = toUpperCase(c);
if (upper != c) { if (upper != c) {
fun.apply(upper, c, arg); ApplyCaseFold.apply(upper, c, arg);
} }
} }
} }

View File

@ -21,7 +21,6 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isSingleline; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isSingleline;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite;
import jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode;
import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType;
import jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar; import jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar;
@ -53,9 +52,8 @@ class Lexer extends ScannerSupport {
if (!left()) { if (!left()) {
if (synAllow) { if (synAllow) {
return 1; /* "....{" : OK! */ return 1; /* "....{" : OK! */
} else {
throw new SyntaxException(ERR_END_PATTERN_AT_LEFT_BRACE);
} }
throw new SyntaxException(ERR_END_PATTERN_AT_LEFT_BRACE);
} }
if (!synAllow) { if (!synAllow) {
@ -83,7 +81,9 @@ class Lexer extends ScannerSupport {
} }
} }
if (!left()) return invalidRangeQuantifier(synAllow); if (!left()) {
return invalidRangeQuantifier(synAllow);
}
fetch(); fetch();
int up; int up;
@ -99,25 +99,35 @@ class Lexer extends ScannerSupport {
} }
if (p == prev) { if (p == prev) {
if (nonLow) return invalidRangeQuantifier(synAllow); if (nonLow) {
return invalidRangeQuantifier(synAllow);
}
up = QuantifierNode.REPEAT_INFINITE; /* {n,} : {n,infinite} */ up = QuantifierNode.REPEAT_INFINITE; /* {n,} : {n,infinite} */
} }
} else { } else {
if (nonLow) return invalidRangeQuantifier(synAllow); if (nonLow) {
return invalidRangeQuantifier(synAllow);
}
unfetch(); unfetch();
up = low; /* {n} : exact n times */ up = low; /* {n} : exact n times */
ret = 2; /* fixed */ ret = 2; /* fixed */
} }
if (!left()) return invalidRangeQuantifier(synAllow); if (!left()) {
return invalidRangeQuantifier(synAllow);
}
fetch(); fetch();
if (syntax.opEscBraceInterval()) { if (syntax.opEscBraceInterval()) {
if (c != syntax.metaCharTable.esc) return invalidRangeQuantifier(synAllow); if (c != syntax.metaCharTable.esc) {
return invalidRangeQuantifier(synAllow);
}
fetch(); fetch();
} }
if (c != '}') return invalidRangeQuantifier(synAllow); if (c != '}') {
return invalidRangeQuantifier(synAllow);
}
if (!isRepeatInfinite(up) && low > up) { if (!isRepeatInfinite(up) && low > up) {
throw new ValueException(ERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE); throw new ValueException(ERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE);
@ -134,9 +144,8 @@ class Lexer extends ScannerSupport {
if (synAllow) { if (synAllow) {
restore(); restore();
return 1; return 1;
} else {
throw new SyntaxException(ERR_INVALID_REPEAT_RANGE_PATTERN);
} }
throw new SyntaxException(ERR_INVALID_REPEAT_RANGE_PATTERN);
} }
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
@ -218,17 +227,6 @@ class Lexer extends ScannerSupport {
} }
} }
private int nameEndCodePoint(final int start) {
switch(start) {
case '<':
return '>';
case '\'':
return '\'';
default:
return 0;
}
}
private void fetchTokenInCCFor_charType(final boolean flag, final int type) { private void fetchTokenInCCFor_charType(final boolean flag, final int type) {
token.type = TokenType.CHAR_TYPE; token.type = TokenType.CHAR_TYPE;
token.setPropCType(type); token.setPropCType(type);
@ -236,7 +234,9 @@ class Lexer extends ScannerSupport {
} }
private void fetchTokenInCCFor_x() { private void fetchTokenInCCFor_x() {
if (!left()) return; if (!left()) {
return;
}
final int last = p; final int last = p;
if (peekIs('{') && syntax.opEscXBraceHex8()) { if (peekIs('{') && syntax.opEscXBraceHex8()) {
@ -274,7 +274,9 @@ class Lexer extends ScannerSupport {
} }
private void fetchTokenInCCFor_u() { private void fetchTokenInCCFor_u() {
if (!left()) return; if (!left()) {
return;
}
final int last = p; final int last = p;
if (syntax.op2EscUHex4()) { if (syntax.op2EscUHex4()) {
@ -329,7 +331,9 @@ class Lexer extends ScannerSupport {
} else if (c == '-') { } else if (c == '-') {
token.type = TokenType.CC_RANGE; token.type = TokenType.CC_RANGE;
} else if (c == syntax.metaCharTable.esc) { } else if (c == syntax.metaCharTable.esc) {
if (!syntax.backSlashEscapeInCC()) return token.type; if (!syntax.backSlashEscapeInCC()) {
return token.type;
}
if (!left()) { if (!left()) {
throw new SyntaxException(ERR_END_PATTERN_AT_ESCAPE); throw new SyntaxException(ERR_END_PATTERN_AT_ESCAPE);
} }
@ -357,10 +361,14 @@ class Lexer extends ScannerSupport {
fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE);
break; break;
case 'h': case 'h':
if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(false, CharacterType.XDIGIT); if (syntax.op2EscHXDigit()) {
fetchTokenInCCFor_charType(false, CharacterType.XDIGIT);
}
break; break;
case 'H': case 'H':
if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); if (syntax.op2EscHXDigit()) {
fetchTokenInCCFor_charType(true, CharacterType.XDIGIT);
}
break; break;
case 'x': case 'x':
fetchTokenInCCFor_x(); fetchTokenInCCFor_x();
@ -424,7 +432,9 @@ class Lexer extends ScannerSupport {
} }
private void fetchTokenFor_xBrace() { private void fetchTokenFor_xBrace() {
if (!left()) return; if (!left()) {
return;
}
final int last = p; final int last = p;
if (peekIs('{') && syntax.opEscXBraceHex8()) { if (peekIs('{') && syntax.opEscXBraceHex8()) {
@ -461,7 +471,9 @@ class Lexer extends ScannerSupport {
} }
private void fetchTokenFor_uHex() { private void fetchTokenFor_uHex() {
if (!left()) return; if (!left()) {
return;
}
final int last = p; final int last = p;
if (syntax.op2EscUHex4()) { if (syntax.op2EscUHex4()) {
@ -562,79 +574,129 @@ class Lexer extends ScannerSupport {
switch(c) { switch(c) {
case '*': case '*':
if (syntax.opEscAsteriskZeroInf()) fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE); if (syntax.opEscAsteriskZeroInf()) {
fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE);
}
break; break;
case '+': case '+':
if (syntax.opEscPlusOneInf()) fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE); if (syntax.opEscPlusOneInf()) {
fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE);
}
break; break;
case '?': case '?':
if (syntax.opEscQMarkZeroOne()) fetchTokenFor_repeat(0, 1); if (syntax.opEscQMarkZeroOne()) {
fetchTokenFor_repeat(0, 1);
}
break; break;
case '{': case '{':
if (syntax.opEscBraceInterval()) fetchTokenFor_openBrace(); if (syntax.opEscBraceInterval()) {
fetchTokenFor_openBrace();
}
break; break;
case '|': case '|':
if (syntax.opEscVBarAlt()) token.type = TokenType.ALT; if (syntax.opEscVBarAlt()) {
token.type = TokenType.ALT;
}
break; break;
case '(': case '(':
if (syntax.opEscLParenSubexp()) token.type = TokenType.SUBEXP_OPEN; if (syntax.opEscLParenSubexp()) {
token.type = TokenType.SUBEXP_OPEN;
}
break; break;
case ')': case ')':
if (syntax.opEscLParenSubexp()) token.type = TokenType.SUBEXP_CLOSE; if (syntax.opEscLParenSubexp()) {
token.type = TokenType.SUBEXP_CLOSE;
}
break; break;
case 'w': case 'w':
if (syntax.opEscWWord()) fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD); if (syntax.opEscWWord()) {
fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD);
}
break; break;
case 'W': case 'W':
if (syntax.opEscWWord()) fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD); if (syntax.opEscWWord()) {
fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD);
}
break; break;
case 'b': case 'b':
if (syntax.opEscBWordBound()) fetchTokenFor_anchor(AnchorType.WORD_BOUND); if (syntax.opEscBWordBound()) {
fetchTokenFor_anchor(AnchorType.WORD_BOUND);
}
break; break;
case 'B': case 'B':
if (syntax.opEscBWordBound()) fetchTokenFor_anchor(AnchorType.NOT_WORD_BOUND); if (syntax.opEscBWordBound()) {
fetchTokenFor_anchor(AnchorType.NOT_WORD_BOUND);
}
break; break;
case '<': case '<':
if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) fetchTokenFor_anchor(AnchorType.WORD_BEGIN); if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) {
fetchTokenFor_anchor(AnchorType.WORD_BEGIN);
}
break; break;
case '>': case '>':
if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) fetchTokenFor_anchor(AnchorType.WORD_END); if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) {
fetchTokenFor_anchor(AnchorType.WORD_END);
}
break; break;
case 's': case 's':
if (syntax.opEscSWhiteSpace()) fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); if (syntax.opEscSWhiteSpace()) {
fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE);
}
break; break;
case 'S': case 'S':
if (syntax.opEscSWhiteSpace()) fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); if (syntax.opEscSWhiteSpace()) {
fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE);
}
break; break;
case 'd': case 'd':
if (syntax.opEscDDigit()) fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT); if (syntax.opEscDDigit()) {
fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT);
}
break; break;
case 'D': case 'D':
if (syntax.opEscDDigit()) fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT); if (syntax.opEscDDigit()) {
fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT);
}
break; break;
case 'h': case 'h':
if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(false, CharacterType.XDIGIT); if (syntax.op2EscHXDigit()) {
fetchTokenInCCFor_charType(false, CharacterType.XDIGIT);
}
break; break;
case 'H': case 'H':
if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); if (syntax.op2EscHXDigit()) {
fetchTokenInCCFor_charType(true, CharacterType.XDIGIT);
}
break; break;
case 'A': case 'A':
if (syntax.opEscAZBufAnchor()) fetchTokenFor_anchor(AnchorType.BEGIN_BUF); if (syntax.opEscAZBufAnchor()) {
fetchTokenFor_anchor(AnchorType.BEGIN_BUF);
}
break; break;
case 'Z': case 'Z':
if (syntax.opEscAZBufAnchor()) fetchTokenFor_anchor(AnchorType.SEMI_END_BUF); if (syntax.opEscAZBufAnchor()) {
fetchTokenFor_anchor(AnchorType.SEMI_END_BUF);
}
break; break;
case 'z': case 'z':
if (syntax.opEscAZBufAnchor()) fetchTokenFor_anchor(AnchorType.END_BUF); if (syntax.opEscAZBufAnchor()) {
fetchTokenFor_anchor(AnchorType.END_BUF);
}
break; break;
case 'G': case 'G':
if (syntax.opEscCapitalGBeginAnchor()) fetchTokenFor_anchor(AnchorType.BEGIN_POSITION); if (syntax.opEscCapitalGBeginAnchor()) {
fetchTokenFor_anchor(AnchorType.BEGIN_POSITION);
}
break; break;
case '`': case '`':
if (syntax.op2EscGnuBufAnchor()) fetchTokenFor_anchor(AnchorType.BEGIN_BUF); if (syntax.op2EscGnuBufAnchor()) {
fetchTokenFor_anchor(AnchorType.BEGIN_BUF);
}
break; break;
case '\'': case '\'':
if (syntax.op2EscGnuBufAnchor()) fetchTokenFor_anchor(AnchorType.END_BUF); if (syntax.op2EscGnuBufAnchor()) {
fetchTokenFor_anchor(AnchorType.END_BUF);
}
break; break;
case 'x': case 'x':
fetchTokenFor_xBrace(); fetchTokenFor_xBrace();
@ -684,22 +746,34 @@ class Lexer extends ScannerSupport {
{ {
switch(c) { switch(c) {
case '.': case '.':
if (syntax.opDotAnyChar()) token.type = TokenType.ANYCHAR; if (syntax.opDotAnyChar()) {
token.type = TokenType.ANYCHAR;
}
break; break;
case '*': case '*':
if (syntax.opAsteriskZeroInf()) fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE); if (syntax.opAsteriskZeroInf()) {
fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE);
}
break; break;
case '+': case '+':
if (syntax.opPlusOneInf()) fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE); if (syntax.opPlusOneInf()) {
fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE);
}
break; break;
case '?': case '?':
if (syntax.opQMarkZeroOne()) fetchTokenFor_repeat(0, 1); if (syntax.opQMarkZeroOne()) {
fetchTokenFor_repeat(0, 1);
}
break; break;
case '{': case '{':
if (syntax.opBraceInterval()) fetchTokenFor_openBrace(); if (syntax.opBraceInterval()) {
fetchTokenFor_openBrace();
}
break; break;
case '|': case '|':
if (syntax.opVBarAlt()) token.type = TokenType.ALT; if (syntax.opVBarAlt()) {
token.type = TokenType.ALT;
}
break; break;
case '(': case '(':
@ -713,9 +787,13 @@ class Lexer extends ScannerSupport {
} }
fetch(); fetch();
if (c == syntax.metaCharTable.esc) { if (c == syntax.metaCharTable.esc) {
if (left()) fetch(); if (left()) {
fetch();
}
} else { } else {
if (c == ')') break; if (c == ')') {
break;
}
} }
} }
continue start; // goto start continue start; // goto start
@ -723,19 +801,29 @@ class Lexer extends ScannerSupport {
unfetch(); unfetch();
} }
if (syntax.opLParenSubexp()) token.type = TokenType.SUBEXP_OPEN; if (syntax.opLParenSubexp()) {
token.type = TokenType.SUBEXP_OPEN;
}
break; break;
case ')': case ')':
if (syntax.opLParenSubexp()) token.type = TokenType.SUBEXP_CLOSE; if (syntax.opLParenSubexp()) {
token.type = TokenType.SUBEXP_CLOSE;
}
break; break;
case '^': case '^':
if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.BEGIN_BUF : AnchorType.BEGIN_LINE); if (syntax.opLineAnchor()) {
fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.BEGIN_BUF : AnchorType.BEGIN_LINE);
}
break; break;
case '$': case '$':
if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.END_BUF : AnchorType.END_LINE); if (syntax.opLineAnchor()) {
fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.END_BUF : AnchorType.END_LINE);
}
break; break;
case '[': case '[':
if (syntax.opBracketCC()) token.type = TokenType.CC_CC_OPEN; if (syntax.opBracketCC()) {
token.type = TokenType.CC_CC_OPEN;
}
break; break;
case ']': case ']':
//if (*src > env->pattern) /* /].../ is allowed. */ //if (*src > env->pattern) /* /].../ is allowed. */
@ -745,7 +833,9 @@ class Lexer extends ScannerSupport {
if (Option.isExtend(env.option)) { if (Option.isExtend(env.option)) {
while (left()) { while (left()) {
fetch(); fetch();
if (EncodingHelper.isNewLine(c)) break; if (EncodingHelper.isNewLine(c)) {
break;
}
} }
continue start; // goto start continue start; // goto start
} }
@ -756,7 +846,10 @@ class Lexer extends ScannerSupport {
case '\n': case '\n':
case '\r': case '\r':
case '\f': case '\f':
if (Option.isExtend(env.option)) continue start; // goto start if (Option.isExtend(env.option))
{
continue start; // goto start
}
break; break;
default: // string default: // string
@ -798,8 +891,8 @@ class Lexer extends ScannerSupport {
} }
} }
protected final void syntaxWarn(final String message, final char c) { protected final void syntaxWarn(final String message, final char ch) {
syntaxWarn(message.replace("<%n>", Character.toString(c))); syntaxWarn(message.replace("<%n>", Character.toString(ch)));
} }
protected final void syntaxWarn(final String message) { protected final void syntaxWarn(final String message) {

View File

@ -21,10 +21,10 @@
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindLongest; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindLongest;
import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType;
import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder; import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
@SuppressWarnings("javadoc")
public abstract class Matcher extends IntHolder { public abstract class Matcher extends IntHolder {
protected final Regex regex; protected final Regex regex;
@ -73,7 +73,9 @@ public abstract class Matcher extends IntHolder {
protected final void msaInit(final int option, final int start) { protected final void msaInit(final int option, final int start) {
msaOptions = option; msaOptions = option;
msaStart = start; msaStart = start;
if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) msaBestLen = -1; if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) {
msaBestLen = -1;
}
} }
public final int match(final int at, final int range, final int option) { public final int match(final int at, final int range, final int option) {
@ -83,20 +85,19 @@ public abstract class Matcher extends IntHolder {
if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) { if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) {
return matchAt(end /*range*/, at, prev); return matchAt(end /*range*/, at, prev);
} else {
return matchAt(range /*range*/, at, prev);
} }
return matchAt(range /*range*/, at, prev);
} }
int low, high; // these are the return values int low, high; // these are the return values
private boolean forwardSearchRange(final char[] chars, final int str, final int end, final int s, final int range, final IntHolder lowPrev) { private boolean forwardSearchRange(final char[] ch, final int string, final int e, final int s, final int range, final IntHolder lowPrev) {
int pprev = -1; int pprev = -1;
int p = s; int p = s;
if (Config.DEBUG_SEARCH) { if (Config.DEBUG_SEARCH) {
Config.log.println("forward_search_range: "+ Config.log.println("forward_search_range: "+
"str: " + str + "str: " + string +
", end: " + end + ", end: " + e +
", s: " + s + ", s: " + s +
", range: " + range); ", range: " + range);
} }
@ -106,7 +107,7 @@ public abstract class Matcher extends IntHolder {
} }
retry:while (true) { retry:while (true) {
p = regex.searchAlgorithm.search(regex, chars, p, end, range); p = regex.searchAlgorithm.search(regex, ch, p, e, range);
if (p != -1 && p < range) { if (p != -1 && p < range) {
if (p - regex.dMin < s) { if (p - regex.dMin < s) {
@ -119,9 +120,9 @@ public abstract class Matcher extends IntHolder {
if (regex.subAnchor != 0) { if (regex.subAnchor != 0) {
switch (regex.subAnchor) { switch (regex.subAnchor) {
case AnchorType.BEGIN_LINE: case AnchorType.BEGIN_LINE:
if (p != str) { if (p != string) {
final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, p); final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, p);
if (!EncodingHelper.isNewLine(chars, prev, end)) { if (!EncodingHelper.isNewLine(ch, prev, e)) {
// goto retry_gate; // goto retry_gate;
pprev = p; pprev = p;
p++; p++;
@ -131,17 +132,17 @@ public abstract class Matcher extends IntHolder {
break; break;
case AnchorType.END_LINE: case AnchorType.END_LINE:
if (p == end) { if (p == e) {
if (!Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { if (!Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, p); final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, p);
if (prev != -1 && EncodingHelper.isNewLine(chars, prev, end)) { if (prev != -1 && EncodingHelper.isNewLine(ch, prev, e)) {
// goto retry_gate; // goto retry_gate;
pprev = p; pprev = p;
p++; p++;
continue retry; continue retry;
} }
} }
} else if (!EncodingHelper.isNewLine(chars, p, end)) { } else if (!EncodingHelper.isNewLine(ch, p, e)) {
//if () break; //if () break;
// goto retry_gate; // goto retry_gate;
pprev = p; pprev = p;
@ -149,6 +150,9 @@ public abstract class Matcher extends IntHolder {
continue retry; continue retry;
} }
break; break;
default:
break;
} // switch } // switch
} }
@ -158,7 +162,7 @@ public abstract class Matcher extends IntHolder {
if (low > s) { if (low > s) {
lowPrev.value = EncodingHelper.prevCharHead(s, p); lowPrev.value = EncodingHelper.prevCharHead(s, p);
} else { } else {
lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, p); lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, p);
} }
} }
} else { } else {
@ -172,7 +176,7 @@ public abstract class Matcher extends IntHolder {
} }
} else { } else {
if (lowPrev != null) { if (lowPrev != null) {
lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, low); lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, low);
} }
} }
} }
@ -182,8 +186,8 @@ public abstract class Matcher extends IntHolder {
if (Config.DEBUG_SEARCH) { if (Config.DEBUG_SEARCH) {
Config.log.println("forward_search_range success: "+ Config.log.println("forward_search_range success: "+
"low: " + (low - str) + "low: " + (low - string) +
", high: " + (high - str) + ", high: " + (high - string) +
", dmin: " + regex.dMin + ", dmin: " + regex.dMin +
", dmax: " + regex.dMax); ", dmax: " + regex.dMax);
} }
@ -196,20 +200,21 @@ public abstract class Matcher extends IntHolder {
} }
// low, high // low, high
private boolean backwardSearchRange(final char[] chars, final int str, final int end, final int s, int range, final int adjrange) { private boolean backwardSearchRange(final char[] ch, final int string, final int e, final int s, final int range, final int adjrange) {
range += regex.dMin; int r = range;
r += regex.dMin;
int p = s; int p = s;
retry:while (true) { retry:while (true) {
p = regex.searchAlgorithm.searchBackward(regex, chars, range, adjrange, end, p, s, range); p = regex.searchAlgorithm.searchBackward(regex, ch, r, adjrange, e, p, s, r);
if (p != -1) { if (p != -1) {
if (regex.subAnchor != 0) { if (regex.subAnchor != 0) {
switch (regex.subAnchor) { switch (regex.subAnchor) {
case AnchorType.BEGIN_LINE: case AnchorType.BEGIN_LINE:
if (p != str) { if (p != string) {
final int prev = EncodingHelper.prevCharHead(str, p); final int prev = EncodingHelper.prevCharHead(string, p);
if (!EncodingHelper.isNewLine(chars, prev, end)) { if (!EncodingHelper.isNewLine(ch, prev, e)) {
p = prev; p = prev;
continue retry; continue retry;
} }
@ -217,21 +222,28 @@ public abstract class Matcher extends IntHolder {
break; break;
case AnchorType.END_LINE: case AnchorType.END_LINE:
if (p == end) { if (p == e) {
if (!Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { if (!Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
final int prev = EncodingHelper.prevCharHead(adjrange, p); final int prev = EncodingHelper.prevCharHead(adjrange, p);
if (prev == -1) return false; if (prev == -1) {
if (EncodingHelper.isNewLine(chars, prev, end)) { return false;
}
if (EncodingHelper.isNewLine(ch, prev, e)) {
p = prev; p = prev;
continue retry; continue retry;
} }
} }
} else if (!EncodingHelper.isNewLine(chars, p, end)) { } else if (!EncodingHelper.isNewLine(ch, p, e)) {
p = EncodingHelper.prevCharHead(adjrange, p); p = EncodingHelper.prevCharHead(adjrange, p);
if (p == -1) return false; if (p == -1) {
return false;
}
continue retry; continue retry;
} }
break; break;
default:
break;
} // switch } // switch
} }
@ -243,14 +255,16 @@ public abstract class Matcher extends IntHolder {
if (Config.DEBUG_SEARCH) { if (Config.DEBUG_SEARCH) {
Config.log.println("backward_search_range: "+ Config.log.println("backward_search_range: "+
"low: " + (low - str) + "low: " + (low - string) +
", high: " + (high - str)); ", high: " + (high - string));
} }
return true; return true;
} }
if (Config.DEBUG_SEARCH) Config.log.println("backward_search_range: fail."); if (Config.DEBUG_SEARCH) {
Config.log.println("backward_search_range: fail.");
}
return false; return false;
} // while } // while
} }
@ -261,27 +275,36 @@ public abstract class Matcher extends IntHolder {
if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) { if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) {
//range = upperRange; //range = upperRange;
if (matchAt(upperRange, s, prev) != -1) { if (matchAt(upperRange, s, prev) != -1) {
if (!isFindLongest(regex.options)) return true; if (!isFindLongest(regex.options)) {
return true;
}
} }
} else { } else {
//range = upperRange; //range = upperRange;
if (matchAt(upperRange, s, prev) != -1) return true; if (matchAt(upperRange, s, prev) != -1) {
return true;
}
} }
} else { } else {
if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) { if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) {
if (matchAt(end, s, prev) != -1) { if (matchAt(end, s, prev) != -1) {
//range = upperRange; //range = upperRange;
if (!isFindLongest(regex.options)) return true; if (!isFindLongest(regex.options)) {
return true;
}
} }
} else { } else {
//range = upperRange; //range = upperRange;
if (matchAt(end, s, prev) != -1) return true; if (matchAt(end, s, prev) != -1) {
return true;
}
} }
} }
return false; return false;
} }
public final int search(int start, int range, final int option) { public final int search(final int startp, final int rangep, final int option) {
int start = startp, range = rangep;
int s, prev; int s, prev;
int origStart = start; int origStart = start;
final int origRange = range; final int origRange = range;
@ -294,7 +317,9 @@ public abstract class Matcher extends IntHolder {
", range " + (range - str)); ", range " + (range - str));
} }
if (start > end || start < str) return -1; if (start > end || start < str) {
return -1;
}
/* anchor optimize: resume search range */ /* anchor optimize: resume search range */
if (regex.anchor != 0 && str < end) { if (regex.anchor != 0 && str < end) {
@ -311,7 +336,10 @@ public abstract class Matcher extends IntHolder {
} else if ((regex.anchor & AnchorType.BEGIN_BUF) != 0) { } else if ((regex.anchor & AnchorType.BEGIN_BUF) != 0) {
/* search str-position only */ /* search str-position only */
if (range > start) { if (range > start) {
if (start != str) return -1; // mismatch_no_msa; if (start != str)
{
return -1; // mismatch_no_msa;
}
range = str + 1; range = str + 1;
} else { } else {
if (range <= str) { if (range <= str) {
@ -324,7 +352,10 @@ public abstract class Matcher extends IntHolder {
} else if ((regex.anchor & AnchorType.END_BUF) != 0) { } else if ((regex.anchor & AnchorType.END_BUF) != 0) {
minSemiEnd = maxSemiEnd = end; minSemiEnd = maxSemiEnd = end;
// !end_buf:! // !end_buf:!
if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa; if (endBuf(start, range, minSemiEnd, maxSemiEnd))
{
return -1; // mismatch_no_msa;
}
} else if ((regex.anchor & AnchorType.SEMI_END_BUF) != 0) { } else if ((regex.anchor & AnchorType.SEMI_END_BUF) != 0) {
final int preEnd = EncodingHelper.stepBack(str, end, 1); final int preEnd = EncodingHelper.stepBack(str, end, 1);
maxSemiEnd = end; maxSemiEnd = end;
@ -332,12 +363,18 @@ public abstract class Matcher extends IntHolder {
minSemiEnd = preEnd; minSemiEnd = preEnd;
if (minSemiEnd > str && start <= minSemiEnd) { if (minSemiEnd > str && start <= minSemiEnd) {
// !goto end_buf;! // !goto end_buf;!
if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa; if (endBuf(start, range, minSemiEnd, maxSemiEnd))
{
return -1; // mismatch_no_msa;
}
} }
} else { } else {
minSemiEnd = end; minSemiEnd = end;
// !goto end_buf;! // !goto end_buf;!
if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa; if (endBuf(start, range, minSemiEnd, maxSemiEnd))
{
return -1; // mismatch_no_msa;
}
} }
} else if ((regex.anchor & AnchorType.ANYCHAR_STAR_ML) != 0) { } else if ((regex.anchor & AnchorType.ANYCHAR_STAR_ML) != 0) {
// goto !begin_position;! // goto !begin_position;!
@ -359,7 +396,9 @@ public abstract class Matcher extends IntHolder {
prev = -1; prev = -1;
msaInit(option, start); msaInit(option, start);
if (matchCheck(end, s, prev)) return match(s); if (matchCheck(end, s, prev)) {
return match(s);
}
return mismatch(); return mismatch();
} }
return -1; // goto mismatch_no_msa; return -1; // goto mismatch_no_msa;
@ -389,49 +428,62 @@ public abstract class Matcher extends IntHolder {
schRange = end; schRange = end;
} else { } else {
schRange += regex.dMax; schRange += regex.dMax;
if (schRange > end) schRange = end; if (schRange > end) {
schRange = end;
}
} }
} }
if ((end - start) < regex.thresholdLength) return mismatch(); if ((end - start) < regex.thresholdLength) {
return mismatch();
}
if (regex.dMax != MinMaxLen.INFINITE_DISTANCE) { if (regex.dMax != MinMaxLen.INFINITE_DISTANCE) {
do { do {
if (!forwardSearchRange(chars, str, end, s, schRange, this)) return mismatch(); // low, high, lowPrev if (!forwardSearchRange(chars, str, end, s, schRange, this)) {
return mismatch(); // low, high, lowPrev
}
if (s < low) { if (s < low) {
s = low; s = low;
prev = value; prev = value;
} }
while (s <= high) { while (s <= high) {
if (matchCheck(origRange, s, prev)) return match(s); // ??? if (matchCheck(origRange, s, prev)) {
return match(s); // ???
}
prev = s; prev = s;
s++; s++;
} }
} while (s < range); } while (s < range);
}
/* check only. */
if (!forwardSearchRange(chars, str, end, s, schRange, null)) {
return mismatch(); return mismatch();
}
} else { /* check only. */ if ((regex.anchor & AnchorType.ANYCHAR_STAR) != 0) {
if (!forwardSearchRange(chars, str, end, s, schRange, null)) return mismatch(); do {
if (matchCheck(origRange, s, prev)) {
if ((regex.anchor & AnchorType.ANYCHAR_STAR) != 0) { return match(s);
do { }
if (matchCheck(origRange, s, prev)) return match(s); prev = s;
prev = s; s++;
s++; } while (s < range);
} while (s < range); return mismatch();
return mismatch();
}
} }
} }
do { do {
if (matchCheck(origRange, s, prev)) return match(s); if (matchCheck(origRange, s, prev)) {
return match(s);
}
prev = s; prev = s;
s++; s++;
} while (s < range); } while (s < range);
if (s == range) { /* because empty match with /$/. */ if (s == range) { /* because empty match with /$/. */
if (matchCheck(origRange, s, prev)) return match(s); if (matchCheck(origRange, s, prev)) {
return match(s);
}
} }
} else { /* backward search */ } else { /* backward search */
if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) { if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) {
@ -450,37 +502,51 @@ public abstract class Matcher extends IntHolder {
if (regex.dMax != MinMaxLen.INFINITE_DISTANCE && (end - range) >= regex.thresholdLength) { if (regex.dMax != MinMaxLen.INFINITE_DISTANCE && (end - range) >= regex.thresholdLength) {
do { do {
int schStart = s + regex.dMax; int schStart = s + regex.dMax;
if (schStart > end) schStart = end; if (schStart > end) {
if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) return mismatch(); // low, high schStart = end;
if (s > high) s = high; }
if (!backwardSearchRange(chars, str, end, schStart, range, adjrange))
{
return mismatch(); // low, high
}
if (s > high) {
s = high;
}
while (s != -1 && s >= low) { while (s != -1 && s >= low) {
prev = EncodingHelper.prevCharHead(str, s); prev = EncodingHelper.prevCharHead(str, s);
if (matchCheck(origStart, s, prev)) return match(s); if (matchCheck(origStart, s, prev)) {
return match(s);
}
s = prev; s = prev;
} }
} while (s >= range); } while (s >= range);
return mismatch(); return mismatch();
} else { /* check only. */ }
if ((end - range) < regex.thresholdLength) return mismatch(); if ((end - range) < regex.thresholdLength) {
return mismatch();
}
int schStart = s; int schStart = s;
if (regex.dMax != 0) { if (regex.dMax != 0) {
if (regex.dMax == MinMaxLen.INFINITE_DISTANCE) { if (regex.dMax == MinMaxLen.INFINITE_DISTANCE) {
schStart = end;
} else {
schStart += regex.dMax;
if (schStart > end) {
schStart = end; schStart = end;
} else {
schStart += regex.dMax;
if (schStart > end) {
schStart = end;
}
} }
} }
if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) return mismatch(); }
if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) {
return mismatch();
} }
} }
do { do {
prev = EncodingHelper.prevCharHead(str, s); prev = EncodingHelper.prevCharHead(str, s);
if (matchCheck(origStart, s, prev)) return match(s); if (matchCheck(origStart, s, prev)) {
return match(s);
}
s = prev; s = prev;
} while (s >= range); } while (s >= range);
@ -488,8 +554,13 @@ public abstract class Matcher extends IntHolder {
return mismatch(); return mismatch();
} }
private boolean endBuf(int start, int range, final int minSemiEnd, final int maxSemiEnd) { private boolean endBuf(final int startp, final int rangep, final int minSemiEnd, final int maxSemiEnd) {
if ((maxSemiEnd - str) < regex.anchorDmin) return true; // mismatch_no_msa; int start = startp;
int range = rangep;
if ((maxSemiEnd - str) < regex.anchorDmin) {
return true; // mismatch_no_msa;
}
if (range > start) { if (range > start) {
if ((minSemiEnd - start) > regex.anchorDmax) { if ((minSemiEnd - start) > regex.anchorDmax) {
@ -502,7 +573,10 @@ public abstract class Matcher extends IntHolder {
if ((maxSemiEnd - (range - 1)) < regex.anchorDmin) { if ((maxSemiEnd - (range - 1)) < regex.anchorDmin) {
range = maxSemiEnd - regex.anchorDmin + 1; range = maxSemiEnd - regex.anchorDmin + 1;
} }
if (start >= range) return true; // mismatch_no_msa; if (start >= range)
{
return true; // mismatch_no_msa;
}
} else { } else {
if ((minSemiEnd - range) > regex.anchorDmax) { if ((minSemiEnd - range) > regex.anchorDmax) {
range = minSemiEnd - regex.anchorDmax; range = minSemiEnd - regex.anchorDmax;
@ -510,7 +584,10 @@ public abstract class Matcher extends IntHolder {
if ((maxSemiEnd - start) < regex.anchorDmin) { if ((maxSemiEnd - start) < regex.anchorDmin) {
start = maxSemiEnd - regex.anchorDmin; start = maxSemiEnd - regex.anchorDmin;
} }
if (range > start) return true; // mismatch_no_msa; if (range > start)
{
return true; // mismatch_no_msa;
}
} }
return false; return false;
} }

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public abstract class MatcherFactory { public abstract class MatcherFactory {
public abstract Matcher create(Regex regex, char[] chars, int p, int end); public abstract Matcher create(Regex regex, char[] chars, int p, int end);

View File

@ -46,24 +46,40 @@ final class MinMaxLen {
}; };
int distanceValue() { int distanceValue() {
if (max == INFINITE_DISTANCE) return 0; if (max == INFINITE_DISTANCE) {
return 0;
}
final int d = max - min; final int d = max - min;
/* return dist_vals[d] * 16 / (mm->min + 12); */ /* return dist_vals[d] * 16 / (mm->min + 12); */
return d < distValues.length ? distValues[d] : 1; return d < distValues.length ? distValues[d] : 1;
} }
int compareDistanceValue(final MinMaxLen other, int v1, int v2) { int compareDistanceValue(final MinMaxLen other, final int v1p, final int v2p) {
if (v2 <= 0) return -1; int v1 = v1p, v2 = v2p;
if (v1 <= 0) return 1;
if (v2 <= 0) {
return -1;
}
if (v1 <= 0) {
return 1;
}
v1 *= distanceValue(); v1 *= distanceValue();
v2 *= other.distanceValue(); v2 *= other.distanceValue();
if (v2 > v1) return 1; if (v2 > v1) {
if (v2 < v1) return -1; return 1;
}
if (v2 < v1) {
return -1;
}
if (other.min < min) return 1; if (other.min < min) {
if (other.min > min) return -1; return 1;
}
if (other.min > min) {
return -1;
}
return 0; return 0;
} }
@ -96,27 +112,33 @@ final class MinMaxLen {
} }
void altMerge(final MinMaxLen other) { void altMerge(final MinMaxLen other) {
if (min > other.min) min = other.min; if (min > other.min) {
if (max < other.max) max = other.max; min = other.min;
}
if (max < other.max) {
max = other.max;
}
} }
static final int INFINITE_DISTANCE = 0x7FFFFFFF; static final int INFINITE_DISTANCE = 0x7FFFFFFF;
static int distanceAdd(final int d1, final int d2) { static int distanceAdd(final int d1, final int d2) {
if (d1 == INFINITE_DISTANCE || d2 == INFINITE_DISTANCE) { if (d1 == INFINITE_DISTANCE || d2 == INFINITE_DISTANCE) {
return INFINITE_DISTANCE; return INFINITE_DISTANCE;
} else {
if (d1 <= INFINITE_DISTANCE - d2) return d1 + d2;
else return INFINITE_DISTANCE;
} }
if (d1 <= INFINITE_DISTANCE - d2) {
return d1 + d2;
}
return INFINITE_DISTANCE;
} }
static int distanceMultiply(final int d, final int m) { static int distanceMultiply(final int d, final int m) {
if (m == 0) return 0; if (m == 0) {
return 0;
}
if (d < INFINITE_DISTANCE / m) { if (d < INFINITE_DISTANCE / m) {
return d * m; return d * m;
} else {
return INFINITE_DISTANCE;
} }
return INFINITE_DISTANCE;
} }
static String distanceRangeToString(final int a, final int b) { static String distanceRangeToString(final int a, final int b) {

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public final class NodeOptInfo { public final class NodeOptInfo {
final MinMaxLen length = new MinMaxLen(); final MinMaxLen length = new MinMaxLen();
final OptAnchorInfo anchor = new OptAnchorInfo(); final OptAnchorInfo anchor = new OptAnchorInfo();
@ -91,8 +92,12 @@ public final class NodeOptInfo {
if (other.length.max > 0) { if (other.length.max > 0) {
// TODO: make sure it is not an Oniguruma bug (casting unsigned int to int for arithmetic comparison) // TODO: make sure it is not an Oniguruma bug (casting unsigned int to int for arithmetic comparison)
int otherLengthMax = other.length.max; int otherLengthMax = other.length.max;
if (otherLengthMax == MinMaxLen.INFINITE_DISTANCE) otherLengthMax = -1; if (otherLengthMax == MinMaxLen.INFINITE_DISTANCE) {
if (expr.length > otherLengthMax) expr.length = otherLengthMax; otherLengthMax = -1;
}
if (expr.length > otherLengthMax) {
expr.length = otherLengthMax;
}
if (expr.mmd.max == 0) { if (expr.mmd.max == 0) {
exb.select(expr); exb.select(expr);
} else { } else {

View File

@ -36,14 +36,20 @@ final class OptAnchorInfo implements AnchorType {
void concat(final OptAnchorInfo left, final OptAnchorInfo right, final int leftLength, final int rightLength) { void concat(final OptAnchorInfo left, final OptAnchorInfo right, final int leftLength, final int rightLength) {
leftAnchor = left.leftAnchor; leftAnchor = left.leftAnchor;
if (leftLength == 0) leftAnchor |= right.leftAnchor; if (leftLength == 0) {
leftAnchor |= right.leftAnchor;
}
rightAnchor = right.rightAnchor; rightAnchor = right.rightAnchor;
if (rightLength == 0) rightAnchor |= left.rightAnchor; if (rightLength == 0) {
rightAnchor |= left.rightAnchor;
}
} }
boolean isSet(final int anchor) { boolean isSet(final int anchor) {
if ((leftAnchor & anchor) != 0) return true; if ((leftAnchor & anchor) != 0) {
return true;
}
return (rightAnchor & anchor) != 0; return (rightAnchor & anchor) != 0;
} }
@ -77,14 +83,30 @@ final class OptAnchorInfo implements AnchorType {
static String anchorToString(final int anchor) { static String anchorToString(final int anchor) {
final StringBuffer s = new StringBuffer("["); final StringBuffer s = new StringBuffer("[");
if ((anchor & AnchorType.BEGIN_BUF) !=0 ) s.append("begin-buf "); if ((anchor & AnchorType.BEGIN_BUF) !=0 ) {
if ((anchor & AnchorType.BEGIN_LINE) !=0 ) s.append("begin-line "); s.append("begin-buf ");
if ((anchor & AnchorType.BEGIN_POSITION) !=0 ) s.append("begin-pos "); }
if ((anchor & AnchorType.END_BUF) !=0 ) s.append("end-buf "); if ((anchor & AnchorType.BEGIN_LINE) !=0 ) {
if ((anchor & AnchorType.SEMI_END_BUF) !=0 ) s.append("semi-end-buf "); s.append("begin-line ");
if ((anchor & AnchorType.END_LINE) !=0 ) s.append("end-line "); }
if ((anchor & AnchorType.ANYCHAR_STAR) !=0 ) s.append("anychar-star "); if ((anchor & AnchorType.BEGIN_POSITION) !=0 ) {
if ((anchor & AnchorType.ANYCHAR_STAR_ML) !=0 ) s.append("anychar-star-pl "); s.append("begin-pos ");
}
if ((anchor & AnchorType.END_BUF) !=0 ) {
s.append("end-buf ");
}
if ((anchor & AnchorType.SEMI_END_BUF) !=0 ) {
s.append("semi-end-buf ");
}
if ((anchor & AnchorType.END_LINE) !=0 ) {
s.append("end-line ");
}
if ((anchor & AnchorType.ANYCHAR_STAR) !=0 ) {
s.append("anychar-star ");
}
if ((anchor & AnchorType.ANYCHAR_STAR_ML) !=0 ) {
s.append("anychar-star-pl ");
}
s.append("]"); s.append("]");
return s.toString(); return s.toString();

View File

@ -56,7 +56,9 @@ final class OptExactInfo {
void concat(final OptExactInfo other) { void concat(final OptExactInfo other) {
if (!ignoreCase && other.ignoreCase) { if (!ignoreCase && other.ignoreCase) {
if (length >= other.length) return; /* avoid */ if (length >= other.length) {
return; /* avoid */
}
ignoreCase = true; ignoreCase = true;
} }
@ -65,7 +67,9 @@ final class OptExactInfo {
int i; int i;
for (i = length; p < end;) { for (i = length; p < end;) {
if (i + 1 > OPT_EXACT_MAXLEN) break; if (i + 1 > OPT_EXACT_MAXLEN) {
break;
}
chars[i++] = other.chars[p++]; chars[i++] = other.chars[p++];
} }
@ -74,15 +78,20 @@ final class OptExactInfo {
final OptAnchorInfo tmp = new OptAnchorInfo(); final OptAnchorInfo tmp = new OptAnchorInfo();
tmp.concat(anchor, other.anchor, 1, 1); tmp.concat(anchor, other.anchor, 1, 1);
if (!other.reachEnd) tmp.rightAnchor = 0; if (!other.reachEnd) {
tmp.rightAnchor = 0;
}
anchor.copy(tmp); anchor.copy(tmp);
} }
// ?? raw is not used here // ?? raw is not used here
void concatStr(final char[] lchars, int p, final int end, final boolean raw) { void concatStr(final char[] lchars, final int pp, final int end, final boolean raw) {
int i; int i;
int p = pp;
for (i = length; p < end && i < OPT_EXACT_MAXLEN;) { for (i = length; p < end && i < OPT_EXACT_MAXLEN;) {
if (i + 1 > OPT_EXACT_MAXLEN) break; if (i + 1 > OPT_EXACT_MAXLEN) {
break;
}
chars[i++] = lchars[p++]; chars[i++] = lchars[p++];
} }
@ -102,17 +111,23 @@ final class OptExactInfo {
int i; int i;
for (i = 0; i < length && i < other.length; i++) { for (i = 0; i < length && i < other.length; i++) {
if (chars[i] != other.chars[i]) break; if (chars[i] != other.chars[i]) {
break;
}
} }
if (!other.reachEnd || i<other.length || i<length) reachEnd = false; if (!other.reachEnd || i<other.length || i<length) {
reachEnd = false;
}
length = i; length = i;
ignoreCase |= other.ignoreCase; ignoreCase |= other.ignoreCase;
anchor.altMerge(other.anchor); anchor.altMerge(other.anchor);
if (!reachEnd) anchor.rightAnchor = 0; if (!reachEnd) {
anchor.rightAnchor = 0;
}
} }
@ -130,20 +145,32 @@ final class OptExactInfo {
v2 = OptMapInfo.positionValue(chars[0] & 0xff); v2 = OptMapInfo.positionValue(chars[0] & 0xff);
v1 = OptMapInfo.positionValue(alt.chars[0] & 0xff); v1 = OptMapInfo.positionValue(alt.chars[0] & 0xff);
if (length > 1) v1 += 5; if (length > 1) {
if (alt.length > 1) v2 += 5; v1 += 5;
}
if (alt.length > 1) {
v2 += 5;
}
} }
if (!ignoreCase) v1 *= 2; if (!ignoreCase) {
if (!alt.ignoreCase) v2 *= 2; v1 *= 2;
}
if (!alt.ignoreCase) {
v2 *= 2;
}
if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) copy(alt); if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) {
copy(alt);
}
} }
// comp_opt_exact_or_map_info // comp_opt_exact_or_map_info
private static final int COMP_EM_BASE = 20; private static final int COMP_EM_BASE = 20;
int compare(final OptMapInfo m) { int compare(final OptMapInfo m) {
if (m.value <= 0) return -1; if (m.value <= 0) {
return -1;
}
final int ve = COMP_EM_BASE * length * (ignoreCase ? 1 : 2); final int ve = COMP_EM_BASE * length * (ignoreCase ? 1 : 2);
final int vm = COMP_EM_BASE * 5 * 2 / m.value; final int vm = COMP_EM_BASE * 5 * 2 / m.value;

View File

@ -31,7 +31,9 @@ final class OptMapInfo {
mmd.clear(); mmd.clear();
anchor.clear(); anchor.clear();
value = 0; value = 0;
for (int i=0; i<map.length; i++) map[i] = 0; for (int i=0; i<map.length; i++) {
map[i] = 0;
}
} }
void copy(final OptMapInfo other) { void copy(final OptMapInfo other) {
@ -50,11 +52,10 @@ final class OptMapInfo {
} }
} }
void addCharAmb(final char[] chars, final int p, final int end, int caseFoldFlag) { void addCharAmb(final char[] chars, final int p, final int end, final int caseFoldFlag) {
addChar(chars[p]); addChar(chars[p]);
caseFoldFlag &= ~Config.INTERNAL_ENC_CASE_FOLD_MULTI_CHAR; final char[]items = EncodingHelper.caseFoldCodesByString(caseFoldFlag & ~Config.INTERNAL_ENC_CASE_FOLD_MULTI_CHAR, chars[p]);
final char[]items = EncodingHelper.caseFoldCodesByString(caseFoldFlag, chars[p]);
for (int i=0; i<items.length; i++) { for (int i=0; i<items.length; i++) {
addChar(items[i]); addChar(items[i]);
@ -64,7 +65,9 @@ final class OptMapInfo {
// select_opt_map_info // select_opt_map_info
private static final int z = 1<<15; /* 32768: something big value */ private static final int z = 1<<15; /* 32768: something big value */
void select(final OptMapInfo alt) { void select(final OptMapInfo alt) {
if (alt.value == 0) return; if (alt.value == 0) {
return;
}
if (value == 0) { if (value == 0) {
copy(alt); copy(alt);
return; return;
@ -73,13 +76,17 @@ final class OptMapInfo {
final int v1 = z / value; final int v1 = z / value;
final int v2 = z /alt.value; final int v2 = z /alt.value;
if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) copy(alt); if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) {
copy(alt);
}
} }
// alt_merge_opt_map_info // alt_merge_opt_map_info
void altMerge(final OptMapInfo other) { void altMerge(final OptMapInfo other) {
/* if (! is_equal_mml(&to->mmd, &add->mmd)) return ; */ /* if (! is_equal_mml(&to->mmd, &add->mmd)) return ; */
if (value == 0) return; if (value == 0) {
return;
}
if (other.value == 0 || mmd.max < other.mmd.max) { if (other.value == 0 || mmd.max < other.mmd.max) {
clear(); clear();
return; return;
@ -89,8 +96,12 @@ final class OptMapInfo {
int val = 0; int val = 0;
for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) { for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) {
if (other.map[i] != 0) map[i] = 1; if (other.map[i] != 0) {
if (map[i] != 0) val += positionValue(i); map[i] = 1;
}
if (map[i] != 0) {
val += positionValue(i);
}
} }
value = val; value = val;
@ -112,9 +123,8 @@ final class OptMapInfo {
static int positionValue(final int i) { static int positionValue(final int i) {
if (i < ByteValTable.length) { if (i < ByteValTable.length) {
return ByteValTable[i]; return ByteValTable[i];
} else {
return 4; /* Take it easy. */
} }
return 4; /* Take it easy. */
} }
} }

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public class Option { public class Option {
/* options */ /* options */
@ -43,19 +44,43 @@ public class Option {
public static String toString(final int option) { public static String toString(final int option) {
String options = ""; String options = "";
if (isIgnoreCase(option)) options += "IGNORECASE "; if (isIgnoreCase(option)) {
if (isExtend(option)) options += "EXTEND "; options += "IGNORECASE ";
if (isMultiline(option)) options += "MULTILINE "; }
if (isSingleline(option)) options += "SINGLELINE "; if (isExtend(option)) {
if (isFindLongest(option)) options += "FIND_LONGEST "; options += "EXTEND ";
if (isFindNotEmpty(option)) options += "FIND_NOT_EMPTY "; }
if (isNegateSingleline(option)) options += "NEGATE_SINGLELINE "; if (isMultiline(option)) {
if (isDontCaptureGroup(option)) options += "DONT_CAPTURE_GROUP "; options += "MULTILINE ";
if (isCaptureGroup(option)) options += "CAPTURE_GROUP "; }
if (isSingleline(option)) {
options += "SINGLELINE ";
}
if (isFindLongest(option)) {
options += "FIND_LONGEST ";
}
if (isFindNotEmpty(option)) {
options += "FIND_NOT_EMPTY ";
}
if (isNegateSingleline(option)) {
options += "NEGATE_SINGLELINE ";
}
if (isDontCaptureGroup(option)) {
options += "DONT_CAPTURE_GROUP ";
}
if (isCaptureGroup(option)) {
options += "CAPTURE_GROUP ";
}
if (isNotBol(option)) options += "NOTBOL "; if (isNotBol(option)) {
if (isNotEol(option)) options += "NOTEOL "; options += "NOTBOL ";
if (isPosixRegion(option)) options += "POSIX_REGION "; }
if (isNotEol(option)) {
options += "NOTEOL ";
}
if (isPosixRegion(option)) {
options += "POSIX_REGION ";
}
return options; return options;
} }

View File

@ -22,7 +22,6 @@ package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnOff; 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.isDontCaptureGroup;
import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase;
import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; 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.AnyCharNode;
import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode;
@ -77,7 +76,9 @@ class Parser extends Lexer {
restore(); restore();
return true; return true;
} }
if (c == syntax.metaCharTable.esc) inEsc = true; if (c == syntax.metaCharTable.esc) {
inEsc = true;
}
} }
} }
@ -165,7 +166,9 @@ class Parser extends Lexer {
arg.vIsRaw = false; arg.vIsRaw = false;
fetchTokenInCC(); fetchTokenInCC();
fetched = true; fetched = true;
if (token.type == TokenType.CC_RANGE || andStart) env.ccEscWarn("-"); /* [--x] or [a&&-x] is warned. */ if (token.type == TokenType.CC_RANGE || andStart) {
env.ccEscWarn("-"); /* [--x] or [a&&-x] is warned. */
}
parseCharClassValEntry(cc, arg); // goto val_entry parseCharClassValEntry(cc, arg); // goto val_entry
break; break;
} else if (arg.state == CCSTATE.RANGE) { } else if (arg.state == CCSTATE.RANGE) {
@ -214,7 +217,9 @@ class Parser extends Lexer {
prevCC.and(cc); prevCC.and(cc);
} else { } else {
prevCC = cc; prevCC = cc;
if (workCC == null) workCC = new CClassNode(); if (workCC == null) {
workCC = new CClassNode();
}
cc = workCC; cc = workCC;
} }
cc.clear(); cc.clear();
@ -227,7 +232,9 @@ class Parser extends Lexer {
throw new InternalException(ERR_PARSER_BUG); throw new InternalException(ERR_PARSER_BUG);
} // switch } // switch
if (!fetched) fetchTokenInCC(); if (!fetched) {
fetchTokenInCC();
}
} // while } // while
@ -443,7 +450,10 @@ class Parser extends Lexer {
} }
private Node parseExp(final TokenType term) { private Node parseExp(final TokenType term) {
if (token.type == term) return StringNode.EMPTY; // goto end_of_token if (token.type == term)
{
return StringNode.EMPTY; // goto end_of_token
}
Node node = null; Node node = null;
boolean group = false; boolean group = false;
@ -474,9 +484,8 @@ class Parser extends Lexer {
} }
if (token.escaped) { if (token.escaped) {
return parseExpTkRawByte(group); // goto tk_raw_byte return parseExpTkRawByte(group); // goto tk_raw_byte
} else {
return parseExpTkByte(group); // goto tk_byte
} }
return parseExpTkByte(group); // goto tk_byte
case STRING: case STRING:
return parseExpTkByte(group); // tk_byte: return parseExpTkByte(group); // tk_byte:
@ -496,7 +505,9 @@ class Parser extends Lexer {
if (Config.NON_UNICODE_SDW) { if (Config.NON_UNICODE_SDW) {
final CClassNode cc = new CClassNode(); final CClassNode cc = new CClassNode();
cc.addCType(token.getPropCType(), false, env, this); cc.addCType(token.getPropCType(), false, env, this);
if (token.getPropNot()) cc.setNot(); if (token.getPropNot()) {
cc.setNot();
}
node = cc; node = cc;
} }
break; break;
@ -507,7 +518,9 @@ class Parser extends Lexer {
// #ifdef USE_SHARED_CCLASS_TABLE ... #endif // #ifdef USE_SHARED_CCLASS_TABLE ... #endif
final CClassNode ccn = new CClassNode(); final CClassNode ccn = new CClassNode();
ccn.addCType(token.getPropCType(), false, env, this); ccn.addCType(token.getPropCType(), false, env, this);
if (token.getPropNot()) ccn.setNot(); if (token.getPropNot()) {
ccn.setNot();
}
node = ccn; node = ccn;
break; break;
@ -555,9 +568,8 @@ class Parser extends Lexer {
if (syntax.contextIndepRepeatOps()) { if (syntax.contextIndepRepeatOps()) {
if (syntax.contextInvalidRepeatOps()) { if (syntax.contextInvalidRepeatOps()) {
throw new SyntaxException(ERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED); throw new SyntaxException(ERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
} else {
node = StringNode.EMPTY; // node_new_empty
} }
node = StringNode.EMPTY; // node_new_empty
} else { } else {
return parseExpTkByte(group); // goto tk_byte return parseExpTkByte(group); // goto tk_byte
} }
@ -578,7 +590,9 @@ class Parser extends Lexer {
final StringNode node = new StringNode(chars, token.backP, p); // tk_byte: final StringNode node = new StringNode(chars, token.backP, p); // tk_byte:
while (true) { while (true) {
fetchToken(); fetchToken();
if (token.type != TokenType.STRING) break; if (token.type != TokenType.STRING) {
break;
}
if (token.backP == node.end) { if (token.backP == node.end) {
node.end = p; // non escaped character, remain shared, just increase shared range node.end = p; // non escaped character, remain shared, just increase shared range
@ -605,7 +619,8 @@ class Parser extends Lexer {
return parseExpRepeat(node, group); return parseExpRepeat(node, group);
} }
private Node parseExpRepeat(Node target, final boolean group) { private Node parseExpRepeat(final Node targetp, final boolean group) {
Node target = targetp;
while (token.type == TokenType.OP_REPEAT || token.type == TokenType.INTERVAL) { // repeat: while (token.type == TokenType.OP_REPEAT || token.type == TokenType.INTERVAL) { // repeat:
if (target.isInvalidQuantifier()) { if (target.isInvalidQuantifier()) {
throw new SyntaxException(ERR_TARGET_OF_REPEAT_OPERATOR_INVALID); throw new SyntaxException(ERR_TARGET_OF_REPEAT_OPERATOR_INVALID);
@ -674,24 +689,25 @@ class Parser extends Lexer {
if (token.type == TokenType.EOT || token.type == term || token.type == TokenType.ALT) { if (token.type == TokenType.EOT || token.type == term || token.type == TokenType.ALT) {
return node; return node;
} else {
final ConsAltNode top = ConsAltNode.newListNode(node, null);
ConsAltNode t = top;
while (token.type != TokenType.EOT && token.type != term && token.type != TokenType.ALT) {
node = parseExp(term);
if (node.getType() == NodeType.LIST) {
t.setCdr((ConsAltNode)node);
while (((ConsAltNode)node).cdr != null ) node = ((ConsAltNode)node).cdr;
t = ((ConsAltNode)node);
} else {
t.setCdr(ConsAltNode.newListNode(node, null));
t = t.cdr;
}
}
return top;
} }
final ConsAltNode top = ConsAltNode.newListNode(node, null);
ConsAltNode t = top;
while (token.type != TokenType.EOT && token.type != term && token.type != TokenType.ALT) {
node = parseExp(term);
if (node.getType() == NodeType.LIST) {
t.setCdr((ConsAltNode)node);
while (((ConsAltNode)node).cdr != null ) {
node = ((ConsAltNode)node).cdr;
}
t = ((ConsAltNode)node);
} else {
t.setCdr(ConsAltNode.newListNode(node, null));
t = t.cdr;
}
}
return top;
} }
/* term_tok: TK_EOT or TK_SUBEXP_CLOSE */ /* term_tok: TK_EOT or TK_SUBEXP_CLOSE */
@ -711,7 +727,9 @@ class Parser extends Lexer {
t = t.cdr; t = t.cdr;
} }
if (token.type != term) parseSubExpError(term); if (token.type != term) {
parseSubExpError(term);
}
return top; return top;
} else { } else {
parseSubExpError(term); parseSubExpError(term);
@ -719,12 +737,11 @@ class Parser extends Lexer {
} }
} }
private void parseSubExpError(final TokenType term) { private static void parseSubExpError(final TokenType term) {
if (term == TokenType.SUBEXP_CLOSE) { if (term == TokenType.SUBEXP_CLOSE) {
throw new SyntaxException(ERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS); throw new SyntaxException(ERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS);
} else {
throw new InternalException(ERR_PARSER_BUG);
} }
throw new InternalException(ERR_PARSER_BUG);
} }
private Node parseRegexp() { private Node parseRegexp() {

View File

@ -24,6 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.RegexState;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;
@SuppressWarnings("javadoc")
public final class Regex implements RegexState { public final class Regex implements RegexState {
int[] code; /* compiled pattern */ int[] code; /* compiled pattern */
@ -107,7 +108,8 @@ public final class Regex implements RegexState {
} }
// onig_alloc_init // onig_alloc_init
public Regex(final char[] chars, final int p, final int end, int option, final int caseFoldFlag, final Syntax syntax, final WarnCallback warnings) { public Regex(final char[] chars, final int p, final int end, final int optionp, final int caseFoldFlag, final Syntax syntax, final WarnCallback warnings) {
int option = optionp;
if ((option & (Option.DONT_CAPTURE_GROUP | Option.CAPTURE_GROUP)) == if ((option & (Option.DONT_CAPTURE_GROUP | Option.CAPTURE_GROUP)) ==
(Option.DONT_CAPTURE_GROUP | Option.CAPTURE_GROUP)) { (Option.DONT_CAPTURE_GROUP | Option.CAPTURE_GROUP)) {
@ -169,19 +171,33 @@ public final class Regex implements RegexState {
if (len < Config.CHAR_TABLE_SIZE) { if (len < Config.CHAR_TABLE_SIZE) {
// map/skip // map/skip
if (map == null) map = new byte[Config.CHAR_TABLE_SIZE]; if (map == null) {
map = new byte[Config.CHAR_TABLE_SIZE];
}
for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) map[i] = (byte)len; for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) {
for (int i=0; i<len-1; i++) map[chars[p + i] & 0xff] = (byte)(len - 1 -i); // oxff ?? map[i] = (byte)len;
}
for (int i=0; i<len-1; i++)
{
map[chars[p + i] & 0xff] = (byte)(len - 1 -i); // oxff ??
}
} else { } else {
if (intMap == null) intMap = new int[Config.CHAR_TABLE_SIZE]; if (intMap == null) {
intMap = new int[Config.CHAR_TABLE_SIZE];
}
for (int i=0; i<len-1; i++) intMap[chars[p + i] & 0xff] = len - 1 - i; // oxff ?? for (int i=0; i<len-1; i++)
{
intMap[chars[p + i] & 0xff] = len - 1 - i; // oxff ??
}
} }
} }
void setExactInfo(final OptExactInfo e) { void setExactInfo(final OptExactInfo e) {
if (e.length == 0) return; if (e.length == 0) {
return;
}
// shall we copy that ? // shall we copy that ?
exact = e.chars; exact = e.chars;
@ -257,7 +273,11 @@ public final class Regex implements RegexState {
s.append("exact: [").append(exact, exactP, exactEnd - exactP).append("]: length: ").append(exactEnd - exactP).append("\n"); s.append("exact: [").append(exact, exactP, exactEnd - exactP).append("]: length: ").append(exactEnd - exactP).append("\n");
} else if (searchAlgorithm == SearchAlgorithm.MAP) { } else if (searchAlgorithm == SearchAlgorithm.MAP) {
int n=0; int n=0;
for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) if (map[i] != 0) n++; for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) {
if (map[i] != 0) {
n++;
}
}
s.append("map: n = ").append(n).append("\n"); s.append("map: n = ").append(n).append("\n");
if (n > 0) { if (n > 0) {

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public final class Region { public final class Region {
static final int REGION_NOTPOS = -1; static final int REGION_NOTPOS = -1;
@ -36,7 +37,9 @@ public final class Region {
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("Region: \n"); sb.append("Region: \n");
for (int i=0; i<beg.length; i++) sb.append(" " + i + ": (" + beg[i] + "-" + end[i] + ")"); for (int i=0; i<beg.length; i++) {
sb.append(" " + i + ": (" + beg[i] + "-" + end[i] + ")");
}
return sb.toString(); return sb.toString();
} }

View File

@ -20,11 +20,11 @@
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsClear; import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsClear;
import jdk.nashorn.internal.runtime.regexp.joni.ast.Node; 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.ErrorMessages;
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
@SuppressWarnings("javadoc")
public final class ScanEnvironment { public final class ScanEnvironment {
private static final int SCANENV_MEMNODES_SIZE = 8; private static final int SCANENV_MEMNODES_SIZE = 8;
@ -92,7 +92,10 @@ public final class ScanEnvironment {
case 'b': return '\010'; case 'b': return '\010';
case 'e': return '\033'; case 'e': return '\033';
case 'v': case 'v':
if (syntax.op2EscVVtab()) return 11; // ??? if (syntax.op2EscVVtab())
{
return 11; // ???
}
break; break;
default: default:
break; break;

View File

@ -60,7 +60,9 @@ abstract class ScannerSupport extends IntHolder implements ErrorMessages {
if (Character.isDigit(c)) { if (Character.isDigit(c)) {
final int onum = num; final int onum = num;
num = num * 10 + EncodingHelper.digitVal(c); num = num * 10 + EncodingHelper.digitVal(c);
if (((onum ^ num) & INT_SIGN_BIT) != 0) return -1; if (((onum ^ num) & INT_SIGN_BIT) != 0) {
return -1;
}
} else { } else {
unfetch(); unfetch();
break; break;
@ -70,16 +72,19 @@ abstract class ScannerSupport extends IntHolder implements ErrorMessages {
return num; return num;
} }
protected final int scanUnsignedHexadecimalNumber(int maxLength) { protected final int scanUnsignedHexadecimalNumber(final int maxLength) {
final int last = c; final int last = c;
int num = 0; int num = 0;
while(left() && maxLength-- != 0) { int ml = maxLength;
while(left() && ml-- != 0) {
fetch(); fetch();
if (EncodingHelper.isXDigit(c)) { if (EncodingHelper.isXDigit(c)) {
final int onum = num; final int onum = num;
final int val = EncodingHelper.xdigitVal(c); final int val = EncodingHelper.xdigitVal(c);
num = (num << 4) + val; num = (num << 4) + val;
if (((onum ^ num) & INT_SIGN_BIT) != 0) return -1; if (((onum ^ num) & INT_SIGN_BIT) != 0) {
return -1;
}
} else { } else {
unfetch(); unfetch();
break; break;
@ -89,16 +94,19 @@ abstract class ScannerSupport extends IntHolder implements ErrorMessages {
return num; return num;
} }
protected final int scanUnsignedOctalNumber(int maxLength) { protected final int scanUnsignedOctalNumber(final int maxLength) {
final int last = c; final int last = c;
int num = 0; int num = 0;
while(left() && maxLength-- != 0) { int ml = maxLength;
while(left() && ml-- != 0) {
fetch(); fetch();
if (Character.isDigit(c) && c < '8') { if (Character.isDigit(c) && c < '8') {
final int onum = num; final int onum = num;
final int val = EncodingHelper.odigitVal(c); final int val = EncodingHelper.odigitVal(c);
num = (num << 3) + val; num = (num << 3) + val;
if (((onum ^ num) & INT_SIGN_BIT) != 0) return -1; if (((onum ^ num) & INT_SIGN_BIT) != 0) {
return -1;
}
} else { } else {
unfetch(); unfetch();
break; break;
@ -144,8 +152,8 @@ abstract class ScannerSupport extends IntHolder implements ErrorMessages {
return p < stop ? chars[p] : 0; return p < stop ? chars[p] : 0;
} }
protected final boolean peekIs(final int c) { protected final boolean peekIs(final int ch) {
return peek() == c; return peek() == ch;
} }
protected final boolean left() { protected final boolean left() {

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public abstract class SearchAlgorithm { public abstract class SearchAlgorithm {
public abstract String getName(); public abstract String getName();
@ -62,7 +63,9 @@ public abstract class SearchAlgorithm {
int end = textEnd; int end = textEnd;
end -= targetEnd - targetP - 1; end -= targetEnd - targetP - 1;
if (end > textRange) end = textRange; if (end > textRange) {
end = textRange;
}
int s = textP; int s = textP;
@ -71,11 +74,15 @@ public abstract class SearchAlgorithm {
int p = s + 1; int p = s + 1;
int t = targetP + 1; int t = targetP + 1;
while (t < targetEnd) { while (t < targetEnd) {
if (target[t] != text[p++]) break; if (target[t] != text[p++]) {
break;
}
t++; t++;
} }
if (t == targetEnd) return s; if (t == targetEnd) {
return s;
}
} }
s++; s++;
} }
@ -101,10 +108,14 @@ public abstract class SearchAlgorithm {
int p = s + 1; int p = s + 1;
int t = targetP + 1; int t = targetP + 1;
while (t < targetEnd) { while (t < targetEnd) {
if (target[t] != text[p++]) break; if (target[t] != text[p++]) {
break;
}
t++; t++;
} }
if (t == targetEnd) return s; if (t == targetEnd) {
return s;
}
} }
// s = enc.prevCharHead or s = s <= adjustText ? -1 : s - 1; // s = enc.prevCharHead or s = s <= adjustText ? -1 : s - 1;
s--; s--;
@ -114,10 +125,8 @@ public abstract class SearchAlgorithm {
}; };
public static final class SLOW_IC extends SearchAlgorithm { public static final class SLOW_IC extends SearchAlgorithm {
private final int caseFoldFlag;
public SLOW_IC(final Regex regex) { public SLOW_IC(final Regex regex) {
this.caseFoldFlag = regex.caseFoldFlag; //empty
} }
@Override @Override
@ -134,11 +143,15 @@ public abstract class SearchAlgorithm {
int end = textEnd; int end = textEnd;
end -= targetEnd - targetP - 1; end -= targetEnd - targetP - 1;
if (end > textRange) end = textRange; if (end > textRange) {
end = textRange;
}
int s = textP; int s = textP;
while (s < end) { while (s < end) {
if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) return s; if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) {
return s;
}
s++; s++;
} }
return -1; return -1;
@ -158,17 +171,21 @@ public abstract class SearchAlgorithm {
} }
while (s >= textP) { while (s >= textP) {
if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) return s; if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) {
return s;
}
s = EncodingHelper.prevCharHead(adjustText, s); s = EncodingHelper.prevCharHead(adjustText, s);
} }
return -1; return -1;
} }
private boolean lowerCaseMatch(final char[] t, int tP, final int tEnd, private static boolean lowerCaseMatch(final char[] t, final int tPp, final int tEnd,
final char[] chars, int p, final int end) { final char[] chars, final int pp, final int end) {
while (tP < tEnd) { for (int tP = tPp, p = pp; tP < tEnd; ) {
if (t[tP++] != EncodingHelper.toLowerCase(chars[p++])) return false; if (t[tP++] != EncodingHelper.toLowerCase(chars[p++])) {
return false;
}
} }
return true; return true;
} }
@ -188,7 +205,9 @@ public abstract class SearchAlgorithm {
final int targetEnd = regex.exactEnd; final int targetEnd = regex.exactEnd;
int end = textRange + (targetEnd - targetP) - 1; int end = textRange + (targetEnd - targetP) - 1;
if (end > textEnd) end = textEnd; if (end > textEnd) {
end = textEnd;
}
final int tail = targetEnd - 1; final int tail = targetEnd - 1;
int s = textP + (targetEnd - targetP) - 1; int s = textP + (targetEnd - targetP) - 1;
@ -199,7 +218,9 @@ public abstract class SearchAlgorithm {
int t = tail; int t = tail;
while (text[p] == target[t]) { while (text[p] == target[t]) {
if (t == targetP) return p; if (t == targetP) {
return p;
}
p--; t--; p--; t--;
} }
@ -211,7 +232,9 @@ public abstract class SearchAlgorithm {
int t = tail; int t = tail;
while (text[p] == target[t]) { while (text[p] == target[t]) {
if (t == targetP) return p; if (t == targetP) {
return p;
}
p--; t--; p--; t--;
} }
@ -249,7 +272,9 @@ public abstract class SearchAlgorithm {
while (t < targetEnd && text[p] == target[t]) { while (t < targetEnd && text[p] == target[t]) {
p++; t++; p++; t++;
} }
if (t == targetEnd) return s; if (t == targetEnd) {
return s;
}
s -= regex.intMapBackward[text[s] & 0xff]; s -= regex.intMapBackward[text[s] & 0xff];
} }
@ -268,8 +293,12 @@ public abstract class SearchAlgorithm {
final int len = end - p; final int len = end - p;
for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) skip[i] = len; for (int i=0; i<Config.CHAR_TABLE_SIZE; i++) {
for (int i=len-1; i>0; i--) skip[chars[i] & 0xff] = i; skip[i] = len;
}
for (int i=len-1; i>0; i--) {
skip[chars[i] & 0xff] = i;
}
} }
}; };
@ -286,7 +315,9 @@ public abstract class SearchAlgorithm {
int s = textP; int s = textP;
while (s < textRange) { while (s < textRange) {
if (text[s] > 0xff || map[text[s]] != 0) return s; if (text[s] > 0xff || map[text[s]] != 0) {
return s;
}
s++; s++;
} }
return -1; return -1;
@ -297,9 +328,13 @@ public abstract class SearchAlgorithm {
final byte[] map = regex.map; final byte[] map = regex.map;
int s = textStart; int s = textStart;
if (s >= textEnd) s = textEnd - 1; if (s >= textEnd) {
s = textEnd - 1;
}
while (s >= textP) { while (s >= textP) {
if (text[s] > 0xff || map[text[s]] != 0) return s; if (text[s] > 0xff || map[text[s]] != 0) {
return s;
}
s--; s--;
} }
return -1; return -1;

View File

@ -20,7 +20,6 @@
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt; import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel; import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel;
import jdk.nashorn.internal.runtime.regexp.joni.constants.StackType; import jdk.nashorn.internal.runtime.regexp.joni.constants.StackType;
@ -61,12 +60,14 @@ abstract class StackMachine extends Matcher implements StackType {
static final ThreadLocal<WeakReference<StackEntry[]>> stacks static final ThreadLocal<WeakReference<StackEntry[]>> stacks
= new ThreadLocal<WeakReference<StackEntry[]>>() { = new ThreadLocal<WeakReference<StackEntry[]>>() {
@SuppressWarnings("unused")
@Override @Override
protected WeakReference<StackEntry[]> initialValue() { protected WeakReference<StackEntry[]> initialValue() {
return new WeakReference<StackEntry[]>(allocateStack()); return new WeakReference<StackEntry[]>(allocateStack());
} }
}; };
@SuppressWarnings("unused")
private static StackEntry[] fetchStack() { private static StackEntry[] fetchStack() {
WeakReference<StackEntry[]> ref = stacks.get(); WeakReference<StackEntry[]> ref = stacks.get();
StackEntry[] stack = ref.get(); StackEntry[] stack = ref.get();
@ -78,7 +79,9 @@ abstract class StackMachine extends Matcher implements StackType {
} }
protected final void init() { protected final void init() {
if (stack != null) pushEnsured(ALT, regex.codeLength - 1); /* bottom stack */ if (stack != null) {
pushEnsured(ALT, regex.codeLength - 1); /* bottom stack */
}
if (repeatStk != null) { if (repeatStk != null) {
for (int i=1; i<=regex.numMem; i++) { for (int i=1; i<=regex.numMem; i++) {
repeatStk[i + memStartStk] = repeatStk[i + memEndStk] = INVALID_INDEX; repeatStk[i + memStartStk] = repeatStk[i + memEndStk] = INVALID_INDEX;
@ -87,9 +90,13 @@ abstract class StackMachine extends Matcher implements StackType {
} }
protected final StackEntry ensure1() { protected final StackEntry ensure1() {
if (stk >= stack.length) doubleStack(); if (stk >= stack.length) {
doubleStack();
}
StackEntry e = stack[stk]; StackEntry e = stack[stk];
if (e == null) stack[stk] = e = new StackEntry(); if (e == null) {
stack[stk] = e = new StackEntry();
}
return e; return e;
} }
@ -190,7 +197,9 @@ abstract class StackMachine extends Matcher implements StackType {
if ((e.type & MASK_MEM_END_OR_MARK) != 0 && e.getMemNum() == mnum) { if ((e.type & MASK_MEM_END_OR_MARK) != 0 && e.getMemNum() == mnum) {
level++; level++;
} else if (e.type == MEM_START && e.getMemNum() == mnum) { } else if (e.type == MEM_START && e.getMemNum() == mnum) {
if (level == 0) break; if (level == 0) {
break;
}
level--; level--;
} }
} }
@ -371,9 +380,8 @@ abstract class StackMachine extends Matcher implements StackType {
if (e.getNullCheckNum() == id) { if (e.getNullCheckNum() == id) {
if (level == 0) { if (level == 0) {
return e.getNullCheckPStr() == s ? 1 : 0; return e.getNullCheckPStr() == s ? 1 : 0;
} else {
level--;
} }
level--;
} }
} else if (e.type == NULL_CHECK_END) { } else if (e.type == NULL_CHECK_END) {
level++; level++;
@ -393,7 +401,52 @@ abstract class StackMachine extends Matcher implements StackType {
if (e.getNullCheckPStr() != s) { if (e.getNullCheckPStr() != s) {
isNull = 0; isNull = 0;
break; break;
} else { }
int endp;
isNull = 1;
while (k < stk) {
if (e.type == MEM_START) {
if (e.getMemEnd() == INVALID_INDEX) {
isNull = 0;
break;
}
if (bsAt(regex.btMemEnd, e.getMemNum())) {
endp = stack[e.getMemEnd()].getMemPStr();
} else {
endp = e.getMemEnd();
}
if (stack[e.getMemStart()].getMemPStr() != endp) {
isNull = 0;
break;
} else if (endp != s) {
isNull = -1; /* empty, but position changed */
}
}
k++;
e = stack[k]; // !!
}
break;
}
}
}
return isNull;
}
protected final int nullCheckMemStRec(final int id, final int s) {
int level = 0;
int k = stk;
int isNull;
while (true) {
k--;
StackEntry e = stack[k];
if (e.type == NULL_CHECK_START) {
if (e.getNullCheckNum() == id) {
if (level == 0) {
if (e.getNullCheckPStr() != s) {
isNull = 0;
break;
}
int endp; int endp;
isNull = 1; isNull = 1;
while (k < stk) { while (k < stk) {
@ -415,62 +468,16 @@ abstract class StackMachine extends Matcher implements StackType {
} }
} }
k++; k++;
e = stack[k]; // !! e = stack[k];
} }
break; break;
} }
} level--;
}
}
return isNull;
}
protected final int nullCheckMemStRec(final int id, final int s) {
int level = 0;
int k = stk;
int isNull;
while (true) {
k--;
StackEntry e = stack[k];
if (e.type == NULL_CHECK_START) {
if (e.getNullCheckNum() == id) {
if (level == 0) {
if (e.getNullCheckPStr() != s) {
isNull = 0;
break;
} else {
int endp;
isNull = 1;
while (k < stk) {
if (e.type == MEM_START) {
if (e.getMemEnd() == INVALID_INDEX) {
isNull = 0;
break;
}
if (bsAt(regex.btMemEnd, e.getMemNum())) {
endp = stack[e.getMemEnd()].getMemPStr();
} else {
endp = e.getMemEnd();
}
if (stack[e.getMemStart()].getMemPStr() != endp) {
isNull = 0;
break;
} else if (endp != s) {
isNull = -1; /* empty, but position changed */
}
}
k++;
e = stack[k];
}
break;
}
} else {
level--;
}
} }
} else if (e.type == NULL_CHECK_END) { } else if (e.type == NULL_CHECK_END) {
if (e.getNullCheckNum() == id) level++; if (e.getNullCheckNum() == id) {
level++;
}
} }
} }
return isNull; return isNull;
@ -485,7 +492,9 @@ abstract class StackMachine extends Matcher implements StackType {
if (e.type == REPEAT) { if (e.type == REPEAT) {
if (level == 0) { if (level == 0) {
if (e.getRepeatNum() == id) return k; if (e.getRepeatNum() == id) {
return k;
}
} }
} else if (e.type == CALL_FRAME) { } else if (e.type == CALL_FRAME) {
level--; level--;
@ -505,9 +514,8 @@ abstract class StackMachine extends Matcher implements StackType {
if (e.type == CALL_FRAME) { if (e.type == CALL_FRAME) {
if (level == 0) { if (level == 0) {
return e.getCallFrameRetAddr(); return e.getCallFrameRetAddr();
} else {
level--;
} }
level--;
} else if (e.type == RETURN) { } else if (e.type == RETURN) {
level++; level++;
} }

View File

@ -20,10 +20,10 @@
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
import static jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar.INEFFECTIVE_META_CHAR; import static jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar.INEFFECTIVE_META_CHAR;
import jdk.nashorn.internal.runtime.regexp.joni.constants.SyntaxProperties; import jdk.nashorn.internal.runtime.regexp.joni.constants.SyntaxProperties;
public final class Syntax implements SyntaxProperties{ @SuppressWarnings("javadoc")
public final class Syntax implements SyntaxProperties {
private final int op; private final int op;
private final int op2; private final int op2;
private final int behavior; private final int behavior;

View File

@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni;
/** /**
* @author <a href="mailto:ola.bini@gmail.com">Ola Bini</a> * @author <a href="mailto:ola.bini@gmail.com">Ola Bini</a>
*/ */
@SuppressWarnings("javadoc")
public interface WarnCallback { public interface WarnCallback {
WarnCallback DEFAULT = new WarnCallback() { WarnCallback DEFAULT = new WarnCallback() {
@Override @Override

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni; package jdk.nashorn.internal.runtime.regexp.joni;
@SuppressWarnings("javadoc")
public interface Warnings { public interface Warnings {
final String INVALID_BACKREFERENCE = "invalid back reference"; final String INVALID_BACKREFERENCE = "invalid back reference";
final String INVALID_SUBEXP_CALL = "invalid subexp call"; final String INVALID_SUBEXP_CALL = "invalid subexp call";

View File

@ -21,6 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType;
@SuppressWarnings("javadoc")
public final class AnchorNode extends Node implements AnchorType { public final class AnchorNode extends Node implements AnchorType {
public int type; public int type;
public Node target; public Node target;
@ -65,28 +66,60 @@ public final class AnchorNode extends Node implements AnchorType {
} }
public String typeToString() { public String typeToString() {
final StringBuilder type = new StringBuilder(); final StringBuilder sb = new StringBuilder();
if (isType(BEGIN_BUF)) type.append("BEGIN_BUF "); if (isType(BEGIN_BUF)) {
if (isType(BEGIN_LINE)) type.append("BEGIN_LINE "); sb.append("BEGIN_BUF ");
if (isType(BEGIN_POSITION)) type.append("BEGIN_POSITION "); }
if (isType(END_BUF)) type.append("END_BUF "); if (isType(BEGIN_LINE)) {
if (isType(SEMI_END_BUF)) type.append("SEMI_END_BUF "); sb.append("BEGIN_LINE ");
if (isType(END_LINE)) type.append("END_LINE "); }
if (isType(WORD_BOUND)) type.append("WORD_BOUND "); if (isType(BEGIN_POSITION)) {
if (isType(NOT_WORD_BOUND)) type.append("NOT_WORD_BOUND "); sb.append("BEGIN_POSITION ");
if (isType(WORD_BEGIN)) type.append("WORD_BEGIN "); }
if (isType(WORD_END)) type.append("WORD_END "); if (isType(END_BUF)) {
if (isType(PREC_READ)) type.append("PREC_READ "); sb.append("END_BUF ");
if (isType(PREC_READ_NOT)) type.append("PREC_READ_NOT "); }
if (isType(LOOK_BEHIND)) type.append("LOOK_BEHIND "); if (isType(SEMI_END_BUF)) {
if (isType(LOOK_BEHIND_NOT)) type.append("LOOK_BEHIND_NOT "); sb.append("SEMI_END_BUF ");
if (isType(ANYCHAR_STAR)) type.append("ANYCHAR_STAR "); }
if (isType(ANYCHAR_STAR_ML)) type.append("ANYCHAR_STAR_ML "); if (isType(END_LINE)) {
return type.toString(); sb.append("END_LINE ");
}
if (isType(WORD_BOUND)) {
sb.append("WORD_BOUND ");
}
if (isType(NOT_WORD_BOUND)) {
sb.append("NOT_WORD_BOUND ");
}
if (isType(WORD_BEGIN)) {
sb.append("WORD_BEGIN ");
}
if (isType(WORD_END)) {
sb.append("WORD_END ");
}
if (isType(PREC_READ)) {
sb.append("PREC_READ ");
}
if (isType(PREC_READ_NOT)) {
sb.append("PREC_READ_NOT ");
}
if (isType(LOOK_BEHIND)) {
sb.append("LOOK_BEHIND ");
}
if (isType(LOOK_BEHIND_NOT)) {
sb.append("LOOK_BEHIND_NOT ");
}
if (isType(ANYCHAR_STAR)) {
sb.append("ANYCHAR_STAR ");
}
if (isType(ANYCHAR_STAR_ML)) {
sb.append("ANYCHAR_STAR_ML ");
}
return sb.toString();
} }
private boolean isType(final int type) { private boolean isType(final int t) {
return (this.type & type) != 0; return (this.type & t) != 0;
} }
} }

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.ast; package jdk.nashorn.internal.runtime.regexp.joni.ast;
@SuppressWarnings("javadoc")
public final class AnyCharNode extends Node { public final class AnyCharNode extends Node {
public AnyCharNode(){} public AnyCharNode(){}

View File

@ -21,6 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment; import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment;
@SuppressWarnings("javadoc")
public final class BackRefNode extends StateNode { public final class BackRefNode extends StateNode {
public final int backRef; public final int backRef;

View File

@ -34,6 +34,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
import jdk.nashorn.internal.runtime.regexp.joni.exception.SyntaxException; import jdk.nashorn.internal.runtime.regexp.joni.exception.SyntaxException;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;
@SuppressWarnings("javadoc")
public final class CClassNode extends Node { public final class CClassNode extends Node {
private static final int FLAG_NCCLASS_NOT = 1<<0; private static final int FLAG_NCCLASS_NOT = 1<<0;
private static final int FLAG_NCCLASS_SHARE = 1<<1; private static final int FLAG_NCCLASS_SHARE = 1<<1;
@ -100,7 +101,9 @@ public final class CClassNode extends Node {
@Override @Override
public boolean equals(final Object other) { public boolean equals(final Object other) {
if (!(other instanceof CClassNode)) return false; if (!(other instanceof CClassNode)) {
return false;
}
final CClassNode cc = (CClassNode)other; final CClassNode cc = (CClassNode)other;
return ctype == cc.ctype && isNot() == cc.isNot(); return ctype == cc.ctype && isNot() == cc.isNot();
} }
@ -110,11 +113,12 @@ public final class CClassNode extends Node {
if (Config.USE_SHARED_CCLASS_TABLE) { if (Config.USE_SHARED_CCLASS_TABLE) {
int hash = 0; int hash = 0;
hash += ctype; hash += ctype;
if (isNot()) hash++; if (isNot()) {
hash++;
}
return hash + (hash >> 5); return hash + (hash >> 5);
} else {
return super.hashCode();
} }
return super.hashCode();
} }
@Override @Override
@ -128,10 +132,14 @@ public final class CClassNode extends Node {
} }
public String flagsToString() { public String flagsToString() {
final StringBuilder flags = new StringBuilder(); final StringBuilder f = new StringBuilder();
if (isNot()) flags.append("NOT "); if (isNot()) {
if (isShare()) flags.append("SHARE "); f.append("NOT ");
return flags.toString(); }
if (isShare()) {
f.append("SHARE ");
}
return f.toString();
} }
public boolean isEmpty() { public boolean isEmpty() {
@ -251,7 +259,7 @@ public final class CClassNode extends Node {
} }
// add_ctype_to_cc_by_range // Encoding out! // add_ctype_to_cc_by_range // Encoding out!
public void addCTypeByRange(final int ctype, final boolean not, final int sbOut, final int mbr[]) { public void addCTypeByRange(final int ct, final boolean not, final int sbOut, final int mbr[]) {
final int n = mbr[0]; final int n = mbr[0];
if (!not) { if (!not) {
@ -294,10 +302,14 @@ public final class CClassNode extends Node {
// !goto sb_end2!, remove duplication // !goto sb_end2!, remove duplication
prev = sbOut; prev = sbOut;
for (i=0; i<n; i++) { for (i=0; i<n; i++) {
if (prev < mbr[2 * i + 1]) addCodeRangeToBuf(prev, mbr[i * 2 + 1] - 1); if (prev < mbr[2 * i + 1]) {
addCodeRangeToBuf(prev, mbr[i * 2 + 1] - 1);
}
prev = mbr[i * 2 + 2] + 1; prev = mbr[i * 2 + 2] + 1;
} }
if (prev < 0x7fffffff/*!!!*/) addCodeRangeToBuf(prev, 0x7fffffff); if (prev < 0x7fffffff/*!!!*/) {
addCodeRangeToBuf(prev, 0x7fffffff);
}
return; return;
} }
bs.set(j); bs.set(j);
@ -312,22 +324,27 @@ public final class CClassNode extends Node {
// !sb_end2:! // !sb_end2:!
prev = sbOut; prev = sbOut;
for (int i=0; i<n; i++) { for (int i=0; i<n; i++) {
if (prev < mbr[2 * i + 1]) addCodeRangeToBuf(prev, mbr[i * 2 + 1] - 1); if (prev < mbr[2 * i + 1]) {
addCodeRangeToBuf(prev, mbr[i * 2 + 1] - 1);
}
prev = mbr[i * 2 + 2] + 1; prev = mbr[i * 2 + 2] + 1;
} }
if (prev < 0x7fffffff/*!!!*/) addCodeRangeToBuf(prev, 0x7fffffff); if (prev < 0x7fffffff/*!!!*/) {
addCodeRangeToBuf(prev, 0x7fffffff);
}
} }
} }
public void addCType(int ctype, final boolean not, final ScanEnvironment env, final IntHolder sbOut) { public void addCType(final int ctp, final boolean not, final ScanEnvironment env, final IntHolder sbOut) {
int ct = ctp;
if (Config.NON_UNICODE_SDW) { if (Config.NON_UNICODE_SDW) {
switch(ctype) { switch (ct) {
case CharacterType.D: case CharacterType.D:
case CharacterType.S: case CharacterType.S:
case CharacterType.W: case CharacterType.W:
ctype ^= CharacterType.SPECIAL_MASK; ct ^= CharacterType.SPECIAL_MASK;
if (env.syntax == Syntax.JAVASCRIPT && ctype == CharacterType.SPACE) { if (env.syntax == Syntax.JAVASCRIPT && ct == CharacterType.SPACE) {
// \s in JavaScript includes unicode characters. // \s in JavaScript includes unicode characters.
break; break;
} }
@ -335,26 +352,32 @@ public final class CClassNode extends Node {
if (not) { if (not) {
for (int c = 0; c < BitSet.SINGLE_BYTE_SIZE; c++) { for (int c = 0; c < BitSet.SINGLE_BYTE_SIZE; c++) {
// if (!ASCIIEncoding.INSTANCE.isCodeCType(c, ctype)) bs.set(c); // if (!ASCIIEncoding.INSTANCE.isCodeCType(c, ctype)) bs.set(c);
if ((AsciiCtypeTable[c] & (1 << ctype)) == 0) bs.set(c); if ((AsciiCtypeTable[c] & (1 << ct)) == 0) {
bs.set(c);
}
} }
addAllMultiByteRange(); addAllMultiByteRange();
} else { } else {
for (int c = 0; c < BitSet.SINGLE_BYTE_SIZE; c++) { for (int c = 0; c < BitSet.SINGLE_BYTE_SIZE; c++) {
// if (ASCIIEncoding.INSTANCE.isCodeCType(c, ctype)) bs.set(c); // if (ASCIIEncoding.INSTANCE.isCodeCType(c, ctype)) bs.set(c);
if ((AsciiCtypeTable[c] & (1 << ctype)) != 0) bs.set(c); if ((AsciiCtypeTable[c] & (1 << ct)) != 0) {
bs.set(c);
}
} }
} }
return; return;
default:
break;
} }
} }
final int[] ranges = EncodingHelper.ctypeCodeRange(ctype, sbOut); final int[] ranges = EncodingHelper.ctypeCodeRange(ct, sbOut);
if (ranges != null) { if (ranges != null) {
addCTypeByRange(ctype, not, sbOut.value, ranges); addCTypeByRange(ct, not, sbOut.value, ranges);
return; return;
} }
switch(ctype) { switch(ct) {
case CharacterType.ALPHA: case CharacterType.ALPHA:
case CharacterType.BLANK: case CharacterType.BLANK:
case CharacterType.CNTRL: case CharacterType.CNTRL:
@ -368,12 +391,16 @@ public final class CClassNode extends Node {
case CharacterType.ALNUM: case CharacterType.ALNUM:
if (not) { if (not) {
for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) { for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) {
if (!EncodingHelper.isCodeCType(c, ctype)) bs.set(c); if (!EncodingHelper.isCodeCType(c, ct)) {
bs.set(c);
}
} }
addAllMultiByteRange(); addAllMultiByteRange();
} else { } else {
for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) { for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) {
if (EncodingHelper.isCodeCType(c, ctype)) bs.set(c); if (EncodingHelper.isCodeCType(c, ct)) {
bs.set(c);
}
} }
} }
break; break;
@ -382,11 +409,15 @@ public final class CClassNode extends Node {
case CharacterType.PRINT: case CharacterType.PRINT:
if (not) { if (not) {
for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) { for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) {
if (!EncodingHelper.isCodeCType(c, ctype)) bs.set(c); if (!EncodingHelper.isCodeCType(c, ct)) {
bs.set(c);
}
} }
} else { } else {
for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) { for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) {
if (EncodingHelper.isCodeCType(c, ctype)) bs.set(c); if (EncodingHelper.isCodeCType(c, ct)) {
bs.set(c);
}
} }
addAllMultiByteRange(); addAllMultiByteRange();
} }
@ -395,13 +426,17 @@ public final class CClassNode extends Node {
case CharacterType.WORD: case CharacterType.WORD:
if (!not) { if (!not) {
for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) { for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) {
if (EncodingHelper.isWord(c)) bs.set(c); if (EncodingHelper.isWord(c)) {
bs.set(c);
}
} }
addAllMultiByteRange(); addAllMultiByteRange();
} else { } else {
for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) { for (int c=0; c<BitSet.SINGLE_BYTE_SIZE; c++) {
if (!EncodingHelper.isWord(c)) bs.set(c); if (!EncodingHelper.isWord(c)) {
bs.set(c);
}
} }
} }
break; break;
@ -422,7 +457,9 @@ public final class CClassNode extends Node {
} }
public void nextStateClass(final CCStateArg arg, final ScanEnvironment env) { public void nextStateClass(final CCStateArg arg, final ScanEnvironment env) {
if (arg.state == CCSTATE.RANGE) throw new SyntaxException(ErrorMessages.ERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE); if (arg.state == CCSTATE.RANGE) {
throw new SyntaxException(ErrorMessages.ERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE);
}
if (arg.state == CCSTATE.VALUE && arg.type != CCVALTYPE.CLASS) { if (arg.state == CCSTATE.VALUE && arg.type != CCVALTYPE.CLASS) {
if (arg.type == CCVALTYPE.SB) { if (arg.type == CCVALTYPE.SB) {
@ -440,7 +477,9 @@ public final class CClassNode extends Node {
switch(arg.state) { switch(arg.state) {
case VALUE: case VALUE:
if (arg.type == CCVALTYPE.SB) { if (arg.type == CCVALTYPE.SB) {
if (arg.vs > 0xff) throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE); if (arg.vs > 0xff) {
throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE);
}
bs.set(arg.vs); bs.set(arg.vs);
} else if (arg.type == CCVALTYPE.CODE_POINT) { } else if (arg.type == CCVALTYPE.CODE_POINT) {
addCodeRange(env, arg.vs, arg.vs); addCodeRange(env, arg.vs, arg.vs);
@ -450,16 +489,17 @@ public final class CClassNode extends Node {
case RANGE: case RANGE:
if (arg.inType == arg.type) { if (arg.inType == arg.type) {
if (arg.inType == CCVALTYPE.SB) { if (arg.inType == CCVALTYPE.SB) {
if (arg.vs > 0xff || arg.v > 0xff) throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE); if (arg.vs > 0xff || arg.v > 0xff) {
throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE);
}
if (arg.vs > arg.v) { if (arg.vs > arg.v) {
if (env.syntax.allowEmptyRangeInCC()) { if (env.syntax.allowEmptyRangeInCC()) {
// goto ccs_range_end // goto ccs_range_end
arg.state = CCSTATE.COMPLETE; arg.state = CCSTATE.COMPLETE;
break; break;
} else {
throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS);
} }
throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS);
} }
bs.setRange(arg.vs, arg.v); bs.setRange(arg.vs, arg.v);
} else { } else {
@ -471,9 +511,8 @@ public final class CClassNode extends Node {
// goto ccs_range_end // goto ccs_range_end
arg.state = CCSTATE.COMPLETE; arg.state = CCSTATE.COMPLETE;
break; break;
} else {
throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS);
} }
throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS);
} }
bs.setRange(arg.vs, arg.v < 0xff ? arg.v : 0xff); bs.setRange(arg.vs, arg.v < 0xff ? arg.v : 0xff);
addCodeRange(env, arg.vs, arg.v); addCodeRange(env, arg.vs, arg.v);
@ -509,9 +548,8 @@ public final class CClassNode extends Node {
if (isNot()) { if (isNot()) {
return !found; return !found;
} else {
return found;
} }
return found;
} }
// onig_is_code_in_cc // onig_is_code_in_cc

View File

@ -24,6 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.WarnCallback;
import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
@SuppressWarnings("javadoc")
public final class ConsAltNode extends Node { public final class ConsAltNode extends Node {
public Node car; public Node car;
public ConsAltNode cdr; public ConsAltNode cdr;
@ -31,9 +32,13 @@ public final class ConsAltNode extends Node {
private ConsAltNode(final Node car, final ConsAltNode cdr, final int type) { private ConsAltNode(final Node car, final ConsAltNode cdr, final int type) {
this.car = car; this.car = car;
if (car != null) car.parent = this; if (car != null) {
car.parent = this;
}
this.cdr = cdr; this.cdr = cdr;
if (cdr != null) cdr.parent = this; if (cdr != null) {
cdr.parent = this;
}
this.type = type; this.type = type;
} }
@ -46,8 +51,9 @@ public final class ConsAltNode extends Node {
return new ConsAltNode(left, right, LIST); return new ConsAltNode(left, right, LIST);
} }
public static ConsAltNode listAdd(ConsAltNode list, final Node x) { public static ConsAltNode listAdd(final ConsAltNode listp, final Node x) {
final ConsAltNode n = newListNode(x, null); final ConsAltNode n = newListNode(x, null);
ConsAltNode list = listp;
if (list != null) { if (list != null) {
while (list.cdr != null) { while (list.cdr != null) {

View File

@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.Option; import jdk.nashorn.internal.runtime.regexp.joni.Option;
import jdk.nashorn.internal.runtime.regexp.joni.constants.EncloseType; import jdk.nashorn.internal.runtime.regexp.joni.constants.EncloseType;
@SuppressWarnings("javadoc")
public final class EncloseNode extends StateNode implements EncloseType { public final class EncloseNode extends StateNode implements EncloseType {
public final int type; // enclose type public final int type; // enclose type

View File

@ -24,6 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.Config;
import jdk.nashorn.internal.runtime.regexp.joni.WarnCallback; import jdk.nashorn.internal.runtime.regexp.joni.WarnCallback;
import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeType; import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeType;
@SuppressWarnings("javadoc")
public abstract class Node implements NodeType { public abstract class Node implements NodeType {
public Node parent; public Node parent;
@ -33,8 +34,12 @@ public abstract class Node implements NodeType {
return 1 << getType(); return 1 << getType();
} }
protected void setChild(final Node tgt){} // default definition protected void setChild(final Node tgt) {
protected Node getChild(){return null;} // default definition //empty, default definition
}
protected Node getChild() {
return null; // default definition
}
public void swap(final Node with) { public void swap(final Node with) {
Node tmp; Node tmp;
@ -46,9 +51,13 @@ public abstract class Node implements NodeType {
//setChild(with.getChild()); //setChild(with.getChild());
//with.setChild(tmp); //with.setChild(tmp);
if (parent != null) parent.setChild(with); if (parent != null) {
parent.setChild(with);
}
if (with.parent != null) with.parent.setChild(this); if (with.parent != null) {
with.parent.setChild(this);
}
tmp = parent; tmp = parent;
parent = with.parent; parent = with.parent;
@ -81,16 +90,22 @@ public abstract class Node implements NodeType {
} }
protected static String pad(final Object value, final int level) { protected static String pad(final Object value, final int level) {
if (value == null) return "NULL"; if (value == null) {
return "NULL";
}
final StringBuilder pad = new StringBuilder(" "); final StringBuilder pad = new StringBuilder(" ");
for (int i=0; i<level; i++) pad.append(pad); for (int i=0; i<level; i++) {
pad.append(pad);
}
return value.toString().replace("\n", "\n" + pad); return value.toString().replace("\n", "\n" + pad);
} }
public final boolean isInvalidQuantifier() { public final boolean isInvalidQuantifier() {
if (!Config.VANILLA) return false; if (!Config.VANILLA) {
return false;
}
ConsAltNode node; ConsAltNode node;
@ -107,14 +122,18 @@ public abstract class Node implements NodeType {
case LIST: case LIST:
node = (ConsAltNode)this; node = (ConsAltNode)this;
do { do {
if (!node.car.isInvalidQuantifier()) return false; if (!node.car.isInvalidQuantifier()) {
return false;
}
} while ((node = node.cdr) != null); } while ((node = node.cdr) != null);
return false; return false;
case ALT: case ALT:
node = (ConsAltNode)this; node = (ConsAltNode)this;
do { do {
if (node.car.isInvalidQuantifier()) return true; if (node.car.isInvalidQuantifier()) {
return true;
}
} while ((node = node.cdr) != null); } while ((node = node.cdr) != null);
break; break;

View File

@ -26,11 +26,11 @@ import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.Reduce
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.PQ_Q; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.PQ_Q;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.P_QQ; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.P_QQ;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.QQ; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.QQ;
import jdk.nashorn.internal.runtime.regexp.joni.Config; import jdk.nashorn.internal.runtime.regexp.joni.Config;
import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment; import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment;
import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo; import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo;
@SuppressWarnings("javadoc")
public final class QuantifierNode extends StateNode { public final class QuantifierNode extends StateNode {
public Node target; public Node target;
@ -78,7 +78,9 @@ public final class QuantifierNode extends StateNode {
greedy = true; greedy = true;
targetEmptyInfo = TargetInfo.ISNOT_EMPTY; targetEmptyInfo = TargetInfo.ISNOT_EMPTY;
if (byNumber) setByNumber(); if (byNumber) {
setByNumber();
}
} }
@Override @Override
@ -136,17 +138,27 @@ public final class QuantifierNode extends StateNode {
protected int popularNum() { protected int popularNum() {
if (greedy) { if (greedy) {
if (lower == 0) { if (lower == 0) {
if (upper == 1) return 0; if (upper == 1) {
else if (isRepeatInfinite(upper)) return 1; return 0;
} else if (isRepeatInfinite(upper)) {
return 1;
}
} else if (lower == 1) { } else if (lower == 1) {
if (isRepeatInfinite(upper)) return 2; if (isRepeatInfinite(upper)) {
return 2;
}
} }
} else { } else {
if (lower == 0) { if (lower == 0) {
if (upper == 1) return 3; if (upper == 1) {
else if (isRepeatInfinite(upper)) return 4; return 3;
} else if (isRepeatInfinite(upper)) {
return 4;
}
} else if (lower == 1) { } else if (lower == 1) {
if (isRepeatInfinite(upper)) return 5; if (isRepeatInfinite(upper)) {
return 5;
}
} }
} }
return -1; return -1;
@ -171,7 +183,9 @@ public final class QuantifierNode extends StateNode {
final int pnum = popularNum(); final int pnum = popularNum();
final int cnum = other.popularNum(); final int cnum = other.popularNum();
if (pnum < 0 || cnum < 0) return; if (pnum < 0 || cnum < 0) {
return;
}
switch(REDUCE_TABLE[cnum][pnum]) { switch(REDUCE_TABLE[cnum][pnum]) {
case DEL: case DEL:
@ -224,6 +238,9 @@ public final class QuantifierNode extends StateNode {
case ASIS: case ASIS:
setTarget(other); setTarget(other);
return; return;
default:
break;
} }
// ??? remove the parent from target ??? // ??? remove the parent from target ???
other.target = null; // remove target from reduced quantifier other.target = null; // remove target from reduced quantifier
@ -231,7 +248,9 @@ public final class QuantifierNode extends StateNode {
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
public int setQuantifier(final Node tgt, final boolean group, final ScanEnvironment env, final char[] chars, final int p, final int end) { public int setQuantifier(final Node tgt, final boolean group, final ScanEnvironment env, final char[] chars, final int p, final int end) {
if (lower == 1 && upper == 1) return 1; if (lower == 1 && upper == 1) {
return 1;
}
switch(tgt.getType()) { switch(tgt.getType()) {

View File

@ -21,6 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeStatus; import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeStatus;
@SuppressWarnings("javadoc")
public abstract class StateNode extends Node implements NodeStatus { public abstract class StateNode extends Node implements NodeStatus {
protected int state; protected int state;

View File

@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast;
import jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper; import jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper;
import jdk.nashorn.internal.runtime.regexp.joni.constants.StringType; import jdk.nashorn.internal.runtime.regexp.joni.constants.StringType;
@SuppressWarnings("javadoc")
public final class StringNode extends Node implements StringType { public final class StringNode extends Node implements StringType {
private static final int NODE_STR_MARGIN = 16; private static final int NODE_STR_MARGIN = 16;

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface AnchorType { public interface AnchorType {
final int BEGIN_BUF = (1<<0); final int BEGIN_BUF = (1<<0);
final int BEGIN_LINE = (1<<1); final int BEGIN_LINE = (1<<1);

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface Arguments { public interface Arguments {
final int SPECIAL = -1; final int SPECIAL = -1;
final int NON = 0; final int NON = 0;

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface AsmConstants { public interface AsmConstants {
final int THIS = 0; final int THIS = 0;

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public enum CCSTATE { public enum CCSTATE {
VALUE, VALUE,
RANGE, RANGE,

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public enum CCVALTYPE { public enum CCVALTYPE {
SB, SB,
CODE_POINT, CODE_POINT,

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface EncloseType { public interface EncloseType {
final int MEMORY = 1<<0; final int MEMORY = 1<<0;
final int OPTION = 1<<1; final int OPTION = 1<<1;

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface MetaChar { public interface MetaChar {
final int ESCAPE = 0; final int ESCAPE = 0;
final int ANYCHAR = 1; final int ANYCHAR = 1;

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface NodeStatus { public interface NodeStatus {
/* status bits */ /* status bits */
final int NST_MIN_FIXED = (1<<0); final int NST_MIN_FIXED = (1<<0);

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface NodeType { public interface NodeType {
/* node type */ /* node type */
final int STR = 0; final int STR = 0;

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface OPCode { public interface OPCode {
final int FINISH = 0; /* matching process terminator (no more alternative) */ final int FINISH = 0; /* matching process terminator (no more alternative) */
final int END = 1; /* pattern code terminator (success end) */ final int END = 1; /* pattern code terminator (success end) */

View File

@ -19,6 +19,7 @@
*/ */
package jdk.nashorn.internal.runtime.regexp.joni.constants; package jdk.nashorn.internal.runtime.regexp.joni.constants;
@SuppressWarnings("javadoc")
public interface OPSize { public interface OPSize {
// this might be helpful for potential byte[] migration // this might be helpful for potential byte[] migration

Some files were not shown because too many files have changed in this diff Show More