e94134b81aa851a9539ceb86d38e72971279fa78
[platform/upstream/v8.git] / src / harmony-array.js
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 (function(global, utils) {
6
7 'use strict';
8
9 %CheckIsBootstrapping();
10
11 // -------------------------------------------------------------------
12 // Imports
13
14 var GlobalArray = global.Array;
15 var GlobalSymbol = global.Symbol;
16
17 var GetIterator;
18 var GetMethod;
19 var MathMax;
20 var MathMin;
21 var ObjectIsFrozen;
22 var ObjectDefineProperty;
23
24 utils.Import(function(from) {
25   GetIterator = from.GetIterator;
26   GetMethod = from.GetMethod;
27   MathMax = from.MathMax;
28   MathMin = from.MathMin;
29   ObjectIsFrozen = from.ObjectIsFrozen;
30   ObjectDefineProperty = from.ObjectDefineProperty;
31 });
32
33 // -------------------------------------------------------------------
34
35 function InnerArrayCopyWithin(target, start, end, array, length) {
36   target = TO_INTEGER(target);
37   var to;
38   if (target < 0) {
39     to = MathMax(length + target, 0);
40   } else {
41     to = MathMin(target, length);
42   }
43
44   start = TO_INTEGER(start);
45   var from;
46   if (start < 0) {
47     from = MathMax(length + start, 0);
48   } else {
49     from = MathMin(start, length);
50   }
51
52   end = IS_UNDEFINED(end) ? length : TO_INTEGER(end);
53   var final;
54   if (end < 0) {
55     final = MathMax(length + end, 0);
56   } else {
57     final = MathMin(end, length);
58   }
59
60   var count = MathMin(final - from, length - to);
61   var direction = 1;
62   if (from < to && to < (from + count)) {
63     direction = -1;
64     from = from + count - 1;
65     to = to + count - 1;
66   }
67
68   while (count > 0) {
69     if (from in array) {
70       array[to] = array[from];
71     } else {
72       delete array[to];
73     }
74     from = from + direction;
75     to = to + direction;
76     count--;
77   }
78
79   return array;
80 }
81
82 // ES6 draft 03-17-15, section 22.1.3.3
83 function ArrayCopyWithin(target, start, end) {
84   CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
85
86   var array = TO_OBJECT_INLINE(this);
87   var length = $toLength(array.length);
88
89   return InnerArrayCopyWithin(target, start, end, array, length);
90 }
91
92 function InnerArrayFind(predicate, thisArg, array, length) {
93   if (!IS_SPEC_FUNCTION(predicate)) {
94     throw MakeTypeError(kCalledNonCallable, predicate);
95   }
96
97   var needs_wrapper = false;
98   if (IS_NULL(thisArg)) {
99     if (%IsSloppyModeFunction(predicate)) thisArg = UNDEFINED;
100   } else if (!IS_UNDEFINED(thisArg)) {
101     needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
102   }
103
104   for (var i = 0; i < length; i++) {
105     var element = array[i];
106     var newThisArg = needs_wrapper ? $toObject(thisArg) : thisArg;
107     if (%_CallFunction(newThisArg, element, i, array, predicate)) {
108       return element;
109     }
110   }
111
112   return;
113 }
114
115 // ES6 draft 07-15-13, section 15.4.3.23
116 function ArrayFind(predicate, thisArg) {
117   CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find");
118
119   var array = $toObject(this);
120   var length = $toInteger(array.length);
121
122   return InnerArrayFind(predicate, thisArg, array, length);
123 }
124
125 function InnerArrayFindIndex(predicate, thisArg, array, length) {
126   if (!IS_SPEC_FUNCTION(predicate)) {
127     throw MakeTypeError(kCalledNonCallable, predicate);
128   }
129
130   var needs_wrapper = false;
131   if (IS_NULL(thisArg)) {
132     if (%IsSloppyModeFunction(predicate)) thisArg = UNDEFINED;
133   } else if (!IS_UNDEFINED(thisArg)) {
134     needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
135   }
136
137   for (var i = 0; i < length; i++) {
138     var element = array[i];
139     var newThisArg = needs_wrapper ? $toObject(thisArg) : thisArg;
140     if (%_CallFunction(newThisArg, element, i, array, predicate)) {
141       return i;
142     }
143   }
144
145   return -1;
146 }
147
148 // ES6 draft 07-15-13, section 15.4.3.24
149 function ArrayFindIndex(predicate, thisArg) {
150   CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex");
151
152   var array = $toObject(this);
153   var length = $toInteger(array.length);
154
155   return InnerArrayFindIndex(predicate, thisArg, array, length);
156 }
157
158 // ES6, draft 04-05-14, section 22.1.3.6
159 function InnerArrayFill(value, start, end, array, length) {
160   var i = IS_UNDEFINED(start) ? 0 : TO_INTEGER(start);
161   var end = IS_UNDEFINED(end) ? length : TO_INTEGER(end);
162
163   if (i < 0) {
164     i += length;
165     if (i < 0) i = 0;
166   } else {
167     if (i > length) i = length;
168   }
169
170   if (end < 0) {
171     end += length;
172     if (end < 0) end = 0;
173   } else {
174     if (end > length) end = length;
175   }
176
177   if ((end - i) > 0 && ObjectIsFrozen(array)) {
178     throw MakeTypeError(kArrayFunctionsOnFrozen);
179   }
180
181   for (; i < end; i++)
182     array[i] = value;
183   return array;
184 }
185
186 // ES6, draft 04-05-14, section 22.1.3.6
187 function ArrayFill(value, start, end) {
188   CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill");
189
190   var array = $toObject(this);
191   var length = TO_UINT32(array.length);
192
193   return InnerArrayFill(value, start, end, array, length);
194 }
195
196 function AddArrayElement(constructor, array, i, value) {
197   if (constructor === GlobalArray) {
198     %AddElement(array, i, value);
199   } else {
200     ObjectDefineProperty(array, i, {
201       value: value, writable: true, configurable: true, enumerable: true
202     });
203   }
204 }
205
206 // ES6, draft 10-14-14, section 22.1.2.1
207 function ArrayFrom(arrayLike, mapfn, receiver) {
208   var items = $toObject(arrayLike);
209   var mapping = !IS_UNDEFINED(mapfn);
210
211   if (mapping) {
212     if (!IS_SPEC_FUNCTION(mapfn)) {
213       throw MakeTypeError(kCalledNonCallable, mapfn);
214     } else if (%IsSloppyModeFunction(mapfn)) {
215       if (IS_NULL(receiver)) {
216         receiver = UNDEFINED;
217       } else if (!IS_UNDEFINED(receiver)) {
218         receiver = TO_OBJECT_INLINE(receiver);
219       }
220     }
221   }
222
223   var iterable = GetMethod(items, symbolIterator);
224   var k;
225   var result;
226   var mappedValue;
227   var nextValue;
228
229   if (!IS_UNDEFINED(iterable)) {
230     result = %IsConstructor(this) ? new this() : [];
231
232     var iterator = GetIterator(items, iterable);
233
234     k = 0;
235     while (true) {
236       var next = iterator.next();
237
238       if (!IS_OBJECT(next)) {
239         throw MakeTypeError(kIteratorResultNotAnObject, next);
240       }
241
242       if (next.done) {
243         result.length = k;
244         return result;
245       }
246
247       nextValue = next.value;
248       if (mapping) {
249         mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
250       } else {
251         mappedValue = nextValue;
252       }
253       AddArrayElement(this, result, k, mappedValue);
254       k++;
255     }
256   } else {
257     var len = $toLength(items.length);
258     result = %IsConstructor(this) ? new this(len) : new GlobalArray(len);
259
260     for (k = 0; k < len; ++k) {
261       nextValue = items[k];
262       if (mapping) {
263         mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
264       } else {
265         mappedValue = nextValue;
266       }
267       AddArrayElement(this, result, k, mappedValue);
268     }
269
270     result.length = k;
271     return result;
272   }
273 }
274
275 // ES6, draft 05-22-14, section 22.1.2.3
276 function ArrayOf() {
277   var length = %_ArgumentsLength();
278   var constructor = this;
279   // TODO: Implement IsConstructor (ES6 section 7.2.5)
280   var array = %IsConstructor(constructor) ? new constructor(length) : [];
281   for (var i = 0; i < length; i++) {
282     AddArrayElement(constructor, array, i, %_Arguments(i));
283   }
284   array.length = length;
285   return array;
286 }
287
288 // -------------------------------------------------------------------
289
290 %FunctionSetLength(ArrayCopyWithin, 2);
291 %FunctionSetLength(ArrayFrom, 1);
292 %FunctionSetLength(ArrayFill, 1);
293 %FunctionSetLength(ArrayFind, 1);
294 %FunctionSetLength(ArrayFindIndex, 1);
295
296 // Set up non-enumerable functions on the Array object.
297 utils.InstallFunctions(GlobalArray, DONT_ENUM, [
298   "from", ArrayFrom,
299   "of", ArrayOf
300 ]);
301
302 // Set up the non-enumerable functions on the Array prototype object.
303 utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
304   "copyWithin", ArrayCopyWithin,
305   "find", ArrayFind,
306   "findIndex", ArrayFindIndex,
307   "fill", ArrayFill
308 ]);
309
310 // -------------------------------------------------------------------
311 // Exports
312
313 utils.Export(function(to) {
314   to.ArrayFrom = ArrayFrom;
315   to.InnerArrayCopyWithin = InnerArrayCopyWithin;
316   to.InnerArrayFill = InnerArrayFill;
317   to.InnerArrayFind = InnerArrayFind;
318   to.InnerArrayFindIndex = InnerArrayFindIndex;
319 });
320
321 })