Changeset 191190 in webkit
- Timestamp:
- Oct 16, 2015 11:37:14 AM (9 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r191175 r191190 1 2015-10-16 Keith Miller <keith_miller@apple.com> 2 3 Fix some issues with TypedArrays 4 https://bugs.webkit.org/show_bug.cgi?id=150216 5 6 Reviewed by Michael Saboff. 7 8 This fixes a couple of issues: 9 1) The DFG had a separate case for creating new typedarrays in the dfg when the first argument is an object. 10 Since the code for creating a Typedarray in the dfg is almost the same as the code in Baseline/LLInt 11 the two cases have been merged. 12 2) If the length property on an object was unset then the construction could crash. 13 3) The TypedArray.prototype.set function and the TypedArray constructor should not call [[Get]] for the 14 length of the source object when the source object is a TypedArray. 15 4) The conditions that were used to decide if the iterator could be skipped were incorrect. 16 Instead of checking for have a bad time we should have checked the Indexing type did not allow for 17 indexed accessors. 18 19 * dfg/DFGOperations.cpp: 20 (JSC::DFG::newTypedArrayWithOneArgument): Deleted. 21 * runtime/JSGenericTypedArrayViewConstructorInlines.h: 22 (JSC::constructGenericTypedArrayViewFromIterator): 23 (JSC::constructGenericTypedArrayViewWithFirstArgument): 24 (JSC::constructGenericTypedArrayView): 25 * runtime/JSGenericTypedArrayViewPrototypeFunctions.h: 26 (JSC::genericTypedArrayViewProtoFuncSet): 27 * tests/stress/typedarray-construct-iterator.js: Added. 28 (iterator.return.next): 29 (iterator): 30 (body): 31 1 32 2015-10-15 Michael Saboff <msaboff@apple.com> 2 33 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r190896 r191190 143 143 } 144 144 145 template<typename ViewClass>146 char* newTypedArrayWithOneArgument(147 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)148 {149 VM& vm = exec->vm();150 NativeCallFrameTracer tracer(&vm, exec);151 152 JSValue value = JSValue::decode(encodedValue);153 154 if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) {155 RefPtr<ArrayBuffer> buffer = jsBuffer->impl();156 157 if (buffer->byteLength() % ViewClass::elementSize) {158 vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size")));159 return 0;160 }161 return bitwise_cast<char*>(162 ViewClass::create(163 exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize));164 }165 166 if (JSObject* object = jsDynamicCast<JSObject*>(value)) {167 unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec);168 if (exec->hadException())169 return 0;170 171 ViewClass* result = ViewClass::createUninitialized(exec, structure, length);172 if (!result)173 return 0;174 175 if (!result->set(exec, object, 0, length))176 return 0;177 178 return bitwise_cast<char*>(result);179 }180 181 int length;182 if (value.isInt32())183 length = value.asInt32();184 else if (!value.isNumber()) {185 vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument")));186 return 0;187 } else {188 length = static_cast<int>(value.asNumber());189 if (length != value.asNumber()) {190 vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)")));191 return 0;192 }193 }194 195 if (length < 0) {196 vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative")));197 return 0;198 }199 200 return bitwise_cast<char*>(ViewClass::create(exec, structure, length));201 }202 203 145 extern "C" { 204 146 … … 665 607 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 666 608 { 667 return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue);609 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSInt8Array>(exec, structure, encodedValue)); 668 610 } 669 611 … … 677 619 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 678 620 { 679 return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue);621 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSInt16Array>(exec, structure, encodedValue)); 680 622 } 681 623 … … 689 631 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 690 632 { 691 return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue);633 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSInt32Array>(exec, structure, encodedValue)); 692 634 } 693 635 … … 701 643 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 702 644 { 703 return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue);645 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSUint8Array>(exec, structure, encodedValue)); 704 646 } 705 647 … … 713 655 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 714 656 { 715 return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue);657 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSUint8ClampedArray>(exec, structure, encodedValue)); 716 658 } 717 659 … … 725 667 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 726 668 { 727 return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue);669 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSUint16Array>(exec, structure, encodedValue)); 728 670 } 729 671 … … 737 679 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 738 680 { 739 return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue);681 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSUint32Array>(exec, structure, encodedValue)); 740 682 } 741 683 … … 749 691 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 750 692 { 751 return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue);693 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSFloat32Array>(exec, structure, encodedValue)); 752 694 } 753 695 … … 761 703 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 762 704 { 763 return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);705 return bitwise_cast<char*>(constructGenericTypedArrayViewWithFirstArgument<JSFloat64Array>(exec, structure, encodedValue)); 764 706 } 765 707 -
trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h
r191059 r191190 78 78 79 79 template<typename ViewClass> 80 static EncodedJSValueconstructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)80 static JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator) 81 81 { 82 82 if (!iterator.isObject()) 83 return JSValue::encode(throwTypeError(exec, "Symbol.Iterator for the first argument did not return an object."));83 return throwTypeError(exec, "Symbol.Iterator for the first argument did not return an object."); 84 84 85 85 MarkedArgumentBuffer storage; … … 87 87 JSValue next = iteratorStep(exec, iterator); 88 88 if (exec->hadException()) 89 return JSValue::encode(jsUndefined());89 return nullptr; 90 90 91 91 if (next.isFalse()) … … 94 94 JSValue nextItem = iteratorValue(exec, next); 95 95 if (exec->hadException()) 96 return JSValue::encode(jsUndefined());96 return nullptr; 97 97 98 98 storage.append(nextItem); … … 102 102 if (!result) { 103 103 ASSERT(exec->hadException()); 104 return JSValue::encode(jsUndefined());104 return nullptr; 105 105 } 106 106 … … 108 108 if (!result->setIndex(exec, i, storage.at(i))) { 109 109 ASSERT(exec->hadException()); 110 return JSValue::encode(jsUndefined()); 111 } 112 } 113 114 return JSValue::encode(result); 115 } 116 117 template<typename ViewClass> 118 static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec) 119 { 120 Structure* structure = 121 asInternalFunction(exec->callee())->globalObject()->typedArrayStructure( 122 ViewClass::TypedArrayStorageType); 123 110 return nullptr; 111 } 112 } 113 114 return result; 115 } 116 117 template<typename ViewClass, bool checkForOtherArguments = false> 118 static JSObject* constructGenericTypedArrayViewWithFirstArgument(ExecState* exec, Structure* structure, EncodedJSValue firstArgument) 119 { 120 JSValue firstValue = JSValue::decode(firstArgument); 124 121 VM& vm = exec->vm(); 125 122 126 if (!exec->argumentCount()) { 127 if (ViewClass::TypedArrayStorageType == TypeDataView) 128 return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument.")); 129 130 // Even though the documentation doesn't say so, it's correct to say 131 // "new Int8Array()". This is the same as allocating an array of zero 132 // length. 133 return JSValue::encode(ViewClass::create(exec, structure, 0)); 134 } 135 136 if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0))) { 123 if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(firstValue)) { 137 124 RefPtr<ArrayBuffer> buffer = jsBuffer->impl(); 138 139 unsigned offset = (exec->argumentCount() > 1) ? exec->uncheckedArgument(1).toUInt32(exec) : 0; 140 if (exec->hadException()) 141 return JSValue::encode(jsUndefined()); 125 126 unsigned offset = 0; 142 127 unsigned length = 0; 143 if (exec->argumentCount() > 2) { 128 if (checkForOtherArguments && exec->argumentCount() > 1) { 129 offset = exec->uncheckedArgument(1).toUInt32(exec); 130 if (exec->hadException()) 131 return nullptr; 132 } 133 134 if (checkForOtherArguments && exec->argumentCount() > 2) { 144 135 length = exec->uncheckedArgument(2).toUInt32(exec); 145 136 if (exec->hadException()) 146 return JSValue::encode(jsUndefined());137 return nullptr; 147 138 } else { 148 139 if ((buffer->byteLength() - offset) % ViewClass::elementSize) 149 return throw VMError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));140 return throwRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"); 150 141 length = (buffer->byteLength() - offset) / ViewClass::elementSize; 151 } 152 return JSValue::encode(ViewClass::create(exec, structure, buffer, offset, length)); 142 143 } 144 145 return ViewClass::create(exec, structure, buffer, offset, length); 153 146 } 154 147 155 148 if (ViewClass::TypedArrayStorageType == TypeDataView) 156 return throw VMError(exec, createTypeError(exec, "Expected ArrayBuffer for the first argument."));149 return throwTypeError(exec, "Expected ArrayBuffer for the first argument."); 157 150 158 151 // For everything but DataView, we allow construction with any of: 159 152 // - Another array. This creates a copy of the of that array. 160 153 // - An integer. This creates a new typed array of that length and zero-initializes it. 161 162 if (JSObject* object = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0))) { 163 PropertySlot lengthSlot(object); 164 object->getPropertySlot(exec, vm.propertyNames->length, lengthSlot); 165 166 if (!isTypedView(object->classInfo()->typedArrayStorageType)) { 154 155 if (JSObject* object = jsDynamicCast<JSObject*>(firstValue)) { 156 unsigned length; 157 158 if (isTypedView(object->classInfo()->typedArrayStorageType)) 159 length = jsCast<JSArrayBufferView*>(object)->length(); 160 else { 161 PropertySlot lengthSlot(object); 162 object->getPropertySlot(exec, vm.propertyNames->length, lengthSlot); 163 167 164 JSValue iteratorFunc = object->get(exec, vm.propertyNames->iteratorSymbol); 168 165 if (exec->hadException()) 169 return JSValue::encode(jsUndefined());166 return nullptr; 170 167 171 168 // We would like not use the iterator as it is painfully slow. Fortunately, unless 172 169 // 1) The iterator is not a known iterator. 173 170 // 2) The base object does not have a length getter. 174 // 3) Bad times are being had.171 // 3) The base object might have indexed getters. 175 172 // it should not be observable that we do not use the iterator. 176 173 177 174 if (!iteratorFunc.isUndefined() 178 && (iteratorFunc != exec->lexicalGlobalObject()->arrayProtoValuesFunction()175 && (iteratorFunc != object->globalObject()->arrayProtoValuesFunction() 179 176 || lengthSlot.isAccessor() || lengthSlot.isCustom() 180 || exec->lexicalGlobalObject()->isHavingABadTime())) {177 || hasAnyArrayStorage(object->indexingType()))) { 181 178 182 179 CallData callData; 183 180 CallType callType = getCallData(iteratorFunc, callData); 184 181 if (callType == CallTypeNone) 185 return JSValue::encode(throwTypeError(exec, "Symbol.Iterator for the first argument cannot be called."));182 return throwTypeError(exec, "Symbol.Iterator for the first argument cannot be called."); 186 183 187 184 ArgList arguments; 188 185 JSValue iterator = call(exec, iteratorFunc, callType, callData, object, arguments); 189 186 if (exec->hadException()) 190 return JSValue::encode(jsUndefined());187 return nullptr; 191 188 192 189 return constructGenericTypedArrayViewFromIterator<ViewClass>(exec, structure, iterator); 193 194 190 } 195 } 196 197 unsigned length = lengthSlot.getValue(exec, vm.propertyNames->length).toUInt32(exec); 198 if (exec->hadException()) 199 return JSValue::encode(jsUndefined()); 191 192 length = lengthSlot.isUnset() ? 0 : lengthSlot.getValue(exec, vm.propertyNames->length).toUInt32(exec); 193 if (exec->hadException()) 194 return nullptr; 195 } 196 200 197 201 198 ViewClass* result = ViewClass::createUninitialized(exec, structure, length); 202 199 if (!result) { 203 200 ASSERT(exec->hadException()); 204 return JSValue::encode(jsUndefined());201 return nullptr; 205 202 } 206 203 207 204 if (!result->set(exec, object, 0, length)) 208 return JSValue::encode(jsUndefined());205 return nullptr; 209 206 210 return JSValue::encode(result);207 return result; 211 208 } 212 209 213 210 int length; 214 if ( exec->uncheckedArgument(0).isInt32())215 length = exec->uncheckedArgument(0).asInt32();216 else if (! exec->uncheckedArgument(0).isNumber())217 return throw VMError(exec, createTypeError(exec, "Invalid array length argument"));211 if (firstValue.isInt32()) 212 length = firstValue.asInt32(); 213 else if (!firstValue.isNumber()) 214 return throwTypeError(exec, "Invalid array length argument"); 218 215 else { 219 length = static_cast<int>( exec->uncheckedArgument(0).asNumber());220 if (length != exec->uncheckedArgument(0).asNumber())221 return throw VMError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));216 length = static_cast<int>(firstValue.asNumber()); 217 if (length != firstValue.asNumber()) 218 return throwTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"); 222 219 } 223 220 224 221 if (length < 0) 225 return throwVMError(exec, createRangeError(exec, "Requested length is negative")); 226 return JSValue::encode(ViewClass::create(exec, structure, length)); 222 return throwRangeError(exec, "Requested length is negative"); 223 return ViewClass::create(exec, structure, length); 224 } 225 226 template<typename ViewClass> 227 static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec) 228 { 229 Structure* structure = 230 asInternalFunction(exec->callee())->globalObject()->typedArrayStructure( 231 ViewClass::TypedArrayStorageType); 232 233 if (!exec->argumentCount()) { 234 if (ViewClass::TypedArrayStorageType == TypeDataView) 235 return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument.")); 236 237 return JSValue::encode(ViewClass::create(exec, structure, 0)); 238 } 239 240 return JSValue::encode(constructGenericTypedArrayViewWithFirstArgument<ViewClass, true>(exec, structure, JSValue::encode(exec->uncheckedArgument(0)))); 227 241 } 228 242 -
trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h
r191059 r191190 67 67 return throwVMError(exec, createTypeError(exec, "Expected at least one argument")); 68 68 69 JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0));70 if (!sourceArray)71 return throwVMError(exec, createTypeError(exec, "First argument should be an object"));72 73 69 unsigned offset; 74 70 if (exec->argumentCount() >= 2) { … … 79 75 offset = 0; 80 76 81 unsigned length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec); 77 JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0)); 78 if (!sourceArray) 79 return throwVMError(exec, createTypeError(exec, "First argument should be an object")); 80 81 unsigned length; 82 if (isTypedView(sourceArray->classInfo()->typedArrayStorageType)) 83 length = jsDynamicCast<JSArrayBufferView*>(sourceArray)->length(); 84 else 85 length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec); 86 82 87 if (exec->hadException()) 83 88 return JSValue::encode(jsUndefined()); … … 284 289 } 285 290 286 287 291 template<typename ViewClass> 288 292 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncReverse(ExecState* exec)
Note: See TracChangeset
for help on using the changeset viewer.