Thu, 24 Jan 2013 14:55:57 +0100
8006408: Clean up and specialize NativeString
Reviewed-by: jlaskey, lagergren
src/jdk/nashorn/internal/objects/NativeString.java | file | annotate | diff | comparison | revisions | |
test/examples/string-micro.js | file | annotate | diff | comparison | revisions |
1.1 --- a/src/jdk/nashorn/internal/objects/NativeString.java Thu Jan 24 17:49:03 2013 +0530 1.2 +++ b/src/jdk/nashorn/internal/objects/NativeString.java Thu Jan 24 14:55:57 2013 +0100 1.3 @@ -36,6 +36,7 @@ 1.4 import java.text.Collator; 1.5 import java.util.ArrayList; 1.6 import java.util.Arrays; 1.7 +import java.util.LinkedList; 1.8 import java.util.List; 1.9 import java.util.regex.Pattern; 1.10 import jdk.nashorn.internal.objects.annotations.Attribute; 1.11 @@ -428,17 +429,30 @@ 1.12 */ 1.13 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.14 public static Object charAt(final Object self, final Object pos) { 1.15 - try { 1.16 - return String.valueOf(((String)self).charAt(((Number)pos).intValue())); 1.17 - } catch (final ClassCastException | IndexOutOfBoundsException | NullPointerException e) { 1.18 - Global.checkObjectCoercible(self); 1.19 - final String str = JSType.toString(self); 1.20 - final int at = JSType.toInteger(pos); 1.21 - if (at < 0 || at >= str.length()) { 1.22 - return ""; 1.23 - } 1.24 - return String.valueOf(str.charAt(at)); 1.25 - } 1.26 + return charAt(self, JSType.toInteger(pos)); 1.27 + } 1.28 + 1.29 + /** 1.30 + * ECMA 15.5.4.4 String.prototype.charAt (pos) - specialized version for double position 1.31 + * @param self self reference 1.32 + * @param pos position in string 1.33 + * @return string representing the char at the given position 1.34 + */ 1.35 + @SpecializedFunction 1.36 + public static String charAt(final Object self, final double pos) { 1.37 + return charAt(self, (int)pos); 1.38 + } 1.39 + 1.40 + /** 1.41 + * ECMA 15.5.4.4 String.prototype.charAt (pos) - specialized version for int position 1.42 + * @param self self reference 1.43 + * @param pos position in string 1.44 + * @return string representing the char at the given position 1.45 + */ 1.46 + @SpecializedFunction 1.47 + public static String charAt(final Object self, final int pos) { 1.48 + final String str = checkObjectToString(self); 1.49 + return (pos < 0 || pos >= str.length()) ? "" : String.valueOf(str.charAt(pos)); 1.50 } 1.51 1.52 /** 1.53 @@ -449,18 +463,30 @@ 1.54 */ 1.55 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.56 public static Object charCodeAt(final Object self, final Object pos) { 1.57 - try { 1.58 - return (int)((String)self).charAt(((Number)pos).intValue()); 1.59 - } catch (final ClassCastException | IndexOutOfBoundsException | NullPointerException e) { 1.60 - Global.checkObjectCoercible(self); 1.61 - final String str = JSType.toString(self); 1.62 - final int at = JSType.toInteger(pos); 1.63 - if (at < 0 || at >= str.length()) { 1.64 - return Double.NaN; 1.65 - } 1.66 + return charCodeAt(self, JSType.toInteger(pos)); 1.67 + } 1.68 1.69 - return JSType.toObject(str.charAt(at)); 1.70 - } 1.71 + /** 1.72 + * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for double position 1.73 + * @param self self reference 1.74 + * @param pos position in string 1.75 + * @return number representing charcode at position 1.76 + */ 1.77 + @SpecializedFunction 1.78 + public static double charCodeAt(final Object self, final double pos) { 1.79 + return charCodeAt(self, (int) pos); 1.80 + } 1.81 + 1.82 + /** 1.83 + * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for int position 1.84 + * @param self self reference 1.85 + * @param pos position in string 1.86 + * @return number representing charcode at position 1.87 + */ 1.88 + @SpecializedFunction 1.89 + public static double charCodeAt(final Object self, final int pos) { 1.90 + final String str = checkObjectToString(self); 1.91 + return (pos < 0 || pos >= str.length()) ? Double.NaN : str.charAt(pos); 1.92 } 1.93 1.94 /** 1.95 @@ -471,14 +497,13 @@ 1.96 */ 1.97 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1.98 public static Object concat(final Object self, final Object... args) { 1.99 - Global.checkObjectCoercible(self); 1.100 - final StringBuilder sb = new StringBuilder(JSType.toString(self)); 1.101 + CharSequence cs = checkObjectToString(self); 1.102 if (args != null) { 1.103 for (final Object obj : args) { 1.104 - sb.append(JSType.toString(obj)); 1.105 + cs = new ConsString(cs, JSType.toCharSequence(obj)); 1.106 } 1.107 } 1.108 - return sb.toString(); 1.109 + return cs; 1.110 } 1.111 1.112 /** 1.113 @@ -490,12 +515,43 @@ 1.114 */ 1.115 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1.116 public static Object indexOf(final Object self, final Object search, final Object pos) { 1.117 - try { 1.118 - return ((String)self).indexOf((String)search, ((Number)pos).intValue()); //assuming that the conversions really mean "toInteger" and not "toInt32" this is ok. 1.119 - } catch (final ClassCastException | IndexOutOfBoundsException | NullPointerException e) { 1.120 - Global.checkObjectCoercible(self); 1.121 - return JSType.toString(self).indexOf(JSType.toString(search), JSType.toInteger(pos)); 1.122 - } 1.123 + final String str = checkObjectToString(self); 1.124 + return str.indexOf(JSType.toString(search), JSType.toInteger(pos)); 1.125 + } 1.126 + 1.127 + /** 1.128 + * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for no position parameter 1.129 + * @param self self reference 1.130 + * @param search string to search for 1.131 + * @return position of first match or -1 1.132 + */ 1.133 + @SpecializedFunction 1.134 + public static int indexOf(final Object self, final Object search) { 1.135 + return indexOf(self, search, 0); 1.136 + } 1.137 + 1.138 + /** 1.139 + * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for double position parameter 1.140 + * @param self self reference 1.141 + * @param search string to search for 1.142 + * @param pos position to start search 1.143 + * @return position of first match or -1 1.144 + */ 1.145 + @SpecializedFunction 1.146 + public static int indexOf(final Object self, final Object search, final double pos) { 1.147 + return indexOf(self, search, (int) pos); 1.148 + } 1.149 + 1.150 + /** 1.151 + * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for int position parameter 1.152 + * @param self self reference 1.153 + * @param search string to search for 1.154 + * @param pos position to start search 1.155 + * @return position of first match or -1 1.156 + */ 1.157 + @SpecializedFunction 1.158 + public static int indexOf(final Object self, final Object search, final int pos) { 1.159 + return checkObjectToString(self).indexOf(JSType.toString(search), pos); 1.160 } 1.161 1.162 /** 1.163 @@ -507,9 +563,8 @@ 1.164 */ 1.165 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1.166 public static Object lastIndexOf(final Object self, final Object search, final Object pos) { 1.167 - Global.checkObjectCoercible(self); 1.168 1.169 - final String str = JSType.toString(self); 1.170 + final String str = checkObjectToString(self); 1.171 final String searchStr = JSType.toString(search); 1.172 1.173 int from; 1.174 @@ -532,9 +587,8 @@ 1.175 */ 1.176 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.177 public static Object localeCompare(final Object self, final Object that) { 1.178 - Global.checkObjectCoercible(self); 1.179 1.180 - final String str = JSType.toString(self); 1.181 + final String str = checkObjectToString(self); 1.182 final Collator collator = Collator.getInstance(Global.getThisContext().getLocale()); 1.183 1.184 collator.setStrength(Collator.IDENTICAL); 1.185 @@ -551,9 +605,8 @@ 1.186 */ 1.187 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.188 public static Object match(final Object self, final Object regexp) { 1.189 - Global.checkObjectCoercible(self); 1.190 1.191 - final String str = JSType.toString(self); 1.192 + final String str = checkObjectToString(self); 1.193 1.194 NativeRegExp nativeRegExp; 1.195 if (regexp == UNDEFINED) { 1.196 @@ -599,9 +652,8 @@ 1.197 */ 1.198 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.199 public static Object replace(final Object self, final Object string, final Object replacement) { 1.200 - Global.checkObjectCoercible(self); 1.201 1.202 - final String str = JSType.toString(self); 1.203 + final String str = checkObjectToString(self); 1.204 1.205 final NativeRegExp nativeRegExp; 1.206 if (string instanceof NativeRegExp) { 1.207 @@ -626,9 +678,8 @@ 1.208 */ 1.209 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.210 public static Object search(final Object self, final Object string) { 1.211 - Global.checkObjectCoercible(self); 1.212 1.213 - final String str = JSType.toString(self); 1.214 + final String str = checkObjectToString(self); 1.215 final NativeRegExp nativeRegExp = Global.toRegExp(string == UNDEFINED ? "" : string); 1.216 1.217 return nativeRegExp.search(str); 1.218 @@ -644,30 +695,70 @@ 1.219 */ 1.220 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.221 public static Object slice(final Object self, final Object start, final Object end) { 1.222 - Global.checkObjectCoercible(self); 1.223 1.224 - final String str = JSType.toString(self); 1.225 - final int len = str.length(); 1.226 - final int intStart = JSType.toInteger(start); 1.227 - final int intEnd = (end == UNDEFINED) ? len : JSType.toInteger(end); 1.228 + final String str = checkObjectToString(self); 1.229 + if (end == UNDEFINED) { 1.230 + return slice(str, JSType.toInteger(start)); 1.231 + } 1.232 + return slice(str, JSType.toInteger(start), JSType.toInteger(end)); 1.233 + } 1.234 1.235 - int from; 1.236 + /** 1.237 + * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for single int parameter 1.238 + * 1.239 + * @param self self reference 1.240 + * @param start start position for slice 1.241 + * @return sliced out substring 1.242 + */ 1.243 + @SpecializedFunction 1.244 + public static Object slice(final Object self, final int start) { 1.245 + final String str = checkObjectToString(self); 1.246 + final int from = (start < 0) ? Math.max(str.length() + start, 0) : Math.min(start, str.length()); 1.247 1.248 - if (intStart < 0) { 1.249 - from = Math.max(len + intStart, 0); 1.250 - } else { 1.251 - from = Math.min(intStart, len); 1.252 - } 1.253 + return str.substring(from); 1.254 + } 1.255 1.256 - int to; 1.257 + /** 1.258 + * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for single double parameter 1.259 + * 1.260 + * @param self self reference 1.261 + * @param start start position for slice 1.262 + * @return sliced out substring 1.263 + */ 1.264 + @SpecializedFunction 1.265 + public static Object slice(final Object self, final double start) { 1.266 + return slice(self, (int)start); 1.267 + } 1.268 1.269 - if (intEnd < 0) { 1.270 - to = Math.max(len + intEnd,0); 1.271 - } else { 1.272 - to = Math.min(intEnd, len); 1.273 - } 1.274 + /** 1.275 + * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for two int parameters 1.276 + * 1.277 + * @param self self reference 1.278 + * @param start start position for slice 1.279 + * @return sliced out substring 1.280 + */ 1.281 + @SpecializedFunction 1.282 + public static Object slice(final Object self, final int start, final int end) { 1.283 1.284 - return str.substring(Math.min(from, to), to); 1.285 + final String str = checkObjectToString(self); 1.286 + final int len = str.length(); 1.287 + 1.288 + final int from = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len); 1.289 + final int to = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len); 1.290 + 1.291 + return str.substring(Math.min(from, to), to); 1.292 + } 1.293 + 1.294 + /** 1.295 + * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for two double parameters 1.296 + * 1.297 + * @param self self reference 1.298 + * @param start start position for slice 1.299 + * @return sliced out substring 1.300 + */ 1.301 + @SpecializedFunction 1.302 + public static Object slice(final Object self, final double start, final double end) { 1.303 + return slice(self, (int)start, (int)end); 1.304 } 1.305 1.306 /** 1.307 @@ -680,9 +771,8 @@ 1.308 */ 1.309 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.310 public static Object split(final Object self, final Object separator, final Object limit) { 1.311 - Global.checkObjectCoercible(self); 1.312 1.313 - final String str = JSType.toString(self); 1.314 + final String str = checkObjectToString(self); 1.315 1.316 if (separator == UNDEFINED) { 1.317 return new NativeArray(new Object[]{str}); 1.318 @@ -694,9 +784,40 @@ 1.319 return ((NativeRegExp) separator).split(str, lim); 1.320 } 1.321 1.322 - // when separator is a string, it has to be treated as a 1.323 - // literal search string to be used for splitting. 1.324 - return new NativeRegExp(Pattern.compile(JSType.toString(separator), Pattern.LITERAL)).split(str, lim); 1.325 + // when separator is a string, it is treated as a literal search string to be used for splitting. 1.326 + return splitString(str, JSType.toString(separator), lim); 1.327 + } 1.328 + 1.329 + private static Object splitString(String str, String separator, long limit) { 1.330 + 1.331 + if (separator.equals("")) { 1.332 + Object[] array = new Object[str.length()]; 1.333 + for (int i = 0; i < array.length; i++) { 1.334 + array[i] = String.valueOf(str.charAt(i)); 1.335 + } 1.336 + return new NativeArray(array); 1.337 + } 1.338 + 1.339 + final List<String> elements = new LinkedList<>(); 1.340 + final int strLength = str.length(); 1.341 + final int sepLength = separator.length(); 1.342 + int pos = 0; 1.343 + int count = 0; 1.344 + 1.345 + while (pos < strLength && count < limit) { 1.346 + int found = str.indexOf(separator, pos); 1.347 + if (found == -1) { 1.348 + break; 1.349 + } 1.350 + elements.add(str.substring(pos, found)); 1.351 + count++; 1.352 + pos = found + sepLength; 1.353 + } 1.354 + if (pos <= strLength && count < limit) { 1.355 + elements.add(str.substring(pos)); 1.356 + } 1.357 + 1.358 + return new NativeArray(elements.toArray()); 1.359 } 1.360 1.361 /** 1.362 @@ -732,25 +853,78 @@ 1.363 */ 1.364 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.365 public static Object substring(final Object self, final Object start, final Object end) { 1.366 - Global.checkObjectCoercible(self); 1.367 1.368 - final String str = JSType.toString(self); 1.369 - final int len = str.length(); 1.370 - final int intStart = JSType.toInteger(start); 1.371 - final int intEnd = (end == UNDEFINED) ? len : JSType.toInteger(end); 1.372 - final int finalStart = Math.min((intStart < 0) ? 0 : intStart, len); 1.373 - final int finalEnd = Math.min((intEnd < 0) ? 0 : intEnd, len); 1.374 + final String str = checkObjectToString(self); 1.375 + if (end == UNDEFINED) { 1.376 + return substring(str, JSType.toInteger(start)); 1.377 + } 1.378 + return substring(str, JSType.toInteger(start), JSType.toInteger(end)); 1.379 + } 1.380 1.381 - int from, to; 1.382 + /** 1.383 + * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for int start parameter 1.384 + * 1.385 + * @param self self reference 1.386 + * @param start start position of substring 1.387 + * @return substring given start and end indexes 1.388 + */ 1.389 + @SpecializedFunction 1.390 + public static String substring(final Object self, final int start) { 1.391 + final String str = checkObjectToString(self); 1.392 + if (start < 0) { 1.393 + return str; 1.394 + } else if (start >= str.length()) { 1.395 + return ""; 1.396 + } else { 1.397 + return str.substring(start); 1.398 + } 1.399 + } 1.400 1.401 - if (finalStart < finalEnd) { 1.402 - from = finalStart; 1.403 - to = finalEnd; 1.404 + /** 1.405 + * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for double start parameter 1.406 + * 1.407 + * @param self self reference 1.408 + * @param start start position of substring 1.409 + * @return substring given start and end indexes 1.410 + */ 1.411 + @SpecializedFunction 1.412 + public static String substring(final Object self, final double start) { 1.413 + return substring(self, (int)start); 1.414 + } 1.415 + 1.416 + /** 1.417 + * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for int start and end parameters 1.418 + * 1.419 + * @param self self reference 1.420 + * @param start start position of substring 1.421 + * @param end end position of substring 1.422 + * @return substring given start and end indexes 1.423 + */ 1.424 + @SpecializedFunction 1.425 + public static String substring(final Object self, final int start, final int end) { 1.426 + final String str = checkObjectToString(self); 1.427 + final int len = str.length(); 1.428 + final int validStart = start < 0 ? 0 : (start > len ? len : start); 1.429 + final int validEnd = end < 0 ? 0 : (end > len ? len : end); 1.430 + 1.431 + if (validStart < validEnd) { 1.432 + return str.substring(validStart, validEnd); 1.433 } else { 1.434 - from = finalEnd; 1.435 - to = finalStart; 1.436 + return str.substring(validEnd, validStart); 1.437 } 1.438 - return str.substring(from, to); 1.439 + } 1.440 + 1.441 + /** 1.442 + * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for double start and end parameters 1.443 + * 1.444 + * @param self self reference 1.445 + * @param start start position of substring 1.446 + * @param end end position of substring 1.447 + * @return substring given start and end indexes 1.448 + */ 1.449 + @SpecializedFunction 1.450 + public static String substring(final Object self, final double start, final double end) { 1.451 + return substring(self, (int)start, (int)end); 1.452 } 1.453 1.454 /** 1.455 @@ -760,8 +934,7 @@ 1.456 */ 1.457 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.458 public static Object toLowerCase(final Object self) { 1.459 - Global.checkObjectCoercible(self); 1.460 - return JSType.toString(self).toLowerCase(); 1.461 + return checkObjectToString(self).toLowerCase(); 1.462 } 1.463 1.464 /** 1.465 @@ -771,8 +944,7 @@ 1.466 */ 1.467 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.468 public static Object toLocaleLowerCase(final Object self) { 1.469 - Global.checkObjectCoercible(self); 1.470 - return JSType.toString(self).toLowerCase(Global.getThisContext().getLocale()); 1.471 + return checkObjectToString(self).toLowerCase(Global.getThisContext().getLocale()); 1.472 } 1.473 1.474 /** 1.475 @@ -782,8 +954,7 @@ 1.476 */ 1.477 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.478 public static Object toUpperCase(final Object self) { 1.479 - Global.checkObjectCoercible(self); 1.480 - return JSType.toString(self).toUpperCase(); 1.481 + return checkObjectToString(self).toUpperCase(); 1.482 } 1.483 1.484 /** 1.485 @@ -793,8 +964,7 @@ 1.486 */ 1.487 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.488 public static Object toLocaleUpperCase(final Object self) { 1.489 - Global.checkObjectCoercible(self); 1.490 - return JSType.toString(self).toUpperCase(Global.getThisContext().getLocale()); 1.491 + return checkObjectToString(self).toUpperCase(Global.getThisContext().getLocale()); 1.492 } 1.493 1.494 /** 1.495 @@ -804,12 +974,11 @@ 1.496 */ 1.497 @Function(attributes = Attribute.NOT_ENUMERABLE) 1.498 public static Object trim(final Object self) { 1.499 - Global.checkObjectCoercible(self); 1.500 1.501 - final String str = JSType.toString(self); 1.502 - 1.503 + final String str = checkObjectToString(self); 1.504 + final int len = str.length(); 1.505 int start = 0; 1.506 - int end = str.length() - 1; 1.507 + int end = len - 1; 1.508 1.509 while (start <= end && Lexer.isJSWhitespace(str.charAt(start))) { 1.510 start++; 1.511 @@ -818,7 +987,7 @@ 1.512 end--; 1.513 } 1.514 1.515 - return str.substring(start, end + 1); 1.516 + return start == 0 && end + 1 == len ? str : str.substring(start, end + 1); 1.517 } 1.518 1.519 private static Object newObj(final Object self, final CharSequence str) { 1.520 @@ -860,7 +1029,22 @@ 1.521 return newObj ? newObj(self, "") : ""; 1.522 } 1.523 1.524 - //TODO - why is there no String with one String arg constructor? 1.525 + /** 1.526 + * ECMA 15.5.2.1 new String ( [ value ] ) - special version with one arg 1.527 + * 1.528 + * Constructor 1.529 + * 1.530 + * @param newObj is this constructor invoked with the new operator 1.531 + * @param self self reference 1.532 + * @param arg argument 1.533 + * 1.534 + * @return new NativeString (arg) 1.535 + */ 1.536 + @SpecializedConstructor 1.537 + public static Object constructor(final boolean newObj, final Object self, final Object arg) { 1.538 + final CharSequence cs = JSType.toCharSequence(arg); 1.539 + return newObj ? newObj(self, cs) : cs; 1.540 + } 1.541 1.542 /** 1.543 * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg 1.544 @@ -924,6 +1108,23 @@ 1.545 } 1.546 } 1.547 1.548 + /** 1.549 + * Combines ECMA 9.10 CheckObjectCoercible and ECMA 9.8 ToString with a shortcut for strings. 1.550 + * 1.551 + * @param self the object 1.552 + * @return the object as string 1.553 + */ 1.554 + private static String checkObjectToString(final Object self) { 1.555 + if (self instanceof String) { 1.556 + return (String)self; 1.557 + } else if (self instanceof ConsString) { 1.558 + return self.toString(); 1.559 + } else { 1.560 + Global.checkObjectCoercible(self); 1.561 + return JSType.toString(self); 1.562 + } 1.563 + } 1.564 + 1.565 private boolean isValid(final int key) { 1.566 return key >= 0 && key < value.length(); 1.567 }
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/examples/string-micro.js Thu Jan 24 14:55:57 2013 +0100 2.3 @@ -0,0 +1,179 @@ 2.4 +/* 2.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * 2.7 + * Redistribution and use in source and binary forms, with or without 2.8 + * modification, are permitted provided that the following conditions 2.9 + * are met: 2.10 + * 2.11 + * - Redistributions of source code must retain the above copyright 2.12 + * notice, this list of conditions and the following disclaimer. 2.13 + * 2.14 + * - Redistributions in binary form must reproduce the above copyright 2.15 + * notice, this list of conditions and the following disclaimer in the 2.16 + * documentation and/or other materials provided with the distribution. 2.17 + * 2.18 + * - Neither the name of Oracle nor the names of its 2.19 + * contributors may be used to endorse or promote products derived 2.20 + * from this software without specific prior written permission. 2.21 + * 2.22 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 2.23 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 2.24 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2.25 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 2.26 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2.27 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2.28 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2.29 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2.30 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2.31 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2.32 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2.33 + */ 2.34 + 2.35 + 2.36 +var str = "The quick gray nashorn jumps over the lazy zebra."; 2.37 + 2.38 +function bench(name, func) { 2.39 + var start = Date.now(); 2.40 + for (var iter = 0; iter < 5000000; iter++) { 2.41 + func(); 2.42 + } 2.43 + print((Date.now() - start) + "\t" + name); 2.44 +} 2.45 + 2.46 +bench("[]", function() { 2.47 + str[0]; 2.48 + str[1]; 2.49 + str[2]; 2.50 +}); 2.51 + 2.52 +bench("fromCharCode", function() { 2.53 + String.fromCharCode(97); 2.54 + String.fromCharCode(98); 2.55 + String.fromCharCode(99); 2.56 +}); 2.57 + 2.58 +bench("charAt 1", function() { 2.59 + str.charAt(0); 2.60 + str.charAt(1); 2.61 + str.charAt(2); 2.62 +}); 2.63 + 2.64 +bench("charAt 2", function() { 2.65 + str.charAt(100); 2.66 + str.charAt(-1); 2.67 +}); 2.68 + 2.69 +bench("charCodeAt 1", function() { 2.70 + str.charCodeAt(0); 2.71 + str.charCodeAt(1); 2.72 + str.charCodeAt(2); 2.73 +}); 2.74 + 2.75 +bench("charCodeAt 2", function() { 2.76 + str.charCodeAt(100); 2.77 + str.charCodeAt(-1); 2.78 +}); 2.79 + 2.80 +bench("indexOf 1", function() { 2.81 + str.indexOf("T"); 2.82 + str.indexOf("h"); 2.83 + str.indexOf("e"); 2.84 +}); 2.85 + 2.86 +bench("indexOf 2", function() { 2.87 + str.indexOf("T", 0); 2.88 + str.indexOf("h", 1); 2.89 + str.indexOf("e", 2); 2.90 +}); 2.91 + 2.92 +bench("lastIndexOf", function() { 2.93 + str.indexOf("a"); 2.94 + str.indexOf("r"); 2.95 + str.indexOf("b"); 2.96 +}); 2.97 + 2.98 +bench("slice", function() { 2.99 + str.slice(5); 2.100 + str.slice(5); 2.101 + str.slice(5); 2.102 +}); 2.103 + 2.104 +bench("split 1", function() { 2.105 + str.split(); 2.106 +}); 2.107 + 2.108 +bench("split 2", function() { 2.109 + str.split("foo"); 2.110 +}); 2.111 + 2.112 +bench("split 3", function() { 2.113 + str.split(/foo/); 2.114 +}); 2.115 + 2.116 +bench("substring 1", function() { 2.117 + str.substring(0); 2.118 + str.substring(0); 2.119 + str.substring(0); 2.120 +}); 2.121 + 2.122 +bench("substring 2", function() { 2.123 + str.substring(0, 5); 2.124 + str.substring(0, 5); 2.125 + str.substring(0, 5); 2.126 +}); 2.127 + 2.128 +bench("substr", function() { 2.129 + str.substr(0); 2.130 + str.substr(0); 2.131 + str.substr(0); 2.132 +}); 2.133 + 2.134 +bench("slice", function() { 2.135 + str.slice(0); 2.136 + str.slice(0); 2.137 + str.slice(0); 2.138 +}); 2.139 + 2.140 +bench("concat", function() { 2.141 + str.concat(str); 2.142 + str.concat(str); 2.143 + str.concat(str); 2.144 +}); 2.145 + 2.146 +bench("trim", function() { 2.147 + str.trim(); 2.148 + str.trim(); 2.149 + str.trim(); 2.150 +}); 2.151 + 2.152 +bench("toUpperCase", function() { 2.153 + str.toUpperCase(); 2.154 +}); 2.155 + 2.156 +bench("toLowerCase", function() { 2.157 + str.toLowerCase(); 2.158 +}); 2.159 + 2.160 +bench("valueOf", function() { 2.161 + str.valueOf(); 2.162 + str.valueOf(); 2.163 + str.valueOf(); 2.164 +}); 2.165 + 2.166 +bench("toString", function() { 2.167 + str.toString(); 2.168 + str.toString(); 2.169 + str.toString(); 2.170 +}); 2.171 + 2.172 +bench("String", function() { 2.173 + String(str); 2.174 + String(str); 2.175 + String(str); 2.176 +}); 2.177 + 2.178 +bench("new String", function() { 2.179 + new String(str); 2.180 + new String(str); 2.181 + new String(str); 2.182 +});