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