src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java

Sat, 16 Nov 2013 00:23:46 +0100

author
hannesw
date
Sat, 16 Nov 2013 00:23:46 +0100
changeset 678
a165c0fb5be6
parent 482
0ad00ae4fec6
child 952
6d5471a497fb
child 1070
094f0d95ef78
permissions
-rw-r--r--

8028210: Missing conversions on array index expression
Reviewed-by: attila, jlaskey, lagergren

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.runtime.arrays;
jlaskey@3 27
jlaskey@3 28 import jdk.nashorn.internal.runtime.ConsString;
jlaskey@3 29 import jdk.nashorn.internal.runtime.JSType;
hannesw@678 30 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 31
jlaskey@3 32 /**
jlaskey@3 33 * Array index computation helpers. that both throw exceptions or return
jlaskey@3 34 * invalid values.
jlaskey@3 35 *
jlaskey@3 36 */
jlaskey@3 37 public final class ArrayIndex {
jlaskey@3 38
jlaskey@3 39 private static final int INVALID_ARRAY_INDEX = -1;
jlaskey@3 40 private static final long MAX_ARRAY_INDEX = 0xfffffffeL;
jlaskey@3 41
jlaskey@3 42 private ArrayIndex() {
jlaskey@3 43 }
jlaskey@3 44
jlaskey@3 45 /**
jlaskey@3 46 * Fast conversion of non-negative integer string to long.
jlaskey@3 47 * @param key Key as a string.
hannesw@334 48 * @return long value of string or {@code -1} if string does not represent a valid index.
jlaskey@3 49 */
jlaskey@3 50 private static long fromString(final String key) {
jlaskey@3 51 long value = 0;
jlaskey@3 52 final int length = key.length();
jlaskey@3 53
jlaskey@3 54 // Check for empty string or leading 0
jlaskey@3 55 if (length == 0 || (length > 1 && key.charAt(0) == '0')) {
hannesw@334 56 return INVALID_ARRAY_INDEX;
jlaskey@3 57 }
jlaskey@3 58
jlaskey@3 59 // Fast toNumber.
jlaskey@3 60 for (int i = 0; i < length; i++) {
jlaskey@3 61 final char digit = key.charAt(i);
jlaskey@3 62
jlaskey@3 63 // If not a digit.
jlaskey@3 64 if (digit < '0' || digit > '9') {
hannesw@334 65 return INVALID_ARRAY_INDEX;
jlaskey@3 66 }
jlaskey@3 67
jlaskey@3 68 // Insert digit.
jlaskey@3 69 value = value * 10 + digit - '0';
jlaskey@3 70
jlaskey@3 71 // Check for overflow (need to catch before wrap around.)
jlaskey@3 72 if (value > MAX_ARRAY_INDEX) {
hannesw@334 73 return INVALID_ARRAY_INDEX;
jlaskey@3 74 }
jlaskey@3 75 }
jlaskey@3 76
jlaskey@3 77 return value;
jlaskey@3 78 }
jlaskey@3 79
jlaskey@3 80 /**
jlaskey@3 81 * Returns a valid array index in an int, if the object represents one. This
jlaskey@3 82 * routine needs to perform quickly since all keys are tested with it.
jlaskey@3 83 *
hannesw@678 84 * <p>The {@code key} parameter must be a JavaScript primitive type, i.e. one of
hannesw@678 85 * {@code String}, {@code Number}, {@code Boolean}, {@code null}, or {@code undefined}.
hannesw@678 86 * {@code ScriptObject} instances should be converted to primitive with
hannesw@678 87 * {@code String.class} hint before being passed to this method.</p>
hannesw@678 88 *
hannesw@678 89 * @param key key to check for array index.
hannesw@334 90 * @return the array index, or {@code -1} if {@code key} does not represent a valid index.
hannesw@334 91 * Note that negative return values other than {@code -1} are considered valid and can be converted to
hannesw@334 92 * the actual index using {@link #toLongIndex(int)}.
jlaskey@3 93 */
hannesw@334 94 public static int getArrayIndex(final Object key) {
jlaskey@228 95 if (key instanceof Integer) {
hannesw@334 96 return getArrayIndex(((Integer) key).intValue());
hannesw@678 97 } else if (key instanceof Double) {
hannesw@678 98 return getArrayIndex(((Double) key).doubleValue());
jlaskey@3 99 } else if (key instanceof String) {
hannesw@334 100 return (int)fromString((String) key);
hannesw@678 101 } else if (key instanceof Long) {
hannesw@678 102 return getArrayIndex(((Long) key).longValue());
jlaskey@3 103 } else if (key instanceof ConsString) {
jlaskey@3 104 return (int)fromString(key.toString());
jlaskey@3 105 }
jlaskey@3 106
hannesw@678 107 assert !(key instanceof ScriptObject);
hannesw@334 108 return INVALID_ARRAY_INDEX;
jlaskey@3 109 }
jlaskey@3 110
jlaskey@3 111 /**
hannesw@678 112 * Returns a valid array index in an int, if {@code key} represents one.
hannesw@678 113 *
hannesw@678 114 * @param key key to check
hannesw@678 115 * @return the array index, or {@code -1} if {@code key} is not a valid array index.
hannesw@678 116 */
hannesw@678 117 public static int getArrayIndex(final int key) {
hannesw@678 118 return (key >= 0) ? key : INVALID_ARRAY_INDEX;
hannesw@678 119 }
hannesw@678 120
hannesw@678 121 /**
hannesw@334 122 * Returns a valid array index in an int, if the long represents one.
jlaskey@3 123 *
jlaskey@3 124 * @param key key to check
hannesw@334 125 * @return the array index, or {@code -1} if long is not a valid array index.
hannesw@334 126 * Note that negative return values other than {@code -1} are considered valid and can be converted to
hannesw@334 127 * the actual index using {@link #toLongIndex(int)}.
jlaskey@3 128 */
hannesw@334 129 public static int getArrayIndex(final long key) {
jlaskey@3 130 if (key >= 0 && key <= MAX_ARRAY_INDEX) {
jlaskey@3 131 return (int)key;
jlaskey@3 132 }
jlaskey@3 133
hannesw@334 134 return INVALID_ARRAY_INDEX;
jlaskey@3 135 }
jlaskey@3 136
jlaskey@3 137
jlaskey@3 138 /**
hannesw@334 139 * Return a valid index for this double, if it represents one.
jlaskey@3 140 *
jlaskey@3 141 * Doubles that aren't representable exactly as longs/ints aren't working
jlaskey@3 142 * array indexes, however, array[1.1] === array["1.1"] in JavaScript.
jlaskey@3 143 *
jlaskey@3 144 * @param key the key to check
hannesw@334 145 * @return the array index this double represents or {@code -1} if this isn't a valid index.
hannesw@334 146 * Note that negative return values other than {@code -1} are considered valid and can be converted to
hannesw@334 147 * the actual index using {@link #toLongIndex(int)}.
jlaskey@3 148 */
hannesw@334 149 public static int getArrayIndex(final double key) {
jlaskey@3 150 if (JSType.isRepresentableAsInt(key)) {
hannesw@678 151 return getArrayIndex((int) key);
jlaskey@3 152 } else if (JSType.isRepresentableAsLong(key)) {
hannesw@334 153 return getArrayIndex((long) key);
jlaskey@3 154 }
jlaskey@3 155
hannesw@334 156 return INVALID_ARRAY_INDEX;
jlaskey@3 157 }
jlaskey@3 158
hannesw@334 159
jlaskey@3 160 /**
hannesw@334 161 * Return a valid array index for this string, if it represents one.
jlaskey@3 162 *
jlaskey@3 163 * @param key the key to check
hannesw@334 164 * @return the array index this string represents or {@code -1} if this isn't a valid index.
hannesw@334 165 * Note that negative return values other than {@code -1} are considered valid and can be converted to
hannesw@334 166 * the actual index using {@link #toLongIndex(int)}.
jlaskey@3 167 */
hannesw@334 168 public static int getArrayIndex(final String key) {
jlaskey@3 169 return (int)fromString(key);
jlaskey@3 170 }
jlaskey@3 171
jlaskey@3 172 /**
jlaskey@3 173 * Check whether an index is valid as an array index. This check only tests if
jlaskey@3 174 * it is the special "invalid array index" type, not if it is e.g. less than zero
jlaskey@3 175 * or corrupt in some other way
jlaskey@3 176 *
jlaskey@3 177 * @param index index to test
jlaskey@3 178 * @return true if {@code index} is not the special invalid array index type
jlaskey@3 179 */
jlaskey@3 180 public static boolean isValidArrayIndex(final int index) {
jlaskey@3 181 return index != INVALID_ARRAY_INDEX;
jlaskey@3 182 }
jlaskey@3 183
jlaskey@3 184 /**
jlaskey@3 185 * Convert an index to a long value. This basically amounts to ANDing it
jlaskey@3 186 * with {@link JSType#MAX_UINT}, as the maximum array index in JavaScript
hannesw@334 187 * is 0xfffffffe
jlaskey@3 188 *
jlaskey@3 189 * @param index index to convert to long form
jlaskey@3 190 * @return index as uint32 in a long
jlaskey@3 191 */
jlaskey@3 192 public static long toLongIndex(final int index) {
jlaskey@3 193 return index & JSType.MAX_UINT;
jlaskey@3 194 }
jlaskey@3 195
hannesw@678 196 /**
hannesw@678 197 * Convert an index to a key string. This is the same as calling {@link #toLongIndex(int)}
hannesw@678 198 * and converting the result to String.
hannesw@678 199 *
hannesw@678 200 * @param index index to convert
hannesw@678 201 * @return index as string
hannesw@678 202 */
hannesw@678 203 public static String toKey(final int index) {
hannesw@678 204 return Long.toString(index & JSType.MAX_UINT);
hannesw@678 205 }
hannesw@678 206
jlaskey@3 207 }
jlaskey@3 208

mercurial