aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/objects/NativeRegExp.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/objects/NativeRegExp.java')
-rw-r--r--src/jdk/nashorn/internal/objects/NativeRegExp.java88
1 files changed, 52 insertions, 36 deletions
diff --git a/src/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk/nashorn/internal/objects/NativeRegExp.java
index 34657d25..33ef2849 100644
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -28,9 +28,11 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
@@ -38,19 +40,20 @@ import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.BitVector;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.regexp.RegExp;
-import jdk.nashorn.internal.runtime.regexp.RegExpFactory;
-import jdk.nashorn.internal.runtime.regexp.RegExpResult;
-import jdk.nashorn.internal.runtime.regexp.RegExpMatcher;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.regexp.RegExp;
+import jdk.nashorn.internal.runtime.regexp.RegExpFactory;
+import jdk.nashorn.internal.runtime.regexp.RegExpMatcher;
+import jdk.nashorn.internal.runtime.regexp.RegExpResult;
/**
* ECMA 15.10 RegExp Objects.
@@ -141,7 +144,7 @@ public final class NativeRegExp extends ScriptObject {
* @param self self reference
* @return new NativeRegExp
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self) {
return new NativeRegExp("", "");
}
@@ -156,7 +159,7 @@ public final class NativeRegExp extends ScriptObject {
* @param pattern pattern
* @return new NativeRegExp
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern) {
return newRegExp(pattern, UNDEFINED);
}
@@ -172,7 +175,7 @@ public final class NativeRegExp extends ScriptObject {
* @param flags flags
* @return new NativeRegExp
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) {
return newRegExp(pattern, flags);
}
@@ -211,7 +214,7 @@ public final class NativeRegExp extends ScriptObject {
* @param string pattern string
* @return flat regexp
*/
- static NativeRegExp flatRegExp(String string) {
+ static NativeRegExp flatRegExp(final String string) {
// escape special characters
StringBuilder sb = null;
final int length = string.length();
@@ -379,7 +382,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "input")
- public static Object getLastInput(Object self) {
+ public static Object getLastInput(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getInput();
}
@@ -390,7 +393,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "multiline")
- public static Object getLastMultiline(Object self) {
+ public static Object getLastMultiline(final Object self) {
return false; // doesn't ever seem to become true and isn't documented anyhwere
}
@@ -400,7 +403,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastMatch")
- public static Object getLastMatch(Object self) {
+ public static Object getLastMatch(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(0);
}
@@ -411,7 +414,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastParen")
- public static Object getLastParen(Object self) {
+ public static Object getLastParen(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getLastParen();
}
@@ -422,7 +425,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "leftContext")
- public static Object getLeftContext(Object self) {
+ public static Object getLeftContext(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getInput().substring(0, match.getIndex());
}
@@ -433,7 +436,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "rightContext")
- public static Object getRightContext(Object self) {
+ public static Object getRightContext(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getInput().substring(match.getIndex() + match.length());
}
@@ -444,7 +447,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$1")
- public static Object getGroup1(Object self) {
+ public static Object getGroup1(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(1);
}
@@ -455,7 +458,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$2")
- public static Object getGroup2(Object self) {
+ public static Object getGroup2(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(2);
}
@@ -466,7 +469,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$3")
- public static Object getGroup3(Object self) {
+ public static Object getGroup3(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(3);
}
@@ -477,7 +480,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$4")
- public static Object getGroup4(Object self) {
+ public static Object getGroup4(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(4);
}
@@ -488,7 +491,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$5")
- public static Object getGroup5(Object self) {
+ public static Object getGroup5(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(5);
}
@@ -499,7 +502,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$6")
- public static Object getGroup6(Object self) {
+ public static Object getGroup6(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(6);
}
@@ -510,7 +513,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$7")
- public static Object getGroup7(Object self) {
+ public static Object getGroup7(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(7);
}
@@ -521,7 +524,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$8")
- public static Object getGroup8(Object self) {
+ public static Object getGroup8(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(8);
}
@@ -532,7 +535,7 @@ public final class NativeRegExp extends ScriptObject {
* @return last regexp input
*/
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$9")
- public static Object getGroup9(Object self) {
+ public static Object getGroup9(final Object self) {
final RegExpResult match = Global.instance().getLastRegExpResult();
return match == null ? "" : match.getGroup(9);
}
@@ -569,7 +572,7 @@ public final class NativeRegExp extends ScriptObject {
}
// String.prototype.split method ignores the global flag and should not update lastIndex property.
- private RegExpResult execSplit(final String string, int start) {
+ private RegExpResult execSplit(final String string, final int start) {
if (start < 0 || start > string.length()) {
return null;
}
@@ -596,7 +599,7 @@ public final class NativeRegExp extends ScriptObject {
for (int i = 0, lastGroupStart = matcher.start(); i <= groupCount; i++) {
final int groupStart = matcher.start(i);
if (lastGroupStart > groupStart
- || (groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i))) {
+ || groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i)) {
// (1) ECMA 15.10.2.5 NOTE 3: need to clear Atom's captures each time Atom is repeated.
// (2) ECMA 15.10.2.8 NOTE 3: Backreferences to captures in (?!Disjunction) from elsewhere
// in the pattern always return undefined because the negative lookahead must fail.
@@ -649,7 +652,7 @@ public final class NativeRegExp extends ScriptObject {
* @param replacement Replacement string.
* @return String with substitutions.
*/
- String replace(final String string, final String replacement, final ScriptFunction function) {
+ String replace(final String string, final String replacement, final ScriptFunction function) throws Throwable {
final RegExpMatcher matcher = regexp.match(string);
if (matcher == null) {
@@ -665,7 +668,8 @@ public final class NativeRegExp extends ScriptObject {
sb.append(string, 0, matcher.start());
if (function != null) {
- sb.append(callReplaceValue(function, matcher, string));
+ final Object self = function.isStrict() ? UNDEFINED : Global.instance();
+ sb.append(callReplaceValue(getReplaceValueInvoker(), function, self, matcher, string));
} else {
appendReplacement(matcher, string, replacement, sb);
}
@@ -683,10 +687,13 @@ public final class NativeRegExp extends ScriptObject {
int previousLastIndex = 0;
final StringBuilder sb = new StringBuilder();
+ final MethodHandle invoker = function == null ? null : getReplaceValueInvoker();
+ final Object self = function == null || function.isStrict() ? UNDEFINED : Global.instance();
+
do {
sb.append(string, thisIndex, matcher.start());
if (function != null) {
- sb.append(callReplaceValue(function, matcher, string));
+ sb.append(callReplaceValue(invoker, function, self, matcher, string));
} else {
appendReplacement(matcher, string, replacement, sb);
}
@@ -746,8 +753,8 @@ public final class NativeRegExp extends ScriptObject {
cursor++;
if (cursor < replacement.length() && firstDigit < matcher.groupCount()) {
final int secondDigit = replacement.charAt(cursor) - '0';
- if ((secondDigit >= 0) && (secondDigit <= 9)) {
- final int newRefNum = (firstDigit * 10) + secondDigit;
+ if (secondDigit >= 0 && secondDigit <= 9) {
+ final int newRefNum = firstDigit * 10 + secondDigit;
if (newRefNum <= matcher.groupCount() && newRefNum > 0) {
// $nn ($01-$99)
refNum = newRefNum;
@@ -790,16 +797,26 @@ public final class NativeRegExp extends ScriptObject {
}
}
- private String callReplaceValue(final ScriptFunction function, final RegExpMatcher matcher, final String string) {
+ private static final Object REPLACE_VALUE = new Object();
+
+ private static final MethodHandle getReplaceValueInvoker() {
+ return Global.instance().getDynamicInvoker(REPLACE_VALUE,
+ new Callable<MethodHandle>() {
+ @Override
+ public MethodHandle call() {
+ return Bootstrap.createDynamicInvoker("dyn:call", String.class, ScriptFunction.class, Object.class, Object[].class);
+ }
+ });
+ }
+
+ private String callReplaceValue(final MethodHandle invoker, final ScriptFunction function, final Object self, final RegExpMatcher matcher, final String string) throws Throwable {
final Object[] groups = groups(matcher);
final Object[] args = Arrays.copyOf(groups, groups.length + 2);
args[groups.length] = matcher.start();
args[groups.length + 1] = string;
- final Object self = function.isStrict() ? UNDEFINED : Global.instance();
-
- return JSType.toString(ScriptRuntime.apply(function, self, args));
+ return (String)invoker.invokeExact(function, self, args);
}
/**
@@ -908,7 +925,6 @@ public final class NativeRegExp extends ScriptObject {
}
private static NativeRegExp checkRegExp(final Object self) {
- Global.checkObjectCoercible(self);
if (self instanceof NativeRegExp) {
return (NativeRegExp)self;
} else if (self != null && self == Global.instance().getRegExpPrototype()) {