Array.prototype.toString should be generic
[WebKit-https.git] / Source / JavaScriptCore / runtime / ArrayPrototype.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
4  *  Copyright (C) 2003 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
20  *  USA
21  *
22  */
23
24 #include "config.h"
25 #include "ArrayPrototype.h"
26
27 #include "CachedCall.h"
28 #include "CodeBlock.h"
29 #include "Interpreter.h"
30 #include "JIT.h"
31 #include "JSStringBuilder.h"
32 #include "JSStringJoiner.h"
33 #include "Lookup.h"
34 #include "ObjectPrototype.h"
35 #include "Operations.h"
36 #include "StringRecursionChecker.h"
37 #include <algorithm>
38 #include <wtf/Assertions.h>
39 #include <wtf/HashSet.h>
40
41 namespace JSC {
42
43 ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype);
44
45 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
46 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*);
47 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*);
48 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*);
49 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*);
50 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*);
51 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*);
52 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*);
53 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*);
55 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*);
56 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*);
57 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*);
58 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*);
59 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*);
60 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*);
61 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*);
62 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*);
63 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*);
64 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*);
65 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*);
66
67 }
68
69 #include "ArrayPrototype.lut.h"
70
71 namespace JSC {
72
73 static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, const CallData& callData)
74 {
75     if (callType != CallTypeJS)
76         return false;
77
78     FunctionExecutable* executable = callData.js.functionExecutable;
79
80     JSObject* error = executable->compileForCall(exec, callData.js.scopeChain);
81     if (error)
82         return false;
83
84     return executable->generatedBytecodeForCall().isNumericCompareFunction();
85 }
86
87 // ------------------------------ ArrayPrototype ----------------------------
88
89 const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecState::arrayPrototypeTable, CREATE_METHOD_TABLE(ArrayPrototype)};
90
91 /* Source for ArrayPrototype.lut.h
92 @begin arrayPrototypeTable 16
93   toString       arrayProtoFuncToString       DontEnum|Function 0
94   toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0
95   concat         arrayProtoFuncConcat         DontEnum|Function 1
96   join           arrayProtoFuncJoin           DontEnum|Function 1
97   pop            arrayProtoFuncPop            DontEnum|Function 0
98   push           arrayProtoFuncPush           DontEnum|Function 1
99   reverse        arrayProtoFuncReverse        DontEnum|Function 0
100   shift          arrayProtoFuncShift          DontEnum|Function 0
101   slice          arrayProtoFuncSlice          DontEnum|Function 2
102   sort           arrayProtoFuncSort           DontEnum|Function 1
103   splice         arrayProtoFuncSplice         DontEnum|Function 2
104   unshift        arrayProtoFuncUnShift        DontEnum|Function 1
105   every          arrayProtoFuncEvery          DontEnum|Function 1
106   forEach        arrayProtoFuncForEach        DontEnum|Function 1
107   some           arrayProtoFuncSome           DontEnum|Function 1
108   indexOf        arrayProtoFuncIndexOf        DontEnum|Function 1
109   lastIndexOf    arrayProtoFuncLastIndexOf    DontEnum|Function 1
110   filter         arrayProtoFuncFilter         DontEnum|Function 1
111   reduce         arrayProtoFuncReduce         DontEnum|Function 1
112   reduceRight    arrayProtoFuncReduceRight    DontEnum|Function 1
113   map            arrayProtoFuncMap            DontEnum|Function 1
114 @end
115 */
116
117 // ECMA 15.4.4
118 ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
119     : JSArray(globalObject->globalData(), structure)
120 {
121 }
122
123 void ArrayPrototype::finishCreation(JSGlobalObject* globalObject)
124 {
125     Base::finishCreation(globalObject->globalData());
126     ASSERT(inherits(&s_info));
127 }
128
129 bool ArrayPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
130 {
131     return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayPrototypeTable(exec), jsCast<ArrayPrototype*>(cell), propertyName, slot);
132 }
133
134 bool ArrayPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
135 {
136     return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayPrototypeTable(exec), jsCast<ArrayPrototype*>(object), propertyName, descriptor);
137 }
138
139 // ------------------------------ Array Functions ----------------------------
140
141 // Helper function
142 static JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index)
143 {
144     PropertySlot slot(obj);
145     if (!obj->getPropertySlot(exec, index, slot))
146         return JSValue();
147     return slot.getValue(exec, index);
148 }
149
150 static void putProperty(ExecState* exec, JSObject* obj, const Identifier& propertyName, JSValue value)
151 {
152     PutPropertySlot slot;
153     obj->methodTable()->put(obj, exec, propertyName, value, slot);
154 }
155
156 static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
157 {
158     JSValue value = exec->argument(argument);
159     if (value.isUndefined())
160         return undefinedValue;
161
162     double indexDouble = value.toInteger(exec);
163     if (indexDouble < 0) {
164         indexDouble += length;
165         return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
166     }
167     return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
168 }
169
170
171 // The shift/unshift function implement the shift/unshift behaviour required
172 // by the corresponding array prototype methods, and by splice. In both cases,
173 // the methods are operating an an array or array like object.
174 //
175 //  header  currentCount  (remainder)
176 // [------][------------][-----------]
177 //  header  resultCount  (remainder)
178 // [------][-----------][-----------]
179 //
180 // The set of properties in the range 'header' must be unchanged. The set of
181 // properties in the range 'remainder' (where remainder = length - header -
182 // currentCount) will be shifted to the left or right as appropriate; in the
183 // case of shift this must be removing values, in the case of unshift this
184 // must be introducing new values.
185 static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
186 {
187     ASSERT(currentCount > resultCount);
188     unsigned count = currentCount - resultCount;
189
190     ASSERT(header <= length);
191     ASSERT(currentCount <= (length - header));
192
193     if (!header && isJSArray(thisObj) && asArray(thisObj)->shiftCount(exec, count))
194         return;
195
196     for (unsigned k = header; k < length - currentCount; ++k) {
197         unsigned from = k + currentCount;
198         unsigned to = k + resultCount;
199         PropertySlot slot(thisObj);
200         if (thisObj->getPropertySlot(exec, from, slot)) {
201             JSValue value = slot.getValue(exec, from);
202             if (exec->hadException())
203                 return;
204             thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true);
205             if (exec->hadException())
206                 return;
207         } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) {
208             throwTypeError(exec, "Unable to delete property.");
209             return;
210         }
211     }
212     for (unsigned k = length; k > length - count; --k) {
213         if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1)) {
214             throwTypeError(exec, "Unable to delete property.");
215             return;
216         }
217     }
218 }
219 static inline void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
220 {
221     ASSERT(resultCount > currentCount);
222     unsigned count = resultCount - currentCount;
223
224     ASSERT(header <= length);
225     ASSERT(currentCount <= (length - header));
226
227     // Guard against overflow.
228     if (count > (UINT_MAX - length)) {
229         throwOutOfMemoryError(exec);
230         return;
231     }
232
233     if (!header && isJSArray(thisObj) && asArray(thisObj)->unshiftCount(exec, count))
234         return;
235
236     for (unsigned k = length - currentCount; k > header; --k) {
237         unsigned from = k + currentCount - 1;
238         unsigned to = k + resultCount - 1;
239         PropertySlot slot(thisObj);
240         if (thisObj->getPropertySlot(exec, from, slot)) {
241             JSValue value = slot.getValue(exec, from);
242             if (exec->hadException())
243                 return;
244             thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true);
245         } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) {
246             throwTypeError(exec, "Unable to delete property.");
247             return;
248         }
249         if (exec->hadException())
250             return;
251     }
252 }
253
254 EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
255 {
256     JSValue thisValue = exec->hostThisValue();
257
258     // 1. Let array be the result of calling ToObject on the this value.
259     JSObject* thisObject = thisValue.toObject(exec);
260     if (exec->hadException())
261         return JSValue::encode(jsUndefined());
262     
263     // 2. Let func be the result of calling the [[Get]] internal method of array with argument "join".
264     JSValue function = JSValue(thisObject).get(exec, exec->propertyNames().join);
265
266     // 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
267     if (!function.isCell())
268         return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
269     CallData callData;
270     CallType callType = getCallData(function, callData);
271     if (callType == CallTypeNone)
272         return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
273
274     // 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
275     if (!isJSArray(thisObject) || callType != CallTypeHost || callData.native.function != arrayProtoFuncJoin)
276         return JSValue::encode(call(exec, function, callType, callData, thisObject, exec->emptyList()));
277
278     ASSERT(isJSArray(thisValue));
279     JSArray* thisObj = asArray(thisValue);
280     
281     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
282     if (exec->hadException())
283         return JSValue::encode(jsUndefined());
284
285     StringRecursionChecker checker(exec, thisObj);
286     if (JSValue earlyReturnValue = checker.earlyReturnValue())
287         return JSValue::encode(earlyReturnValue);
288
289     unsigned totalSize = length ? length - 1 : 0;
290     Vector<RefPtr<StringImpl>, 256> strBuffer(length);
291     bool allStrings8Bit = true;
292
293     for (unsigned k = 0; k < length; k++) {
294         JSValue element;
295         if (thisObj->canGetIndex(k))
296             element = thisObj->getIndex(k);
297         else
298             element = thisObj->get(exec, k);
299         
300         if (element.isUndefinedOrNull())
301             continue;
302         
303         UString str = element.toUString(exec);
304         strBuffer[k] = str.impl();
305         totalSize += str.length();
306         allStrings8Bit = allStrings8Bit && str.is8Bit();
307         
308         if (!strBuffer.data()) {
309             throwOutOfMemoryError(exec);
310         }
311         
312         if (exec->hadException())
313             break;
314     }
315     if (!totalSize)
316         return JSValue::encode(jsEmptyString(exec));
317
318     if (allStrings8Bit) {
319         Vector<LChar> buffer;
320         buffer.reserveCapacity(totalSize);
321         if (!buffer.data())
322             return JSValue::encode(throwOutOfMemoryError(exec));
323         
324         for (unsigned i = 0; i < length; i++) {
325             if (i)
326                 buffer.append(',');
327             if (RefPtr<StringImpl> rep = strBuffer[i])
328                 buffer.append(rep->characters8(), rep->length());
329         }
330         ASSERT(buffer.size() == totalSize);
331         return JSValue::encode(jsString(exec, UString::adopt(buffer)));        
332     }
333
334     Vector<UChar> buffer;
335     buffer.reserveCapacity(totalSize);
336     if (!buffer.data())
337         return JSValue::encode(throwOutOfMemoryError(exec));
338         
339     for (unsigned i = 0; i < length; i++) {
340         if (i)
341             buffer.append(',');
342         if (RefPtr<StringImpl> rep = strBuffer[i])
343             buffer.append(rep->characters(), rep->length());
344     }
345     ASSERT(buffer.size() == totalSize);
346     return JSValue::encode(jsString(exec, UString::adopt(buffer)));
347 }
348
349 EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
350 {
351     JSValue thisValue = exec->hostThisValue();
352
353     if (!thisValue.inherits(&JSArray::s_info))
354         return throwVMTypeError(exec);
355     JSObject* thisObj = asArray(thisValue);
356
357     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
358     if (exec->hadException())
359         return JSValue::encode(jsUndefined());
360
361     StringRecursionChecker checker(exec, thisObj);
362     if (JSValue earlyReturnValue = checker.earlyReturnValue())
363         return JSValue::encode(earlyReturnValue);
364
365     UString separator(",");
366     JSStringJoiner stringJoiner(separator, length);
367     for (unsigned k = 0; k < length; k++) {
368         JSValue element = thisObj->get(exec, k);
369         if (exec->hadException())
370             return JSValue::encode(jsUndefined());
371         if (!element.isUndefinedOrNull()) {
372             JSObject* o = element.toObject(exec);
373             JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
374             if (exec->hadException())
375                 return JSValue::encode(jsUndefined());
376             UString str;
377             CallData callData;
378             CallType callType = getCallData(conversionFunction, callData);
379             if (callType != CallTypeNone)
380                 str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toUString(exec);
381             else
382                 str = element.toUString(exec);
383             if (exec->hadException())
384                 return JSValue::encode(jsUndefined());
385             stringJoiner.append(str);
386         }
387     }
388
389     return JSValue::encode(stringJoiner.build(exec));
390 }
391
392 EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
393 {
394     JSObject* thisObj = exec->hostThisValue().toObject(exec);
395     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
396     if (exec->hadException())
397         return JSValue::encode(jsUndefined());
398
399     StringRecursionChecker checker(exec, thisObj);
400     if (JSValue earlyReturnValue = checker.earlyReturnValue())
401         return JSValue::encode(earlyReturnValue);
402
403     UString separator;
404     if (!exec->argument(0).isUndefined())
405         separator = exec->argument(0).toUString(exec);
406     if (separator.isNull())
407         separator = UString(",");
408
409     JSStringJoiner stringJoiner(separator, length);
410
411     unsigned k = 0;
412     if (isJSArray(thisObj)) {
413         JSArray* array = asArray(thisObj);
414
415         for (; k < length; k++) {
416             if (!array->canGetIndex(k))
417                 break;
418
419             JSValue element = array->getIndex(k);
420             if (!element.isUndefinedOrNull())
421                 stringJoiner.append(element.toUStringInline(exec));
422             else
423                 stringJoiner.append(UString());
424         }
425     }
426
427     for (; k < length; k++) {
428         JSValue element = thisObj->get(exec, k);
429         if (!element.isUndefinedOrNull())
430             stringJoiner.append(element.toUStringInline(exec));
431         else
432             stringJoiner.append(UString());
433     }
434
435     return JSValue::encode(stringJoiner.build(exec));
436 }
437
438 EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
439 {
440     JSValue thisValue = exec->hostThisValue();
441     JSArray* arr = constructEmptyArray(exec);
442     unsigned n = 0;
443     JSValue curArg = thisValue.toObject(exec);
444     if (exec->hadException())
445         return JSValue::encode(jsUndefined());
446     size_t i = 0;
447     size_t argCount = exec->argumentCount();
448     while (1) {
449         if (curArg.inherits(&JSArray::s_info)) {
450             unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec);
451             JSObject* curObject = curArg.toObject(exec);
452             for (unsigned k = 0; k < length; ++k) {
453                 JSValue v = getProperty(exec, curObject, k);
454                 if (exec->hadException())
455                     return JSValue::encode(jsUndefined());
456                 if (v)
457                     arr->putDirectIndex(exec, n, v);
458                 n++;
459             }
460         } else {
461             arr->putDirectIndex(exec, n, curArg);
462             n++;
463         }
464         if (i == argCount)
465             break;
466         curArg = (exec->argument(i));
467         ++i;
468     }
469     arr->setLength(exec, n);
470     return JSValue::encode(arr);
471 }
472
473 EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
474 {
475     JSValue thisValue = exec->hostThisValue();
476
477     if (isJSArray(thisValue))
478         return JSValue::encode(asArray(thisValue)->pop(exec));
479
480     JSObject* thisObj = thisValue.toObject(exec);
481     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
482     if (exec->hadException())
483         return JSValue::encode(jsUndefined());
484
485     JSValue result;
486     if (length == 0) {
487         putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
488         result = jsUndefined();
489     } else {
490         result = thisObj->get(exec, length - 1);
491         if (exec->hadException())
492             return JSValue::encode(jsUndefined());
493         if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1)) {
494             throwTypeError(exec, "Unable to delete property.");
495             return JSValue::encode(jsUndefined());
496         }
497         putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
498     }
499     return JSValue::encode(result);
500 }
501
502 EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
503 {
504     JSValue thisValue = exec->hostThisValue();
505
506     if (isJSArray(thisValue) && exec->argumentCount() == 1) {
507         JSArray* array = asArray(thisValue);
508         array->push(exec, exec->argument(0));
509         return JSValue::encode(jsNumber(array->length()));
510     }
511
512     JSObject* thisObj = thisValue.toObject(exec);
513     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
514     if (exec->hadException())
515         return JSValue::encode(jsUndefined());
516
517     for (unsigned n = 0; n < exec->argumentCount(); n++) {
518         // Check for integer overflow; where safe we can do a fast put by index.
519         if (length + n >= length)
520             thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n), true);
521         else {
522             PutPropertySlot slot;
523             Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toUString(exec));
524             thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot);
525         }
526         if (exec->hadException())
527             return JSValue::encode(jsUndefined());
528     }
529     JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount()));
530     putProperty(exec, thisObj, exec->propertyNames().length, newLength);
531     return JSValue::encode(newLength);
532 }
533
534 EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec)
535 {
536     JSObject* thisObj = exec->hostThisValue().toObject(exec);
537     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
538     if (exec->hadException())
539         return JSValue::encode(jsUndefined());
540
541     unsigned middle = length / 2;
542     for (unsigned k = 0; k < middle; k++) {
543         unsigned lk1 = length - k - 1;
544         JSValue obj2 = getProperty(exec, thisObj, lk1);
545         if (exec->hadException())
546             return JSValue::encode(jsUndefined());
547         JSValue obj = getProperty(exec, thisObj, k);
548         if (exec->hadException())
549             return JSValue::encode(jsUndefined());
550
551         if (obj2) {
552             thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2, true);
553             if (exec->hadException())
554                 return JSValue::encode(jsUndefined());
555         } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k)) {
556             throwTypeError(exec, "Unable to delete property.");
557             return JSValue::encode(jsUndefined());
558         }
559
560         if (obj) {
561             thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj, true);
562             if (exec->hadException())
563                 return JSValue::encode(jsUndefined());
564         } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1)) {
565             throwTypeError(exec, "Unable to delete property.");
566             return JSValue::encode(jsUndefined());
567         }
568     }
569     return JSValue::encode(thisObj);
570 }
571
572 EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
573 {
574     JSObject* thisObj = exec->hostThisValue().toObject(exec);
575     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
576     if (exec->hadException())
577         return JSValue::encode(jsUndefined());
578
579     JSValue result;
580     if (length == 0) {
581         putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
582         result = jsUndefined();
583     } else {
584         result = thisObj->get(exec, 0);
585         shift(exec, thisObj, 0, 1, 0, length);
586         if (exec->hadException())
587             return JSValue::encode(jsUndefined());
588         putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
589     }
590     return JSValue::encode(result);
591 }
592
593 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
594 {
595     // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
596     JSObject* thisObj = exec->hostThisValue().toObject(exec);
597     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
598     if (exec->hadException())
599         return JSValue::encode(jsUndefined());
600
601     // We return a new array
602     JSArray* resObj = constructEmptyArray(exec);
603     JSValue result = resObj;
604
605     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
606     unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
607
608     unsigned n = 0;
609     for (unsigned k = begin; k < end; k++, n++) {
610         JSValue v = getProperty(exec, thisObj, k);
611         if (exec->hadException())
612             return JSValue::encode(jsUndefined());
613         if (v)
614             resObj->putDirectIndex(exec, n, v);
615     }
616     resObj->setLength(exec, n);
617     return JSValue::encode(result);
618 }
619
620 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
621 {
622     JSObject* thisObj = exec->hostThisValue().toObject(exec);
623     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
624     if (!length || exec->hadException())
625         return JSValue::encode(thisObj);
626
627     JSValue function = exec->argument(0);
628     CallData callData;
629     CallType callType = getCallData(function, callData);
630
631     if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseMode()) {
632         if (isNumericCompareFunction(exec, callType, callData))
633             asArray(thisObj)->sortNumeric(exec, function, callType, callData);
634         else if (callType != CallTypeNone)
635             asArray(thisObj)->sort(exec, function, callType, callData);
636         else
637             asArray(thisObj)->sort(exec);
638         return JSValue::encode(thisObj);
639     }
640
641     // "Min" sort. Not the fastest, but definitely less code than heapsort
642     // or quicksort, and much less swapping than bubblesort/insertionsort.
643     for (unsigned i = 0; i < length - 1; ++i) {
644         JSValue iObj = thisObj->get(exec, i);
645         if (exec->hadException())
646             return JSValue::encode(jsUndefined());
647         unsigned themin = i;
648         JSValue minObj = iObj;
649         for (unsigned j = i + 1; j < length; ++j) {
650             JSValue jObj = thisObj->get(exec, j);
651             if (exec->hadException())
652                 return JSValue::encode(jsUndefined());
653             double compareResult;
654             if (jObj.isUndefined())
655                 compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
656             else if (minObj.isUndefined())
657                 compareResult = -1;
658             else if (callType != CallTypeNone) {
659                 MarkedArgumentBuffer l;
660                 l.append(jObj);
661                 l.append(minObj);
662                 compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
663             } else
664                 compareResult = (jObj.toUStringInline(exec) < minObj.toUStringInline(exec)) ? -1 : 1;
665
666             if (compareResult < 0) {
667                 themin = j;
668                 minObj = jObj;
669             }
670         }
671         // Swap themin and i
672         if (themin > i) {
673             thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true);
674             if (exec->hadException())
675                 return JSValue::encode(jsUndefined());
676             thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true);
677             if (exec->hadException())
678                 return JSValue::encode(jsUndefined());
679         }
680     }
681     return JSValue::encode(thisObj);
682 }
683
684 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
685 {
686     // 15.4.4.12
687
688     JSObject* thisObj = exec->hostThisValue().toObject(exec);
689     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
690     if (exec->hadException())
691         return JSValue::encode(jsUndefined());
692
693     if (!exec->argumentCount())
694         return JSValue::encode(constructEmptyArray(exec));
695
696     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
697
698     unsigned deleteCount = length - begin;
699     if (exec->argumentCount() > 1) {
700         double deleteDouble = exec->argument(1).toInteger(exec);
701         if (deleteDouble < 0)
702             deleteCount = 0;
703         else if (deleteDouble > length - begin)
704             deleteCount = length - begin;
705         else
706             deleteCount = static_cast<unsigned>(deleteDouble);
707     }
708
709     JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount);
710     if (!resObj)
711         return JSValue::encode(throwOutOfMemoryError(exec));
712
713     JSValue result = resObj;
714     JSGlobalData& globalData = exec->globalData();
715     for (unsigned k = 0; k < deleteCount; k++) {
716         JSValue v = getProperty(exec, thisObj, k + begin);
717         if (exec->hadException())
718             return JSValue::encode(jsUndefined());
719         resObj->initializeIndex(globalData, k, v);
720     }
721     resObj->completeInitialization(deleteCount);
722
723     unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
724     if (additionalArgs < deleteCount) {
725         shift(exec, thisObj, begin, deleteCount, additionalArgs, length);
726         if (exec->hadException())
727             return JSValue::encode(jsUndefined());
728     } else if (additionalArgs > deleteCount) {
729         unshift(exec, thisObj, begin, deleteCount, additionalArgs, length);
730         if (exec->hadException())
731             return JSValue::encode(jsUndefined());
732     }
733     for (unsigned k = 0; k < additionalArgs; ++k) {
734         thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->argument(k + 2), true);
735         if (exec->hadException())
736             return JSValue::encode(jsUndefined());
737     }
738
739     putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
740     return JSValue::encode(result);
741 }
742
743 EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
744 {
745     // 15.4.4.13
746
747     JSObject* thisObj = exec->hostThisValue().toObject(exec);
748     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
749     if (exec->hadException())
750         return JSValue::encode(jsUndefined());
751
752     unsigned nrArgs = exec->argumentCount();
753     if (nrArgs) {
754         unshift(exec, thisObj, 0, 0, nrArgs, length);
755         if (exec->hadException())
756             return JSValue::encode(jsUndefined());
757     }
758     for (unsigned k = 0; k < nrArgs; ++k) {
759         thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->argument(k), true);
760         if (exec->hadException())
761             return JSValue::encode(jsUndefined());
762     }
763     JSValue result = jsNumber(length + nrArgs);
764     putProperty(exec, thisObj, exec->propertyNames().length, result);
765     return JSValue::encode(result);
766 }
767
768 EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
769 {
770     JSObject* thisObj = exec->hostThisValue().toObject(exec);
771     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
772     if (exec->hadException())
773         return JSValue::encode(jsUndefined());
774
775     JSValue function = exec->argument(0);
776     CallData callData;
777     CallType callType = getCallData(function, callData);
778     if (callType == CallTypeNone)
779         return throwVMTypeError(exec);
780
781     JSValue applyThis = exec->argument(1);
782     JSArray* resultArray = constructEmptyArray(exec);
783
784     unsigned filterIndex = 0;
785     unsigned k = 0;
786     if (callType == CallTypeJS && isJSArray(thisObj)) {
787         JSFunction* f = jsCast<JSFunction*>(function);
788         JSArray* array = asArray(thisObj);
789         CachedCall cachedCall(exec, f, 3);
790         for (; k < length && !exec->hadException(); ++k) {
791             if (!array->canGetIndex(k))
792                 break;
793             JSValue v = array->getIndex(k);
794             cachedCall.setThis(applyThis);
795             cachedCall.setArgument(0, v);
796             cachedCall.setArgument(1, jsNumber(k));
797             cachedCall.setArgument(2, thisObj);
798             
799             JSValue result = cachedCall.call();
800             if (result.toBoolean(exec))
801                 resultArray->putDirectIndex(exec, filterIndex++, v);
802         }
803         if (k == length)
804             return JSValue::encode(resultArray);
805     }
806     for (; k < length && !exec->hadException(); ++k) {
807         PropertySlot slot(thisObj);
808         if (!thisObj->getPropertySlot(exec, k, slot))
809             continue;
810         JSValue v = slot.getValue(exec, k);
811
812         if (exec->hadException())
813             return JSValue::encode(jsUndefined());
814
815         MarkedArgumentBuffer eachArguments;
816         eachArguments.append(v);
817         eachArguments.append(jsNumber(k));
818         eachArguments.append(thisObj);
819
820         JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
821         if (result.toBoolean(exec))
822             resultArray->putDirectIndex(exec, filterIndex++, v);
823     }
824     return JSValue::encode(resultArray);
825 }
826
827 EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
828 {
829     JSObject* thisObj = exec->hostThisValue().toObject(exec);
830     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
831     if (exec->hadException())
832         return JSValue::encode(jsUndefined());
833
834     JSValue function = exec->argument(0);
835     CallData callData;
836     CallType callType = getCallData(function, callData);
837     if (callType == CallTypeNone)
838         return throwVMTypeError(exec);
839
840     JSValue applyThis = exec->argument(1);
841
842     JSArray* resultArray = constructEmptyArray(exec, length);
843     unsigned k = 0;
844     if (callType == CallTypeJS && isJSArray(thisObj)) {
845         JSFunction* f = jsCast<JSFunction*>(function);
846         JSArray* array = asArray(thisObj);
847         CachedCall cachedCall(exec, f, 3);
848         for (; k < length && !exec->hadException(); ++k) {
849             if (UNLIKELY(!array->canGetIndex(k)))
850                 break;
851
852             cachedCall.setThis(applyThis);
853             cachedCall.setArgument(0, array->getIndex(k));
854             cachedCall.setArgument(1, jsNumber(k));
855             cachedCall.setArgument(2, thisObj);
856
857             resultArray->putDirectIndex(exec, k, cachedCall.call());
858         }
859     }
860     for (; k < length && !exec->hadException(); ++k) {
861         PropertySlot slot(thisObj);
862         if (!thisObj->getPropertySlot(exec, k, slot))
863             continue;
864         JSValue v = slot.getValue(exec, k);
865
866         if (exec->hadException())
867             return JSValue::encode(jsUndefined());
868
869         MarkedArgumentBuffer eachArguments;
870         eachArguments.append(v);
871         eachArguments.append(jsNumber(k));
872         eachArguments.append(thisObj);
873
874         if (exec->hadException())
875             return JSValue::encode(jsUndefined());
876
877         JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
878         resultArray->putDirectIndex(exec, k, result);
879     }
880
881     return JSValue::encode(resultArray);
882 }
883
884 // Documentation for these three is available at:
885 // http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
886 // http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
887 // http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
888
889 EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
890 {
891     JSObject* thisObj = exec->hostThisValue().toObject(exec);
892     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
893     if (exec->hadException())
894         return JSValue::encode(jsUndefined());
895
896     JSValue function = exec->argument(0);
897     CallData callData;
898     CallType callType = getCallData(function, callData);
899     if (callType == CallTypeNone)
900         return throwVMTypeError(exec);
901
902     JSValue applyThis = exec->argument(1);
903
904     JSValue result = jsBoolean(true);
905
906     unsigned k = 0;
907     if (callType == CallTypeJS && isJSArray(thisObj)) {
908         JSFunction* f = jsCast<JSFunction*>(function);
909         JSArray* array = asArray(thisObj);
910         CachedCall cachedCall(exec, f, 3);
911         for (; k < length && !exec->hadException(); ++k) {
912             if (UNLIKELY(!array->canGetIndex(k)))
913                 break;
914             
915             cachedCall.setThis(applyThis);
916             cachedCall.setArgument(0, array->getIndex(k));
917             cachedCall.setArgument(1, jsNumber(k));
918             cachedCall.setArgument(2, thisObj);
919             JSValue result = cachedCall.call();
920             if (!result.toBoolean(cachedCall.newCallFrame(exec)))
921                 return JSValue::encode(jsBoolean(false));
922         }
923     }
924     for (; k < length && !exec->hadException(); ++k) {
925         PropertySlot slot(thisObj);
926         if (!thisObj->getPropertySlot(exec, k, slot))
927             continue;
928
929         MarkedArgumentBuffer eachArguments;
930         eachArguments.append(slot.getValue(exec, k));
931         eachArguments.append(jsNumber(k));
932         eachArguments.append(thisObj);
933
934         if (exec->hadException())
935             return JSValue::encode(jsUndefined());
936
937         bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
938         if (!predicateResult) {
939             result = jsBoolean(false);
940             break;
941         }
942     }
943
944     return JSValue::encode(result);
945 }
946
947 EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
948 {
949     JSObject* thisObj = exec->hostThisValue().toObject(exec);
950     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
951     if (exec->hadException())
952         return JSValue::encode(jsUndefined());
953
954     JSValue function = exec->argument(0);
955     CallData callData;
956     CallType callType = getCallData(function, callData);
957     if (callType == CallTypeNone)
958         return throwVMTypeError(exec);
959
960     JSValue applyThis = exec->argument(1);
961
962     unsigned k = 0;
963     if (callType == CallTypeJS && isJSArray(thisObj)) {
964         JSFunction* f = jsCast<JSFunction*>(function);
965         JSArray* array = asArray(thisObj);
966         CachedCall cachedCall(exec, f, 3);
967         for (; k < length && !exec->hadException(); ++k) {
968             if (UNLIKELY(!array->canGetIndex(k)))
969                 break;
970
971             cachedCall.setThis(applyThis);
972             cachedCall.setArgument(0, array->getIndex(k));
973             cachedCall.setArgument(1, jsNumber(k));
974             cachedCall.setArgument(2, thisObj);
975
976             cachedCall.call();
977         }
978     }
979     for (; k < length && !exec->hadException(); ++k) {
980         PropertySlot slot(thisObj);
981         if (!thisObj->getPropertySlot(exec, k, slot))
982             continue;
983
984         MarkedArgumentBuffer eachArguments;
985         eachArguments.append(slot.getValue(exec, k));
986         eachArguments.append(jsNumber(k));
987         eachArguments.append(thisObj);
988
989         if (exec->hadException())
990             return JSValue::encode(jsUndefined());
991
992         call(exec, function, callType, callData, applyThis, eachArguments);
993     }
994     return JSValue::encode(jsUndefined());
995 }
996
997 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
998 {
999     JSObject* thisObj = exec->hostThisValue().toObject(exec);
1000     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
1001     if (exec->hadException())
1002         return JSValue::encode(jsUndefined());
1003
1004     JSValue function = exec->argument(0);
1005     CallData callData;
1006     CallType callType = getCallData(function, callData);
1007     if (callType == CallTypeNone)
1008         return throwVMTypeError(exec);
1009
1010     JSValue applyThis = exec->argument(1);
1011
1012     JSValue result = jsBoolean(false);
1013
1014     unsigned k = 0;
1015     if (callType == CallTypeJS && isJSArray(thisObj)) {
1016         JSFunction* f = jsCast<JSFunction*>(function);
1017         JSArray* array = asArray(thisObj);
1018         CachedCall cachedCall(exec, f, 3);
1019         for (; k < length && !exec->hadException(); ++k) {
1020             if (UNLIKELY(!array->canGetIndex(k)))
1021                 break;
1022             
1023             cachedCall.setThis(applyThis);
1024             cachedCall.setArgument(0, array->getIndex(k));
1025             cachedCall.setArgument(1, jsNumber(k));
1026             cachedCall.setArgument(2, thisObj);
1027             JSValue result = cachedCall.call();
1028             if (result.toBoolean(cachedCall.newCallFrame(exec)))
1029                 return JSValue::encode(jsBoolean(true));
1030         }
1031     }
1032     for (; k < length && !exec->hadException(); ++k) {
1033         PropertySlot slot(thisObj);
1034         if (!thisObj->getPropertySlot(exec, k, slot))
1035             continue;
1036
1037         MarkedArgumentBuffer eachArguments;
1038         eachArguments.append(slot.getValue(exec, k));
1039         eachArguments.append(jsNumber(k));
1040         eachArguments.append(thisObj);
1041
1042         if (exec->hadException())
1043             return JSValue::encode(jsUndefined());
1044
1045         bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
1046         if (predicateResult) {
1047             result = jsBoolean(true);
1048             break;
1049         }
1050     }
1051     return JSValue::encode(result);
1052 }
1053
1054 EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
1055 {
1056     JSObject* thisObj = exec->hostThisValue().toObject(exec);
1057     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
1058     if (exec->hadException())
1059         return JSValue::encode(jsUndefined());
1060
1061     JSValue function = exec->argument(0);
1062     CallData callData;
1063     CallType callType = getCallData(function, callData);
1064     if (callType == CallTypeNone)
1065         return throwVMTypeError(exec);
1066
1067     unsigned i = 0;
1068     JSValue rv;
1069     if (!length && exec->argumentCount() == 1)
1070         return throwVMTypeError(exec);
1071
1072     JSArray* array = 0;
1073     if (isJSArray(thisObj))
1074         array = asArray(thisObj);
1075
1076     if (exec->argumentCount() >= 2)
1077         rv = exec->argument(1);
1078     else if (array && array->canGetIndex(0)){
1079         rv = array->getIndex(0);
1080         i = 1;
1081     } else {
1082         for (i = 0; i < length; i++) {
1083             rv = getProperty(exec, thisObj, i);
1084             if (exec->hadException())
1085                 return JSValue::encode(jsUndefined());
1086             if (rv)
1087                 break;
1088         }
1089         if (!rv)
1090             return throwVMTypeError(exec);
1091         i++;
1092     }
1093
1094     if (callType == CallTypeJS && array) {
1095         CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4);
1096         for (; i < length && !exec->hadException(); ++i) {
1097             cachedCall.setThis(jsUndefined());
1098             cachedCall.setArgument(0, rv);
1099             JSValue v;
1100             if (LIKELY(array->canGetIndex(i)))
1101                 v = array->getIndex(i);
1102             else
1103                 break; // length has been made unsafe while we enumerate fallback to slow path
1104             cachedCall.setArgument(1, v);
1105             cachedCall.setArgument(2, jsNumber(i));
1106             cachedCall.setArgument(3, array);
1107             rv = cachedCall.call();
1108         }
1109         if (i == length) // only return if we reached the end of the array
1110             return JSValue::encode(rv);
1111     }
1112
1113     for (; i < length && !exec->hadException(); ++i) {
1114         JSValue prop = getProperty(exec, thisObj, i);
1115         if (exec->hadException())
1116             return JSValue::encode(jsUndefined());
1117         if (!prop)
1118             continue;
1119         
1120         MarkedArgumentBuffer eachArguments;
1121         eachArguments.append(rv);
1122         eachArguments.append(prop);
1123         eachArguments.append(jsNumber(i));
1124         eachArguments.append(thisObj);
1125         
1126         rv = call(exec, function, callType, callData, jsUndefined(), eachArguments);
1127     }
1128     return JSValue::encode(rv);
1129 }
1130
1131 EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
1132 {
1133     JSObject* thisObj = exec->hostThisValue().toObject(exec);
1134     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
1135     if (exec->hadException())
1136         return JSValue::encode(jsUndefined());
1137
1138     JSValue function = exec->argument(0);
1139     CallData callData;
1140     CallType callType = getCallData(function, callData);
1141     if (callType == CallTypeNone)
1142         return throwVMTypeError(exec);
1143     
1144     unsigned i = 0;
1145     JSValue rv;
1146     if (!length && exec->argumentCount() == 1)
1147         return throwVMTypeError(exec);
1148
1149     JSArray* array = 0;
1150     if (isJSArray(thisObj))
1151         array = asArray(thisObj);
1152     
1153     if (exec->argumentCount() >= 2)
1154         rv = exec->argument(1);
1155     else if (array && array->canGetIndex(length - 1)){
1156         rv = array->getIndex(length - 1);
1157         i = 1;
1158     } else {
1159         for (i = 0; i < length; i++) {
1160             rv = getProperty(exec, thisObj, length - i - 1);
1161             if (exec->hadException())
1162                 return JSValue::encode(jsUndefined());
1163             if (rv)
1164                 break;
1165         }
1166         if (!rv)
1167             return throwVMTypeError(exec);
1168         i++;
1169     }
1170     
1171     if (callType == CallTypeJS && array) {
1172         CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4);
1173         for (; i < length && !exec->hadException(); ++i) {
1174             unsigned idx = length - i - 1;
1175             cachedCall.setThis(jsUndefined());
1176             cachedCall.setArgument(0, rv);
1177             if (UNLIKELY(!array->canGetIndex(idx)))
1178                 break; // length has been made unsafe while we enumerate fallback to slow path
1179             cachedCall.setArgument(1, array->getIndex(idx));
1180             cachedCall.setArgument(2, jsNumber(idx));
1181             cachedCall.setArgument(3, array);
1182             rv = cachedCall.call();
1183         }
1184         if (i == length) // only return if we reached the end of the array
1185             return JSValue::encode(rv);
1186     }
1187     
1188     for (; i < length && !exec->hadException(); ++i) {
1189         unsigned idx = length - i - 1;
1190         JSValue prop = getProperty(exec, thisObj, idx);
1191         if (exec->hadException())
1192             return JSValue::encode(jsUndefined());
1193         if (!prop)
1194             continue;
1195         
1196         MarkedArgumentBuffer eachArguments;
1197         eachArguments.append(rv);
1198         eachArguments.append(prop);
1199         eachArguments.append(jsNumber(idx));
1200         eachArguments.append(thisObj);
1201         
1202         rv = call(exec, function, callType, callData, jsUndefined(), eachArguments);
1203     }
1204     return JSValue::encode(rv);        
1205 }
1206
1207 EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec)
1208 {
1209     // 15.4.4.14
1210     JSObject* thisObj = exec->hostThisValue().toObject(exec);
1211     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
1212     if (exec->hadException())
1213         return JSValue::encode(jsUndefined());
1214
1215     unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
1216     JSValue searchElement = exec->argument(0);
1217     for (; index < length; ++index) {
1218         JSValue e = getProperty(exec, thisObj, index);
1219         if (exec->hadException())
1220             return JSValue::encode(jsUndefined());
1221         if (!e)
1222             continue;
1223         if (JSValue::strictEqual(exec, searchElement, e))
1224             return JSValue::encode(jsNumber(index));
1225     }
1226
1227     return JSValue::encode(jsNumber(-1));
1228 }
1229
1230 EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec)
1231 {
1232     // 15.4.4.15
1233     JSObject* thisObj = exec->hostThisValue().toObject(exec);
1234     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
1235     if (!length)
1236         return JSValue::encode(jsNumber(-1));
1237
1238     unsigned index = length - 1;
1239     if (exec->argumentCount() >= 2) {
1240         JSValue fromValue = exec->argument(1);
1241         double fromDouble = fromValue.toInteger(exec);
1242         if (fromDouble < 0) {
1243             fromDouble += length;
1244             if (fromDouble < 0)
1245                 return JSValue::encode(jsNumber(-1));
1246         }
1247         if (fromDouble < length)
1248             index = static_cast<unsigned>(fromDouble);
1249     }
1250
1251     JSValue searchElement = exec->argument(0);
1252     do {
1253         ASSERT(index < length);
1254         JSValue e = getProperty(exec, thisObj, index);
1255         if (exec->hadException())
1256             return JSValue::encode(jsUndefined());
1257         if (!e)
1258             continue;
1259         if (JSValue::strictEqual(exec, searchElement, e))
1260             return JSValue::encode(jsNumber(index));
1261     } while (index--);
1262
1263     return JSValue::encode(jsNumber(-1));
1264 }
1265
1266 } // namespace JSC