--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java 2020-04-15 18:49:52.000000000 +0530 +++ /dev/null 2020-04-15 18:49:52.000000000 +0530 @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime; - -import static jdk.nashorn.internal.lookup.Lookup.MH; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Locale; - -/** - * Utilities used by Global class. - */ -public final class GlobalFunctions { - - /** Methodhandle to implementation of ECMA 15.1.2.2, parseInt */ - public static final MethodHandle PARSEINT = findOwnMH("parseInt", double.class, Object.class, Object.class, Object.class); - - /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */ - public static final MethodHandle PARSEINT_OI = findOwnMH("parseInt", double.class, Object.class, Object.class, int.class); - - /** ParseInt - NaN for booleans (thru string conversion to number conversion) */ - public static final MethodHandle PARSEINT_Z = MH.dropArguments(MH.dropArguments(MH.constant(double.class, Double.NaN), 0, boolean.class), 0, Object.class); - - /** ParseInt - identity for ints */ - public static final MethodHandle PARSEINT_I = MH.dropArguments(MH.identity(int.class), 0, Object.class); - - /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */ - public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.2.3, parseFloat */ - public static final MethodHandle PARSEFLOAT = findOwnMH("parseFloat", double.class, Object.class, Object.class); - - /** isNan for integers - always false */ - public static final MethodHandle IS_NAN_I = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class); - - /** isNan for longs - always false */ - public static final MethodHandle IS_NAN_J = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class); - - /** IsNan for doubles - use Double.isNaN */ - public static final MethodHandle IS_NAN_D = MH.dropArguments(MH.findStatic(MethodHandles.lookup(), Double.class, "isNaN", MH.type(boolean.class, double.class)), 0, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.2.4, isNaN */ - public static final MethodHandle IS_NAN = findOwnMH("isNaN", boolean.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.2.5, isFinite */ - public static final MethodHandle IS_FINITE = findOwnMH("isFinite", boolean.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.3.3, encodeURI */ - public static final MethodHandle ENCODE_URI = findOwnMH("encodeURI", Object.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.3.4, encodeURIComponent */ - public static final MethodHandle ENCODE_URICOMPONENT = findOwnMH("encodeURIComponent", Object.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.3.1, decodeURI */ - public static final MethodHandle DECODE_URI = findOwnMH("decodeURI", Object.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.1.3.2, decodeURIComponent */ - public static final MethodHandle DECODE_URICOMPONENT = findOwnMH("decodeURIComponent", Object.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA B.2.1, escape */ - public static final MethodHandle ESCAPE = findOwnMH("escape", String.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA B.2.2, unescape */ - public static final MethodHandle UNESCAPE = findOwnMH("unescape", String.class, Object.class, Object.class); - - /** Methodhandle to implementation of ECMA 15.3.4, "anonymous" - Properties of the Function Prototype Object. */ - public static final MethodHandle ANONYMOUS = findOwnMH("anonymous", Object.class, Object.class); - - private static final String UNESCAPED = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./"; - - private GlobalFunctions() { - } - - /** - * ECMA 15.1.2.2 parseInt implementation - * - * @param self self reference - * @param string string to parse - * @param rad radix - * - * @return numeric type representing string contents as an int - */ - public static double parseInt(final Object self, final Object string, final Object rad) { - return parseIntInternal(JSType.trimLeft(JSType.toString(string)), JSType.toInt32(rad)); - } - - /** - * ECMA 15.1.2.2 parseInt implementation specialized for int radix - * - * @param self self reference - * @param string string to parse - * @param rad radix - * - * @return numeric type representing string contents as an int - */ - public static double parseInt(final Object self, final Object string, final int rad) { - return parseIntInternal(JSType.trimLeft(JSType.toString(string)), rad); - } - - /** - * ECMA 15.1.2.2 parseInt implementation specialized for no radix argument - * - * @param self self reference - * @param string string to parse - * - * @return numeric type representing string contents as an int - */ - public static double parseInt(final Object self, final Object string) { - return parseIntInternal(JSType.trimLeft(JSType.toString(string)), 0); - } - - private static double parseIntInternal(final String str, final int rad) { - final int length = str.length(); - int radix = rad; - - // empty string is not valid - if (length == 0) { - return Double.NaN; - } - - boolean negative = false; - int idx = 0; - - // checking for the sign character - final char firstChar = str.charAt(idx); - if (firstChar < '0') { - // Possible leading "+" or "-" - if (firstChar == '-') { - negative = true; - } else if (firstChar != '+') { - return Double.NaN; - } - // skip the sign character - idx++; - } - - boolean stripPrefix = true; - - if (radix != 0) { - if (radix < 2 || radix > 36) { - return Double.NaN; - } - if (radix != 16) { - stripPrefix = false; - } - } else { - // default radix - radix = 10; - } - // strip "0x" or "0X" and treat radix as 16 - if (stripPrefix && ((idx + 1) < length)) { - final char c1 = str.charAt(idx); - final char c2 = str.charAt(idx + 1); - if (c1 == '0' && (c2 == 'x' || c2 == 'X')) { - radix = 16; - // skip "0x" or "0X" - idx += 2; - } - } - - double result = 0.0; - int digit; - // we should see at least one valid digit - boolean entered = false; - while (idx < length) { - digit = fastDigit(str.charAt(idx++), radix); - if (digit < 0) { - break; - } - // we have seen at least one valid digit in the specified radix - entered = true; - result *= radix; - result += digit; - } - - return entered ? (negative ? -result : result) : Double.NaN; - } - - /** - * ECMA 15.1.2.3 parseFloat implementation - * - * @param self self reference - * @param string string to parse - * - * @return numeric type representing string contents - */ - public static double parseFloat(final Object self, final Object string) { - final String str = JSType.trimLeft(JSType.toString(string)); - final int length = str.length(); - - // empty string is not valid - if (length == 0) { - return Double.NaN; - } - - int start = 0; - boolean negative = false; - char ch = str.charAt(0); - - if (ch == '-') { - start++; - negative = true; - } else if (ch == '+') { - start++; - } else if (ch == 'N') { - if (str.startsWith("NaN")) { - return Double.NaN; - } - } - - if (start == length) { - // just the sign character - return Double.NaN; - } - - ch = str.charAt(start); - if (ch == 'I') { - if (str.substring(start).startsWith("Infinity")) { - return negative? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; - } - } - - boolean dotSeen = false; - boolean exponentOk = false; - int exponentOffset = -1; - int end; - -loop: - for (end = start; end < length; end++) { - ch = str.charAt(end); - - switch (ch) { - case '.': - // dot allowed only once - if (exponentOffset != -1 || dotSeen) { - break loop; - } - dotSeen = true; - break; - - case 'e': - case 'E': - // 'e'/'E' allow only once - if (exponentOffset != -1) { - break loop; - } - exponentOffset = end; - break; - - case '+': - case '-': - // Sign of the exponent. But allowed only if the - // previous char in the string was 'e' or 'E'. - if (exponentOffset != end - 1) { - break loop; - } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (exponentOffset != -1) { - // seeing digit after 'e' or 'E' - exponentOk = true; - } - break; - - default: // ignore garbage at the end - break loop; - } - } - - // ignore 'e'/'E' followed by '+/-' if not real exponent found - if (exponentOffset != -1 && !exponentOk) { - end = exponentOffset; - } - - if (start == end) { - return Double.NaN; - } - - try { - final double result = Double.valueOf(str.substring(start, end)); - return negative ? -result : result; - } catch (final NumberFormatException e) { - return Double.NaN; - } - } - - /** - * ECMA 15.1.2.4, isNaN implementation - * - * @param self self reference - * @param number number to check - * - * @return true if number is NaN - */ - public static boolean isNaN(final Object self, final Object number) { - return Double.isNaN(JSType.toNumber(number)); - } - - /** - * ECMA 15.1.2.5, isFinite implementation - * - * @param self self reference - * @param number number to check - * - * @return true if number is infinite - */ - public static boolean isFinite(final Object self, final Object number) { - final double value = JSType.toNumber(number); - return ! (Double.isInfinite(value) || Double.isNaN(value)); - } - - - /** - * ECMA 15.1.3.3, encodeURI implementation - * - * @param self self reference - * @param uri URI to encode - * - * @return encoded URI - */ - public static Object encodeURI(final Object self, final Object uri) { - return URIUtils.encodeURI(self, JSType.toString(uri)); - } - - /** - * ECMA 15.1.3.4, encodeURIComponent implementation - * - * @param self self reference - * @param uri URI component to encode - * - * @return encoded URIComponent - */ - public static Object encodeURIComponent(final Object self, final Object uri) { - return URIUtils.encodeURIComponent(self, JSType.toString(uri)); - } - - /** - * ECMA 15.1.3.1, decodeURI implementation - * - * @param self self reference - * @param uri URI to decode - * - * @return decoded URI - */ - public static Object decodeURI(final Object self, final Object uri) { - return URIUtils.decodeURI(self, JSType.toString(uri)); - } - - /** - * ECMA 15.1.3.2, decodeURIComponent implementation - * - * @param self self reference - * @param uri URI component to encode - * - * @return decoded URI - */ - public static Object decodeURIComponent(final Object self, final Object uri) { - return URIUtils.decodeURIComponent(self, JSType.toString(uri)); - } - - /** - * ECMA B.2.1, escape implementation - * - * @param self self reference - * @param string string to escape - * - * @return escaped string - */ - public static String escape(final Object self, final Object string) { - final String str = JSType.toString(string); - final int length = str.length(); - - if (length == 0) { - return str; - } - - final StringBuilder sb = new StringBuilder(); - for (int k = 0; k < length; k++) { - final char ch = str.charAt(k); - if (UNESCAPED.indexOf(ch) != -1) { - sb.append(ch); - } else if (ch < 256) { - sb.append('%'); - if (ch < 16) { - sb.append('0'); - } - sb.append(Integer.toHexString(ch).toUpperCase(Locale.ENGLISH)); - } else { - sb.append("%u"); - if (ch < 4096) { - sb.append('0'); - } - sb.append(Integer.toHexString(ch).toUpperCase(Locale.ENGLISH)); - } - } - - return sb.toString(); - } - - /** - * ECMA B.2.2, unescape implementation - * - * @param self self reference - * @param string string to unescape - * - * @return unescaped string - */ - public static String unescape(final Object self, final Object string) { - final String str = JSType.toString(string); - final int length = str.length(); - - if (length == 0) { - return str; - } - - final StringBuilder sb = new StringBuilder(); - for (int k = 0; k < length; k++) { - char ch = str.charAt(k); - if (ch != '%') { - sb.append(ch); - } else { - if (k < (length - 5)) { - if (str.charAt(k + 1) == 'u') { - try { - ch = (char) Integer.parseInt(str.substring(k + 2, k + 6), 16); - sb.append(ch); - k += 5; - continue; - } catch (final NumberFormatException e) { - //ignored - } - } - } - - if (k < (length - 2)) { - try { - ch = (char) Integer.parseInt(str.substring(k + 1, k + 3), 16); - sb.append(ch); - k += 2; - continue; - } catch (final NumberFormatException e) { - //ignored - } - } - - // everything fails - sb.append(ch); - } - } - - return sb.toString(); - } - - - /** - * ECMA 15.3.4 Properties of the Function Prototype Object. - * The Function prototype object is itself a Function object - * (its [[Class]] is "Function") that, when invoked, accepts - * any arguments and returns undefined. This method is used to - * implement that anonymous function. - * - * @param self self reference - * - * @return undefined - */ - public static Object anonymous(final Object self) { - return ScriptRuntime.UNDEFINED; - } - - private static int fastDigit(final int ch, final int radix) { - int n = -1; - if (ch >= '0' && ch <= '9') { - n = ch - '0'; - } else if (radix > 10) { - if (ch >= 'a' && ch <= 'z') { - n = ch - 'a' + 10; - } else if (ch >= 'A' && ch <= 'Z') { - n = ch - 'A' + 10; - } - } - return n < radix ? n : -1; - } - - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { - return MH.findStatic(MethodHandles.lookup(), GlobalFunctions.class, name, MH.type(rtype, types)); - } -}