aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/objects/NativeString.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/objects/NativeString.java')
-rw-r--r--src/jdk/nashorn/internal/objects/NativeString.java1353
1 files changed, 0 insertions, 1353 deletions
diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java
deleted file mode 100644
index 304ec99c..00000000
--- a/src/jdk/nashorn/internal/objects/NativeString.java
+++ /dev/null
@@ -1,1353 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.objects;
-
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
-import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import jdk.internal.dynalink.CallSiteDescriptor;
-import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.nashorn.internal.lookup.MethodHandleFactory.LookupException;
-import jdk.nashorn.internal.objects.annotations.Attribute;
-import jdk.nashorn.internal.objects.annotations.Constructor;
-import jdk.nashorn.internal.objects.annotations.Function;
-import jdk.nashorn.internal.objects.annotations.Getter;
-import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
-import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
-import jdk.nashorn.internal.objects.annotations.Where;
-import jdk.nashorn.internal.runtime.ConsString;
-import jdk.nashorn.internal.runtime.JSType;
-import jdk.nashorn.internal.runtime.OptimisticBuiltins;
-import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
-import jdk.nashorn.internal.runtime.linker.Bootstrap;
-import jdk.nashorn.internal.runtime.linker.NashornGuards;
-import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
-
-/**
- * ECMA 15.5 String Objects.
- */
-@ScriptClass("String")
-public final class NativeString extends ScriptObject implements OptimisticBuiltins {
-
- private final CharSequence value;
-
- /** Method handle to create an object wrapper for a primitive string */
- static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
- /** Method handle to retrieve the String prototype object */
- private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
-
- // initialized by nasgen
- private static PropertyMap $nasgenmap$;
-
- private NativeString(final CharSequence value) {
- this(value, Global.instance());
- }
-
- NativeString(final CharSequence value, final Global global) {
- this(value, global.getStringPrototype(), $nasgenmap$);
- }
-
- private NativeString(final CharSequence value, final ScriptObject proto, final PropertyMap map) {
- super(proto, map);
- assert JSType.isString(value);
- this.value = value;
- }
-
- @Override
- public String safeToString() {
- return "[String " + toString() + "]";
- }
-
- @Override
- public String toString() {
- return getStringValue();
- }
-
- @Override
- public boolean equals(final Object other) {
- if (other instanceof NativeString) {
- return getStringValue().equals(((NativeString) other).getStringValue());
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return getStringValue().hashCode();
- }
-
- private String getStringValue() {
- return value instanceof String ? (String) value : value.toString();
- }
-
- private CharSequence getValue() {
- return value;
- }
-
- @Override
- public String getClassName() {
- return "String";
- }
-
- @Override
- public Object getLength() {
- return value.length();
- }
-
- // This is to support length as method call as well.
- @Override
- protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
- final String name = desc.getNameToken(2);
-
- // if str.length(), then let the bean linker handle it
- if ("length".equals(name) && "getMethod".equals(operator)) {
- return null;
- }
-
- return super.findGetMethod(desc, request, operator);
- }
-
- // This is to provide array-like access to string characters without creating a NativeString wrapper.
- @Override
- protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- final Object self = request.getReceiver();
- final Class<?> returnType = desc.getMethodType().returnType();
-
- if (returnType == Object.class && JSType.isString(self)) {
- try {
- return new GuardedInvocation(MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType()), NashornGuards.getStringGuard());
- } catch (final LookupException e) {
- //empty. Shouldn't happen. Fall back to super
- }
- }
- return super.findGetIndexMethod(desc, request);
- }
-
- @SuppressWarnings("unused")
- private static Object get(final Object self, final Object key) {
- final CharSequence cs = JSType.toCharSequence(self);
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = ArrayIndex.getArrayIndex(primitiveKey);
- if (index >= 0 && index < cs.length()) {
- return String.valueOf(cs.charAt(index));
- }
- return ((ScriptObject) Global.toObject(self)).get(primitiveKey);
- }
-
- @SuppressWarnings("unused")
- private static Object get(final Object self, final double key) {
- if (isRepresentableAsInt(key)) {
- return get(self, (int)key);
- }
- return ((ScriptObject) Global.toObject(self)).get(key);
- }
-
- @SuppressWarnings("unused")
- private static Object get(final Object self, final long key) {
- final CharSequence cs = JSType.toCharSequence(self);
- if (key >= 0 && key < cs.length()) {
- return String.valueOf(cs.charAt((int)key));
- }
- return ((ScriptObject) Global.toObject(self)).get(key);
- }
-
- private static Object get(final Object self, final int key) {
- final CharSequence cs = JSType.toCharSequence(self);
- if (key >= 0 && key < cs.length()) {
- return String.valueOf(cs.charAt(key));
- }
- return ((ScriptObject) Global.toObject(self)).get(key);
- }
-
- // String characters can be accessed with array-like indexing..
- @Override
- public Object get(final Object key) {
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = ArrayIndex.getArrayIndex(primitiveKey);
- if (index >= 0 && index < value.length()) {
- return String.valueOf(value.charAt(index));
- }
- return super.get(primitiveKey);
- }
-
- @Override
- public Object get(final double key) {
- if (isRepresentableAsInt(key)) {
- return get((int)key);
- }
- return super.get(key);
- }
-
- @Override
- public Object get(final int key) {
- if (key >= 0 && key < value.length()) {
- return String.valueOf(value.charAt(key));
- }
- return super.get(key);
- }
-
- @Override
- public int getInt(final Object key, final int programPoint) {
- return JSType.toInt32MaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public int getInt(final double key, final int programPoint) {
- return JSType.toInt32MaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public int getInt(final int key, final int programPoint) {
- return JSType.toInt32MaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public double getDouble(final Object key, final int programPoint) {
- return JSType.toNumberMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public double getDouble(final double key, final int programPoint) {
- return JSType.toNumberMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public double getDouble(final int key, final int programPoint) {
- return JSType.toNumberMaybeOptimistic(get(key), programPoint);
- }
-
- @Override
- public boolean has(final Object key) {
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = ArrayIndex.getArrayIndex(primitiveKey);
- return isValidStringIndex(index) || super.has(primitiveKey);
- }
-
- @Override
- public boolean has(final int key) {
- return isValidStringIndex(key) || super.has(key);
- }
-
- @Override
- public boolean has(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
- return isValidStringIndex(index) || super.has(key);
- }
-
- @Override
- public boolean hasOwnProperty(final Object key) {
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = ArrayIndex.getArrayIndex(primitiveKey);
- return isValidStringIndex(index) || super.hasOwnProperty(primitiveKey);
- }
-
- @Override
- public boolean hasOwnProperty(final int key) {
- return isValidStringIndex(key) || super.hasOwnProperty(key);
- }
-
- @Override
- public boolean hasOwnProperty(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
- return isValidStringIndex(index) || super.hasOwnProperty(key);
- }
-
- @Override
- public boolean delete(final int key, final boolean strict) {
- return checkDeleteIndex(key, strict)? false : super.delete(key, strict);
- }
-
- @Override
- public boolean delete(final double key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
- return checkDeleteIndex(index, strict)? false : super.delete(key, strict);
- }
-
- @Override
- public boolean delete(final Object key, final boolean strict) {
- final Object primitiveKey = JSType.toPrimitive(key, String.class);
- final int index = ArrayIndex.getArrayIndex(primitiveKey);
- return checkDeleteIndex(index, strict)? false : super.delete(primitiveKey, strict);
- }
-
- private boolean checkDeleteIndex(final int index, final boolean strict) {
- if (isValidStringIndex(index)) {
- if (strict) {
- throw typeError("cant.delete.property", Integer.toString(index), ScriptRuntime.safeToString(this));
- }
- return true;
- }
-
- return false;
- }
-
- @Override
- public Object getOwnPropertyDescriptor(final String key) {
- final int index = ArrayIndex.getArrayIndex(key);
- if (index >= 0 && index < value.length()) {
- final Global global = Global.instance();
- return global.newDataDescriptor(String.valueOf(value.charAt(index)), false, true, false);
- }
-
- return super.getOwnPropertyDescriptor(key);
- }
-
- /**
- * return a List of own keys associated with the object.
- * @param all True if to include non-enumerable keys.
- * @param nonEnumerable set of non-enumerable properties seen already.Used
- * to filter out shadowed, but enumerable properties from proto children.
- * @return Array of keys.
- */
- @Override
- protected String[] getOwnKeys(final boolean all, final Set<String> nonEnumerable) {
- final List<Object> keys = new ArrayList<>();
-
- // add string index keys
- for (int i = 0; i < value.length(); i++) {
- keys.add(JSType.toString(i));
- }
-
- // add super class properties
- keys.addAll(Arrays.asList(super.getOwnKeys(all, nonEnumerable)));
- return keys.toArray(new String[keys.size()]);
- }
-
- /**
- * ECMA 15.5.3 String.length
- * @param self self reference
- * @return value of length property for string
- */
- @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
- public static Object length(final Object self) {
- return getCharSequence(self).length();
- }
-
- /**
- * ECMA 15.5.3.2 String.fromCharCode ( [ char0 [ , char1 [ , ... ] ] ] )
- * @param self self reference
- * @param args array of arguments to be interpreted as char
- * @return string with arguments translated to charcodes
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1, where = Where.CONSTRUCTOR)
- public static String fromCharCode(final Object self, final Object... args) {
- final char[] buf = new char[args.length];
- int index = 0;
- for (final Object arg : args) {
- buf[index++] = (char)JSType.toUint16(arg);
- }
- return new String(buf);
- }
-
- /**
- * ECMA 15.5.3.2 - specialization for one char
- * @param self self reference
- * @param value one argument to be interpreted as char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static Object fromCharCode(final Object self, final Object value) {
- if (value instanceof Integer) {
- return fromCharCode(self, (int)value);
- }
- return Character.toString((char)JSType.toUint16(value));
- }
-
- /**
- * ECMA 15.5.3.2 - specialization for one char of int type
- * @param self self reference
- * @param value one argument to be interpreted as char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static String fromCharCode(final Object self, final int value) {
- return Character.toString((char)(value & 0xffff));
- }
-
- /**
- * ECMA 15.5.3.2 - specialization for two chars of int type
- * @param self self reference
- * @param ch1 first char
- * @param ch2 second char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static Object fromCharCode(final Object self, final int ch1, final int ch2) {
- return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff));
- }
-
- /**
- * ECMA 15.5.3.2 - specialization for three chars of int type
- * @param self self reference
- * @param ch1 first char
- * @param ch2 second char
- * @param ch3 third char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static Object fromCharCode(final Object self, final int ch1, final int ch2, final int ch3) {
- return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff)) + Character.toString((char)(ch3 & 0xffff));
- }
-
- /**
- * ECMA 15.5.3.2 - specialization for four chars of int type
- * @param self self reference
- * @param ch1 first char
- * @param ch2 second char
- * @param ch3 third char
- * @param ch4 fourth char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static String fromCharCode(final Object self, final int ch1, final int ch2, final int ch3, final int ch4) {
- return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff)) + Character.toString((char)(ch3 & 0xffff)) + Character.toString((char)(ch4 & 0xffff));
- }
-
- /**
- * ECMA 15.5.3.2 - specialization for one char of double type
- * @param self self reference
- * @param value one argument to be interpreted as char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static String fromCharCode(final Object self, final double value) {
- return Character.toString((char)JSType.toUint16(value));
- }
-
- /**
- * ECMA 15.5.4.2 String.prototype.toString ( )
- * @param self self reference
- * @return self as string
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String toString(final Object self) {
- return getString(self);
- }
-
- /**
- * ECMA 15.5.4.3 String.prototype.valueOf ( )
- * @param self self reference
- * @return self as string
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String valueOf(final Object self) {
- return getString(self);
- }
-
- /**
- * ECMA 15.5.4.4 String.prototype.charAt (pos)
- * @param self self reference
- * @param pos position in string
- * @return string representing the char at the given position
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String charAt(final Object self, final Object pos) {
- return charAtImpl(checkObjectToString(self), JSType.toInteger(pos));
- }
-
- /**
- * ECMA 15.5.4.4 String.prototype.charAt (pos) - specialized version for double position
- * @param self self reference
- * @param pos position in string
- * @return string representing the char at the given position
- */
- @SpecializedFunction
- public static String charAt(final Object self, final double pos) {
- return charAt(self, (int)pos);
- }
-
- /**
- * ECMA 15.5.4.4 String.prototype.charAt (pos) - specialized version for int position
- * @param self self reference
- * @param pos position in string
- * @return string representing the char at the given position
- */
- @SpecializedFunction
- public static String charAt(final Object self, final int pos) {
- return charAtImpl(checkObjectToString(self), pos);
- }
-
- private static String charAtImpl(final String str, final int pos) {
- return pos < 0 || pos >= str.length() ? "" : String.valueOf(str.charAt(pos));
- }
-
- private static int getValidChar(final Object self, final int pos) {
- try {
- return ((CharSequence)self).charAt(pos);
- } catch (final IndexOutOfBoundsException e) {
- throw new ClassCastException(); //invalid char, out of bounds, force relink
- }
- }
-
- /**
- * ECMA 15.5.4.5 String.prototype.charCodeAt (pos)
- * @param self self reference
- * @param pos position in string
- * @return number representing charcode at position
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static double charCodeAt(final Object self, final Object pos) {
- final String str = checkObjectToString(self);
- final int idx = JSType.toInteger(pos);
- return idx < 0 || idx >= str.length() ? Double.NaN : str.charAt(idx);
- }
-
- /**
- * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for double position
- * @param self self reference
- * @param pos position in string
- * @return number representing charcode at position
- */
- @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
- public static int charCodeAt(final Object self, final double pos) {
- return charCodeAt(self, (int)pos); //toInt pos is ok
- }
-
- /**
- * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for long position
- * @param self self reference
- * @param pos position in string
- * @return number representing charcode at position
- */
- @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
- public static int charCodeAt(final Object self, final long pos) {
- return charCodeAt(self, (int)pos);
- }
-
- /**
- * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for int position
- * @param self self reference
- * @param pos position in string
- * @return number representing charcode at position
- */
-
- @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
- public static int charCodeAt(final Object self, final int pos) {
- return getValidChar(self, pos);
- }
-
- /**
- * ECMA 15.5.4.6 String.prototype.concat ( [ string1 [ , string2 [ , ... ] ] ] )
- * @param self self reference
- * @param args list of string to concatenate
- * @return concatenated string
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
- public static Object concat(final Object self, final Object... args) {
- CharSequence cs = checkObjectToString(self);
- if (args != null) {
- for (final Object obj : args) {
- cs = new ConsString(cs, JSType.toCharSequence(obj));
- }
- }
- return cs;
- }
-
- /**
- * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position)
- * @param self self reference
- * @param search string to search for
- * @param pos position to start search
- * @return position of first match or -1
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
- public static int indexOf(final Object self, final Object search, final Object pos) {
- final String str = checkObjectToString(self);
- return str.indexOf(JSType.toString(search), JSType.toInteger(pos));
- }
-
- /**
- * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for no position parameter
- * @param self self reference
- * @param search string to search for
- * @return position of first match or -1
- */
- @SpecializedFunction
- public static int indexOf(final Object self, final Object search) {
- return indexOf(self, search, 0);
- }
-
- /**
- * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for double position parameter
- * @param self self reference
- * @param search string to search for
- * @param pos position to start search
- * @return position of first match or -1
- */
- @SpecializedFunction
- public static int indexOf(final Object self, final Object search, final double pos) {
- return indexOf(self, search, (int) pos);
- }
-
- /**
- * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for int position parameter
- * @param self self reference
- * @param search string to search for
- * @param pos position to start search
- * @return position of first match or -1
- */
- @SpecializedFunction
- public static int indexOf(final Object self, final Object search, final int pos) {
- return checkObjectToString(self).indexOf(JSType.toString(search), pos);
- }
-
- /**
- * ECMA 15.5.4.8 String.prototype.lastIndexOf (searchString, position)
- * @param self self reference
- * @param search string to search for
- * @param pos position to start search
- * @return last position of match or -1
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
- public static int lastIndexOf(final Object self, final Object search, final Object pos) {
-
- final String str = checkObjectToString(self);
- final String searchStr = JSType.toString(search);
- final int length = str.length();
-
- int end;
-
- if (pos == UNDEFINED) {
- end = length;
- } else {
- final double numPos = JSType.toNumber(pos);
- end = Double.isNaN(numPos) ? length : (int)numPos;
- if (end < 0) {
- end = 0;
- } else if (end > length) {
- end = length;
- }
- }
-
-
- return str.lastIndexOf(searchStr, end);
- }
-
- /**
- * ECMA 15.5.4.9 String.prototype.localeCompare (that)
- * @param self self reference
- * @param that comparison object
- * @return result of locale sensitive comparison operation between {@code self} and {@code that}
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static double localeCompare(final Object self, final Object that) {
-
- final String str = checkObjectToString(self);
- final Collator collator = Collator.getInstance(Global.getEnv()._locale);
-
- collator.setStrength(Collator.IDENTICAL);
- collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
-
- return collator.compare(str, JSType.toString(that));
- }
-
- /**
- * ECMA 15.5.4.10 String.prototype.match (regexp)
- * @param self self reference
- * @param regexp regexp expression
- * @return array of regexp matches
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static ScriptObject match(final Object self, final Object regexp) {
-
- final String str = checkObjectToString(self);
-
- NativeRegExp nativeRegExp;
- if (regexp == UNDEFINED) {
- nativeRegExp = new NativeRegExp("");
- } else {
- nativeRegExp = Global.toRegExp(regexp);
- }
-
- if (!nativeRegExp.getGlobal()) {
- return nativeRegExp.exec(str);
- }
-
- nativeRegExp.setLastIndex(0);
-
- int previousLastIndex = 0;
- final List<Object> matches = new ArrayList<>();
-
- Object result;
- while ((result = nativeRegExp.exec(str)) != null) {
- final int thisIndex = nativeRegExp.getLastIndex();
- if (thisIndex == previousLastIndex) {
- nativeRegExp.setLastIndex(thisIndex + 1);
- previousLastIndex = thisIndex + 1;
- } else {
- previousLastIndex = thisIndex;
- }
- matches.add(((ScriptObject)result).get(0));
- }
-
- if (matches.isEmpty()) {
- return null;
- }
-
- return new NativeArray(matches.toArray());
- }
-
- /**
- * ECMA 15.5.4.11 String.prototype.replace (searchValue, replaceValue)
- * @param self self reference
- * @param string item to replace
- * @param replacement item to replace it with
- * @return string after replacement
- * @throws Throwable if replacement fails
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String replace(final Object self, final Object string, final Object replacement) throws Throwable {
-
- final String str = checkObjectToString(self);
-
- final NativeRegExp nativeRegExp;
- if (string instanceof NativeRegExp) {
- nativeRegExp = (NativeRegExp) string;
- } else {
- nativeRegExp = NativeRegExp.flatRegExp(JSType.toString(string));
- }
-
- if (Bootstrap.isCallable(replacement)) {
- return nativeRegExp.replace(str, "", replacement);
- }
-
- return nativeRegExp.replace(str, JSType.toString(replacement), null);
- }
-
- /**
- * ECMA 15.5.4.12 String.prototype.search (regexp)
- *
- * @param self self reference
- * @param string string to search for
- * @return offset where match occurred
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static int search(final Object self, final Object string) {
-
- final String str = checkObjectToString(self);
- final NativeRegExp nativeRegExp = Global.toRegExp(string == UNDEFINED ? "" : string);
-
- return nativeRegExp.search(str);
- }
-
- /**
- * ECMA 15.5.4.13 String.prototype.slice (start, end)
- *
- * @param self self reference
- * @param start start position for slice
- * @param end end position for slice
- * @return sliced out substring
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String slice(final Object self, final Object start, final Object end) {
-
- final String str = checkObjectToString(self);
- if (end == UNDEFINED) {
- return slice(str, JSType.toInteger(start));
- }
- return slice(str, JSType.toInteger(start), JSType.toInteger(end));
- }
-
- /**
- * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for single int parameter
- *
- * @param self self reference
- * @param start start position for slice
- * @return sliced out substring
- */
- @SpecializedFunction
- public static String slice(final Object self, final int start) {
- final String str = checkObjectToString(self);
- final int from = start < 0 ? Math.max(str.length() + start, 0) : Math.min(start, str.length());
-
- return str.substring(from);
- }
-
- /**
- * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for single double parameter
- *
- * @param self self reference
- * @param start start position for slice
- * @return sliced out substring
- */
- @SpecializedFunction
- public static String slice(final Object self, final double start) {
- return slice(self, (int)start);
- }
-
- /**
- * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for two int parameters
- *
- * @param self self reference
- * @param start start position for slice
- * @param end end position for slice
- * @return sliced out substring
- */
- @SpecializedFunction
- public static String slice(final Object self, final int start, final int end) {
-
- final String str = checkObjectToString(self);
- final int len = str.length();
-
- final int from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
- final int to = end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
-
- return str.substring(Math.min(from, to), to);
- }
-
- /**
- * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for two double parameters
- *
- * @param self self reference
- * @param start start position for slice
- * @param end end position for slice
- * @return sliced out substring
- */
- @SpecializedFunction
- public static String slice(final Object self, final double start, final double end) {
- return slice(self, (int)start, (int)end);
- }
-
- /**
- * ECMA 15.5.4.14 String.prototype.split (separator, limit)
- *
- * @param self self reference
- * @param separator separator for split
- * @param limit limit for splits
- * @return array object in which splits have been placed
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static ScriptObject split(final Object self, final Object separator, final Object limit) {
- final String str = checkObjectToString(self);
- final long lim = limit == UNDEFINED ? JSType.MAX_UINT : JSType.toUint32(limit);
-
- if (separator == UNDEFINED) {
- return lim == 0 ? new NativeArray() : new NativeArray(new Object[]{str});
- }
-
- if (separator instanceof NativeRegExp) {
- return ((NativeRegExp) separator).split(str, lim);
- }
-
- // when separator is a string, it is treated as a literal search string to be used for splitting.
- return splitString(str, JSType.toString(separator), lim);
- }
-
- private static ScriptObject splitString(final String str, final String separator, final long limit) {
- if (separator.isEmpty()) {
- final int length = (int) Math.min(str.length(), limit);
- final Object[] array = new Object[length];
- for (int i = 0; i < length; i++) {
- array[i] = String.valueOf(str.charAt(i));
- }
- return new NativeArray(array);
- }
-
- final List<String> elements = new LinkedList<>();
- final int strLength = str.length();
- final int sepLength = separator.length();
- int pos = 0;
- int n = 0;
-
- while (pos < strLength && n < limit) {
- final int found = str.indexOf(separator, pos);
- if (found == -1) {
- break;
- }
- elements.add(str.substring(pos, found));
- n++;
- pos = found + sepLength;
- }
- if (pos <= strLength && n < limit) {
- elements.add(str.substring(pos));
- }
-
- return new NativeArray(elements.toArray());
- }
-
- /**
- * ECMA B.2.3 String.prototype.substr (start, length)
- *
- * @param self self reference
- * @param start start position
- * @param length length of section
- * @return substring given start and length of section
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String substr(final Object self, final Object start, final Object length) {
- final String str = JSType.toString(self);
- final int strLength = str.length();
-
- int intStart = JSType.toInteger(start);
- if (intStart < 0) {
- intStart = Math.max(intStart + strLength, 0);
- }
-
- final int intLen = Math.min(Math.max(length == UNDEFINED ? Integer.MAX_VALUE : JSType.toInteger(length), 0), strLength - intStart);
-
- return intLen <= 0 ? "" : str.substring(intStart, intStart + intLen);
- }
-
- /**
- * ECMA 15.5.4.15 String.prototype.substring (start, end)
- *
- * @param self self reference
- * @param start start position of substring
- * @param end end position of substring
- * @return substring given start and end indexes
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String substring(final Object self, final Object start, final Object end) {
-
- final String str = checkObjectToString(self);
- if (end == UNDEFINED) {
- return substring(str, JSType.toInteger(start));
- }
- return substring(str, JSType.toInteger(start), JSType.toInteger(end));
- }
-
- /**
- * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for int start parameter
- *
- * @param self self reference
- * @param start start position of substring
- * @return substring given start and end indexes
- */
- @SpecializedFunction
- public static String substring(final Object self, final int start) {
- final String str = checkObjectToString(self);
- if (start < 0) {
- return str;
- } else if (start >= str.length()) {
- return "";
- } else {
- return str.substring(start);
- }
- }
-
- /**
- * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for double start parameter
- *
- * @param self self reference
- * @param start start position of substring
- * @return substring given start and end indexes
- */
- @SpecializedFunction
- public static String substring(final Object self, final double start) {
- return substring(self, (int)start);
- }
-
- /**
- * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for int start and end parameters
- *
- * @param self self reference
- * @param start start position of substring
- * @param end end position of substring
- * @return substring given start and end indexes
- */
- @SpecializedFunction
- public static String substring(final Object self, final int start, final int end) {
- final String str = checkObjectToString(self);
- final int len = str.length();
- final int validStart = start < 0 ? 0 : start > len ? len : start;
- final int validEnd = end < 0 ? 0 : end > len ? len : end;
-
- if (validStart < validEnd) {
- return str.substring(validStart, validEnd);
- }
- return str.substring(validEnd, validStart);
- }
-
- /**
- * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for double start and end parameters
- *
- * @param self self reference
- * @param start start position of substring
- * @param end end position of substring
- * @return substring given start and end indexes
- */
- @SpecializedFunction
- public static String substring(final Object self, final double start, final double end) {
- return substring(self, (int)start, (int)end);
- }
-
- /**
- * ECMA 15.5.4.16 String.prototype.toLowerCase ( )
- * @param self self reference
- * @return string to lower case
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String toLowerCase(final Object self) {
- return checkObjectToString(self).toLowerCase(Locale.ROOT);
- }
-
- /**
- * ECMA 15.5.4.17 String.prototype.toLocaleLowerCase ( )
- * @param self self reference
- * @return string to locale sensitive lower case
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String toLocaleLowerCase(final Object self) {
- return checkObjectToString(self).toLowerCase(Global.getEnv()._locale);
- }
-
- /**
- * ECMA 15.5.4.18 String.prototype.toUpperCase ( )
- * @param self self reference
- * @return string to upper case
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String toUpperCase(final Object self) {
- return checkObjectToString(self).toUpperCase(Locale.ROOT);
- }
-
- /**
- * ECMA 15.5.4.19 String.prototype.toLocaleUpperCase ( )
- * @param self self reference
- * @return string to locale sensitive upper case
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String toLocaleUpperCase(final Object self) {
- return checkObjectToString(self).toUpperCase(Global.getEnv()._locale);
- }
-
- /**
- * ECMA 15.5.4.20 String.prototype.trim ( )
- * @param self self reference
- * @return string trimmed from whitespace
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String trim(final Object self) {
- final String str = checkObjectToString(self);
- int start = 0;
- int end = str.length() - 1;
-
- while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
- start++;
- }
- while (end > start && ScriptRuntime.isJSWhitespace(str.charAt(end))) {
- end--;
- }
-
- return str.substring(start, end + 1);
- }
-
- /**
- * Nashorn extension: String.prototype.trimLeft ( )
- * @param self self reference
- * @return string trimmed left from whitespace
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String trimLeft(final Object self) {
-
- final String str = checkObjectToString(self);
- int start = 0;
- final int end = str.length() - 1;
-
- while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
- start++;
- }
-
- return str.substring(start, end + 1);
- }
-
- /**
- * Nashorn extension: String.prototype.trimRight ( )
- * @param self self reference
- * @return string trimmed right from whitespace
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE)
- public static String trimRight(final Object self) {
-
- final String str = checkObjectToString(self);
- final int start = 0;
- int end = str.length() - 1;
-
- while (end >= start && ScriptRuntime.isJSWhitespace(str.charAt(end))) {
- end--;
- }
-
- return str.substring(start, end + 1);
- }
-
- private static ScriptObject newObj(final CharSequence str) {
- return new NativeString(str);
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] )
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- * @param args arguments (a value)
- *
- * @return new NativeString, empty string if no args, extraneous args ignored
- */
- @Constructor(arity = 1)
- public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- final CharSequence str = args.length > 0 ? JSType.toCharSequence(args[0]) : "";
- return newObj ? newObj(str) : str.toString();
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] ) - special version with no args
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- *
- * @return new NativeString ("")
- */
- @SpecializedFunction(isConstructor=true)
- public static Object constructor(final boolean newObj, final Object self) {
- return newObj ? newObj("") : "";
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] ) - special version with one arg
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- * @param arg argument
- *
- * @return new NativeString (arg)
- */
- @SpecializedFunction(isConstructor=true)
- public static Object constructor(final boolean newObj, final Object self, final Object arg) {
- final CharSequence str = JSType.toCharSequence(arg);
- return newObj ? newObj(str) : str.toString();
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- * @param arg the arg
- *
- * @return new NativeString containing the string representation of the arg
- */
- @SpecializedFunction(isConstructor=true)
- public static Object constructor(final boolean newObj, final Object self, final int arg) {
- final String str = Integer.toString(arg);
- return newObj ? newObj(str) : str;
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- * @param arg the arg
- *
- * @return new NativeString containing the string representation of the arg
- */
- @SpecializedFunction(isConstructor=true)
- public static Object constructor(final boolean newObj, final Object self, final long arg) {
- final String str = Long.toString(arg);
- return newObj ? newObj(str) : str;
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- * @param arg the arg
- *
- * @return new NativeString containing the string representation of the arg
- */
- @SpecializedFunction(isConstructor=true)
- public static Object constructor(final boolean newObj, final Object self, final double arg) {
- final String str = JSType.toString(arg);
- return newObj ? newObj(str) : str;
- }
-
- /**
- * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code boolean} arg
- *
- * Constructor
- *
- * @param newObj is this constructor invoked with the new operator
- * @param self self reference
- * @param arg the arg
- *
- * @return new NativeString containing the string representation of the arg
- */
- @SpecializedFunction(isConstructor=true)
- public static Object constructor(final boolean newObj, final Object self, final boolean arg) {
- final String str = Boolean.toString(arg);
- return newObj ? newObj(str) : str;
- }
-
- /**
- * Lookup the appropriate method for an invoke dynamic call.
- *
- * @param request the link request
- * @param receiver receiver of call
- * @return Link to be invoked at call site.
- */
- public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
- return PrimitiveLookup.lookupPrimitive(request, NashornGuards.getStringGuard(),
- new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER);
- }
-
- @SuppressWarnings("unused")
- private static NativeString wrapFilter(final Object receiver) {
- return new NativeString((CharSequence)receiver);
- }
-
- @SuppressWarnings("unused")
- private static Object protoFilter(final Object object) {
- return Global.instance().getStringPrototype();
- }
-
- private static CharSequence getCharSequence(final Object self) {
- if (JSType.isString(self)) {
- return (CharSequence)self;
- } else if (self instanceof NativeString) {
- return ((NativeString)self).getValue();
- } else if (self != null && self == Global.instance().getStringPrototype()) {
- return "";
- } else {
- throw typeError("not.a.string", ScriptRuntime.safeToString(self));
- }
- }
-
- private static String getString(final Object self) {
- if (self instanceof String) {
- return (String)self;
- } else if (self instanceof ConsString) {
- return self.toString();
- } else if (self instanceof NativeString) {
- return ((NativeString)self).getStringValue();
- } else if (self != null && self == Global.instance().getStringPrototype()) {
- return "";
- } else {
- throw typeError("not.a.string", ScriptRuntime.safeToString(self));
- }
- }
-
- /**
- * Combines ECMA 9.10 CheckObjectCoercible and ECMA 9.8 ToString with a shortcut for strings.
- *
- * @param self the object
- * @return the object as string
- */
- private static String checkObjectToString(final Object self) {
- if (self instanceof String) {
- return (String)self;
- } else if (self instanceof ConsString) {
- return self.toString();
- } else {
- Global.checkObjectCoercible(self);
- return JSType.toString(self);
- }
- }
-
- private boolean isValidStringIndex(final int key) {
- return key >= 0 && key < value.length();
- }
-
- private static MethodHandle findOwnMH(final String name, final MethodType type) {
- return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type);
- }
-
- @Override
- public LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
- if (clazz == CharCodeAtLinkLogic.class) {
- return CharCodeAtLinkLogic.INSTANCE;
- }
- return null;
- }
-
- @Override
- public boolean hasPerInstanceAssumptions() {
- return false;
- }
-
- /**
- * This is linker logic charCodeAt - when we specialize further methods in NativeString
- * It may be expanded. It's link check makes sure that we are dealing with a char
- * sequence and that we are in range
- */
- private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic {
- private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic();
-
- @Override
- public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
- try {
- //check that it's a char sequence or throw cce
- final CharSequence cs = (CharSequence)self;
- //check that the index, representable as an int, is inside the array
- final int intIndex = JSType.toInteger(request.getArguments()[2]);
- return intIndex >= 0 && intIndex < cs.length(); //can link
- } catch (final ClassCastException | IndexOutOfBoundsException e) {
- //fallthru
- }
- return false;
- }
-
- /**
- * charCodeAt callsites can throw ClassCastException as a mechanism to have them
- * relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
- * for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
- */
- @Override
- public Class<? extends Throwable> getRelinkException() {
- return ClassCastException.class;
- }
- }
-}