Title: [191212] trunk/Source/_javascript_Core
Revision
191212
Author
keith_mil...@apple.com
Date
2015-10-16 14:40:21 -0700 (Fri, 16 Oct 2015)

Log Message

Fix some issues with TypedArrays
https://bugs.webkit.org/show_bug.cgi?id=150216

Reviewed by Geoffrey Garen.

This fixes a couple of issues:
1) The DFG had a separate case for creating new typedarrays in the dfg when the first argument is an object.
   Since the code for creating a Typedarray in the dfg is almost the same as the code in Baseline/LLInt
   the two cases have been merged.
2) If the length property on an object was unset then the construction could crash.
3) The TypedArray.prototype.set function and the TypedArray constructor should not call [[Get]] for the
   length of the source object when the source object is a TypedArray.
4) The conditions that were used to decide if the iterator could be skipped were incorrect.
   Instead of checking for have a bad time we should have checked the Indexing type did not allow for
   indexed accessors.

* dfg/DFGOperations.cpp:
* runtime/JSGenericTypedArrayViewConstructorInlines.h:
(JSC::constructGenericTypedArrayViewWithArguments):
(JSC::constructGenericTypedArrayView):
(JSC::constructGenericTypedArrayViewWithFirstArgument): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (191211 => 191212)


--- trunk/Source/_javascript_Core/ChangeLog	2015-10-16 21:25:52 UTC (rev 191211)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-10-16 21:40:21 UTC (rev 191212)
@@ -1,3 +1,27 @@
+2015-10-16  Keith Miller  <keith_mil...@apple.com>
+
+        Fix some issues with TypedArrays
+        https://bugs.webkit.org/show_bug.cgi?id=150216
+
+        Reviewed by Geoffrey Garen.
+
+        This fixes a couple of issues:
+        1) The DFG had a separate case for creating new typedarrays in the dfg when the first argument is an object.
+           Since the code for creating a Typedarray in the dfg is almost the same as the code in Baseline/LLInt
+           the two cases have been merged.
+        2) If the length property on an object was unset then the construction could crash.
+        3) The TypedArray.prototype.set function and the TypedArray constructor should not call [[Get]] for the
+           length of the source object when the source object is a TypedArray.
+        4) The conditions that were used to decide if the iterator could be skipped were incorrect.
+           Instead of checking for have a bad time we should have checked the Indexing type did not allow for
+           indexed accessors.
+
+        * dfg/DFGOperations.cpp:
+        * runtime/JSGenericTypedArrayViewConstructorInlines.h:
+        (JSC::constructGenericTypedArrayViewWithArguments):
+        (JSC::constructGenericTypedArrayView):
+        (JSC::constructGenericTypedArrayViewWithFirstArgument): Deleted.
+
 2015-10-16  Anders Carlsson  <ander...@apple.com>
 
         Fix Windows build.

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (191211 => 191212)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2015-10-16 21:25:52 UTC (rev 191211)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2015-10-16 21:40:21 UTC (rev 191212)
@@ -142,64 +142,6 @@
     return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
 }
 
-template<typename ViewClass>
-char* newTypedArrayWithOneArgument(
-    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
-{
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-    
-    JSValue value = JSValue::decode(encodedValue);
-    
-    if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) {
-        RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
-        
-        if (buffer->byteLength() % ViewClass::elementSize) {
-            vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size")));
-            return 0;
-        }
-        return bitwise_cast<char*>(
-            ViewClass::create(
-                exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize));
-    }
-    
-    if (JSObject* object = jsDynamicCast<JSObject*>(value)) {
-        unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec);
-        if (exec->hadException())
-            return 0;
-        
-        ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
-        if (!result)
-            return 0;
-        
-        if (!result->set(exec, object, 0, length))
-            return 0;
-        
-        return bitwise_cast<char*>(result);
-    }
-    
-    int length;
-    if (value.isInt32())
-        length = value.asInt32();
-    else if (!value.isNumber()) {
-        vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument")));
-        return 0;
-    } else {
-        length = static_cast<int>(value.asNumber());
-        if (length != value.asNumber()) {
-            vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)")));
-            return 0;
-        }
-    }
-    
-    if (length < 0) {
-        vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative")));
-        return 0;
-    }
-    
-    return bitwise_cast<char*>(ViewClass::create(exec, structure, length));
-}
-
 extern "C" {
 
 EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
@@ -664,7 +606,7 @@
 char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt8Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewInt16ArrayWithSize(
@@ -676,7 +618,7 @@
 char* JIT_OPERATION operationNewInt16ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt16Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewInt32ArrayWithSize(
@@ -688,7 +630,7 @@
 char* JIT_OPERATION operationNewInt32ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt32Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewUint8ArrayWithSize(
@@ -700,7 +642,7 @@
 char* JIT_OPERATION operationNewUint8ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewUint8ClampedArrayWithSize(
@@ -712,7 +654,7 @@
 char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8ClampedArray>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewUint16ArrayWithSize(
@@ -724,7 +666,7 @@
 char* JIT_OPERATION operationNewUint16ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint16Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewUint32ArrayWithSize(
@@ -736,7 +678,7 @@
 char* JIT_OPERATION operationNewUint32ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint32Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewFloat32ArrayWithSize(
@@ -748,7 +690,7 @@
 char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat32Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 char* JIT_OPERATION operationNewFloat64ArrayWithSize(
@@ -760,7 +702,7 @@
 char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
     ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
 {
-    return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);
+    return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat64Array>(exec, structure, encodedValue, 0, Nullopt));
 }
 
 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table, EncodedJSValue initialValueEncoded)

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewConstructorInlines.h (191211 => 191212)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewConstructorInlines.h	2015-10-16 21:25:52 UTC (rev 191211)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewConstructorInlines.h	2015-10-16 21:40:21 UTC (rev 191212)
@@ -77,23 +77,23 @@
 }
 
 template<typename ViewClass>
-static EncodedJSValue constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)
+static JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)
 {
     if (!iterator.isObject())
-        return JSValue::encode(throwTypeError(exec, "Symbol.Iterator for the first argument did not return an object."));
+        return throwTypeError(exec, "Symbol.Iterator for the first argument did not return an object.");
 
     MarkedArgumentBuffer storage;
     while (true) {
         JSValue next = iteratorStep(exec, iterator);
         if (exec->hadException())
-            return JSValue::encode(jsUndefined());
+            return nullptr;
 
         if (next.isFalse())
             break;
 
         JSValue nextItem = iteratorValue(exec, next);
         if (exec->hadException())
-            return JSValue::encode(jsUndefined());
+            return nullptr;
 
         storage.append(nextItem);
     }
@@ -101,132 +101,156 @@
     ViewClass* result = ViewClass::createUninitialized(exec, structure, storage.size());
     if (!result) {
         ASSERT(exec->hadException());
-        return JSValue::encode(jsUndefined());
+        return nullptr;
     }
 
     for (unsigned i = 0; i < storage.size(); ++i) {
         if (!result->setIndex(exec, i, storage.at(i))) {
             ASSERT(exec->hadException());
-            return JSValue::encode(jsUndefined());
+            return nullptr;
         }
     }
 
-    return JSValue::encode(result);
+    return result;
 }
 
 template<typename ViewClass>
-static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
+static JSObject* constructGenericTypedArrayViewWithArguments(ExecState* exec, Structure* structure, EncodedJSValue firstArgument, unsigned offset, Optional<unsigned> lengthOpt)
 {
-    Structure* structure =
-        asInternalFunction(exec->callee())->globalObject()->typedArrayStructure(
-            ViewClass::TypedArrayStorageType);
-
+    JSValue firstValue = JSValue::decode(firstArgument);
     VM& vm = exec->vm();
 
-    if (!exec->argumentCount()) {
-        if (ViewClass::TypedArrayStorageType == TypeDataView)
-            return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument."));
-        
-        // Even though the documentation doesn't say so, it's correct to say
-        // "new Int8Array()". This is the same as allocating an array of zero
-        // length.
-        return JSValue::encode(ViewClass::create(exec, structure, 0));
-    }
-    
-    if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0))) {
+    if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(firstValue)) {
         RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
-        
-        unsigned offset = (exec->argumentCount() > 1) ? exec->uncheckedArgument(1).toUInt32(exec) : 0;
-        if (exec->hadException())
-            return JSValue::encode(jsUndefined());
         unsigned length = 0;
-        if (exec->argumentCount() > 2) {
-            length = exec->uncheckedArgument(2).toUInt32(exec);
-            if (exec->hadException())
-                return JSValue::encode(jsUndefined());
-        } else {
+
+        if (lengthOpt)
+            length = lengthOpt.value();
+        else {
             if ((buffer->byteLength() - offset) % ViewClass::elementSize)
-                return throwVMError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
+                return throwRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size");
             length = (buffer->byteLength() - offset) / ViewClass::elementSize;
+
         }
-        return JSValue::encode(ViewClass::create(exec, structure, buffer, offset, length));
+
+        return ViewClass::create(exec, structure, buffer, offset, length);
     }
+    ASSERT(!offset && !lengthOpt);
     
     if (ViewClass::TypedArrayStorageType == TypeDataView)
-        return throwVMError(exec, createTypeError(exec, "Expected ArrayBuffer for the first argument."));
+        return throwTypeError(exec, "Expected ArrayBuffer for the first argument.");
     
     // For everything but DataView, we allow construction with any of:
     // - Another array. This creates a copy of the of that array.
     // - An integer. This creates a new typed array of that length and zero-initializes it.
-    
-    if (JSObject* object = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0))) {
-        PropertySlot lengthSlot(object);
-        object->getPropertySlot(exec, vm.propertyNames->length, lengthSlot);
 
-        if (!isTypedView(object->classInfo()->typedArrayStorageType)) {
+    if (JSObject* object = jsDynamicCast<JSObject*>(firstValue)) {
+        unsigned length;
+
+        if (isTypedView(object->classInfo()->typedArrayStorageType))
+            length = jsCast<JSArrayBufferView*>(object)->length();
+        else {
+            PropertySlot lengthSlot(object);
+            object->getPropertySlot(exec, vm.propertyNames->length, lengthSlot);
+
             JSValue iteratorFunc = object->get(exec, vm.propertyNames->iteratorSymbol);
             if (exec->hadException())
-                return JSValue::encode(jsUndefined());
+                return nullptr;
 
             // We would like not use the iterator as it is painfully slow. Fortunately, unless
             // 1) The iterator is not a known iterator.
             // 2) The base object does not have a length getter.
-            // 3) Bad times are being had.
+            // 3) The base object might have indexed getters.
             // it should not be observable that we do not use the iterator.
 
             if (!iteratorFunc.isUndefined()
-                && (iteratorFunc != exec->lexicalGlobalObject()->arrayProtoValuesFunction()
+                && (iteratorFunc != object->globalObject()->arrayProtoValuesFunction()
                     || lengthSlot.isAccessor() || lengthSlot.isCustom()
-                    || exec->lexicalGlobalObject()->isHavingABadTime())) {
+                    || hasAnyArrayStorage(object->indexingType()))) {
 
                     CallData callData;
                     CallType callType = getCallData(iteratorFunc, callData);
                     if (callType == CallTypeNone)
-                        return JSValue::encode(throwTypeError(exec, "Symbol.Iterator for the first argument cannot be called."));
+                        return throwTypeError(exec, "Symbol.Iterator for the first argument cannot be called.");
 
                     ArgList arguments;
                     JSValue iterator = call(exec, iteratorFunc, callType, callData, object, arguments);
                     if (exec->hadException())
-                        return JSValue::encode(jsUndefined());
+                        return nullptr;
 
                     return constructGenericTypedArrayViewFromIterator<ViewClass>(exec, structure, iterator);
+            }
 
-            }
+            length = lengthSlot.isUnset() ? 0 : lengthSlot.getValue(exec, vm.propertyNames->length).toUInt32(exec);
+            if (exec->hadException())
+                return nullptr;
         }
 
-        unsigned length = lengthSlot.getValue(exec, vm.propertyNames->length).toUInt32(exec);
-        if (exec->hadException())
-            return JSValue::encode(jsUndefined());
         
         ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
         if (!result) {
             ASSERT(exec->hadException());
-            return JSValue::encode(jsUndefined());
+            return nullptr;
         }
         
         if (!result->set(exec, object, 0, length))
-            return JSValue::encode(jsUndefined());
+            return nullptr;
         
-        return JSValue::encode(result);
+        return result;
     }
     
     int length;
-    if (exec->uncheckedArgument(0).isInt32())
-        length = exec->uncheckedArgument(0).asInt32();
-    else if (!exec->uncheckedArgument(0).isNumber())
-        return throwVMError(exec, createTypeError(exec, "Invalid array length argument"));
+    if (firstValue.isInt32())
+        length = firstValue.asInt32();
+    else if (!firstValue.isNumber())
+        return throwTypeError(exec, "Invalid array length argument");
     else {
-        length = static_cast<int>(exec->uncheckedArgument(0).asNumber());
-        if (length != exec->uncheckedArgument(0).asNumber())
-            return throwVMError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
+        length = static_cast<int>(firstValue.asNumber());
+        if (length != firstValue.asNumber())
+            return throwTypeError(exec, "Invalid array length argument (fractional lengths not allowed)");
     }
 
     if (length < 0)
-        return throwVMError(exec, createRangeError(exec, "Requested length is negative"));
-    return JSValue::encode(ViewClass::create(exec, structure, length));
+        return throwRangeError(exec, "Requested length is negative");
+    return ViewClass::create(exec, structure, length);
 }
 
 template<typename ViewClass>
+static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
+{
+    Structure* structure =
+        asInternalFunction(exec->callee())->globalObject()->typedArrayStructure(
+            ViewClass::TypedArrayStorageType);
+
+    size_t argCount = exec->argumentCount();
+
+    if (!argCount) {
+        if (ViewClass::TypedArrayStorageType == TypeDataView)
+            return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument."));
+
+        return JSValue::encode(ViewClass::create(exec, structure, 0));
+    }
+
+    JSValue firstValue = exec->uncheckedArgument(0);
+    unsigned offset = 0;
+    Optional<unsigned> length = Nullopt;
+    if (jsDynamicCast<JSArrayBuffer*>(firstValue) && argCount > 1) {
+        offset = exec->uncheckedArgument(1).toUInt32(exec);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+
+        if (argCount > 2) {
+            length = exec->uncheckedArgument(2).toUInt32(exec);
+            if (exec->hadException())
+                return JSValue::encode(jsUndefined());
+        }
+
+    }
+
+    return JSValue::encode(constructGenericTypedArrayViewWithArguments<ViewClass>(exec, structure, JSValue::encode(firstValue), offset, length));
+}
+
+template<typename ViewClass>
 ConstructType JSGenericTypedArrayViewConstructor<ViewClass>::getConstructData(JSCell*, ConstructData& constructData)
 {
     constructData.native.function = constructGenericTypedArrayView<ViewClass>;

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (191211 => 191212)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2015-10-16 21:25:52 UTC (rev 191211)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2015-10-16 21:40:21 UTC (rev 191212)
@@ -66,10 +66,6 @@
     if (!exec->argumentCount())
         return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
 
-    JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0));
-    if (!sourceArray)
-        return throwVMError(exec, createTypeError(exec, "First argument should be an object"));
-
     unsigned offset;
     if (exec->argumentCount() >= 2) {
         offset = exec->uncheckedArgument(1).toUInt32(exec);
@@ -78,7 +74,16 @@
     } else
         offset = 0;
 
-    unsigned length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
+    JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0));
+    if (!sourceArray)
+        return throwVMError(exec, createTypeError(exec, "First argument should be an object"));
+
+    unsigned length;
+    if (isTypedView(sourceArray->classInfo()->typedArrayStorageType))
+        length = jsDynamicCast<JSArrayBufferView*>(sourceArray)->length();
+    else
+        length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
+
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
@@ -283,7 +288,6 @@
     return JSValue::encode(jsNumber(thisObject->byteOffset()));
 }
 
-
 template<typename ViewClass>
 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncReverse(ExecState* exec)
 {

Added: trunk/Source/_javascript_Core/tests/stress/typedarray-construct-iterator.js (0 => 191212)


--- trunk/Source/_javascript_Core/tests/stress/typedarray-construct-iterator.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-construct-iterator.js	2015-10-16 21:40:21 UTC (rev 191212)
@@ -0,0 +1,66 @@
+// Test a bunch of things about typed array constructors with iterators.
+
+// Test that the dfg actually respects iterators.
+let foo = [1,2,3,4];
+
+function iterator() {
+    return { i: 0,
+             next: function() {
+                 if (this.i < foo.length/2) {
+                     return { done: false,
+                              value: foo[this.i++]
+                            };
+                 }
+                 return { done: true };
+             }
+           };
+}
+
+foo[Symbol.iterator] = iterator;
+
+(function body() {
+
+    for (var i = 1; i < 100000; i++) {
+        if (new Int32Array(foo).length !== 2)
+            throw "iterator did not run";
+    }
+
+})();
+
+// Test that the optimizations used for iterators during construction is valid.
+
+foo = { 0:0, 1:1, 2:2, 3:3 };
+count = 4;
+foo.__defineGetter__("length", function() {
+    return count--;
+});
+
+foo[Symbol.iterator] = Array.prototype[Symbol.iterator];
+
+if (new Int32Array(foo).length !== 2)
+    throw "iterator did not run";
+
+// Test that we handle length is unset... whoops.
+
+foo = { 0:0, 2:2, 3:3 };
+
+if (new Int32Array(foo).length !== 0)
+    throw "did not handle object with unset length";
+
+// Test that we handle prototypes with accessors.
+
+foo = { 0:0, 2:2, 3:3 };
+foo[Symbol.iterator] = Array.prototype[Symbol.iterator];
+foo.length = 4;
+bar = { };
+
+bar.__defineGetter__("1", function() {
+    foo.length = 0;
+    return 1;
+});
+
+
+foo.__proto__ = bar;
+
+if (new Int32Array(foo).length !== 2)
+    throw "did not handle object with accessor on prototype";
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to