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