Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / JavaScriptCore / runtime / ArrayPrototype.cpp
index e0a57be..d2ec30d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2007, 2008, 2009, 2011, 2013 Apple Inc. All rights reserved.
  *  Copyright (C) 2003 Peter Kelly (pmk@post.com)
  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
  *
 #include "config.h"
 #include "ArrayPrototype.h"
 
+#include "ButterflyInlines.h"
 #include "CachedCall.h"
 #include "CodeBlock.h"
+#include "CopiedSpaceInlines.h"
+#include "Error.h"
 #include "Interpreter.h"
 #include "JIT.h"
 #include "JSStringBuilder.h"
+#include "JSStringJoiner.h"
 #include "Lookup.h"
 #include "ObjectPrototype.h"
 #include "Operations.h"
@@ -39,8 +43,6 @@
 
 namespace JSC {
 
-ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype);
-
 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*);
 static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*);
@@ -76,7 +78,7 @@ static inline bool isNumericCompareFunction(ExecState* exec, CallType callType,
 
     FunctionExecutable* executable = callData.js.functionExecutable;
 
-    JSObject* error = executable->compileForCall(exec, callData.js.scopeChain);
+    JSObject* error = executable->compileForCall(exec, callData.js.scope);
     if (error)
         return false;
 
@@ -113,31 +115,35 @@ const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecStat
 @end
 */
 
-// ECMA 15.4.4
-ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
-    : JSArray(globalObject->globalData(), structure)
+ArrayPrototype* ArrayPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
 {
+    ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure);
+    prototype->finishCreation(globalObject);
+    return prototype;
 }
 
-void ArrayPrototype::finishCreation(JSGlobalObject* globalObject)
+// ECMA 15.4.4
+ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
+    : JSArray(globalObject->vm(), structure, 0)
 {
-    Base::finishCreation(globalObject->globalData());
-    ASSERT(inherits(&s_info));
 }
 
-bool ArrayPrototype::getOwnPropertySlotVirtual(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+void ArrayPrototype::finishCreation(JSGlobalObject* globalObject)
 {
-    return getOwnPropertySlot(this, exec, propertyName, slot);
+    VM& vm = globalObject->vm();
+    Base::finishCreation(vm);
+    ASSERT(inherits(info()));
+    vm.prototypeMap.addPrototype(this);
 }
 
-bool ArrayPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+bool ArrayPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
-    return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayPrototypeTable(exec), static_cast<ArrayPrototype*>(cell), propertyName, slot);
+    return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayPrototypeTable(exec), jsCast<ArrayPrototype*>(object), propertyName, slot);
 }
 
-bool ArrayPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+bool ArrayPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
 {
-    return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayPrototypeTable(exec), this, propertyName, descriptor);
+    return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayPrototypeTable(exec), jsCast<ArrayPrototype*>(object), propertyName, descriptor);
 }
 
 // ------------------------------ Array Functions ----------------------------
@@ -151,7 +157,7 @@ static JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index)
     return slot.getValue(exec, index);
 }
 
-static void putProperty(ExecState* exec, JSObject* obj, const Identifier& propertyName, JSValue value)
+static void putProperty(ExecState* exec, JSObject* obj, PropertyName propertyName, JSValue value)
 {
     PutPropertySlot slot;
     obj->methodTable()->put(obj, exec, propertyName, value, slot);
@@ -171,13 +177,123 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument
     return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
 }
 
+
+// The shift/unshift function implement the shift/unshift behaviour required
+// by the corresponding array prototype methods, and by splice. In both cases,
+// the methods are operating an an array or array like object.
+//
+//  header  currentCount  (remainder)
+// [------][------------][-----------]
+//  header  resultCount  (remainder)
+// [------][-----------][-----------]
+//
+// The set of properties in the range 'header' must be unchanged. The set of
+// properties in the range 'remainder' (where remainder = length - header -
+// currentCount) will be shifted to the left or right as appropriate; in the
+// case of shift this must be removing values, in the case of unshift this
+// must be introducing new values.
+template<JSArray::ShiftCountMode shiftCountMode>
+void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
+{
+    RELEASE_ASSERT(currentCount > resultCount);
+    unsigned count = currentCount - resultCount;
+
+    RELEASE_ASSERT(header <= length);
+    RELEASE_ASSERT(currentCount <= (length - header));
+
+    if (isJSArray(thisObj)) {
+        JSArray* array = asArray(thisObj);
+        if (array->length() == length && asArray(thisObj)->shiftCount<shiftCountMode>(exec, header, count))
+            return;
+    }
+
+    for (unsigned k = header; k < length - currentCount; ++k) {
+        unsigned from = k + currentCount;
+        unsigned to = k + resultCount;
+        PropertySlot slot(thisObj);
+        if (thisObj->getPropertySlot(exec, from, slot)) {
+            JSValue value = slot.getValue(exec, from);
+            if (exec->hadException())
+                return;
+            thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true);
+            if (exec->hadException())
+                return;
+        } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) {
+            throwTypeError(exec, ASCIILiteral("Unable to delete property."));
+            return;
+        }
+    }
+    for (unsigned k = length; k > length - count; --k) {
+        if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1)) {
+            throwTypeError(exec, ASCIILiteral("Unable to delete property."));
+            return;
+        }
+    }
+}
+template<JSArray::ShiftCountMode shiftCountMode>
+void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
+{
+    RELEASE_ASSERT(resultCount > currentCount);
+    unsigned count = resultCount - currentCount;
+
+    RELEASE_ASSERT(header <= length);
+    RELEASE_ASSERT(currentCount <= (length - header));
+
+    // Guard against overflow.
+    if (count > (UINT_MAX - length)) {
+        throwOutOfMemoryError(exec);
+        return;
+    }
+
+    if (isJSArray(thisObj)) {
+        JSArray* array = asArray(thisObj);
+        if (array->length() == length && array->unshiftCount<shiftCountMode>(exec, header, count))
+            return;
+    }
+    
+    for (unsigned k = length - currentCount; k > header; --k) {
+        unsigned from = k + currentCount - 1;
+        unsigned to = k + resultCount - 1;
+        PropertySlot slot(thisObj);
+        if (thisObj->getPropertySlot(exec, from, slot)) {
+            JSValue value = slot.getValue(exec, from);
+            if (exec->hadException())
+                return;
+            thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true);
+        } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) {
+            throwTypeError(exec, ASCIILiteral("Unable to delete property."));
+            return;
+        }
+        if (exec->hadException())
+            return;
+    }
+}
+
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
+    JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
 
-    bool isRealArray = isJSArray(&exec->globalData(), thisValue);
-    if (!isRealArray && !thisValue.inherits(&JSArray::s_info))
-        return throwVMTypeError(exec);
+    // 1. Let array be the result of calling ToObject on the this value.
+    JSObject* thisObject = thisValue.toObject(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    
+    // 2. Let func be the result of calling the [[Get]] internal method of array with argument "join".
+    JSValue function = JSValue(thisObject).get(exec, exec->propertyNames().join);
+
+    // 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
+    if (!function.isCell())
+        return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+    CallData callData;
+    CallType callType = getCallData(function, callData);
+    if (callType == CallTypeNone)
+        return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+
+    // 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
+    if (!isJSArray(thisObject) || callType != CallTypeHost || callData.native.function != arrayProtoFuncJoin)
+        return JSValue::encode(call(exec, function, callType, callData, thisObject, exec->emptyList()));
+
+    ASSERT(isJSArray(thisValue));
     JSArray* thisObj = asArray(thisValue);
     
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
@@ -188,54 +304,36 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
     if (JSValue earlyReturnValue = checker.earlyReturnValue())
         return JSValue::encode(earlyReturnValue);
 
-    unsigned totalSize = length ? length - 1 : 0;
-    Vector<RefPtr<StringImpl>, 256> strBuffer(length);
-
+    String separator(",", String::ConstructFromLiteral);
+    JSStringJoiner stringJoiner(separator, length);
     for (unsigned k = 0; k < length; k++) {
         JSValue element;
-        if (isRealArray && thisObj->canGetIndex(k))
-            element = thisObj->getIndex(k);
-        else
+        if (thisObj->canGetIndexQuickly(k))
+            element = thisObj->getIndexQuickly(k);
+        else {
             element = thisObj->get(exec, k);
-        
-        if (element.isUndefinedOrNull())
-            continue;
-        
-        UString str = element.toString(exec);
-        strBuffer[k] = str.impl();
-        totalSize += str.length();
-        
-        if (!strBuffer.data()) {
-            throwOutOfMemoryError(exec);
+            if (exec->hadException())
+                return JSValue::encode(jsUndefined());
         }
-        
+
+        if (element.isUndefinedOrNull())
+            stringJoiner.append(String());
+        else
+            stringJoiner.append(element.toWTFString(exec));
+
         if (exec->hadException())
-            break;
-    }
-    if (!totalSize)
-        return JSValue::encode(jsEmptyString(exec));
-    Vector<UChar> buffer;
-    buffer.reserveCapacity(totalSize);
-    if (!buffer.data())
-        return JSValue::encode(throwOutOfMemoryError(exec));
-        
-    for (unsigned i = 0; i < length; i++) {
-        if (i)
-            buffer.append(',');
-        if (RefPtr<StringImpl> rep = strBuffer[i])
-            buffer.append(rep->characters(), rep->length());
+            return JSValue::encode(jsUndefined());
     }
-    ASSERT(buffer.size() == totalSize);
-    return JSValue::encode(jsString(exec, UString::adopt(buffer)));
+    return JSValue::encode(stringJoiner.join(exec));
 }
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
+    JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
 
-    if (!thisValue.inherits(&JSArray::s_info))
-        return throwVMTypeError(exec);
-    JSObject* thisObj = asArray(thisValue);
+    JSObject* thisObj = thisValue.toObject(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
 
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
@@ -245,32 +343,36 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
     if (JSValue earlyReturnValue = checker.earlyReturnValue())
         return JSValue::encode(earlyReturnValue);
 
-    JSStringBuilder strBuffer;
+    String separator(",", String::ConstructFromLiteral);
+    JSStringJoiner stringJoiner(separator, length);
     for (unsigned k = 0; k < length; k++) {
-        if (k >= 1)
-            strBuffer.append(',');
-
         JSValue element = thisObj->get(exec, k);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
         if (!element.isUndefinedOrNull()) {
             JSObject* o = element.toObject(exec);
             JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
-            UString str;
+            if (exec->hadException())
+                return JSValue::encode(jsUndefined());
+            String str;
             CallData callData;
             CallType callType = getCallData(conversionFunction, callData);
             if (callType != CallTypeNone)
-                str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec);
+                str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toWTFString(exec);
             else
-                str = element.toString(exec);
-            strBuffer.append(str);
+                str = element.toWTFString(exec);
+            if (exec->hadException())
+                return JSValue::encode(jsUndefined());
+            stringJoiner.append(str);
         }
     }
 
-    return JSValue::encode(strBuffer.build(exec));
+    return JSValue::encode(stringJoiner.join(exec));
 }
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -279,66 +381,45 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
     if (JSValue earlyReturnValue = checker.earlyReturnValue())
         return JSValue::encode(earlyReturnValue);
 
-    JSStringBuilder strBuffer;
-
-    UString separator;
+    String separator;
     if (!exec->argument(0).isUndefined())
-        separator = exec->argument(0).toString(exec);
+        separator = exec->argument(0).toWTFString(exec);
+    if (separator.isNull())
+        separator = String(",", String::ConstructFromLiteral);
+
+    JSStringJoiner stringJoiner(separator, length);
 
     unsigned k = 0;
-    if (isJSArray(&exec->globalData(), thisObj)) {
+    if (isJSArray(thisObj)) {
         JSArray* array = asArray(thisObj);
 
-        if (length) {
-            if (!array->canGetIndex(k)) 
-                goto skipFirstLoop;
-            JSValue element = array->getIndex(k);
-            if (!element.isUndefinedOrNull())
-                strBuffer.append(element.toString(exec));
-            k++;
-        }
+        for (; k < length; k++) {
+            if (!array->canGetIndexQuickly(k))
+                break;
 
-        if (separator.isNull()) {
-            for (; k < length; k++) {
-                if (!array->canGetIndex(k))
-                    break;
-                strBuffer.append(',');
-                JSValue element = array->getIndex(k);
-                if (!element.isUndefinedOrNull())
-                    strBuffer.append(element.toString(exec));
-            }
-        } else {
-            for (; k < length; k++) {
-                if (!array->canGetIndex(k))
-                    break;
-                strBuffer.append(separator);
-                JSValue element = array->getIndex(k);
-                if (!element.isUndefinedOrNull())
-                    strBuffer.append(element.toString(exec));
-            }
-        }
-    }
- skipFirstLoop:
-    for (; k < length; k++) {
-        if (k >= 1) {
-            if (separator.isNull())
-                strBuffer.append(',');
+            JSValue element = array->getIndexQuickly(k);
+            if (!element.isUndefinedOrNull())
+                stringJoiner.append(element.toWTFStringInline(exec));
             else
-                strBuffer.append(separator);
+                stringJoiner.append(String());
         }
+    }
 
+    for (; k < length; k++) {
         JSValue element = thisObj->get(exec, k);
         if (!element.isUndefinedOrNull())
-            strBuffer.append(element.toString(exec));
+            stringJoiner.append(element.toWTFStringInline(exec));
+        else
+            stringJoiner.append(String());
     }
 
-    return JSValue::encode(strBuffer.build(exec));
+    return JSValue::encode(stringJoiner.join(exec));
 }
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    JSArray* arr = constructEmptyArray(exec);
+    JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+    JSArray* arr = constructEmptyArray(exec, 0);
     unsigned n = 0;
     JSValue curArg = thisValue.toObject(exec);
     if (exec->hadException())
@@ -346,7 +427,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
     size_t i = 0;
     size_t argCount = exec->argumentCount();
     while (1) {
-        if (curArg.inherits(&JSArray::s_info)) {
+        if (curArg.inherits(JSArray::info())) {
             unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec);
             JSObject* curObject = curArg.toObject(exec);
             for (unsigned k = 0; k < length; ++k) {
@@ -354,11 +435,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
                 if (exec->hadException())
                     return JSValue::encode(jsUndefined());
                 if (v)
-                    arr->methodTable()->putByIndex(arr, exec, n, v);
+                    arr->putDirectIndex(exec, n, v);
                 n++;
             }
         } else {
-            arr->methodTable()->putByIndex(arr, exec, n, curArg);
+            arr->putDirectIndex(exec, n, curArg);
             n++;
         }
         if (i == argCount)
@@ -366,16 +447,16 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
         curArg = (exec->argument(i));
         ++i;
     }
-    arr->setLength(n);
+    arr->setLength(exec, n);
     return JSValue::encode(arr);
 }
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
+    JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
 
-    if (isJSArray(&exec->globalData(), thisValue))
-        return JSValue::encode(asArray(thisValue)->pop());
+    if (isJSArray(thisValue))
+        return JSValue::encode(asArray(thisValue)->pop(exec));
 
     JSObject* thisObj = thisValue.toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
@@ -388,7 +469,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
         result = jsUndefined();
     } else {
         result = thisObj->get(exec, length - 1);
-        thisObj->deletePropertyVirtual(exec, length - 1);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+        if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1)) {
+            throwTypeError(exec, ASCIILiteral("Unable to delete property."));
+            return JSValue::encode(jsUndefined());
+        }
         putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
     }
     return JSValue::encode(result);
@@ -396,14 +482,14 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
+    JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
 
-    if (isJSArray(&exec->globalData(), thisValue) && exec->argumentCount() == 1) {
+    if (isJSArray(thisValue) && exec->argumentCount() == 1) {
         JSArray* array = asArray(thisValue);
         array->push(exec, exec->argument(0));
         return JSValue::encode(jsNumber(array->length()));
     }
-
+    
     JSObject* thisObj = thisValue.toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
@@ -412,13 +498,16 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
     for (unsigned n = 0; n < exec->argumentCount(); n++) {
         // Check for integer overflow; where safe we can do a fast put by index.
         if (length + n >= length)
-            thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n));
+            thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n), true);
         else {
             PutPropertySlot slot;
-            Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec));
+            Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toWTFString(exec));
             thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot);
         }
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
     }
+    
     JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount()));
     putProperty(exec, thisObj, exec->propertyNames().length, newLength);
     return JSValue::encode(newLength);
@@ -426,7 +515,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -441,22 +530,30 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec)
         if (exec->hadException())
             return JSValue::encode(jsUndefined());
 
-        if (obj2)
-            thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2);
-        else
-            thisObj->deletePropertyVirtual(exec, k);
+        if (obj2) {
+            thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2, true);
+            if (exec->hadException())
+                return JSValue::encode(jsUndefined());
+        } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k)) {
+            throwTypeError(exec, ASCIILiteral("Unable to delete property."));
+            return JSValue::encode(jsUndefined());
+        }
 
-        if (obj)
-            thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj);
-        else
-            thisObj->deletePropertyVirtual(exec, lk1);
+        if (obj) {
+            thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj, true);
+            if (exec->hadException())
+                return JSValue::encode(jsUndefined());
+        } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1)) {
+            throwTypeError(exec, ASCIILiteral("Unable to delete property."));
+            return JSValue::encode(jsUndefined());
+        }
     }
     return JSValue::encode(thisObj);
 }
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -467,20 +564,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
         result = jsUndefined();
     } else {
         result = thisObj->get(exec, 0);
-        if (isJSArray(&exec->globalData(), thisObj))
-            ((JSArray *)thisObj)->shiftCount(exec, 1);
-        else {
-            for (unsigned k = 1; k < length; k++) {
-                JSValue obj = getProperty(exec, thisObj, k);
-                if (exec->hadException())
-                    return JSValue::encode(jsUndefined());
-                if (obj)
-                    thisObj->methodTable()->putByIndex(thisObj, exec, k - 1, obj);
-                else
-                    thisObj->deletePropertyVirtual(exec, k - 1);
-            }
-            thisObj->deletePropertyVirtual(exec, length - 1);
-        }
+        shift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 1, 0, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
         putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
     }
     return JSValue::encode(result);
@@ -489,13 +575,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
 {
     // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
     // We return a new array
-    JSArray* resObj = constructEmptyArray(exec);
+    JSArray* resObj = constructEmptyArray(exec, 0);
     JSValue result = resObj;
 
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -507,47 +593,57 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
         if (exec->hadException())
             return JSValue::encode(jsUndefined());
         if (v)
-            resObj->methodTable()->putByIndex(resObj, exec, n, v);
+            resObj->putDirectIndex(exec, n, v);
     }
-    resObj->setLength(n);
+    resObj->setLength(exec, n);
     return JSValue::encode(result);
 }
 
-EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
+inline JSValue getOrHole(JSObject* obj, ExecState* exec, unsigned propertyName)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
-    unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
-    if (!length || exec->hadException())
-        return JSValue::encode(thisObj);
+    PropertySlot slot(obj);
+    if (obj->getPropertySlot(exec, propertyName, slot))
+        return slot.getValue(exec, propertyName);
 
-    JSValue function = exec->argument(0);
-    CallData callData;
-    CallType callType = getCallData(function, callData);
+    return JSValue();
+}
 
-    if (thisObj->classInfo() == &JSArray::s_info) {
-        if (isNumericCompareFunction(exec, callType, callData))
-            asArray(thisObj)->sortNumeric(exec, function, callType, callData);
-        else if (callType != CallTypeNone)
-            asArray(thisObj)->sort(exec, function, callType, callData);
-        else
-            asArray(thisObj)->sort(exec);
-        return JSValue::encode(thisObj);
-    }
+static bool attemptFastSort(ExecState* exec, JSObject* thisObj, JSValue function, CallData& callData, CallType& callType)
+{
+    if (thisObj->classInfo() != JSArray::info()
+        || asArray(thisObj)->hasSparseMap()
+        || shouldUseSlowPut(thisObj->structure()->indexingType()))
+        return false;
+    
+    if (isNumericCompareFunction(exec, callType, callData))
+        asArray(thisObj)->sortNumeric(exec, function, callType, callData);
+    else if (callType != CallTypeNone)
+        asArray(thisObj)->sort(exec, function, callType, callData);
+    else
+        asArray(thisObj)->sort(exec);
+    return true;
+}
 
+static bool performSlowSort(ExecState* exec, JSObject* thisObj, unsigned length, JSValue function, CallData& callData, CallType& callType)
+{
     // "Min" sort. Not the fastest, but definitely less code than heapsort
     // or quicksort, and much less swapping than bubblesort/insertionsort.
     for (unsigned i = 0; i < length - 1; ++i) {
-        JSValue iObj = thisObj->get(exec, i);
+        JSValue iObj = getOrHole(thisObj, exec, i);
         if (exec->hadException())
-            return JSValue::encode(jsUndefined());
+            return false;
         unsigned themin = i;
         JSValue minObj = iObj;
         for (unsigned j = i + 1; j < length; ++j) {
-            JSValue jObj = thisObj->get(exec, j);
+            JSValue jObj = getOrHole(thisObj, exec, j);
             if (exec->hadException())
-                return JSValue::encode(jsUndefined());
+                return false;
             double compareResult;
-            if (jObj.isUndefined())
+            if (!jObj)
+                compareResult = 1;
+            else if (!minObj)
+                compareResult = -1;
+            else if (jObj.isUndefined())
                 compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
             else if (minObj.isUndefined())
                 compareResult = -1;
@@ -557,7 +653,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
                 l.append(minObj);
                 compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
             } else
-                compareResult = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1;
+                compareResult = codePointCompareLessThan(jObj.toWTFStringInline(exec), minObj.toWTFStringInline(exec)) ? -1 : 1;
 
             if (compareResult < 0) {
                 themin = j;
@@ -566,10 +662,97 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
         }
         // Swap themin and i
         if (themin > i) {
-            thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj);
-            thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj);
+            if (minObj) {
+                thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true);
+                if (exec->hadException())
+                    return false;
+            } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, i)) {
+                throwTypeError(exec, "Unable to delete property.");
+                return false;
+            }
+            if (iObj) {
+                thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true);
+                if (exec->hadException())
+                    return false;
+            } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, themin)) {
+                throwTypeError(exec, "Unable to delete property.");
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
+{
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+    unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+    if (!length || exec->hadException())
+        return JSValue::encode(thisObj);
+
+    JSValue function = exec->argument(0);
+    CallData callData;
+    CallType callType = getCallData(function, callData);
+
+    if (attemptFastSort(exec, thisObj, function, callData, callType))
+        return JSValue::encode(thisObj);
+    
+    // Assume that for small-ish arrays, doing the slow sort directly is better.
+    if (length < 1000)
+        return performSlowSort(exec, thisObj, length, function, callData, callType) ? JSValue::encode(thisObj) : JSValue::encode(jsUndefined());
+    
+    JSGlobalObject* globalObject = JSGlobalObject::create(
+        exec->vm(), JSGlobalObject::createStructure(exec->vm(), jsNull()));
+    JSArray* flatArray = constructEmptyArray(globalObject->globalExec(), 0);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    
+    PropertyNameArray nameArray(exec);
+    thisObj->methodTable()->getPropertyNames(thisObj, exec, nameArray, IncludeDontEnumProperties);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+
+    Vector<uint32_t, 0, UnsafeVectorOverflow> keys;
+    for (size_t i = 0; i < nameArray.size(); ++i) {
+        PropertyName name = nameArray[i];
+        uint32_t index = name.asIndex();
+        if (index == PropertyName::NotAnIndex)
+            continue;
+        
+        JSValue value = getOrHole(thisObj, exec, index);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+        if (!value)
+            continue;
+        keys.append(index);
+        flatArray->push(exec, value);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
+    
+    if (!attemptFastSort(exec, flatArray, function, callData, callType)
+        && !performSlowSort(exec, flatArray, flatArray->length(), function, callData, callType))
+        return JSValue::encode(jsUndefined());
+    
+    for (size_t i = 0; i < keys.size(); ++i) {
+        size_t index = keys[i];
+        if (index < flatArray->length())
+            continue;
+        
+        if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, index)) {
+            throwTypeError(exec, "Unable to delete property.");
+            return JSValue::encode(jsUndefined());
         }
     }
+    
+    for (size_t i = flatArray->length(); i--;) {
+        JSValue value = getOrHole(flatArray, exec, i);
+        RELEASE_ASSERT(value);
+        thisObj->methodTable()->putByIndex(thisObj, exec, i, value, true);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
+    
     return JSValue::encode(thisObj);
 }
 
@@ -577,13 +760,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
 {
     // 15.4.4.12
 
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
-
+    
     if (!exec->argumentCount())
-        return JSValue::encode(constructEmptyArray(exec));
+        return JSValue::encode(constructEmptyArray(exec, 0));
 
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
 
@@ -598,54 +781,34 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
             deleteCount = static_cast<unsigned>(deleteDouble);
     }
 
-    JSArray* resObj = JSArray::create(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact);
+    JSArray* resObj = JSArray::tryCreateUninitialized(exec->vm(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount);
+    if (!resObj)
+        return JSValue::encode(throwOutOfMemoryError(exec));
+
     JSValue result = resObj;
-    JSGlobalData& globalData = exec->globalData();
+    VM& vm = exec->vm();
     for (unsigned k = 0; k < deleteCount; k++) {
         JSValue v = getProperty(exec, thisObj, k + begin);
         if (exec->hadException())
             return JSValue::encode(jsUndefined());
-        resObj->uncheckedSetIndex(globalData, k, v);
+        resObj->initializeIndex(vm, k, v);
     }
 
-    resObj->setLength(deleteCount);
-
     unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
-    if (additionalArgs != deleteCount) {
-        if (additionalArgs < deleteCount) {
-            if ((!begin) && (isJSArray(&exec->globalData(), thisObj)))
-                ((JSArray *)thisObj)->shiftCount(exec, deleteCount - additionalArgs);
-            else {
-                for (unsigned k = begin; k < length - deleteCount; ++k) {
-                    JSValue v = getProperty(exec, thisObj, k + deleteCount);
-                    if (exec->hadException())
-                        return JSValue::encode(jsUndefined());
-                    if (v)
-                        thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs, v);
-                    else
-                        thisObj->deletePropertyVirtual(exec, k + additionalArgs);
-                }
-                for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)
-                    thisObj->deletePropertyVirtual(exec, k - 1);
-            }
-        } else {
-            if ((!begin) && (isJSArray(&exec->globalData(), thisObj)))
-                ((JSArray *)thisObj)->unshiftCount(exec, additionalArgs - deleteCount);
-            else {
-                for (unsigned k = length - deleteCount; k > begin; --k) {
-                    JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1);
-                    if (exec->hadException())
-                        return JSValue::encode(jsUndefined());
-                    if (obj)
-                        thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs - 1, obj);
-                    else
-                        thisObj->deletePropertyVirtual(exec, k + additionalArgs - 1);
-                }
-            }
-        }
+    if (additionalArgs < deleteCount) {
+        shift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    } else if (additionalArgs > deleteCount) {
+        unshift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
+    for (unsigned k = 0; k < additionalArgs; ++k) {
+        thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->argument(k + 2), true);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
     }
-    for (unsigned k = 0; k < additionalArgs; ++k)
-        thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->argument(k + 2));
 
     putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
     return JSValue::encode(result);
@@ -655,29 +818,22 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
 {
     // 15.4.4.13
 
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
     unsigned nrArgs = exec->argumentCount();
-    if ((nrArgs) && (length)) {
-        if (isJSArray(&exec->globalData(), thisObj))
-            ((JSArray *)thisObj)->unshiftCount(exec, nrArgs);
-        else {
-            for (unsigned k = length; k > 0; --k) {
-                JSValue v = getProperty(exec, thisObj, k - 1);
-                if (exec->hadException())
-                    return JSValue::encode(jsUndefined());
-                if (v)
-                    thisObj->methodTable()->putByIndex(thisObj, exec, k + nrArgs - 1, v);
-                else
-                    thisObj->deletePropertyVirtual(exec, k + nrArgs - 1);
-            }
-        }
+    if (nrArgs) {
+        unshift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 0, nrArgs, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
+    for (unsigned k = 0; k < nrArgs; ++k) {
+        thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->argument(k), true);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
     }
-    for (unsigned k = 0; k < nrArgs; ++k)
-        thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->argument(k));
     JSValue result = jsNumber(length + nrArgs);
     putProperty(exec, thisObj, exec->propertyNames().length, result);
     return JSValue::encode(result);
@@ -685,7 +841,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -697,18 +853,18 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
         return throwVMTypeError(exec);
 
     JSValue applyThis = exec->argument(1);
-    JSArray* resultArray = constructEmptyArray(exec);
+    JSArray* resultArray = constructEmptyArray(exec, 0);
 
     unsigned filterIndex = 0;
     unsigned k = 0;
-    if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
-        JSFunction* f = asFunction(function);
+    if (callType == CallTypeJS && isJSArray(thisObj)) {
+        JSFunction* f = jsCast<JSFunction*>(function);
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (!array->canGetIndex(k))
+            if (!array->canGetIndexQuickly(k))
                 break;
-            JSValue v = array->getIndex(k);
+            JSValue v = array->getIndexQuickly(k);
             cachedCall.setThis(applyThis);
             cachedCall.setArgument(0, v);
             cachedCall.setArgument(1, jsNumber(k));
@@ -716,7 +872,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
             
             JSValue result = cachedCall.call();
             if (result.toBoolean(exec))
-                resultArray->methodTable()->putByIndex(resultArray, exec, filterIndex++, v);
+                resultArray->putDirectIndex(exec, filterIndex++, v);
         }
         if (k == length)
             return JSValue::encode(resultArray);
@@ -737,14 +893,14 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
 
         JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
         if (result.toBoolean(exec))
-            resultArray->methodTable()->putByIndex(resultArray, exec, filterIndex++, v);
+            resultArray->putDirectIndex(exec, filterIndex++, v);
     }
     return JSValue::encode(resultArray);
 }
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -757,22 +913,22 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
 
     JSValue applyThis = exec->argument(1);
 
-    JSArray* resultArray = constructEmptyArray(exec, length);
+    JSArray* resultArray = constructEmptyArray(exec, 0, length);
     unsigned k = 0;
-    if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
-        JSFunction* f = asFunction(function);
+    if (callType == CallTypeJS && isJSArray(thisObj)) {
+        JSFunction* f = jsCast<JSFunction*>(function);
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
 
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
 
-            JSArray::putByIndex(resultArray, exec, k, cachedCall.call());
+            resultArray->putDirectIndex(exec, k, cachedCall.call());
         }
     }
     for (; k < length && !exec->hadException(); ++k) {
@@ -793,7 +949,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
             return JSValue::encode(jsUndefined());
 
         JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
-        resultArray->methodTable()->putByIndex(resultArray, exec, k, result);
+        resultArray->putDirectIndex(exec, k, result);
     }
 
     return JSValue::encode(resultArray);
@@ -806,7 +962,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -822,20 +978,20 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
     JSValue result = jsBoolean(true);
 
     unsigned k = 0;
-    if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
-        JSFunction* f = asFunction(function);
+    if (callType == CallTypeJS && isJSArray(thisObj)) {
+        JSFunction* f = jsCast<JSFunction*>(function);
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
             
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
             JSValue result = cachedCall.call();
-            if (!result.toBoolean(cachedCall.newCallFrame(exec)))
+            if (!result.toBoolean(exec))
                 return JSValue::encode(jsBoolean(false));
         }
     }
@@ -864,7 +1020,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -878,16 +1034,16 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
     JSValue applyThis = exec->argument(1);
 
     unsigned k = 0;
-    if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
-        JSFunction* f = asFunction(function);
+    if (callType == CallTypeJS && isJSArray(thisObj)) {
+        JSFunction* f = jsCast<JSFunction*>(function);
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
 
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
 
@@ -914,7 +1070,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -930,20 +1086,20 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
     JSValue result = jsBoolean(false);
 
     unsigned k = 0;
-    if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
-        JSFunction* f = asFunction(function);
+    if (callType == CallTypeJS && isJSArray(thisObj)) {
+        JSFunction* f = jsCast<JSFunction*>(function);
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
             
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
             JSValue result = cachedCall.call();
-            if (result.toBoolean(cachedCall.newCallFrame(exec)))
+            if (result.toBoolean(exec))
                 return JSValue::encode(jsBoolean(true));
         }
     }
@@ -971,7 +1127,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -988,13 +1144,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
         return throwVMTypeError(exec);
 
     JSArray* array = 0;
-    if (isJSArray(&exec->globalData(), thisObj))
+    if (isJSArray(thisObj))
         array = asArray(thisObj);
 
     if (exec->argumentCount() >= 2)
         rv = exec->argument(1);
-    else if (array && array->canGetIndex(0)){
-        rv = array->getIndex(0);
+    else if (array && array->canGetIndexQuickly(0)) {
+        rv = array->getIndexQuickly(0);
         i = 1;
     } else {
         for (i = 0; i < length; i++) {
@@ -1010,13 +1166,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
     }
 
     if (callType == CallTypeJS && array) {
-        CachedCall cachedCall(exec, asFunction(function), 4);
+        CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4);
         for (; i < length && !exec->hadException(); ++i) {
             cachedCall.setThis(jsUndefined());
             cachedCall.setArgument(0, rv);
             JSValue v;
-            if (LIKELY(array->canGetIndex(i)))
-                v = array->getIndex(i);
+            if (LIKELY(array->canGetIndexQuickly(i)))
+                v = array->getIndexQuickly(i);
             else
                 break; // length has been made unsafe while we enumerate fallback to slow path
             cachedCall.setArgument(1, v);
@@ -1048,7 +1204,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
 {
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -1065,13 +1221,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
         return throwVMTypeError(exec);
 
     JSArray* array = 0;
-    if (isJSArray(&exec->globalData(), thisObj))
+    if (isJSArray(thisObj))
         array = asArray(thisObj);
     
     if (exec->argumentCount() >= 2)
         rv = exec->argument(1);
-    else if (array && array->canGetIndex(length - 1)){
-        rv = array->getIndex(length - 1);
+    else if (array && array->canGetIndexQuickly(length - 1)) {
+        rv = array->getIndexQuickly(length - 1);
         i = 1;
     } else {
         for (i = 0; i < length; i++) {
@@ -1087,14 +1243,14 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
     }
     
     if (callType == CallTypeJS && array) {
-        CachedCall cachedCall(exec, asFunction(function), 4);
+        CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4);
         for (; i < length && !exec->hadException(); ++i) {
             unsigned idx = length - i - 1;
             cachedCall.setThis(jsUndefined());
             cachedCall.setArgument(0, rv);
-            if (UNLIKELY(!array->canGetIndex(idx)))
+            if (UNLIKELY(!array->canGetIndexQuickly(idx)))
                 break; // length has been made unsafe while we enumerate fallback to slow path
-            cachedCall.setArgument(1, array->getIndex(idx));
+            cachedCall.setArgument(1, array->getIndexQuickly(idx));
             cachedCall.setArgument(2, jsNumber(idx));
             cachedCall.setArgument(3, array);
             rv = cachedCall.call();
@@ -1125,7 +1281,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec)
 {
     // 15.4.4.14
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
@@ -1148,14 +1304,14 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec)
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec)
 {
     // 15.4.4.15
-    JSObject* thisObj = exec->hostThisValue().toObject(exec);
+    JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
     unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
     if (!length)
         return JSValue::encode(jsNumber(-1));
 
     unsigned index = length - 1;
-    JSValue fromValue = exec->argument(1);
-    if (!fromValue.isUndefined()) {
+    if (exec->argumentCount() >= 2) {
+        JSValue fromValue = exec->argument(1);
         double fromDouble = fromValue.toInteger(exec);
         if (fromDouble < 0) {
             fromDouble += length;
@@ -1168,7 +1324,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec)
 
     JSValue searchElement = exec->argument(0);
     do {
-        ASSERT(index < length);
+        RELEASE_ASSERT(index < length);
         JSValue e = getProperty(exec, thisObj, index);
         if (exec->hadException())
             return JSValue::encode(jsUndefined());