[JSC] Drop PassRefPtr from ArrayBuffer
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGenericTypedArrayViewInlines.h
1 /*
2  * Copyright (C) 2013, 2016 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
37 namespace JSC {
38
39 template<typename Adaptor>
40 JSGenericTypedArrayView<Adaptor>::JSGenericTypedArrayView(
41     VM& vm, ConstructionContext& context)
42     : Base(vm, context)
43 {
44 }
45
46 template<typename Adaptor>
47 JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create(
48     ExecState* exec, Structure* structure, unsigned length)
49 {
50     VM& vm = exec->vm();
51     auto scope = DECLARE_THROW_SCOPE(vm);
52     ConstructionContext context(vm, structure, length, sizeof(typename Adaptor::Type));
53     if (!context) {
54         throwOutOfMemoryError(exec, scope);
55         return nullptr;
56     }
57     JSGenericTypedArrayView* result =
58         new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap))
59         JSGenericTypedArrayView(vm, context);
60     result->finishCreation(vm);
61     return result;
62 }
63
64 template<typename Adaptor>
65 JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::createWithFastVector(
66     ExecState* exec, Structure* structure, unsigned length, void* vector)
67 {
68     VM& vm = exec->vm();
69     ConstructionContext context(structure, length, vector);
70     RELEASE_ASSERT(context);
71     JSGenericTypedArrayView* result =
72         new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap))
73         JSGenericTypedArrayView(vm, context);
74     result->finishCreation(vm);
75     return result;
76 }
77
78 template<typename Adaptor>
79 JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::createUninitialized(
80     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         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         scope.release();
266         return setWithSpecificType<Int8Adaptor>(
267             exec, offset, jsCast<JSInt8Array*>(object), objectOffset, length, type);
268     case TypeInt16:
269         scope.release();
270         return setWithSpecificType<Int16Adaptor>(
271             exec, offset, jsCast<JSInt16Array*>(object), objectOffset, length, type);
272     case TypeInt32:
273         scope.release();
274         return setWithSpecificType<Int32Adaptor>(
275             exec, offset, jsCast<JSInt32Array*>(object), objectOffset, length, type);
276     case TypeUint8:
277         scope.release();
278         return setWithSpecificType<Uint8Adaptor>(
279             exec, offset, jsCast<JSUint8Array*>(object), objectOffset, length, type);
280     case TypeUint8Clamped:
281         scope.release();
282         return setWithSpecificType<Uint8ClampedAdaptor>(
283             exec, offset, jsCast<JSUint8ClampedArray*>(object), objectOffset, length, type);
284     case TypeUint16:
285         scope.release();
286         return setWithSpecificType<Uint16Adaptor>(
287             exec, offset, jsCast<JSUint16Array*>(object), objectOffset, length, type);
288     case TypeUint32:
289         scope.release();
290         return setWithSpecificType<Uint32Adaptor>(
291             exec, offset, jsCast<JSUint32Array*>(object), objectOffset, length, type);
292     case TypeFloat32:
293         scope.release();
294         return setWithSpecificType<Float32Adaptor>(
295             exec, offset, jsCast<JSFloat32Array*>(object), objectOffset, length, type);
296     case TypeFloat64:
297         scope.release();
298         return setWithSpecificType<Float64Adaptor>(
299             exec, offset, jsCast<JSFloat64Array*>(object), objectOffset, length, type);
300     case NotTypedArray:
301     case TypeDataView: {
302         bool success = validateRange(exec, offset, length);
303         ASSERT(!scope.exception() == success);
304         if (!success)
305             return false;
306
307         // We could optimize this case. But right now, we don't.
308         for (unsigned i = 0; i < length; ++i) {
309             JSValue value = object->get(exec, i + objectOffset);
310             RETURN_IF_EXCEPTION(scope, false);
311             bool success = setIndex(exec, offset + i, value);
312             ASSERT(!scope.exception() || !success);
313             if (!success)
314                 return false;
315         }
316         return true;
317     } }
318     
319     RELEASE_ASSERT_NOT_REACHED();
320     return false;
321 }
322
323 template<typename Adaptor>
324 RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl()
325 {
326     return Adaptor::ViewType::create(possiblySharedBuffer(), byteOffset(), length());
327 }
328
329 template<typename Adaptor>
330 RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl()
331 {
332     return Adaptor::ViewType::create(unsharedBuffer(), byteOffset(), length());
333 }
334
335 template<typename Adaptor>
336 ArrayBuffer* JSGenericTypedArrayView<Adaptor>::existingBuffer()
337 {
338     return existingBufferInButterfly();
339 }
340
341 template<typename Adaptor>
342 EncodedJSValue JSGenericTypedArrayView<Adaptor>::throwNeuteredTypedArrayTypeError(ExecState* exec, EncodedJSValue object, PropertyName)
343 {
344     VM& vm = exec->vm();
345     auto scope = DECLARE_THROW_SCOPE(vm);
346     ASSERT_UNUSED(object, jsCast<JSGenericTypedArrayView*>(JSValue::decode(object))->isNeutered());
347     return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
348 }
349
350 template<typename Adaptor>
351 bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot(
352     JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
353 {
354     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
355
356     if (std::optional<uint32_t> index = parseIndex(propertyName)) {
357         if (thisObject->isNeutered()) {
358             slot.setCustom(thisObject, None, throwNeuteredTypedArrayTypeError);
359             return true;
360         }
361
362         if (thisObject->canGetIndexQuickly(index.value()))
363             slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index.value()));
364         else
365             slot.setValue(thisObject, DontDelete | ReadOnly, jsUndefined());
366         return true;
367     }
368     
369     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
370 }
371
372 template<typename Adaptor>
373 bool JSGenericTypedArrayView<Adaptor>::put(
374     JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value,
375     PutPropertySlot& slot)
376 {
377     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
378
379     // https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver
380     // Ignore the receiver even if the receiver is altered to non base value.
381     // 9.4.5.5-2-b-i Return ? IntegerIndexedElementSet(O, numericIndex, V).
382     if (std::optional<uint32_t> index = parseIndex(propertyName))
383         return putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
384     
385     return Base::put(thisObject, exec, propertyName, value, slot);
386 }
387
388 template<typename Adaptor>
389 bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty(
390     JSObject* object, ExecState* exec, PropertyName propertyName,
391     const PropertyDescriptor& descriptor, bool shouldThrow)
392 {
393     VM& vm = exec->vm();
394     auto scope = DECLARE_THROW_SCOPE(vm);
395     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
396
397     if (parseIndex(propertyName)) {
398         if (descriptor.isAccessorDescriptor())
399             return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to store accessor indexed property on a typed array."));
400
401         if (descriptor.configurable())
402             return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to configure non-configurable property."));
403
404         if (!descriptor.enumerable() || !descriptor.writable())
405             return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to store non-enumerable or non-writable indexed property on a typed array."));
406
407         if (descriptor.value()) {
408             PutPropertySlot unused(JSValue(thisObject), shouldThrow);
409             scope.release();
410             return thisObject->put(thisObject, exec, propertyName, descriptor.value(), unused);
411         }
412         return true;
413     }
414     
415     scope.release();
416     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
417 }
418
419 template<typename Adaptor>
420 bool JSGenericTypedArrayView<Adaptor>::deleteProperty(
421     JSCell* cell, ExecState* exec, PropertyName propertyName)
422 {
423     VM& vm = exec->vm();
424     auto scope = DECLARE_THROW_SCOPE(vm);
425     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
426
427     if (thisObject->isNeutered())
428         return typeError(exec, scope, true, ASCIILiteral(typedArrayBufferHasBeenDetachedErrorMessage));
429
430     if (parseIndex(propertyName))
431         return false;
432     
433     return Base::deleteProperty(thisObject, exec, propertyName);
434 }
435
436 template<typename Adaptor>
437 bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlotByIndex(
438     JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
439 {
440     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
441
442     if (thisObject->isNeutered()) {
443         slot.setCustom(thisObject, None, throwNeuteredTypedArrayTypeError);
444         return true;
445     }
446
447     if (propertyName > MAX_ARRAY_INDEX) {
448         return thisObject->methodTable()->getOwnPropertySlot(
449             thisObject, exec, Identifier::from(exec, propertyName), slot);
450     }
451     
452     if (!thisObject->canGetIndexQuickly(propertyName))
453         return false;
454     
455     slot.setValue(thisObject, None, thisObject->getIndexQuickly(propertyName));
456     return true;
457 }
458
459 template<typename Adaptor>
460 bool JSGenericTypedArrayView<Adaptor>::putByIndex(
461     JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
462 {
463     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
464
465     if (propertyName > MAX_ARRAY_INDEX) {
466         PutPropertySlot slot(JSValue(thisObject), shouldThrow);
467         return thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
468     }
469     
470     return thisObject->setIndex(exec, propertyName, value);
471 }
472
473 template<typename Adaptor>
474 bool JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex(
475     JSCell* cell, ExecState* exec, unsigned propertyName)
476 {
477     return cell->methodTable()->deleteProperty(cell, exec, Identifier::from(exec, propertyName));
478 }
479
480 template<typename Adaptor>
481 void JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames(
482     JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
483 {
484     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
485
486     if (array.includeStringProperties()) {
487         for (unsigned i = 0; i < thisObject->m_length; ++i)
488             array.add(Identifier::from(exec, i));
489     }
490     
491     return Base::getOwnPropertyNames(object, exec, array, mode);
492 }
493
494 template<typename Adaptor>
495 size_t JSGenericTypedArrayView<Adaptor>::estimatedSize(JSCell* cell)
496 {
497     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
498
499     if (thisObject->m_mode == OversizeTypedArray)
500         return Base::estimatedSize(thisObject) + thisObject->byteSize();
501     if (thisObject->m_mode == FastTypedArray && thisObject->m_vector)
502         return Base::estimatedSize(thisObject) + thisObject->byteSize();
503
504     return Base::estimatedSize(thisObject);
505 }
506
507 template<typename Adaptor>
508 void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor& visitor)
509 {
510     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
511     
512     switch (thisObject->m_mode) {
513     case FastTypedArray: {
514         if (void* vector = thisObject->m_vector.get())
515             visitor.markAuxiliary(vector);
516         break;
517     }
518         
519     case OversizeTypedArray: {
520         visitor.reportExtraMemoryVisited(thisObject->byteSize());
521         break;
522     }
523         
524     case WastefulTypedArray:
525         break;
526         
527     case DataViewMode:
528         RELEASE_ASSERT_NOT_REACHED();
529         break;
530     }
531     
532     Base::visitChildren(thisObject, visitor);
533 }
534
535 template<typename Adaptor>
536 ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView* object)
537 {
538     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
539     
540     // We play this game because we want this to be callable even from places that
541     // don't have access to ExecState* or the VM, and we only allocate so little
542     // memory here that it's not necessary to trigger a GC - just accounting what
543     // we have done is good enough. The sort of bizarro exception to the "allocating
544     // little memory" is when we transfer a backing buffer into the C heap; this
545     // will temporarily get counted towards heap footprint (incorrectly, in the case
546     // of adopting an oversize typed array) but we don't GC here anyway. That's
547     // almost certainly fine. The worst case is if you created a ton of fast typed
548     // arrays, and did nothing but caused all of them to slow down and waste memory.
549     // In that case, your memory footprint will double before the GC realizes what's
550     // up. But if you do *anything* to trigger a GC watermark check, it will know
551     // that you *had* done those allocations and it will GC appropriately.
552     Heap* heap = Heap::heap(thisObject);
553     VM& vm = *heap->vm();
554     DeferGCForAWhile deferGC(*heap);
555     
556     ASSERT(!thisObject->hasIndexingHeader());
557     
558     RELEASE_ASSERT(!thisObject->hasIndexingHeader());
559     thisObject->m_butterfly.set(vm, thisObject, Butterfly::createOrGrowArrayRight(
560         thisObject->butterfly(), vm, thisObject, thisObject->structure(),
561         thisObject->structure()->outOfLineCapacity(), false, 0, 0));
562
563     RefPtr<ArrayBuffer> buffer;
564     
565     switch (thisObject->m_mode) {
566     case FastTypedArray:
567         buffer = ArrayBuffer::create(thisObject->vector(), thisObject->byteLength());
568         break;
569         
570     case OversizeTypedArray:
571         // FIXME: consider doing something like "subtracting" from extra memory
572         // cost, since right now this case will cause the GC to think that we reallocated
573         // the whole buffer.
574         buffer = ArrayBuffer::createAdopted(thisObject->vector(), thisObject->byteLength());
575         break;
576         
577     default:
578         RELEASE_ASSERT_NOT_REACHED();
579         break;
580     }
581
582     thisObject->butterfly()->indexingHeader()->setArrayBuffer(buffer.get());
583     thisObject->m_vector.setWithoutBarrier(buffer->data());
584     WTF::storeStoreFence();
585     thisObject->m_mode = WastefulTypedArray;
586     heap->addReference(thisObject, buffer.get());
587     
588     return buffer.get();
589 }
590
591 template<typename Adaptor>
592 RefPtr<ArrayBufferView> JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl(JSArrayBufferView* object)
593 {
594     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
595     return thisObject->possiblySharedTypedImpl();
596 }
597
598 } // namespace JSC