< prev index next >

src/jdk.scripting.nashorn/share/classes/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 


 162 
 163         return super.findSetIndexMethod(desc, request);
 164     }
 165 
 166     private static InvokeByName getJOIN() {
 167         return Global.instance().getInvokeByName(JOIN,
 168                 new Callable<InvokeByName>() {
 169                     @Override
 170                     public InvokeByName call() {
 171                         return new InvokeByName("join", ScriptObject.class);
 172                     }
 173                 });
 174     }
 175 
 176     private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class<?> rtype) {
 177         return Global.instance().getDynamicInvoker(key,
 178             new Callable<MethodHandle>() {
 179                 @Override
 180                 public MethodHandle call() {
 181                     return Bootstrap.createDynamicCallInvoker(rtype, Object.class, Object.class, Object.class,
 182                         long.class, Object.class);
 183                 }
 184             });
 185     }
 186 
 187     private static MethodHandle getEVERY_CALLBACK_INVOKER() {
 188         return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class);
 189     }
 190 
 191     private static MethodHandle getSOME_CALLBACK_INVOKER() {
 192         return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.class);
 193     }
 194 
 195     private static MethodHandle getFOREACH_CALLBACK_INVOKER() {
 196         return createIteratorCallbackInvoker(FOREACH_CALLBACK_INVOKER, void.class);
 197     }
 198 
 199     private static MethodHandle getMAP_CALLBACK_INVOKER() {
 200         return createIteratorCallbackInvoker(MAP_CALLBACK_INVOKER, Object.class);
 201     }
 202 
 203     private static MethodHandle getFILTER_CALLBACK_INVOKER() {
 204         return createIteratorCallbackInvoker(FILTER_CALLBACK_INVOKER, boolean.class);
 205     }
 206 
 207     private static MethodHandle getREDUCE_CALLBACK_INVOKER() {
 208         return Global.instance().getDynamicInvoker(REDUCE_CALLBACK_INVOKER,
 209                 new Callable<MethodHandle>() {
 210                     @Override
 211                     public MethodHandle call() {
 212                         return Bootstrap.createDynamicCallInvoker(Object.class, Object.class,
 213                              Undefined.class, Object.class, Object.class, long.class, Object.class);
 214                     }
 215                 });
 216     }
 217 
 218     private static MethodHandle getCALL_CMP() {
 219         return Global.instance().getDynamicInvoker(CALL_CMP,
 220                 new Callable<MethodHandle>() {
 221                     @Override
 222                     public MethodHandle call() {
 223                         return Bootstrap.createDynamicCallInvoker(double.class,
 224                             ScriptFunction.class, Object.class, Object.class, Object.class);
 225                     }
 226                 });
 227     }
 228 
 229     private static InvokeByName getTO_LOCALE_STRING() {
 230         return Global.instance().getInvokeByName(TO_LOCALE_STRING,
 231                 new Callable<InvokeByName>() {
 232                     @Override
 233                     public InvokeByName call() {
 234                         return new InvokeByName("toLocaleString", ScriptObject.class, String.class);
 235                     }
 236                 });
 237     }
 238 
 239     // initialized by nasgen
 240     private static PropertyMap $nasgenmap$;
 241 
 242     @Override
 243     public String getClassName() {
 244         return "Array";
 245     }
 246 
 247     @Override
 248     public Object getLength() {
 249         final long length = JSType.toUint32(getArray().length());
 250         if (length < Integer.MAX_VALUE) {

 251             return (int)length;
 252         }
 253         return length;
 254     }
 255 
 256     private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) {
 257         // Step 3a
 258         if (!desc.has(VALUE)) {
 259             return super.defineOwnProperty("length", desc, reject);
 260         }
 261 
 262         // Step 3b
 263         final PropertyDescriptor newLenDesc = desc;
 264 
 265         // Step 3c and 3d - get new length and convert to long
 266         final long newLen = NativeArray.validLength(newLenDesc.getValue());
 267 
 268         // Step 3e
 269         newLenDesc.setValue(newLen);
 270 


 428     /**
 429      * ECMA 15.4.3.2 Array.isArray ( arg )
 430      *
 431      * @param self self reference
 432      * @param arg  argument - object to check
 433      * @return true if argument is an array
 434      */
 435     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 436     public static boolean isArray(final Object self, final Object arg) {
 437         return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray());
 438     }
 439 
 440     /**
 441      * Length getter
 442      * @param self self reference
 443      * @return the length of the object
 444      */
 445     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
 446     public static Object length(final Object self) {
 447         if (isArray(self)) {
 448             return JSType.toUint32(((ScriptObject) self).getArray().length());






 449         }
 450 
 451         return 0;
 452     }
 453 
 454     /**
 455      * Length setter
 456      * @param self   self reference
 457      * @param length new length property
 458      */
 459     @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
 460     public static void length(final Object self, final Object length) {
 461         if (isArray(self)) {
 462             ((ScriptObject)self).setLength(validLength(length));
 463         }
 464     }
 465 
 466     /**
 467      * Prototype length getter
 468      * @param self self reference


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




  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 


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


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


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


< prev index next >