< prev index next >

src/jdk/nashorn/internal/objects/NativeArray.java

Print this page




  83 @ScriptClass("Array")
  84 public final class NativeArray extends ScriptObject implements OptimisticBuiltins {
  85     private static final Object JOIN                     = new Object();
  86     private static final Object EVERY_CALLBACK_INVOKER   = new Object();
  87     private static final Object SOME_CALLBACK_INVOKER    = new Object();
  88     private static final Object FOREACH_CALLBACK_INVOKER = new Object();
  89     private static final Object MAP_CALLBACK_INVOKER     = new Object();
  90     private static final Object FILTER_CALLBACK_INVOKER  = new Object();
  91     private static final Object REDUCE_CALLBACK_INVOKER  = new Object();
  92     private static final Object CALL_CMP                 = new Object();
  93     private static final Object TO_LOCALE_STRING         = new Object();
  94 
  95     /*
  96      * Constructors.
  97      */
  98     NativeArray() {
  99         this(ArrayData.initialArray());
 100     }
 101 
 102     NativeArray(final long length) {
 103         // TODO assert valid index in long before casting
 104         this(ArrayData.allocate((int)length));
 105     }
 106 
 107     NativeArray(final int[] array) {
 108         this(ArrayData.allocate(array));
 109     }
 110 
 111     NativeArray(final long[] array) {
 112         this(ArrayData.allocate(array));
 113     }
 114 
 115     NativeArray(final double[] array) {
 116         this(ArrayData.allocate(array));



















 117     }
 118 
 119     NativeArray(final Object[] array) {
 120         this(ArrayData.allocate(array.length));
 121 
 122         ArrayData arrayData = this.getArray();
 123 
 124         for (int index = 0; index < array.length; index++) {
 125             final Object value = array[index];
 126 
 127             if (value == ScriptRuntime.EMPTY) {
 128                 arrayData = arrayData.delete(index);
 129             } else {
 130                 arrayData = arrayData.set(index, value, false);
 131             }
 132         }
 133 
 134         this.setArray(arrayData);
 135     }
 136 


 171 
 172         return super.findSetIndexMethod(desc, request);
 173     }
 174 
 175     private static InvokeByName getJOIN() {
 176         return Global.instance().getInvokeByName(JOIN,
 177                 new Callable<InvokeByName>() {
 178                     @Override
 179                     public InvokeByName call() {
 180                         return new InvokeByName("join", ScriptObject.class);
 181                     }
 182                 });
 183     }
 184 
 185     private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class<?> rtype) {
 186         return Global.instance().getDynamicInvoker(key,
 187             new Callable<MethodHandle>() {
 188                 @Override
 189                 public MethodHandle call() {
 190                     return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class,
 191                         long.class, Object.class);
 192                 }
 193             });
 194     }
 195 
 196     private static MethodHandle getEVERY_CALLBACK_INVOKER() {
 197         return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class);
 198     }
 199 
 200     private static MethodHandle getSOME_CALLBACK_INVOKER() {
 201         return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.class);
 202     }
 203 
 204     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 


 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


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     /**




  83 @ScriptClass("Array")
  84 public final class NativeArray extends ScriptObject implements OptimisticBuiltins {
  85     private static final Object JOIN                     = new Object();
  86     private static final Object EVERY_CALLBACK_INVOKER   = new Object();
  87     private static final Object SOME_CALLBACK_INVOKER    = new Object();
  88     private static final Object FOREACH_CALLBACK_INVOKER = new Object();
  89     private static final Object MAP_CALLBACK_INVOKER     = new Object();
  90     private static final Object FILTER_CALLBACK_INVOKER  = new Object();
  91     private static final Object REDUCE_CALLBACK_INVOKER  = new Object();
  92     private static final Object CALL_CMP                 = new Object();
  93     private static final Object TO_LOCALE_STRING         = new Object();
  94 
  95     /*
  96      * Constructors.
  97      */
  98     NativeArray() {
  99         this(ArrayData.initialArray());
 100     }
 101 
 102     NativeArray(final long length) {
 103         this(ArrayData.allocate(length));

 104     }
 105 
 106     NativeArray(final int[] array) {
 107         this(ArrayData.allocate(array));
 108     }
 109 
 110     NativeArray(final double[] array) {
 111         this(ArrayData.allocate(array));
 112     }
 113 
 114     NativeArray(final long[] array) {
 115         this(ArrayData.allocate(array.length));
 116 
 117         ArrayData arrayData = this.getArray();
 118         Class<?> widest = int.class;
 119 
 120         for (int index = 0; index < array.length; index++) {
 121             final long value = array[index];
 122 
 123             if (widest == int.class && JSType.isRepresentableAsInt(value)) {
 124                 arrayData = arrayData.set(index, (int) value, false);
 125             } else if (widest != Object.class && JSType.isRepresentableAsDouble(value)) {
 126                 arrayData = arrayData.set(index, (double) value, false);
 127                 widest = double.class;
 128             } else {
 129                 arrayData = arrayData.set(index, (Object) value, false);
 130                 widest = Object.class;
 131             }
 132         }
 133 
 134         this.setArray(arrayData);
 135     }
 136 
 137     NativeArray(final Object[] array) {
 138         this(ArrayData.allocate(array.length));
 139 
 140         ArrayData arrayData = this.getArray();
 141 
 142         for (int index = 0; index < array.length; index++) {
 143             final Object value = array[index];
 144 
 145             if (value == ScriptRuntime.EMPTY) {
 146                 arrayData = arrayData.delete(index);
 147             } else {
 148                 arrayData = arrayData.set(index, value, false);
 149             }
 150         }
 151 
 152         this.setArray(arrayData);
 153     }
 154 


 189 
 190         return super.findSetIndexMethod(desc, request);
 191     }
 192 
 193     private static InvokeByName getJOIN() {
 194         return Global.instance().getInvokeByName(JOIN,
 195                 new Callable<InvokeByName>() {
 196                     @Override
 197                     public InvokeByName call() {
 198                         return new InvokeByName("join", ScriptObject.class);
 199                     }
 200                 });
 201     }
 202 
 203     private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class<?> rtype) {
 204         return Global.instance().getDynamicInvoker(key,
 205             new Callable<MethodHandle>() {
 206                 @Override
 207                 public MethodHandle call() {
 208                     return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class,
 209                         double.class, Object.class);
 210                 }
 211             });
 212     }
 213 
 214     private static MethodHandle getEVERY_CALLBACK_INVOKER() {
 215         return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class);
 216     }
 217 
 218     private static MethodHandle getSOME_CALLBACK_INVOKER() {
 219         return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.class);
 220     }
 221 
 222     private static MethodHandle getFOREACH_CALLBACK_INVOKER() {
 223         return createIteratorCallbackInvoker(FOREACH_CALLBACK_INVOKER, void.class);
 224     }
 225 
 226     private static MethodHandle getMAP_CALLBACK_INVOKER() {
 227         return createIteratorCallbackInvoker(MAP_CALLBACK_INVOKER, Object.class);
 228     }
 229 
 230     private static MethodHandle getFILTER_CALLBACK_INVOKER() {
 231         return createIteratorCallbackInvoker(FILTER_CALLBACK_INVOKER, boolean.class);
 232     }
 233 
 234     private static MethodHandle getREDUCE_CALLBACK_INVOKER() {
 235         return Global.instance().getDynamicInvoker(REDUCE_CALLBACK_INVOKER,
 236                 new Callable<MethodHandle>() {
 237                     @Override
 238                     public MethodHandle call() {
 239                         return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class,
 240                              Undefined.class, Object.class, Object.class, double.class, Object.class);
 241                     }
 242                 });
 243     }
 244 
 245     private static MethodHandle getCALL_CMP() {
 246         return Global.instance().getDynamicInvoker(CALL_CMP,
 247                 new Callable<MethodHandle>() {
 248                     @Override
 249                     public MethodHandle call() {
 250                         return Bootstrap.createDynamicInvoker("dyn:call", double.class,
 251                             ScriptFunction.class, Object.class, Object.class, Object.class);
 252                     }
 253                 });
 254     }
 255 
 256     private static InvokeByName getTO_LOCALE_STRING() {
 257         return Global.instance().getInvokeByName(TO_LOCALE_STRING,
 258                 new Callable<InvokeByName>() {
 259                     @Override
 260                     public InvokeByName call() {
 261                         return new InvokeByName("toLocaleString", ScriptObject.class, String.class);
 262                     }
 263                 });
 264     }
 265 
 266     // initialized by nasgen
 267     private static PropertyMap $nasgenmap$;
 268 
 269     @Override
 270     public String getClassName() {
 271         return "Array";
 272     }
 273 
 274     @Override
 275     public Object getLength() {
 276         final long length = getArray().length();
 277         assert length >= 0L;
 278         if (length <= Integer.MAX_VALUE) {
 279             return (int)length;
 280         }
 281         return length;
 282     }
 283 
 284     private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) {
 285         // Step 3a
 286         if (!desc.has(VALUE)) {
 287             return super.defineOwnProperty("length", desc, reject);
 288         }
 289 
 290         // Step 3b
 291         final PropertyDescriptor newLenDesc = desc;
 292 
 293         // Step 3c and 3d - get new length and convert to long
 294         final long newLen = NativeArray.validLength(newLenDesc.getValue());
 295 
 296         // Step 3e
 297         newLenDesc.setValue(newLen);
 298 


 456     /**
 457      * ECMA 15.4.3.2 Array.isArray ( arg )
 458      *
 459      * @param self self reference
 460      * @param arg  argument - object to check
 461      * @return true if argument is an array
 462      */
 463     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 464     public static boolean isArray(final Object self, final Object arg) {
 465         return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray());
 466     }
 467 
 468     /**
 469      * Length getter
 470      * @param self self reference
 471      * @return the length of the object
 472      */
 473     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
 474     public static Object length(final Object self) {
 475         if (isArray(self)) {
 476             final long length = ((ScriptObject) self).getArray().length();
 477             assert length >= 0L;
 478             // Cast to the narrowest supported numeric type to help optimistic type calculator
 479             if (length <= Integer.MAX_VALUE) {
 480                 return (int) length;
 481             }
 482             return (double) length;
 483         }
 484 
 485         return 0;
 486     }
 487 
 488     /**
 489      * Length setter
 490      * @param self   self reference
 491      * @param length new length property
 492      */
 493     @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
 494     public static void length(final Object self, final Object length) {
 495         if (isArray(self)) {
 496             ((ScriptObject)self).setLength(validLength(length));
 497         }
 498     }
 499 
 500     /**
 501      * Prototype length getter
 502      * @param self self reference


1570     }
1571 
1572     /**
1573      * ECMA 15.4.4.16 Array.prototype.every ( callbackfn [ , thisArg ] )
1574      *
1575      * @param self        self reference
1576      * @param callbackfn  callback function per element
1577      * @param thisArg     this argument
1578      * @return true if callback function return true for every element in the array, false otherwise
1579      */
1580     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
1581     public static boolean every(final Object self, final Object callbackfn, final Object thisArg) {
1582         return applyEvery(Global.toObject(self), callbackfn, thisArg);
1583     }
1584 
1585     private static boolean applyEvery(final Object self, final Object callbackfn, final Object thisArg) {
1586         return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, true) {
1587             private final MethodHandle everyInvoker = getEVERY_CALLBACK_INVOKER();
1588 
1589             @Override
1590             protected boolean forEach(final Object val, final double i) throws Throwable {
1591                 return result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self);
1592             }
1593         }.apply();
1594     }
1595 
1596     /**
1597      * ECMA 15.4.4.17 Array.prototype.some ( callbackfn [ , thisArg ] )
1598      *
1599      * @param self        self reference
1600      * @param callbackfn  callback function per element
1601      * @param thisArg     this argument
1602      * @return true if callback function returned true for any element in the array, false otherwise
1603      */
1604     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
1605     public static boolean some(final Object self, final Object callbackfn, final Object thisArg) {
1606         return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, false) {
1607             private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER();
1608 
1609             @Override
1610             protected boolean forEach(final Object val, final double i) throws Throwable {
1611                 return !(result = (boolean)someInvoker.invokeExact(callbackfn, thisArg, val, i, self));
1612             }
1613         }.apply();
1614     }
1615 
1616     /**
1617      * ECMA 15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
1618      *
1619      * @param self        self reference
1620      * @param callbackfn  callback function per element
1621      * @param thisArg     this argument
1622      * @return undefined
1623      */
1624     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
1625     public static Object forEach(final Object self, final Object callbackfn, final Object thisArg) {
1626         return new IteratorAction<Object>(Global.toObject(self), callbackfn, thisArg, ScriptRuntime.UNDEFINED) {
1627             private final MethodHandle forEachInvoker = getFOREACH_CALLBACK_INVOKER();
1628 
1629             @Override
1630             protected boolean forEach(final Object val, final double i) throws Throwable {
1631                 forEachInvoker.invokeExact(callbackfn, thisArg, val, i, self);
1632                 return true;
1633             }
1634         }.apply();
1635     }
1636 
1637     /**
1638      * ECMA 15.4.4.19 Array.prototype.map ( callbackfn [ , thisArg ] )
1639      *
1640      * @param self        self reference
1641      * @param callbackfn  callback function per element
1642      * @param thisArg     this argument
1643      * @return array with elements transformed by map function
1644      */
1645     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
1646     public static NativeArray map(final Object self, final Object callbackfn, final Object thisArg) {
1647         return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, null) {
1648             private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER();
1649 
1650             @Override
1651             protected boolean forEach(final Object val, final double i) throws Throwable {
1652                 final Object r = mapInvoker.invokeExact(callbackfn, thisArg, val, i, self);
1653                 result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r);
1654                 return true;
1655             }
1656 
1657             @Override
1658             public void applyLoopBegin(final ArrayLikeIterator<Object> iter0) {
1659                 // map return array should be of same length as source array
1660                 // even if callback reduces source array length
1661                 result = new NativeArray(iter0.getLength());
1662             }
1663         }.apply();
1664     }
1665 
1666     /**
1667      * ECMA 15.4.4.20 Array.prototype.filter ( callbackfn [ , thisArg ] )
1668      *
1669      * @param self        self reference
1670      * @param callbackfn  callback function per element
1671      * @param thisArg     this argument
1672      * @return filtered array
1673      */
1674     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
1675     public static NativeArray filter(final Object self, final Object callbackfn, final Object thisArg) {
1676         return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, new NativeArray()) {
1677             private long to = 0;
1678             private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER();
1679 
1680             @Override
1681             protected boolean forEach(final Object val, final double i) throws Throwable {
1682                 if ((boolean)filterInvoker.invokeExact(callbackfn, thisArg, val, i, self)) {
1683                     result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val);
1684                 }
1685                 return true;
1686             }
1687         }.apply();
1688     }
1689 
1690     private static Object reduceInner(final ArrayLikeIterator<Object> iter, final Object self, final Object... args) {
1691         final Object  callbackfn          = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED;
1692         final boolean initialValuePresent = args.length > 1;
1693 
1694         Object initialValue = initialValuePresent ? args[1] : ScriptRuntime.UNDEFINED;
1695 
1696         if (callbackfn == ScriptRuntime.UNDEFINED) {
1697             throw typeError("not.a.function", "undefined");
1698         }
1699 
1700         if (!initialValuePresent) {
1701             if (iter.hasNext()) {
1702                 initialValue = iter.next();
1703             } else {
1704                 throw typeError("array.reduce.invalid.init");
1705             }
1706         }
1707 
1708         //if initial value is ScriptRuntime.UNDEFINED - step forward once.
1709         return new IteratorAction<Object>(Global.toObject(self), callbackfn, ScriptRuntime.UNDEFINED, initialValue, iter) {
1710             private final MethodHandle reduceInvoker = getREDUCE_CALLBACK_INVOKER();
1711 
1712             @Override
1713             protected boolean forEach(final Object val, final double i) throws Throwable {
1714                 // TODO: why can't I declare the second arg as Undefined.class?
1715                 result = reduceInvoker.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self);
1716                 return true;
1717             }
1718         }.apply();
1719     }
1720 
1721     /**
1722      * ECMA 15.4.4.21 Array.prototype.reduce ( callbackfn [ , initialValue ] )
1723      *
1724      * @param self self reference
1725      * @param args arguments to reduce
1726      * @return accumulated result
1727      */
1728     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
1729     public static Object reduce(final Object self, final Object... args) {
1730         return reduceInner(arrayLikeIterator(self), self, args);
1731     }
1732 
1733     /**


< prev index next >