1 | /* |
2 | * Copyright (C) 2013-2019 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include "ArrayBufferView.h" |
29 | #include "DeferGC.h" |
30 | #include "Error.h" |
31 | #include "ExceptionHelpers.h" |
32 | #include "JSArrayBuffer.h" |
33 | #include "JSGenericTypedArrayView.h" |
34 | #include "TypeError.h" |
35 | #include "TypedArrays.h" |
36 | #include <wtf/text/StringConcatenateNumbers.h> |
37 | |
38 | namespace JSC { |
39 | |
40 | template<typename Adaptor> |
41 | JSGenericTypedArrayView<Adaptor>::JSGenericTypedArrayView( |
42 | VM& vm, ConstructionContext& context) |
43 | : Base(vm, context) |
44 | { |
45 | } |
46 | |
47 | template<typename Adaptor> |
48 | JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create( |
49 | ExecState* exec, Structure* structure, unsigned length) |
50 | { |
51 | VM& vm = exec->vm(); |
52 | auto scope = DECLARE_THROW_SCOPE(vm); |
53 | ConstructionContext context(vm, structure, length, sizeof(typename Adaptor::Type)); |
54 | if (!context) { |
55 | throwOutOfMemoryError(exec, scope); |
56 | return nullptr; |
57 | } |
58 | JSGenericTypedArrayView* result = |
59 | new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap)) |
60 | JSGenericTypedArrayView(vm, context); |
61 | result->finishCreation(vm); |
62 | return result; |
63 | } |
64 | |
65 | template<typename Adaptor> |
66 | JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::createWithFastVector( |
67 | ExecState* exec, Structure* structure, unsigned length, void* vector) |
68 | { |
69 | VM& vm = exec->vm(); |
70 | ConstructionContext context(structure, length, vector); |
71 | RELEASE_ASSERT(context); |
72 | JSGenericTypedArrayView* result = |
73 | new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap)) |
74 | JSGenericTypedArrayView(vm, context); |
75 | result->finishCreation(vm); |
76 | return result; |
77 | } |
78 | |
79 | template<typename Adaptor> |
80 | JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::createUninitialized(ExecState* exec, Structure* structure, unsigned length) |
81 | { |
82 | VM& vm = exec->vm(); |
83 | auto scope = DECLARE_THROW_SCOPE(vm); |
84 | ConstructionContext context( |
85 | vm, structure, length, sizeof(typename Adaptor::Type), |
86 | ConstructionContext::DontInitialize); |
87 | if (!context) { |
88 | throwOutOfMemoryError(exec, scope); |
89 | return nullptr; |
90 | } |
91 | JSGenericTypedArrayView* result = |
92 | new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap)) |
93 | JSGenericTypedArrayView(vm, context); |
94 | result->finishCreation(vm); |
95 | return result; |
96 | } |
97 | |
98 | template<typename Adaptor> |
99 | JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create( |
100 | ExecState* exec, Structure* structure, RefPtr<ArrayBuffer>&& buffer, |
101 | unsigned byteOffset, unsigned length) |
102 | { |
103 | VM& vm = exec->vm(); |
104 | auto scope = DECLARE_THROW_SCOPE(vm); |
105 | size_t size = sizeof(typename Adaptor::Type); |
106 | ASSERT(buffer); |
107 | if (!ArrayBufferView::verifySubRangeLength(*buffer, byteOffset, length, size)) { |
108 | throwException(exec, scope, createRangeError(exec, "Length out of range of buffer" )); |
109 | return nullptr; |
110 | } |
111 | if (!ArrayBufferView::verifyByteOffsetAlignment(byteOffset, size)) { |
112 | throwException(exec, scope, createRangeError(exec, "Byte offset is not aligned" )); |
113 | return nullptr; |
114 | } |
115 | ConstructionContext context(vm, structure, WTFMove(buffer), byteOffset, length); |
116 | ASSERT(context); |
117 | JSGenericTypedArrayView* result = |
118 | new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap)) |
119 | JSGenericTypedArrayView(vm, context); |
120 | result->finishCreation(vm); |
121 | return result; |
122 | } |
123 | |
124 | template<typename Adaptor> |
125 | JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create( |
126 | VM& vm, Structure* structure, RefPtr<typename Adaptor::ViewType>&& impl) |
127 | { |
128 | ConstructionContext context(vm, structure, impl->possiblySharedBuffer(), impl->byteOffset(), impl->length()); |
129 | ASSERT(context); |
130 | JSGenericTypedArrayView* result = |
131 | new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap)) |
132 | JSGenericTypedArrayView(vm, context); |
133 | result->finishCreation(vm); |
134 | return result; |
135 | } |
136 | |
137 | template<typename Adaptor> |
138 | JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create( |
139 | Structure* structure, JSGlobalObject* globalObject, |
140 | RefPtr<typename Adaptor::ViewType>&& impl) |
141 | { |
142 | return create(globalObject->vm(), structure, WTFMove(impl)); |
143 | } |
144 | |
145 | template<typename Adaptor> |
146 | bool JSGenericTypedArrayView<Adaptor>::validateRange( |
147 | ExecState* exec, unsigned offset, unsigned length) |
148 | { |
149 | VM& vm = exec->vm(); |
150 | auto scope = DECLARE_THROW_SCOPE(vm); |
151 | if (canAccessRangeQuickly(offset, length)) |
152 | return true; |
153 | |
154 | throwException(exec, scope, createRangeError(exec, "Range consisting of offset and length are out of bounds" )); |
155 | return false; |
156 | } |
157 | |
158 | template<typename Adaptor> |
159 | template<typename OtherAdaptor> |
160 | bool JSGenericTypedArrayView<Adaptor>::setWithSpecificType( |
161 | ExecState* exec, unsigned offset, JSGenericTypedArrayView<OtherAdaptor>* other, |
162 | unsigned otherOffset, unsigned length, CopyType type) |
163 | { |
164 | // Handle the hilarious case: the act of getting the length could have resulted |
165 | // in neutering. Well, no. That'll never happen because there cannot be |
166 | // side-effects on getting the length of a typed array. But predicting where there |
167 | // are, or aren't, side-effects is a fool's game so we resort to this cheap |
168 | // check. Worst case, if we're wrong, people start seeing less things get copied |
169 | // but we won't have a security vulnerability. |
170 | length = std::min(length, other->length()); |
171 | |
172 | RELEASE_ASSERT(other->canAccessRangeQuickly(otherOffset, length)); |
173 | if (!validateRange(exec, offset, length)) |
174 | return false; |
175 | |
176 | // This method doesn't support copying between the same array. Note that |
177 | // set() will only call this if the types differ, which implicitly guarantees |
178 | // that we can't be the same array. This is relevant because the way we detect |
179 | // non-overlapping is by checking if either (a) either array doesn't have a |
180 | // backing buffer or (b) the backing buffers are different, but that doesn't |
181 | // catch the case where it's the *same* array - fortunately though, this code |
182 | // path never needs to worry about that case. |
183 | ASSERT(static_cast<JSCell*>(this) != static_cast<JSCell*>(other)); |
184 | |
185 | // 1) If the two arrays are non-overlapping, we can copy in any order we like |
186 | // and we don't need an intermediate buffer. Arrays are definitely |
187 | // non-overlapping if either one of them has no backing buffer (that means |
188 | // that it *owns* its philosophical backing buffer) or if they have |
189 | // different backing buffers. |
190 | // 2) If the two arrays overlap but have the same element size, we can do a |
191 | // memmove-like copy where we flip-flop direction based on which vector |
192 | // starts before the other: |
193 | // A) If the destination vector is before the source vector, then a forward |
194 | // copy is in order. |
195 | // B) If the destination vector is after the source vector, then a backward |
196 | // copy is in order. |
197 | // 3) If we have different element sizes and there is a chance of overlap then |
198 | // we need an intermediate vector. |
199 | |
200 | // NB. Comparisons involving elementSize will be constant-folded by template |
201 | // specialization. |
202 | |
203 | unsigned otherElementSize = sizeof(typename OtherAdaptor::Type); |
204 | |
205 | // Handle cases (1) and (2A). |
206 | if (!hasArrayBuffer() || !other->hasArrayBuffer() |
207 | || existingBuffer() != other->existingBuffer() |
208 | || (elementSize == otherElementSize && vector() <= other->vector()) |
209 | || type == CopyType::LeftToRight) { |
210 | for (unsigned i = 0; i < length; ++i) { |
211 | setIndexQuicklyToNativeValue( |
212 | offset + i, OtherAdaptor::template convertTo<Adaptor>( |
213 | other->getIndexQuicklyAsNativeValue(i + otherOffset))); |
214 | } |
215 | return true; |
216 | } |
217 | |
218 | // Now we either have (2B) or (3) - so first we try to cover (2B). |
219 | if (elementSize == otherElementSize) { |
220 | for (unsigned i = length; i--;) { |
221 | setIndexQuicklyToNativeValue( |
222 | offset + i, OtherAdaptor::template convertTo<Adaptor>( |
223 | other->getIndexQuicklyAsNativeValue(i + otherOffset))); |
224 | } |
225 | return true; |
226 | } |
227 | |
228 | // Fail: we need an intermediate transfer buffer (i.e. case (3)). |
229 | Vector<typename Adaptor::Type, 32> transferBuffer(length); |
230 | for (unsigned i = length; i--;) { |
231 | transferBuffer[i] = OtherAdaptor::template convertTo<Adaptor>( |
232 | other->getIndexQuicklyAsNativeValue(i + otherOffset)); |
233 | } |
234 | for (unsigned i = length; i--;) |
235 | setIndexQuicklyToNativeValue(offset + i, transferBuffer[i]); |
236 | |
237 | return true; |
238 | } |
239 | |
240 | template<typename Adaptor> |
241 | bool JSGenericTypedArrayView<Adaptor>::set( |
242 | ExecState* exec, unsigned offset, JSObject* object, unsigned objectOffset, unsigned length, CopyType type) |
243 | { |
244 | VM& vm = exec->vm(); |
245 | auto scope = DECLARE_THROW_SCOPE(vm); |
246 | |
247 | const ClassInfo* ci = object->classInfo(vm); |
248 | if (ci->typedArrayStorageType == Adaptor::typeValue) { |
249 | // The super fast case: we can just memcpy since we're the same type. |
250 | JSGenericTypedArrayView* other = jsCast<JSGenericTypedArrayView*>(object); |
251 | length = std::min(length, other->length()); |
252 | |
253 | RELEASE_ASSERT(other->canAccessRangeQuickly(objectOffset, length)); |
254 | bool success = validateRange(exec, offset, length); |
255 | EXCEPTION_ASSERT(!scope.exception() == success); |
256 | if (!success) |
257 | return false; |
258 | |
259 | memmove(typedVector() + offset, other->typedVector() + objectOffset, length * elementSize); |
260 | return true; |
261 | } |
262 | |
263 | switch (ci->typedArrayStorageType) { |
264 | case TypeInt8: |
265 | RELEASE_AND_RETURN(scope, setWithSpecificType<Int8Adaptor>( |
266 | exec, offset, jsCast<JSInt8Array*>(object), objectOffset, length, type)); |
267 | case TypeInt16: |
268 | RELEASE_AND_RETURN(scope, setWithSpecificType<Int16Adaptor>( |
269 | exec, offset, jsCast<JSInt16Array*>(object), objectOffset, length, type)); |
270 | case TypeInt32: |
271 | RELEASE_AND_RETURN(scope, setWithSpecificType<Int32Adaptor>( |
272 | exec, offset, jsCast<JSInt32Array*>(object), objectOffset, length, type)); |
273 | case TypeUint8: |
274 | RELEASE_AND_RETURN(scope, setWithSpecificType<Uint8Adaptor>( |
275 | exec, offset, jsCast<JSUint8Array*>(object), objectOffset, length, type)); |
276 | case TypeUint8Clamped: |
277 | RELEASE_AND_RETURN(scope, setWithSpecificType<Uint8ClampedAdaptor>( |
278 | exec, offset, jsCast<JSUint8ClampedArray*>(object), objectOffset, length, type)); |
279 | case TypeUint16: |
280 | RELEASE_AND_RETURN(scope, setWithSpecificType<Uint16Adaptor>( |
281 | exec, offset, jsCast<JSUint16Array*>(object), objectOffset, length, type)); |
282 | case TypeUint32: |
283 | RELEASE_AND_RETURN(scope, setWithSpecificType<Uint32Adaptor>( |
284 | exec, offset, jsCast<JSUint32Array*>(object), objectOffset, length, type)); |
285 | case TypeFloat32: |
286 | RELEASE_AND_RETURN(scope, setWithSpecificType<Float32Adaptor>( |
287 | exec, offset, jsCast<JSFloat32Array*>(object), objectOffset, length, type)); |
288 | case TypeFloat64: |
289 | RELEASE_AND_RETURN(scope, setWithSpecificType<Float64Adaptor>( |
290 | exec, offset, jsCast<JSFloat64Array*>(object), objectOffset, length, type)); |
291 | case NotTypedArray: |
292 | case TypeDataView: { |
293 | bool success = validateRange(exec, offset, length); |
294 | EXCEPTION_ASSERT(!scope.exception() == success); |
295 | if (!success) |
296 | return false; |
297 | |
298 | // We could optimize this case. But right now, we don't. |
299 | for (unsigned i = 0; i < length; ++i) { |
300 | JSValue value = object->get(exec, i + objectOffset); |
301 | RETURN_IF_EXCEPTION(scope, false); |
302 | bool success = setIndex(exec, offset + i, value); |
303 | EXCEPTION_ASSERT(!scope.exception() || !success); |
304 | if (!success) |
305 | return false; |
306 | } |
307 | return true; |
308 | } } |
309 | |
310 | RELEASE_ASSERT_NOT_REACHED(); |
311 | return false; |
312 | } |
313 | |
314 | template<typename Adaptor> |
315 | RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl() |
316 | { |
317 | return Adaptor::ViewType::tryCreate(possiblySharedBuffer(), byteOffset(), length()); |
318 | } |
319 | |
320 | template<typename Adaptor> |
321 | RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl() |
322 | { |
323 | return Adaptor::ViewType::tryCreate(unsharedBuffer(), byteOffset(), length()); |
324 | } |
325 | |
326 | template<typename Adaptor> |
327 | ArrayBuffer* JSGenericTypedArrayView<Adaptor>::existingBuffer() |
328 | { |
329 | return existingBufferInButterfly(); |
330 | } |
331 | |
332 | template<typename Adaptor> |
333 | EncodedJSValue JSGenericTypedArrayView<Adaptor>::throwNeuteredTypedArrayTypeError(ExecState* exec, EncodedJSValue object, PropertyName) |
334 | { |
335 | VM& vm = exec->vm(); |
336 | auto scope = DECLARE_THROW_SCOPE(vm); |
337 | ASSERT_UNUSED(object, jsCast<JSGenericTypedArrayView*>(JSValue::decode(object))->isNeutered()); |
338 | return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage); |
339 | } |
340 | |
341 | template<typename Adaptor> |
342 | bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot( |
343 | JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
344 | { |
345 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object); |
346 | |
347 | if (Optional<uint32_t> index = parseIndex(propertyName)) { |
348 | if (thisObject->isNeutered()) { |
349 | slot.setCustom(thisObject, static_cast<unsigned>(PropertyAttribute::None), throwNeuteredTypedArrayTypeError); |
350 | return true; |
351 | } |
352 | |
353 | if (thisObject->canGetIndexQuickly(index.value())) { |
354 | slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::DontDelete), thisObject->getIndexQuickly(index.value())); |
355 | return true; |
356 | } |
357 | |
358 | return false; |
359 | } |
360 | |
361 | if (isCanonicalNumericIndexString(propertyName)) { |
362 | if (thisObject->isNeutered()) { |
363 | slot.setCustom(thisObject, static_cast<unsigned>(PropertyAttribute::None), throwNeuteredTypedArrayTypeError); |
364 | return true; |
365 | } |
366 | |
367 | return false; |
368 | } |
369 | |
370 | return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
371 | } |
372 | |
373 | template<typename Adaptor> |
374 | bool JSGenericTypedArrayView<Adaptor>::put( |
375 | JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, |
376 | PutPropertySlot& slot) |
377 | { |
378 | VM& vm = exec->vm(); |
379 | auto scope = DECLARE_THROW_SCOPE(vm); |
380 | |
381 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell); |
382 | |
383 | // https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver |
384 | // Ignore the receiver even if the receiver is altered to non base value. |
385 | // 9.4.5.5-2-b-i Return ? IntegerIndexedElementSet(O, numericIndex, V). |
386 | if (Optional<uint32_t> index = parseIndex(propertyName)) |
387 | RELEASE_AND_RETURN(scope, putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode())); |
388 | |
389 | if (isCanonicalNumericIndexString(propertyName)) { |
390 | if (thisObject->isNeutered()) |
391 | throwTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage); |
392 | return false; |
393 | } |
394 | |
395 | RELEASE_AND_RETURN(scope, Base::put(thisObject, exec, propertyName, value, slot)); |
396 | } |
397 | |
398 | template<typename Adaptor> |
399 | bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty( |
400 | JSObject* object, ExecState* exec, PropertyName propertyName, |
401 | const PropertyDescriptor& descriptor, bool shouldThrow) |
402 | { |
403 | VM& vm = exec->vm(); |
404 | auto scope = DECLARE_THROW_SCOPE(vm); |
405 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object); |
406 | |
407 | if (Optional<uint32_t> index = parseIndex(propertyName)) { |
408 | auto throwTypeErrorIfNeeded = [&] (const char* errorMessage) -> bool { |
409 | if (shouldThrow) |
410 | throwTypeError(exec, scope, makeString(errorMessage, *index)); |
411 | return false; |
412 | }; |
413 | |
414 | if (index.value() >= thisObject->m_length) |
415 | return false; |
416 | |
417 | if (descriptor.isAccessorDescriptor()) |
418 | return throwTypeErrorIfNeeded("Attempting to store accessor property on a typed array at index: " ); |
419 | |
420 | if (descriptor.configurable()) |
421 | return throwTypeErrorIfNeeded("Attempting to configure non-configurable property on a typed array at index: " ); |
422 | |
423 | if (!descriptor.enumerable() || !descriptor.writable()) |
424 | return throwTypeErrorIfNeeded("Attempting to store non-enumerable or non-writable property on a typed array at index: " ); |
425 | |
426 | if (descriptor.value()) |
427 | RELEASE_AND_RETURN(scope, thisObject->putByIndex(thisObject, exec, index.value(), descriptor.value(), shouldThrow)); |
428 | |
429 | return true; |
430 | } |
431 | |
432 | if (isCanonicalNumericIndexString(propertyName)) |
433 | return false; |
434 | |
435 | RELEASE_AND_RETURN(scope, Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow)); |
436 | } |
437 | |
438 | template<typename Adaptor> |
439 | bool JSGenericTypedArrayView<Adaptor>::deleteProperty( |
440 | JSCell* cell, ExecState* exec, PropertyName propertyName) |
441 | { |
442 | VM& vm = exec->vm(); |
443 | auto scope = DECLARE_THROW_SCOPE(vm); |
444 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell); |
445 | |
446 | if (thisObject->isNeutered()) |
447 | return typeError(exec, scope, true, typedArrayBufferHasBeenDetachedErrorMessage); |
448 | |
449 | if (parseIndex(propertyName)) |
450 | return false; |
451 | |
452 | return Base::deleteProperty(thisObject, exec, propertyName); |
453 | } |
454 | |
455 | template<typename Adaptor> |
456 | bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlotByIndex( |
457 | JSObject* object, ExecState*, unsigned propertyName, PropertySlot& slot) |
458 | { |
459 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object); |
460 | |
461 | if (thisObject->isNeutered()) { |
462 | slot.setCustom(thisObject, static_cast<unsigned>(PropertyAttribute::None), throwNeuteredTypedArrayTypeError); |
463 | return true; |
464 | } |
465 | |
466 | if (!thisObject->canGetIndexQuickly(propertyName)) |
467 | return false; |
468 | |
469 | slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::DontDelete), thisObject->getIndexQuickly(propertyName)); |
470 | return true; |
471 | } |
472 | |
473 | template<typename Adaptor> |
474 | bool JSGenericTypedArrayView<Adaptor>::putByIndex( |
475 | JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool) |
476 | { |
477 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell); |
478 | return thisObject->setIndex(exec, propertyName, value); |
479 | } |
480 | |
481 | template<typename Adaptor> |
482 | bool JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex( |
483 | JSCell* cell, ExecState* exec, unsigned propertyName) |
484 | { |
485 | return cell->methodTable(exec->vm())->deleteProperty(cell, exec, Identifier::from(exec, propertyName)); |
486 | } |
487 | |
488 | template<typename Adaptor> |
489 | void JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames( |
490 | JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode) |
491 | { |
492 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object); |
493 | |
494 | if (array.includeStringProperties()) { |
495 | for (unsigned i = 0; i < thisObject->m_length; ++i) |
496 | array.add(Identifier::from(exec, i)); |
497 | } |
498 | |
499 | return Base::getOwnPropertyNames(object, exec, array, mode); |
500 | } |
501 | |
502 | template<typename Adaptor> |
503 | size_t JSGenericTypedArrayView<Adaptor>::estimatedSize(JSCell* cell, VM& vm) |
504 | { |
505 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell); |
506 | |
507 | if (thisObject->m_mode == OversizeTypedArray) |
508 | return Base::estimatedSize(thisObject, vm) + thisObject->byteSize(); |
509 | if (thisObject->m_mode == FastTypedArray && thisObject->hasVector()) |
510 | return Base::estimatedSize(thisObject, vm) + thisObject->byteSize(); |
511 | |
512 | return Base::estimatedSize(thisObject, vm); |
513 | } |
514 | |
515 | template<typename Adaptor> |
516 | void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor& visitor) |
517 | { |
518 | JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell); |
519 | Base::visitChildren(thisObject, visitor); |
520 | |
521 | TypedArrayMode mode; |
522 | void* vector; |
523 | size_t byteSize; |
524 | |
525 | { |
526 | auto locker = holdLock(thisObject->cellLock()); |
527 | mode = thisObject->m_mode; |
528 | vector = thisObject->vector(); |
529 | byteSize = thisObject->byteSize(); |
530 | } |
531 | |
532 | switch (mode) { |
533 | case FastTypedArray: { |
534 | if (vector) |
535 | visitor.markAuxiliary(vector); |
536 | break; |
537 | } |
538 | |
539 | case OversizeTypedArray: { |
540 | visitor.reportExtraMemoryVisited(byteSize); |
541 | break; |
542 | } |
543 | |
544 | case WastefulTypedArray: |
545 | break; |
546 | |
547 | case DataViewMode: |
548 | RELEASE_ASSERT_NOT_REACHED(); |
549 | break; |
550 | } |
551 | } |
552 | |
553 | } // namespace JSC |
554 | |