NativeArray.java revision 1271:b506754c7d64
12341Scsgr/* 22341Scsgr * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 32341Scsgr * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 42341Scsgr * 52341Scsgr * This code is free software; you can redistribute it and/or modify it 62341Scsgr * under the terms of the GNU General Public License version 2 only, as 72341Scsgr * published by the Free Software Foundation. Oracle designates this 82341Scsgr * particular file as subject to the "Classpath" exception as provided 92341Scsgr * by Oracle in the LICENSE file that accompanied this code. 102341Scsgr * 112341Scsgr * This code is distributed in the hope that it will be useful, but WITHOUT 122341Scsgr * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132341Scsgr * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 142341Scsgr * version 2 for more details (a copy is included in the LICENSE file that 152341Scsgr * accompanied this code). 162341Scsgr * 172341Scsgr * You should have received a copy of the GNU General Public License version 182341Scsgr * 2 along with this work; if not, write to the Free Software Foundation, 192341Scsgr * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 202341Scsgr * 212341Scsgr * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 222341Scsgr * or visit www.oracle.com if you need additional information or have any 232341Scsgr * questions. 242341Scsgr */ 252341Scsgr 262341Scsgrpackage jdk.nashorn.internal.objects; 272341Scsgr 282341Scsgrimport static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; 292341Scsgrimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 30216560Scharnierimport static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE; 31216560Scharnierimport static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; 322341Scsgrimport static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 3331488Scharnierimport static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator; 342341Scsgrimport static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator; 3531488Scharnierimport static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; 362341Scsgr 3731488Scharnierimport java.lang.invoke.MethodHandle; 382341Scsgrimport java.util.ArrayList; 3931488Scharnierimport java.util.Arrays; 4090868Smikeimport java.util.Collections; 4131488Scharnierimport java.util.Comparator; 4231488Scharnierimport java.util.Iterator; 432341Scsgrimport java.util.List; 4431488Scharnierimport java.util.concurrent.Callable; 452341Scsgrimport jdk.internal.dynalink.CallSiteDescriptor; 4631488Scharnierimport jdk.internal.dynalink.linker.GuardedInvocation; 472341Scsgrimport jdk.internal.dynalink.linker.LinkRequest; 482341Scsgrimport jdk.nashorn.api.scripting.JSObject; 492341Scsgrimport jdk.nashorn.internal.objects.annotations.Attribute; 502341Scsgrimport jdk.nashorn.internal.objects.annotations.Constructor; 512341Scsgrimport jdk.nashorn.internal.objects.annotations.Function; 522341Scsgrimport jdk.nashorn.internal.objects.annotations.Getter; 532341Scsgrimport jdk.nashorn.internal.objects.annotations.ScriptClass; 5490336Simpimport jdk.nashorn.internal.objects.annotations.Setter; 5590336Simpimport jdk.nashorn.internal.objects.annotations.SpecializedFunction; 5690336Simpimport jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic; 5790336Simpimport jdk.nashorn.internal.objects.annotations.Where; 582341Scsgrimport jdk.nashorn.internal.runtime.Context; 592341Scsgrimport jdk.nashorn.internal.runtime.Debug; 602341Scsgrimport jdk.nashorn.internal.runtime.JSType; 612341Scsgrimport jdk.nashorn.internal.runtime.OptimisticBuiltins; 6231488Scharnierimport jdk.nashorn.internal.runtime.PropertyDescriptor; 6390336Simpimport jdk.nashorn.internal.runtime.PropertyMap; 642341Scsgrimport jdk.nashorn.internal.runtime.ScriptFunction; 652341Scsgrimport jdk.nashorn.internal.runtime.ScriptObject; 66141918Sstefanfimport jdk.nashorn.internal.runtime.ScriptRuntime; 67141918Sstefanfimport jdk.nashorn.internal.runtime.Undefined; 68100120Salfredimport jdk.nashorn.internal.runtime.arrays.ArrayData; 692341Scsgrimport jdk.nashorn.internal.runtime.arrays.ArrayIndex; 702341Scsgrimport jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; 712341Scsgrimport jdk.nashorn.internal.runtime.arrays.ContinuousArrayData; 7231488Scharnierimport jdk.nashorn.internal.runtime.arrays.IntElements; 7331488Scharnierimport jdk.nashorn.internal.runtime.arrays.IntOrLongElements; 742341Scsgrimport jdk.nashorn.internal.runtime.arrays.IteratorAction; 752341Scsgrimport jdk.nashorn.internal.runtime.arrays.NumericElements; 762341Scsgrimport jdk.nashorn.internal.runtime.linker.Bootstrap; 772341Scsgrimport jdk.nashorn.internal.runtime.linker.InvokeByName; 782341Scsgr 792341Scsgr/** 802341Scsgr * Runtime representation of a JavaScript array. NativeArray only holds numeric 812341Scsgr * keyed values. All other values are stored in spill. 822341Scsgr */ 832341Scsgr@ScriptClass("Array") 842341Scsgrpublic final class NativeArray extends ScriptObject implements OptimisticBuiltins { 852341Scsgr private static final Object JOIN = new Object(); 864659Sats private static final Object EVERY_CALLBACK_INVOKER = new Object(); 872341Scsgr private static final Object SOME_CALLBACK_INVOKER = new Object(); 882341Scsgr private static final Object FOREACH_CALLBACK_INVOKER = new Object(); 892341Scsgr private static final Object MAP_CALLBACK_INVOKER = new Object(); 908870Srgrimes private static final Object FILTER_CALLBACK_INVOKER = new Object(); 912341Scsgr private static final Object REDUCE_CALLBACK_INVOKER = new Object(); 922341Scsgr private static final Object CALL_CMP = new Object(); 932341Scsgr private static final Object TO_LOCALE_STRING = new Object(); 942341Scsgr 95100120Salfred /* 962341Scsgr * Constructors. 972341Scsgr */ 982341Scsgr NativeArray() { 992341Scsgr this(ArrayData.initialArray()); 10031488Scharnier } 10131488Scharnier 102100120Salfred NativeArray(final long length) { 103100120Salfred // TODO assert valid index in long before casting 104100120Salfred this(ArrayData.allocate((int)length)); 105100120Salfred } 106100120Salfred 107100120Salfred NativeArray(final int[] array) { 108100120Salfred this(ArrayData.allocate(array)); 109100120Salfred } 110100120Salfred 111100120Salfred NativeArray(final long[] array) { 112100120Salfred this(ArrayData.allocate(array)); 113100120Salfred } 114100120Salfred 115100120Salfred NativeArray(final double[] array) { 1162341Scsgr this(ArrayData.allocate(array)); 1172341Scsgr } 1182341Scsgr 11931488Scharnier NativeArray(final Object[] array) { 1202341Scsgr this(ArrayData.allocate(array.length)); 12131488Scharnier 1222341Scsgr ArrayData arrayData = this.getArray(); 12331488Scharnier 12490336Simp for (int index = 0; index < array.length; index++) { 12531488Scharnier final Object value = array[index]; 12631488Scharnier 12731488Scharnier if (value == ScriptRuntime.EMPTY) { 1282341Scsgr arrayData = arrayData.delete(index); 1292341Scsgr } else { 13090336Simp arrayData = arrayData.set(index, value, false); 13190336Simp } 1322341Scsgr } 1332341Scsgr 1342341Scsgr this.setArray(arrayData); 1352341Scsgr } 13690336Simp 137216560Scharnier NativeArray(final ArrayData arrayData) { 1382341Scsgr this(arrayData, Global.instance()); 1392341Scsgr } 1402341Scsgr 1412341Scsgr NativeArray(final ArrayData arrayData, final Global global) { 1422341Scsgr super(global.getArrayPrototype(), $nasgenmap$); 14390336Simp setArray(arrayData); 144216560Scharnier setIsArray(); 1452341Scsgr } 14632629Swpaul 14732629Swpaul @Override 1482341Scsgr protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 1492341Scsgr final GuardedInvocation inv = getArray().findFastGetMethod(getArray().getClass(), desc, request, operator); 1502341Scsgr if (inv != null) { 1512341Scsgr return inv; 1522341Scsgr } 1532341Scsgr return super.findGetMethod(desc, request, operator); 1542341Scsgr } 1552341Scsgr 1562341Scsgr @Override 1572341Scsgr protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { 1582341Scsgr final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request); 15932629Swpaul if (inv != null) { 1602341Scsgr return inv; 1612341Scsgr } 1622341Scsgr return super.findGetIndexMethod(desc, request); 16390336Simp } 1642341Scsgr 1652341Scsgr @Override 1662341Scsgr protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { 1672341Scsgr final GuardedInvocation inv = getArray().findFastSetIndexMethod(getArray().getClass(), desc, request); 1682341Scsgr if (inv != null) { 1692341Scsgr return inv; 1702341Scsgr } 1712341Scsgr 1722341Scsgr return super.findSetIndexMethod(desc, request); 1732341Scsgr } 17495658Sdes 1752341Scsgr private static InvokeByName getJOIN() { 1762341Scsgr return Global.instance().getInvokeByName(JOIN, 1772341Scsgr new Callable<InvokeByName>() { 1782341Scsgr @Override 1792341Scsgr public InvokeByName call() { 18032629Swpaul return new InvokeByName("join", ScriptObject.class); 1812341Scsgr } 1822341Scsgr }); 1832341Scsgr } 1842341Scsgr 1852341Scsgr private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class<?> rtype) { 1862341Scsgr return Global.instance().getDynamicInvoker(key, 18795658Sdes new Callable<MethodHandle>() { 18895658Sdes @Override 1892341Scsgr public MethodHandle call() { 1902341Scsgr return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class, 1912341Scsgr long.class, Object.class); 1922341Scsgr } 19395658Sdes }); 19495658Sdes } 1952341Scsgr 1962341Scsgr private static MethodHandle getEVERY_CALLBACK_INVOKER() { 19795658Sdes return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class); 19831488Scharnier } 1992341Scsgr 2002341Scsgr private static MethodHandle getSOME_CALLBACK_INVOKER() { 2012341Scsgr return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.class); 2022341Scsgr } 2032341Scsgr 2042341Scsgr private static MethodHandle getFOREACH_CALLBACK_INVOKER() { 205 return createIteratorCallbackInvoker(FOREACH_CALLBACK_INVOKER, void.class); 206 } 207 208 private static MethodHandle getMAP_CALLBACK_INVOKER() { 209 return createIteratorCallbackInvoker(MAP_CALLBACK_INVOKER, Object.class); 210 } 211 212 private static MethodHandle getFILTER_CALLBACK_INVOKER() { 213 return createIteratorCallbackInvoker(FILTER_CALLBACK_INVOKER, boolean.class); 214 } 215 216 private static MethodHandle getREDUCE_CALLBACK_INVOKER() { 217 return Global.instance().getDynamicInvoker(REDUCE_CALLBACK_INVOKER, 218 new Callable<MethodHandle>() { 219 @Override 220 public MethodHandle call() { 221 return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, 222 Undefined.class, Object.class, Object.class, long.class, Object.class); 223 } 224 }); 225 } 226 227 private static MethodHandle getCALL_CMP() { 228 return Global.instance().getDynamicInvoker(CALL_CMP, 229 new Callable<MethodHandle>() { 230 @Override 231 public MethodHandle call() { 232 return Bootstrap.createDynamicInvoker("dyn:call", double.class, 233 ScriptFunction.class, Object.class, Object.class, Object.class); 234 } 235 }); 236 } 237 238 private static InvokeByName getTO_LOCALE_STRING() { 239 return Global.instance().getInvokeByName(TO_LOCALE_STRING, 240 new Callable<InvokeByName>() { 241 @Override 242 public InvokeByName call() { 243 return new InvokeByName("toLocaleString", ScriptObject.class, String.class); 244 } 245 }); 246 } 247 248 // initialized by nasgen 249 private static PropertyMap $nasgenmap$; 250 251 @Override 252 public String getClassName() { 253 return "Array"; 254 } 255 256 @Override 257 public Object getLength() { 258 final long length = JSType.toUint32(getArray().length()); 259 if (length < Integer.MAX_VALUE) { 260 return (int)length; 261 } 262 return length; 263 } 264 265 private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) { 266 // Step 3a 267 if (!desc.has(VALUE)) { 268 return super.defineOwnProperty("length", desc, reject); 269 } 270 271 // Step 3b 272 final PropertyDescriptor newLenDesc = desc; 273 274 // Step 3c and 3d - get new length and convert to long 275 final long newLen = NativeArray.validLength(newLenDesc.getValue()); 276 277 // Step 3e 278 newLenDesc.setValue(newLen); 279 280 // Step 3f 281 // increasing array length - just need to set new length value (and attributes if any) and return 282 if (newLen >= oldLen) { 283 return super.defineOwnProperty("length", newLenDesc, reject); 284 } 285 286 // Step 3g 287 if (!oldLenDesc.isWritable()) { 288 if (reject) { 289 throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this)); 290 } 291 return false; 292 } 293 294 // Step 3h and 3i 295 final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable(); 296 if (!newWritable) { 297 newLenDesc.setWritable(true); 298 } 299 300 // Step 3j and 3k 301 final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject); 302 if (!succeeded) { 303 return false; 304 } 305 306 // Step 3l 307 // make sure that length is set till the point we can delete the old elements 308 long o = oldLen; 309 while (newLen < o) { 310 o--; 311 final boolean deleteSucceeded = delete(o, false); 312 if (!deleteSucceeded) { 313 newLenDesc.setValue(o + 1); 314 if (!newWritable) { 315 newLenDesc.setWritable(false); 316 } 317 super.defineOwnProperty("length", newLenDesc, false); 318 if (reject) { 319 throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this)); 320 } 321 return false; 322 } 323 } 324 325 // Step 3m 326 if (!newWritable) { 327 // make 'length' property not writable 328 final ScriptObject newDesc = Global.newEmptyInstance(); 329 newDesc.set(WRITABLE, false, 0); 330 return super.defineOwnProperty("length", newDesc, false); 331 } 332 333 return true; 334 } 335 336 /** 337 * ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw ) 338 */ 339 @Override 340 public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) { 341 final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc); 342 343 // never be undefined as "length" is always defined and can't be deleted for arrays 344 // Step 1 345 final PropertyDescriptor oldLenDesc = (PropertyDescriptor) super.getOwnPropertyDescriptor("length"); 346 347 // Step 2 348 // get old length and convert to long. Always a Long/Uint32 but we take the safe road. 349 final long oldLen = JSType.toUint32(oldLenDesc.getValue()); 350 351 // Step 3 352 if ("length".equals(key)) { 353 // check for length being made non-writable 354 final boolean result = defineLength(oldLen, oldLenDesc, desc, reject); 355 if (desc.has(WRITABLE) && !desc.isWritable()) { 356 setIsLengthNotWritable(); 357 } 358 return result; 359 } 360 361 // Step 4a 362 final int index = ArrayIndex.getArrayIndex(key); 363 if (ArrayIndex.isValidArrayIndex(index)) { 364 final long longIndex = ArrayIndex.toLongIndex(index); 365 // Step 4b 366 // setting an element beyond current length, but 'length' is not writable 367 if (longIndex >= oldLen && !oldLenDesc.isWritable()) { 368 if (reject) { 369 throw typeError("property.not.writable", Long.toString(longIndex), ScriptRuntime.safeToString(this)); 370 } 371 return false; 372 } 373 374 // Step 4c 375 // set the new array element 376 final boolean succeeded = super.defineOwnProperty(key, desc, false); 377 378 // Step 4d 379 if (!succeeded) { 380 if (reject) { 381 throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); 382 } 383 return false; 384 } 385 386 // Step 4e -- adjust new length based on new element index that is set 387 if (longIndex >= oldLen) { 388 oldLenDesc.setValue(longIndex + 1); 389 super.defineOwnProperty("length", oldLenDesc, false); 390 } 391 392 // Step 4f 393 return true; 394 } 395 396 // not an index property 397 return super.defineOwnProperty(key, desc, reject); 398 } 399 400 /** 401 * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in 402 * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set 403 * method in such cases. This is because set method uses inherited setters (if any) 404 * from any object in proto chain such as Array.prototype, Object.prototype. 405 * This method directly sets a particular element value in the current object. 406 * 407 * @param index key for property 408 * @param value value to define 409 */ 410 @Override 411 public final void defineOwnProperty(final int index, final Object value) { 412 assert isValidArrayIndex(index) : "invalid array index"; 413 final long longIndex = ArrayIndex.toLongIndex(index); 414 if (longIndex >= getArray().length()) { 415 // make array big enough to hold.. 416 setArray(getArray().ensure(longIndex)); 417 } 418 setArray(getArray().set(index, value, false)); 419 } 420 421 /** 422 * Return the array contents upcasted as an ObjectArray, regardless of 423 * representation 424 * 425 * @return an object array 426 */ 427 public Object[] asObjectArray() { 428 return getArray().asObjectArray(); 429 } 430 431 @Override 432 public void setIsLengthNotWritable() { 433 super.setIsLengthNotWritable(); 434 setArray(ArrayData.setIsLengthNotWritable(getArray())); 435 } 436 437 /** 438 * ECMA 15.4.3.2 Array.isArray ( arg ) 439 * 440 * @param self self reference 441 * @param arg argument - object to check 442 * @return true if argument is an array 443 */ 444 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 445 public static boolean isArray(final Object self, final Object arg) { 446 return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray()); 447 } 448 449 /** 450 * Length getter 451 * @param self self reference 452 * @return the length of the object 453 */ 454 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 455 public static Object length(final Object self) { 456 if (isArray(self)) { 457 return JSType.toUint32(((ScriptObject) self).getArray().length()); 458 } 459 460 return 0; 461 } 462 463 /** 464 * Length setter 465 * @param self self reference 466 * @param length new length property 467 */ 468 @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 469 public static void length(final Object self, final Object length) { 470 if (isArray(self)) { 471 ((ScriptObject)self).setLength(validLength(length)); 472 } 473 } 474 475 /** 476 * Prototype length getter 477 * @param self self reference 478 * @return the length of the object 479 */ 480 @Getter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 481 public static Object getProtoLength(final Object self) { 482 return length(self); // Same as instance getter but we can't make nasgen use the same method for prototype 483 } 484 485 /** 486 * Prototype length setter 487 * @param self self reference 488 * @param length new length property 489 */ 490 @Setter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 491 public static void setProtoLength(final Object self, final Object length) { 492 length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype 493 } 494 495 static long validLength(final Object length) { 496 // ES5 15.4.5.1, steps 3.c and 3.d require two ToNumber conversions here 497 final double doubleLength = JSType.toNumber(length); 498 if (doubleLength != JSType.toUint32(length)) { 499 throw rangeError("inappropriate.array.length", ScriptRuntime.safeToString(length)); 500 } 501 return (long) doubleLength; 502 } 503 504 /** 505 * ECMA 15.4.4.2 Array.prototype.toString ( ) 506 * 507 * @param self self reference 508 * @return string representation of array 509 */ 510 @Function(attributes = Attribute.NOT_ENUMERABLE) 511 public static Object toString(final Object self) { 512 final Object obj = Global.toObject(self); 513 if (obj instanceof ScriptObject) { 514 final InvokeByName joinInvoker = getJOIN(); 515 final ScriptObject sobj = (ScriptObject)obj; 516 try { 517 final Object join = joinInvoker.getGetter().invokeExact(sobj); 518 if (Bootstrap.isCallable(join)) { 519 return joinInvoker.getInvoker().invokeExact(join, sobj); 520 } 521 } catch (final RuntimeException | Error e) { 522 throw e; 523 } catch (final Throwable t) { 524 throw new RuntimeException(t); 525 } 526 } 527 528 // FIXME: should lookup Object.prototype.toString and call that? 529 return ScriptRuntime.builtinObjectToString(self); 530 } 531 532 /** 533 * Assert that an array is numeric, if not throw type error 534 * @param self self array to check 535 * @return true if numeric 536 */ 537 @Function(attributes = Attribute.NOT_ENUMERABLE) 538 public static Object assertNumeric(final Object self) { 539 if(!(self instanceof NativeArray && ((NativeArray)self).getArray().getOptimisticType().isNumeric())) { 540 throw typeError("not.a.numeric.array", ScriptRuntime.safeToString(self)); 541 } 542 return Boolean.TRUE; 543 } 544 545 /** 546 * ECMA 15.4.4.3 Array.prototype.toLocaleString ( ) 547 * 548 * @param self self reference 549 * @return locale specific string representation for array 550 */ 551 @Function(attributes = Attribute.NOT_ENUMERABLE) 552 public static String toLocaleString(final Object self) { 553 final StringBuilder sb = new StringBuilder(); 554 final Iterator<Object> iter = arrayLikeIterator(self, true); 555 556 while (iter.hasNext()) { 557 final Object obj = iter.next(); 558 559 if (obj != null && obj != ScriptRuntime.UNDEFINED) { 560 final Object val = JSType.toScriptObject(obj); 561 562 try { 563 if (val instanceof ScriptObject) { 564 final InvokeByName localeInvoker = getTO_LOCALE_STRING(); 565 final ScriptObject sobj = (ScriptObject)val; 566 final Object toLocaleString = localeInvoker.getGetter().invokeExact(sobj); 567 568 if (Bootstrap.isCallable(toLocaleString)) { 569 sb.append((String)localeInvoker.getInvoker().invokeExact(toLocaleString, sobj)); 570 } else { 571 throw typeError("not.a.function", "toLocaleString"); 572 } 573 } 574 } catch (final Error|RuntimeException t) { 575 throw t; 576 } catch (final Throwable t) { 577 throw new RuntimeException(t); 578 } 579 } 580 581 if (iter.hasNext()) { 582 sb.append(","); 583 } 584 } 585 586 return sb.toString(); 587 } 588 589 /** 590 * ECMA 15.4.2.2 new Array (len) 591 * 592 * @param newObj was the new operator used to instantiate this array 593 * @param self self reference 594 * @param args arguments (length) 595 * @return the new NativeArray 596 */ 597 @Constructor(arity = 1) 598 public static NativeArray construct(final boolean newObj, final Object self, final Object... args) { 599 switch (args.length) { 600 case 0: 601 return new NativeArray(0); 602 case 1: 603 final Object len = args[0]; 604 if (len instanceof Number) { 605 long length; 606 if (len instanceof Integer || len instanceof Long) { 607 length = ((Number) len).longValue(); 608 if (length >= 0 && length < JSType.MAX_UINT) { 609 return new NativeArray(length); 610 } 611 } 612 613 length = JSType.toUint32(len); 614 615 /* 616 * If the argument len is a Number and ToUint32(len) is equal to 617 * len, then the length property of the newly constructed object 618 * is set to ToUint32(len). If the argument len is a Number and 619 * ToUint32(len) is not equal to len, a RangeError exception is 620 * thrown. 621 */ 622 final double numberLength = ((Number) len).doubleValue(); 623 if (length != numberLength) { 624 throw rangeError("inappropriate.array.length", JSType.toString(numberLength)); 625 } 626 627 return new NativeArray(length); 628 } 629 /* 630 * If the argument len is not a Number, then the length property of 631 * the newly constructed object is set to 1 and the 0 property of 632 * the newly constructed object is set to len 633 */ 634 return new NativeArray(new Object[]{args[0]}); 635 //fallthru 636 default: 637 return new NativeArray(args); 638 } 639 } 640 641 /** 642 * ECMA 15.4.2.2 new Array (len) 643 * 644 * Specialized constructor for zero arguments - empty array 645 * 646 * @param newObj was the new operator used to instantiate this array 647 * @param self self reference 648 * @return the new NativeArray 649 */ 650 @SpecializedFunction(isConstructor=true) 651 public static NativeArray construct(final boolean newObj, final Object self) { 652 return new NativeArray(0); 653 } 654 655 /** 656 * ECMA 15.4.2.2 new Array (len) 657 * 658 * Specialized constructor for zero arguments - empty array 659 * 660 * @param newObj was the new operator used to instantiate this array 661 * @param self self reference 662 * @param element first element 663 * @return the new NativeArray 664 */ 665 @SpecializedFunction(isConstructor=true) 666 public static Object construct(final boolean newObj, final Object self, final boolean element) { 667 return new NativeArray(new Object[] { element }); 668 } 669 670 /** 671 * ECMA 15.4.2.2 new Array (len) 672 * 673 * Specialized constructor for one integer argument (length) 674 * 675 * @param newObj was the new operator used to instantiate this array 676 * @param self self reference 677 * @param length array length 678 * @return the new NativeArray 679 */ 680 @SpecializedFunction(isConstructor=true) 681 public static NativeArray construct(final boolean newObj, final Object self, final int length) { 682 if (length >= 0) { 683 return new NativeArray(length); 684 } 685 686 return construct(newObj, self, new Object[]{length}); 687 } 688 689 /** 690 * ECMA 15.4.2.2 new Array (len) 691 * 692 * Specialized constructor for one long argument (length) 693 * 694 * @param newObj was the new operator used to instantiate this array 695 * @param self self reference 696 * @param length array length 697 * @return the new NativeArray 698 */ 699 @SpecializedFunction(isConstructor=true) 700 public static NativeArray construct(final boolean newObj, final Object self, final long length) { 701 if (length >= 0L && length <= JSType.MAX_UINT) { 702 return new NativeArray(length); 703 } 704 705 return construct(newObj, self, new Object[]{length}); 706 } 707 708 /** 709 * ECMA 15.4.2.2 new Array (len) 710 * 711 * Specialized constructor for one double argument (length) 712 * 713 * @param newObj was the new operator used to instantiate this array 714 * @param self self reference 715 * @param length array length 716 * @return the new NativeArray 717 */ 718 @SpecializedFunction(isConstructor=true) 719 public static NativeArray construct(final boolean newObj, final Object self, final double length) { 720 final long uint32length = JSType.toUint32(length); 721 722 if (uint32length == length) { 723 return new NativeArray(uint32length); 724 } 725 726 return construct(newObj, self, new Object[]{length}); 727 } 728 729 /** 730 * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) 731 * 732 * @param self self reference 733 * @param arg argument 734 * @return resulting NativeArray 735 */ 736 @SpecializedFunction(linkLogic=ConcatLinkLogic.class) 737 public static NativeArray concat(final Object self, final int arg) { 738 final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Integer.class).copy(); //get at least an integer data copy of this data 739 newData.fastPush(arg); //add an integer to its end 740 return new NativeArray(newData); 741 } 742 743 /** 744 * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) 745 * 746 * @param self self reference 747 * @param arg argument 748 * @return resulting NativeArray 749 */ 750 @SpecializedFunction(linkLogic=ConcatLinkLogic.class) 751 public static NativeArray concat(final Object self, final long arg) { 752 final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Long.class).copy(); //get at least a long array data copy of this data 753 newData.fastPush(arg); //add a long at the end 754 return new NativeArray(newData); 755 } 756 757 /** 758 * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) 759 * 760 * @param self self reference 761 * @param arg argument 762 * @return resulting NativeArray 763 */ 764 @SpecializedFunction(linkLogic=ConcatLinkLogic.class) 765 public static NativeArray concat(final Object self, final double arg) { 766 final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Double.class).copy(); //get at least a number array data copy of this data 767 newData.fastPush(arg); //add a double at the end 768 return new NativeArray(newData); 769 } 770 771 /** 772 * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) 773 * 774 * @param self self reference 775 * @param arg argument 776 * @return resulting NativeArray 777 */ 778 @SpecializedFunction(linkLogic=ConcatLinkLogic.class) 779 public static NativeArray concat(final Object self, final Object arg) { 780 //arg is [NativeArray] of same type. 781 final ContinuousArrayData selfData = getContinuousArrayDataCCE(self); 782 final ContinuousArrayData newData; 783 784 if (arg instanceof NativeArray) { 785 final ContinuousArrayData argData = (ContinuousArrayData)((NativeArray)arg).getArray(); 786 if (argData.isEmpty()) { 787 newData = selfData.copy(); 788 } else if (selfData.isEmpty()) { 789 newData = argData.copy(); 790 } else { 791 final Class<?> widestElementType = selfData.widest(argData).getBoxedElementType(); 792 newData = ((ContinuousArrayData)selfData.convert(widestElementType)).fastConcat((ContinuousArrayData)argData.convert(widestElementType)); 793 } 794 } else { 795 newData = getContinuousArrayDataCCE(self, Object.class).copy(); 796 newData.fastPush(arg); 797 } 798 799 return new NativeArray(newData); 800 } 801 802 /** 803 * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) 804 * 805 * @param self self reference 806 * @param args arguments 807 * @return resulting NativeArray 808 */ 809 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 810 public static NativeArray concat(final Object self, final Object... args) { 811 final ArrayList<Object> list = new ArrayList<>(); 812 813 concatToList(list, Global.toObject(self)); 814 815 for (final Object obj : args) { 816 concatToList(list, obj); 817 } 818 819 return new NativeArray(list.toArray()); 820 } 821 822 private static void concatToList(final ArrayList<Object> list, final Object obj) { 823 final boolean isScriptArray = isArray(obj); 824 final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject; 825 if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) { 826 final Iterator<Object> iter = arrayLikeIterator(obj, true); 827 if (iter.hasNext()) { 828 for (int i = 0; iter.hasNext(); ++i) { 829 final Object value = iter.next(); 830 final boolean lacksIndex = obj != null && !((ScriptObject)obj).has(i); 831 if (value == ScriptRuntime.UNDEFINED && isScriptObject && lacksIndex) { 832 // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling 833 // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE, 834 // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it 835 // into the concatenated array. 836 list.add(ScriptRuntime.EMPTY); 837 } else { 838 list.add(value); 839 } 840 } 841 } else if (!isScriptArray) { 842 list.add(obj); // add empty object, but not an empty array 843 } 844 } else { 845 // single element, add it 846 list.add(obj); 847 } 848 } 849 850 /** 851 * ECMA 15.4.4.5 Array.prototype.join (separator) 852 * 853 * @param self self reference 854 * @param separator element separator 855 * @return string representation after join 856 */ 857 @Function(attributes = Attribute.NOT_ENUMERABLE) 858 public static String join(final Object self, final Object separator) { 859 final StringBuilder sb = new StringBuilder(); 860 final Iterator<Object> iter = arrayLikeIterator(self, true); 861 final String sep = separator == ScriptRuntime.UNDEFINED ? "," : JSType.toString(separator); 862 863 while (iter.hasNext()) { 864 final Object obj = iter.next(); 865 866 if (obj != null && obj != ScriptRuntime.UNDEFINED) { 867 sb.append(JSType.toString(obj)); 868 } 869 870 if (iter.hasNext()) { 871 sb.append(sep); 872 } 873 } 874 875 return sb.toString(); 876 } 877 878 /** 879 * Specialization of pop for ContinuousArrayData 880 * The link guard checks that the array is continuous AND not empty. 881 * The runtime guard checks that the guard is continuous (CCE otherwise) 882 * 883 * Primitive specialization, {@link LinkLogic} 884 * 885 * @param self self reference 886 * @return element popped 887 * @throws ClassCastException if array is empty, facilitating Undefined return value 888 */ 889 @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class) 890 public static int popInt(final Object self) { 891 //must be non empty IntArrayData 892 return getContinuousNonEmptyArrayDataCCE(self, IntElements.class).fastPopInt(); 893 } 894 895 /** 896 * Specialization of pop for ContinuousArrayData 897 * 898 * Primitive specialization, {@link LinkLogic} 899 * 900 * @param self self reference 901 * @return element popped 902 * @throws ClassCastException if array is empty, facilitating Undefined return value 903 */ 904 @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class) 905 public static long popLong(final Object self) { 906 //must be non empty Int or LongArrayData 907 return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong(); 908 } 909 910 /** 911 * Specialization of pop for ContinuousArrayData 912 * 913 * Primitive specialization, {@link LinkLogic} 914 * 915 * @param self self reference 916 * @return element popped 917 * @throws ClassCastException if array is empty, facilitating Undefined return value 918 */ 919 @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class) 920 public static double popDouble(final Object self) { 921 //must be non empty int long or double array data 922 return getContinuousNonEmptyArrayDataCCE(self, NumericElements.class).fastPopDouble(); 923 } 924 925 /** 926 * Specialization of pop for ContinuousArrayData 927 * 928 * Primitive specialization, {@link LinkLogic} 929 * 930 * @param self self reference 931 * @return element popped 932 * @throws ClassCastException if array is empty, facilitating Undefined return value 933 */ 934 @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class) 935 public static Object popObject(final Object self) { 936 //can be any data, because the numeric ones will throw cce and force relink 937 return getContinuousArrayDataCCE(self, null).fastPopObject(); 938 } 939 940 /** 941 * ECMA 15.4.4.6 Array.prototype.pop () 942 * 943 * @param self self reference 944 * @return array after pop 945 */ 946 @Function(attributes = Attribute.NOT_ENUMERABLE) 947 public static Object pop(final Object self) { 948 try { 949 final ScriptObject sobj = (ScriptObject)self; 950 951 if (bulkable(sobj)) { 952 return sobj.getArray().pop(); 953 } 954 955 final long len = JSType.toUint32(sobj.getLength()); 956 957 if (len == 0) { 958 sobj.set("length", 0, CALLSITE_STRICT); 959 return ScriptRuntime.UNDEFINED; 960 } 961 962 final long index = len - 1; 963 final Object element = sobj.get(index); 964 965 sobj.delete(index, true); 966 sobj.set("length", index, CALLSITE_STRICT); 967 968 return element; 969 } catch (final ClassCastException | NullPointerException e) { 970 throw typeError("not.an.object", ScriptRuntime.safeToString(self)); 971 } 972 } 973 974 /** 975 * ECMA 15.4.4.7 Array.prototype.push (args...) 976 * 977 * Primitive specialization, {@link LinkLogic} 978 * 979 * @param self self reference 980 * @param arg a primitive to push 981 * @return array length after push 982 */ 983 @SpecializedFunction(linkLogic=PushLinkLogic.class) 984 public static long push(final Object self, final int arg) { 985 return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg); 986 } 987 988 /** 989 * ECMA 15.4.4.7 Array.prototype.push (args...) 990 * 991 * Primitive specialization, {@link LinkLogic} 992 * 993 * @param self self reference 994 * @param arg a primitive to push 995 * @return array length after push 996 */ 997 @SpecializedFunction(linkLogic=PushLinkLogic.class) 998 public static long push(final Object self, final long arg) { 999 return getContinuousArrayDataCCE(self, Long.class).fastPush(arg); 1000 } 1001 1002 /** 1003 * ECMA 15.4.4.7 Array.prototype.push (args...) 1004 * 1005 * Primitive specialization, {@link LinkLogic} 1006 * 1007 * @param self self reference 1008 * @param arg a primitive to push 1009 * @return array length after push 1010 */ 1011 @SpecializedFunction(linkLogic=PushLinkLogic.class) 1012 public static long push(final Object self, final double arg) { 1013 return getContinuousArrayDataCCE(self, Double.class).fastPush(arg); 1014 } 1015 1016 /** 1017 * ECMA 15.4.4.7 Array.prototype.push (args...) 1018 * 1019 * Primitive specialization, {@link LinkLogic} 1020 * 1021 * @param self self reference 1022 * @param arg a primitive to push 1023 * @return array length after push 1024 */ 1025 @SpecializedFunction(name="push", linkLogic=PushLinkLogic.class) 1026 public static long pushObject(final Object self, final Object arg) { 1027 return getContinuousArrayDataCCE(self, Object.class).fastPush(arg); 1028 } 1029 1030 /** 1031 * ECMA 15.4.4.7 Array.prototype.push (args...) 1032 * 1033 * @param self self reference 1034 * @param args arguments to push 1035 * @return array length after pushes 1036 */ 1037 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1038 public static Object push(final Object self, final Object... args) { 1039 try { 1040 final ScriptObject sobj = (ScriptObject)self; 1041 1042 if (bulkable(sobj) && sobj.getArray().length() + args.length <= JSType.MAX_UINT) { 1043 final ArrayData newData = sobj.getArray().push(true, args); 1044 sobj.setArray(newData); 1045 return newData.length(); 1046 } 1047 1048 long len = JSType.toUint32(sobj.getLength()); 1049 for (final Object element : args) { 1050 sobj.set(len++, element, CALLSITE_STRICT); 1051 } 1052 sobj.set("length", len, CALLSITE_STRICT); 1053 1054 return len; 1055 } catch (final ClassCastException | NullPointerException e) { 1056 throw typeError(Context.getGlobal(), e, "not.an.object", ScriptRuntime.safeToString(self)); 1057 } 1058 } 1059 1060 /** 1061 * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument 1062 * 1063 * @param self self reference 1064 * @param arg argument to push 1065 * @return array after pushes 1066 */ 1067 @SpecializedFunction 1068 public static long push(final Object self, final Object arg) { 1069 try { 1070 final ScriptObject sobj = (ScriptObject)self; 1071 final ArrayData arrayData = sobj.getArray(); 1072 final long length = arrayData.length(); 1073 if (bulkable(sobj) && length < JSType.MAX_UINT) { 1074 sobj.setArray(arrayData.push(true, arg)); 1075 return length + 1; 1076 } 1077 1078 long len = JSType.toUint32(sobj.getLength()); 1079 sobj.set(len++, arg, CALLSITE_STRICT); 1080 sobj.set("length", len, CALLSITE_STRICT); 1081 return len; 1082 } catch (final ClassCastException | NullPointerException e) { 1083 throw typeError("not.an.object", ScriptRuntime.safeToString(self)); 1084 } 1085 } 1086 1087 /** 1088 * ECMA 15.4.4.8 Array.prototype.reverse () 1089 * 1090 * @param self self reference 1091 * @return reversed array 1092 */ 1093 @Function(attributes = Attribute.NOT_ENUMERABLE) 1094 public static Object reverse(final Object self) { 1095 try { 1096 final ScriptObject sobj = (ScriptObject)self; 1097 final long len = JSType.toUint32(sobj.getLength()); 1098 final long middle = len / 2; 1099 1100 for (long lower = 0; lower != middle; lower++) { 1101 final long upper = len - lower - 1; 1102 final Object lowerValue = sobj.get(lower); 1103 final Object upperValue = sobj.get(upper); 1104 final boolean lowerExists = sobj.has(lower); 1105 final boolean upperExists = sobj.has(upper); 1106 1107 if (lowerExists && upperExists) { 1108 sobj.set(lower, upperValue, CALLSITE_STRICT); 1109 sobj.set(upper, lowerValue, CALLSITE_STRICT); 1110 } else if (!lowerExists && upperExists) { 1111 sobj.set(lower, upperValue, CALLSITE_STRICT); 1112 sobj.delete(upper, true); 1113 } else if (lowerExists && !upperExists) { 1114 sobj.delete(lower, true); 1115 sobj.set(upper, lowerValue, CALLSITE_STRICT); 1116 } 1117 } 1118 return sobj; 1119 } catch (final ClassCastException | NullPointerException e) { 1120 throw typeError("not.an.object", ScriptRuntime.safeToString(self)); 1121 } 1122 } 1123 1124 /** 1125 * ECMA 15.4.4.9 Array.prototype.shift () 1126 * 1127 * @param self self reference 1128 * @return shifted array 1129 */ 1130 @Function(attributes = Attribute.NOT_ENUMERABLE) 1131 public static Object shift(final Object self) { 1132 final Object obj = Global.toObject(self); 1133 1134 Object first = ScriptRuntime.UNDEFINED; 1135 1136 if (!(obj instanceof ScriptObject)) { 1137 return first; 1138 } 1139 1140 final ScriptObject sobj = (ScriptObject) obj; 1141 1142 long len = JSType.toUint32(sobj.getLength()); 1143 1144 if (len > 0) { 1145 first = sobj.get(0); 1146 1147 if (bulkable(sobj)) { 1148 sobj.getArray().shiftLeft(1); 1149 } else { 1150 boolean hasPrevious = true; 1151 for (long k = 1; k < len; k++) { 1152 final boolean hasCurrent = sobj.has(k); 1153 if (hasCurrent) { 1154 sobj.set(k - 1, sobj.get(k), CALLSITE_STRICT); 1155 } else if (hasPrevious) { 1156 sobj.delete(k - 1, true); 1157 } 1158 hasPrevious = hasCurrent; 1159 } 1160 } 1161 sobj.delete(--len, true); 1162 } else { 1163 len = 0; 1164 } 1165 1166 sobj.set("length", len, CALLSITE_STRICT); 1167 1168 return first; 1169 } 1170 1171 /** 1172 * ECMA 15.4.4.10 Array.prototype.slice ( start [ , end ] ) 1173 * 1174 * @param self self reference 1175 * @param start start of slice (inclusive) 1176 * @param end end of slice (optional, exclusive) 1177 * @return sliced array 1178 */ 1179 @Function(attributes = Attribute.NOT_ENUMERABLE) 1180 public static Object slice(final Object self, final Object start, final Object end) { 1181 final Object obj = Global.toObject(self); 1182 if (!(obj instanceof ScriptObject)) { 1183 return ScriptRuntime.UNDEFINED; 1184 } 1185 1186 final ScriptObject sobj = (ScriptObject)obj; 1187 final long len = JSType.toUint32(sobj.getLength()); 1188 final long relativeStart = JSType.toLong(start); 1189 final long relativeEnd = end == ScriptRuntime.UNDEFINED ? len : JSType.toLong(end); 1190 1191 long k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); 1192 final long finale = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); 1193 1194 if (k >= finale) { 1195 return new NativeArray(0); 1196 } 1197 1198 if (bulkable(sobj)) { 1199 return new NativeArray(sobj.getArray().slice(k, finale)); 1200 } 1201 1202 // Construct array with proper length to have a deleted filter on undefined elements 1203 final NativeArray copy = new NativeArray(finale - k); 1204 for (long n = 0; k < finale; n++, k++) { 1205 if (sobj.has(k)) { 1206 copy.defineOwnProperty(ArrayIndex.getArrayIndex(n), sobj.get(k)); 1207 } 1208 } 1209 1210 return copy; 1211 } 1212 1213 private static ScriptFunction compareFunction(final Object comparefn) { 1214 if (comparefn == ScriptRuntime.UNDEFINED) { 1215 return null; 1216 } 1217 1218 if (! (comparefn instanceof ScriptFunction)) { 1219 throw typeError("not.a.function", ScriptRuntime.safeToString(comparefn)); 1220 } 1221 1222 return (ScriptFunction)comparefn; 1223 } 1224 1225 private static Object[] sort(final Object[] array, final Object comparefn) { 1226 final ScriptFunction cmp = compareFunction(comparefn); 1227 1228 final List<Object> list = Arrays.asList(array); 1229 final Object cmpThis = cmp == null || cmp.isStrict() ? ScriptRuntime.UNDEFINED : Global.instance(); 1230 1231 try { 1232 Collections.sort(list, new Comparator<Object>() { 1233 private final MethodHandle call_cmp = getCALL_CMP(); 1234 @Override 1235 public int compare(final Object x, final Object y) { 1236 if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) { 1237 return 0; 1238 } else if (x == ScriptRuntime.UNDEFINED) { 1239 return 1; 1240 } else if (y == ScriptRuntime.UNDEFINED) { 1241 return -1; 1242 } 1243 1244 if (cmp != null) { 1245 try { 1246 return (int)Math.signum((double)call_cmp.invokeExact(cmp, cmpThis, x, y)); 1247 } catch (final RuntimeException | Error e) { 1248 throw e; 1249 } catch (final Throwable t) { 1250 throw new RuntimeException(t); 1251 } 1252 } 1253 1254 return JSType.toString(x).compareTo(JSType.toString(y)); 1255 } 1256 }); 1257 } catch (final IllegalArgumentException iae) { 1258 // Collections.sort throws IllegalArgumentException when 1259 // Comparison method violates its general contract 1260 1261 // See ECMA spec 15.4.4.11 Array.prototype.sort (comparefn). 1262 // If "comparefn" is not undefined and is not a consistent 1263 // comparison function for the elements of this array, the 1264 // behaviour of sort is implementation-defined. 1265 } 1266 1267 return list.toArray(new Object[array.length]); 1268 } 1269 1270 /** 1271 * ECMA 15.4.4.11 Array.prototype.sort ( comparefn ) 1272 * 1273 * @param self self reference 1274 * @param comparefn element comparison function 1275 * @return sorted array 1276 */ 1277 @Function(attributes = Attribute.NOT_ENUMERABLE) 1278 public static ScriptObject sort(final Object self, final Object comparefn) { 1279 try { 1280 final ScriptObject sobj = (ScriptObject) self; 1281 final long len = JSType.toUint32(sobj.getLength()); 1282 ArrayData array = sobj.getArray(); 1283 1284 if (len > 1) { 1285 // Get only non-missing elements. Missing elements go at the end 1286 // of the sorted array. So, just don't copy these to sort input. 1287 final ArrayList<Object> src = new ArrayList<>(); 1288 1289 for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) { 1290 final long index = iter.next(); 1291 if (index >= len) { 1292 break; 1293 } 1294 src.add(array.getObject((int)index)); 1295 } 1296 1297 final Object[] sorted = sort(src.toArray(), comparefn); 1298 1299 for (int i = 0; i < sorted.length; i++) { 1300 array = array.set(i, sorted[i], true); 1301 } 1302 1303 // delete missing elements - which are at the end of sorted array 1304 if (sorted.length != len) { 1305 array = array.delete(sorted.length, len - 1); 1306 } 1307 1308 sobj.setArray(array); 1309 } 1310 1311 return sobj; 1312 } catch (final ClassCastException | NullPointerException e) { 1313 throw typeError("not.an.object", ScriptRuntime.safeToString(self)); 1314 } 1315 } 1316 1317 /** 1318 * ECMA 15.4.4.12 Array.prototype.splice ( start, deleteCount [ item1 [ , item2 [ , ... ] ] ] ) 1319 * 1320 * @param self self reference 1321 * @param args arguments 1322 * @return result of splice 1323 */ 1324 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 1325 public static Object splice(final Object self, final Object... args) { 1326 final Object obj = Global.toObject(self); 1327 1328 if (!(obj instanceof ScriptObject)) { 1329 return ScriptRuntime.UNDEFINED; 1330 } 1331 1332 final Object start = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED; 1333 final Object deleteCount = args.length > 1 ? args[1] : ScriptRuntime.UNDEFINED; 1334 1335 Object[] items; 1336 1337 if (args.length > 2) { 1338 items = new Object[args.length - 2]; 1339 System.arraycopy(args, 2, items, 0, items.length); 1340 } else { 1341 items = ScriptRuntime.EMPTY_ARRAY; 1342 } 1343 1344 final ScriptObject sobj = (ScriptObject)obj; 1345 final long len = JSType.toUint32(sobj.getLength()); 1346 final long relativeStart = JSType.toLong(start); 1347 1348 final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); 1349 final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart); 1350 1351 NativeArray returnValue; 1352 1353 if (actualStart <= Integer.MAX_VALUE && actualDeleteCount <= Integer.MAX_VALUE && bulkable(sobj)) { 1354 try { 1355 returnValue = new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length)); 1356 1357 // Since this is a dense bulkable array we can use faster defineOwnProperty to copy new elements 1358 int k = (int) actualStart; 1359 for (int i = 0; i < items.length; i++, k++) { 1360 sobj.defineOwnProperty(k, items[i]); 1361 } 1362 } catch (final UnsupportedOperationException uoe) { 1363 returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len); 1364 } 1365 } else { 1366 returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len); 1367 } 1368 1369 return returnValue; 1370 } 1371 1372 private static NativeArray slowSplice(final ScriptObject sobj, final long start, final long deleteCount, final Object[] items, final long len) { 1373 1374 final NativeArray array = new NativeArray(deleteCount); 1375 1376 for (long k = 0; k < deleteCount; k++) { 1377 final long from = start + k; 1378 1379 if (sobj.has(from)) { 1380 array.defineOwnProperty(ArrayIndex.getArrayIndex(k), sobj.get(from)); 1381 } 1382 } 1383 1384 if (items.length < deleteCount) { 1385 for (long k = start; k < len - deleteCount; k++) { 1386 final long from = k + deleteCount; 1387 final long to = k + items.length; 1388 1389 if (sobj.has(from)) { 1390 sobj.set(to, sobj.get(from), CALLSITE_STRICT); 1391 } else { 1392 sobj.delete(to, true); 1393 } 1394 } 1395 1396 for (long k = len; k > len - deleteCount + items.length; k--) { 1397 sobj.delete(k - 1, true); 1398 } 1399 } else if (items.length > deleteCount) { 1400 for (long k = len - deleteCount; k > start; k--) { 1401 final long from = k + deleteCount - 1; 1402 final long to = k + items.length - 1; 1403 1404 if (sobj.has(from)) { 1405 final Object fromValue = sobj.get(from); 1406 sobj.set(to, fromValue, CALLSITE_STRICT); 1407 } else { 1408 sobj.delete(to, true); 1409 } 1410 } 1411 } 1412 1413 long k = start; 1414 for (int i = 0; i < items.length; i++, k++) { 1415 sobj.set(k, items[i], CALLSITE_STRICT); 1416 } 1417 1418 final long newLength = len - deleteCount + items.length; 1419 sobj.set("length", newLength, CALLSITE_STRICT); 1420 1421 return array; 1422 } 1423 1424 /** 1425 * ECMA 15.4.4.13 Array.prototype.unshift ( [ item1 [ , item2 [ , ... ] ] ] ) 1426 * 1427 * @param self self reference 1428 * @param items items for unshift 1429 * @return unshifted array 1430 */ 1431 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1432 public static Object unshift(final Object self, final Object... items) { 1433 final Object obj = Global.toObject(self); 1434 1435 if (!(obj instanceof ScriptObject)) { 1436 return ScriptRuntime.UNDEFINED; 1437 } 1438 1439 final ScriptObject sobj = (ScriptObject)obj; 1440 final long len = JSType.toUint32(sobj.getLength()); 1441 1442 if (items == null) { 1443 return ScriptRuntime.UNDEFINED; 1444 } 1445 1446 if (bulkable(sobj)) { 1447 sobj.getArray().shiftRight(items.length); 1448 1449 for (int j = 0; j < items.length; j++) { 1450 sobj.setArray(sobj.getArray().set(j, items[j], true)); 1451 } 1452 } else { 1453 for (long k = len; k > 0; k--) { 1454 final long from = k - 1; 1455 final long to = k + items.length - 1; 1456 1457 if (sobj.has(from)) { 1458 final Object fromValue = sobj.get(from); 1459 sobj.set(to, fromValue, CALLSITE_STRICT); 1460 } else { 1461 sobj.delete(to, true); 1462 } 1463 } 1464 1465 for (int j = 0; j < items.length; j++) { 1466 sobj.set(j, items[j], CALLSITE_STRICT); 1467 } 1468 } 1469 1470 final long newLength = len + items.length; 1471 sobj.set("length", newLength, CALLSITE_STRICT); 1472 1473 return newLength; 1474 } 1475 1476 /** 1477 * ECMA 15.4.4.14 Array.prototype.indexOf ( searchElement [ , fromIndex ] ) 1478 * 1479 * @param self self reference 1480 * @param searchElement element to search for 1481 * @param fromIndex start index of search 1482 * @return index of element, or -1 if not found 1483 */ 1484 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1485 public static long indexOf(final Object self, final Object searchElement, final Object fromIndex) { 1486 try { 1487 final ScriptObject sobj = (ScriptObject)Global.toObject(self); 1488 final long len = JSType.toUint32(sobj.getLength()); 1489 if (len == 0) { 1490 return -1; 1491 } 1492 1493 final long n = JSType.toLong(fromIndex); 1494 if (n >= len) { 1495 return -1; 1496 } 1497 1498 1499 for (long k = Math.max(0, n < 0 ? len - Math.abs(n) : n); k < len; k++) { 1500 if (sobj.has(k)) { 1501 if (ScriptRuntime.EQ_STRICT(sobj.get(k), searchElement)) { 1502 return k; 1503 } 1504 } 1505 } 1506 } catch (final ClassCastException | NullPointerException e) { 1507 //fallthru 1508 } 1509 1510 return -1; 1511 } 1512 1513 /** 1514 * ECMA 15.4.4.15 Array.prototype.lastIndexOf ( searchElement [ , fromIndex ] ) 1515 * 1516 * @param self self reference 1517 * @param args arguments: element to search for and optional from index 1518 * @return index of element, or -1 if not found 1519 */ 1520 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1521 public static long lastIndexOf(final Object self, final Object... args) { 1522 try { 1523 final ScriptObject sobj = (ScriptObject)Global.toObject(self); 1524 final long len = JSType.toUint32(sobj.getLength()); 1525 1526 if (len == 0) { 1527 return -1; 1528 } 1529 1530 final Object searchElement = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED; 1531 final long n = args.length > 1 ? JSType.toLong(args[1]) : len - 1; 1532 1533 for (long k = n < 0 ? len - Math.abs(n) : Math.min(n, len - 1); k >= 0; k--) { 1534 if (sobj.has(k)) { 1535 if (ScriptRuntime.EQ_STRICT(sobj.get(k), searchElement)) { 1536 return k; 1537 } 1538 } 1539 } 1540 } catch (final ClassCastException | NullPointerException e) { 1541 throw typeError("not.an.object", ScriptRuntime.safeToString(self)); 1542 } 1543 1544 return -1; 1545 } 1546 1547 /** 1548 * ECMA 15.4.4.16 Array.prototype.every ( callbackfn [ , thisArg ] ) 1549 * 1550 * @param self self reference 1551 * @param callbackfn callback function per element 1552 * @param thisArg this argument 1553 * @return true if callback function return true for every element in the array, false otherwise 1554 */ 1555 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1556 public static boolean every(final Object self, final Object callbackfn, final Object thisArg) { 1557 return applyEvery(Global.toObject(self), callbackfn, thisArg); 1558 } 1559 1560 private static boolean applyEvery(final Object self, final Object callbackfn, final Object thisArg) { 1561 return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, true) { 1562 private final MethodHandle everyInvoker = getEVERY_CALLBACK_INVOKER(); 1563 1564 @Override 1565 protected boolean forEach(final Object val, final long i) throws Throwable { 1566 return result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self); 1567 } 1568 }.apply(); 1569 } 1570 1571 /** 1572 * ECMA 15.4.4.17 Array.prototype.some ( callbackfn [ , thisArg ] ) 1573 * 1574 * @param self self reference 1575 * @param callbackfn callback function per element 1576 * @param thisArg this argument 1577 * @return true if callback function returned true for any element in the array, false otherwise 1578 */ 1579 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1580 public static boolean some(final Object self, final Object callbackfn, final Object thisArg) { 1581 return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, false) { 1582 private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER(); 1583 1584 @Override 1585 protected boolean forEach(final Object val, final long i) throws Throwable { 1586 return !(result = (boolean)someInvoker.invokeExact(callbackfn, thisArg, val, i, self)); 1587 } 1588 }.apply(); 1589 } 1590 1591 /** 1592 * ECMA 15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] ) 1593 * 1594 * @param self self reference 1595 * @param callbackfn callback function per element 1596 * @param thisArg this argument 1597 * @return undefined 1598 */ 1599 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1600 public static Object forEach(final Object self, final Object callbackfn, final Object thisArg) { 1601 return new IteratorAction<Object>(Global.toObject(self), callbackfn, thisArg, ScriptRuntime.UNDEFINED) { 1602 private final MethodHandle forEachInvoker = getFOREACH_CALLBACK_INVOKER(); 1603 1604 @Override 1605 protected boolean forEach(final Object val, final long i) throws Throwable { 1606 forEachInvoker.invokeExact(callbackfn, thisArg, val, i, self); 1607 return true; 1608 } 1609 }.apply(); 1610 } 1611 1612 /** 1613 * ECMA 15.4.4.19 Array.prototype.map ( callbackfn [ , thisArg ] ) 1614 * 1615 * @param self self reference 1616 * @param callbackfn callback function per element 1617 * @param thisArg this argument 1618 * @return array with elements transformed by map function 1619 */ 1620 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1621 public static NativeArray map(final Object self, final Object callbackfn, final Object thisArg) { 1622 return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, null) { 1623 private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER(); 1624 1625 @Override 1626 protected boolean forEach(final Object val, final long i) throws Throwable { 1627 final Object r = mapInvoker.invokeExact(callbackfn, thisArg, val, i, self); 1628 result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r); 1629 return true; 1630 } 1631 1632 @Override 1633 public void applyLoopBegin(final ArrayLikeIterator<Object> iter0) { 1634 // map return array should be of same length as source array 1635 // even if callback reduces source array length 1636 result = new NativeArray(iter0.getLength()); 1637 } 1638 }.apply(); 1639 } 1640 1641 /** 1642 * ECMA 15.4.4.20 Array.prototype.filter ( callbackfn [ , thisArg ] ) 1643 * 1644 * @param self self reference 1645 * @param callbackfn callback function per element 1646 * @param thisArg this argument 1647 * @return filtered array 1648 */ 1649 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1650 public static NativeArray filter(final Object self, final Object callbackfn, final Object thisArg) { 1651 return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { 1652 private long to = 0; 1653 private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER(); 1654 1655 @Override 1656 protected boolean forEach(final Object val, final long i) throws Throwable { 1657 if ((boolean)filterInvoker.invokeExact(callbackfn, thisArg, val, i, self)) { 1658 result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val); 1659 } 1660 return true; 1661 } 1662 }.apply(); 1663 } 1664 1665 private static Object reduceInner(final ArrayLikeIterator<Object> iter, final Object self, final Object... args) { 1666 final Object callbackfn = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED; 1667 final boolean initialValuePresent = args.length > 1; 1668 1669 Object initialValue = initialValuePresent ? args[1] : ScriptRuntime.UNDEFINED; 1670 1671 if (callbackfn == ScriptRuntime.UNDEFINED) { 1672 throw typeError("not.a.function", "undefined"); 1673 } 1674 1675 if (!initialValuePresent) { 1676 if (iter.hasNext()) { 1677 initialValue = iter.next(); 1678 } else { 1679 throw typeError("array.reduce.invalid.init"); 1680 } 1681 } 1682 1683 //if initial value is ScriptRuntime.UNDEFINED - step forward once. 1684 return new IteratorAction<Object>(Global.toObject(self), callbackfn, ScriptRuntime.UNDEFINED, initialValue, iter) { 1685 private final MethodHandle reduceInvoker = getREDUCE_CALLBACK_INVOKER(); 1686 1687 @Override 1688 protected boolean forEach(final Object val, final long i) throws Throwable { 1689 // TODO: why can't I declare the second arg as Undefined.class? 1690 result = reduceInvoker.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self); 1691 return true; 1692 } 1693 }.apply(); 1694 } 1695 1696 /** 1697 * ECMA 15.4.4.21 Array.prototype.reduce ( callbackfn [ , initialValue ] ) 1698 * 1699 * @param self self reference 1700 * @param args arguments to reduce 1701 * @return accumulated result 1702 */ 1703 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1704 public static Object reduce(final Object self, final Object... args) { 1705 return reduceInner(arrayLikeIterator(self), self, args); 1706 } 1707 1708 /** 1709 * ECMA 15.4.4.22 Array.prototype.reduceRight ( callbackfn [ , initialValue ] ) 1710 * 1711 * @param self self reference 1712 * @param args arguments to reduce 1713 * @return accumulated result 1714 */ 1715 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1716 public static Object reduceRight(final Object self, final Object... args) { 1717 return reduceInner(reverseArrayLikeIterator(self), self, args); 1718 } 1719 1720 /** 1721 * Determine if Java bulk array operations may be used on the underlying 1722 * storage. This is possible only if the object's prototype chain is empty 1723 * or each of the prototypes in the chain is empty. 1724 * 1725 * @param self the object to examine 1726 * @return true if optimizable 1727 */ 1728 private static boolean bulkable(final ScriptObject self) { 1729 return self.isArray() && !hasInheritedArrayEntries(self) && !self.isLengthNotWritable(); 1730 } 1731 1732 private static boolean hasInheritedArrayEntries(final ScriptObject self) { 1733 ScriptObject proto = self.getProto(); 1734 while (proto != null) { 1735 if (proto.hasArrayEntries()) { 1736 return true; 1737 } 1738 proto = proto.getProto(); 1739 } 1740 1741 return false; 1742 } 1743 1744 @Override 1745 public String toString() { 1746 return "NativeArray@" + Debug.id(this) + " [" + getArray().getClass().getSimpleName() + ']'; 1747 } 1748 1749 @Override 1750 public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) { 1751 if (clazz == PushLinkLogic.class) { 1752 return PushLinkLogic.INSTANCE; 1753 } else if (clazz == PopLinkLogic.class) { 1754 return PopLinkLogic.INSTANCE; 1755 } else if (clazz == ConcatLinkLogic.class) { 1756 return ConcatLinkLogic.INSTANCE; 1757 } 1758 return null; 1759 } 1760 1761 @Override 1762 public boolean hasPerInstanceAssumptions() { 1763 return true; //length writable switchpoint 1764 } 1765 1766 /** 1767 * This is an abstract super class that contains common functionality for all 1768 * specialized optimistic builtins in NativeArray. For example, it handles the 1769 * modification switchpoint which is touched when length is written. 1770 */ 1771 private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic { 1772 protected ArrayLinkLogic() { 1773 } 1774 1775 protected static ContinuousArrayData getContinuousArrayData(final Object self) { 1776 try { 1777 //cast to NativeArray, to avoid cases like x = {0:0, 1:1}, x.length = 2, where we can't use the array push/pop 1778 return (ContinuousArrayData)((NativeArray)self).getArray(); 1779 } catch (final Exception e) { 1780 return null; 1781 } 1782 } 1783 1784 /** 1785 * Push and pop callsites can throw ClassCastException as a mechanism to have them 1786 * relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x) 1787 * for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink 1788 */ 1789 @Override 1790 public Class<? extends Throwable> getRelinkException() { 1791 return ClassCastException.class; 1792 } 1793 } 1794 1795 /** 1796 * This is linker logic for optimistic concatenations 1797 */ 1798 private static final class ConcatLinkLogic extends ArrayLinkLogic { 1799 private static final LinkLogic INSTANCE = new ConcatLinkLogic(); 1800 1801 @Override 1802 public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { 1803 final Object[] args = request.getArguments(); 1804 1805 if (args.length != 3) { //single argument check 1806 return false; 1807 } 1808 1809 final ContinuousArrayData selfData = getContinuousArrayData(self); 1810 if (selfData == null) { 1811 return false; 1812 } 1813 1814 final Object arg = args[2]; 1815 //args[2] continuousarray or non arraydata, let past non array datas 1816 if (arg instanceof NativeArray) { 1817 final ContinuousArrayData argData = getContinuousArrayData(arg); 1818 if (argData == null) { 1819 return false; 1820 } 1821 } 1822 1823 return true; 1824 } 1825 } 1826 1827 /** 1828 * This is linker logic for optimistic pushes 1829 */ 1830 private static final class PushLinkLogic extends ArrayLinkLogic { 1831 private static final LinkLogic INSTANCE = new PushLinkLogic(); 1832 1833 @Override 1834 public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { 1835 return getContinuousArrayData(self) != null; 1836 } 1837 } 1838 1839 /** 1840 * This is linker logic for optimistic pops 1841 */ 1842 private static final class PopLinkLogic extends ArrayLinkLogic { 1843 private static final LinkLogic INSTANCE = new PopLinkLogic(); 1844 1845 /** 1846 * We need to check if we are dealing with a continuous non empty array data here, 1847 * as pop with a primitive return value returns undefined for arrays with length 0 1848 */ 1849 @Override 1850 public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { 1851 final ContinuousArrayData data = getContinuousNonEmptyArrayData(self); 1852 if (data != null) { 1853 final Class<?> elementType = data.getElementType(); 1854 final Class<?> returnType = desc.getMethodType().returnType(); 1855 final boolean typeFits = JSType.getAccessorTypeIndex(returnType) >= JSType.getAccessorTypeIndex(elementType); 1856 return typeFits; 1857 } 1858 return false; 1859 } 1860 1861 private static ContinuousArrayData getContinuousNonEmptyArrayData(final Object self) { 1862 final ContinuousArrayData data = getContinuousArrayData(self); 1863 if (data != null) { 1864 return data.length() == 0 ? null : data; 1865 } 1866 return null; 1867 } 1868 } 1869 1870 //runtime calls for push and pops. they could be used as guards, but they also perform the runtime logic, 1871 //so rather than synthesizing them into a guard method handle that would also perform the push on the 1872 //retrieved receiver, we use this as runtime logic 1873 1874 //TODO - fold these into the Link logics, but I'll do that as a later step, as I want to do a checkin 1875 //where everything works first 1876 1877 private static final <T> ContinuousArrayData getContinuousNonEmptyArrayDataCCE(final Object self, final Class<T> clazz) { 1878 try { 1879 @SuppressWarnings("unchecked") 1880 final ContinuousArrayData data = (ContinuousArrayData)(T)((NativeArray)self).getArray(); 1881 if (data.length() != 0L) { 1882 return data; //if length is 0 we cannot pop and have to relink, because then we'd have to return an undefined, which is a wider type than e.g. int 1883 } 1884 } catch (final NullPointerException e) { 1885 //fallthru 1886 } 1887 throw new ClassCastException(); 1888 } 1889 1890 private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) { 1891 try { 1892 return (ContinuousArrayData)((NativeArray)self).getArray(); 1893 } catch (final NullPointerException e) { 1894 throw new ClassCastException(); 1895 } 1896 } 1897 1898 private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) { 1899 try { 1900 return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType" 1901 } catch (final NullPointerException e) { 1902 throw new ClassCastException(); 1903 } 1904 } 1905} 1906