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