621de2559ac06b654134a5c82a93f0250fab4c22
[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, PassRefPtr<ArrayBuffer> passedBuffer,
101     unsigned byteOffset, unsigned length)
102 {
103     VM& vm = exec->vm();
104     auto scope = DECLARE_THROW_SCOPE(vm);
105     RefPtr<ArrayBuffer> buffer = passedBuffer;
106     size_t size = sizeof(typename Adaptor::Type);
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, 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, PassRefPtr<typename Adaptor::ViewType> impl)
127 {
128     RefPtr<ArrayBuffer> buffer = impl->possiblySharedBuffer();
129     ConstructionContext context(vm, structure, buffer, impl->byteOffset(), impl->length());
130     ASSERT(context);
131     JSGenericTypedArrayView* result =
132         new (NotNull, allocateCell<JSGenericTypedArrayView>(vm.heap))
133         JSGenericTypedArrayView(vm, context);
134     result->finishCreation(vm);
135     return result;
136 }
137
138 template<typename Adaptor>
139 JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create(
140     Structure* structure, JSGlobalObject* globalObject,
141     PassRefPtr<typename Adaptor::ViewType> impl)
142 {
143     return create(globalObject->vm(), structure, impl);
144 }
145
146 template<typename Adaptor>
147 bool JSGenericTypedArrayView<Adaptor>::validateRange(
148     ExecState* exec, unsigned offset, unsigned length)
149 {
150     VM& vm = exec->vm();
151     auto scope = DECLARE_THROW_SCOPE(vm);
152     if (canAccessRangeQuickly(offset, length))
153         return true;
154     
155     throwException(exec, scope, createRangeError(exec, "Range consisting of offset and length are out of bounds"));
156     return false;
157 }
158
159 template<typename Adaptor>
160 template<typename OtherAdaptor>
161 bool JSGenericTypedArrayView<Adaptor>::setWithSpecificType(
162     ExecState* exec, unsigned offset, JSGenericTypedArrayView<OtherAdaptor>* other,
163     unsigned otherOffset, unsigned length, CopyType type)
164 {
165     // Handle the hilarious case: the act of getting the length could have resulted
166     // in neutering. Well, no. That'll never happen because there cannot be
167     // side-effects on getting the length of a typed array. But predicting where there
168     // are, or aren't, side-effects is a fool's game so we resort to this cheap
169     // check. Worst case, if we're wrong, people start seeing less things get copied
170     // but we won't have a security vulnerability.
171     length = std::min(length, other->length());
172
173     RELEASE_ASSERT(other->canAccessRangeQuickly(otherOffset, length));
174     if (!validateRange(exec, offset, length))
175         return false;
176     
177     // This method doesn't support copying between the same array. Note that
178     // set() will only call this if the types differ, which implicitly guarantees
179     // that we can't be the same array. This is relevant because the way we detect
180     // non-overlapping is by checking if either (a) either array doesn't have a
181     // backing buffer or (b) the backing buffers are different, but that doesn't
182     // catch the case where it's the *same* array - fortunately though, this code
183     // path never needs to worry about that case.
184     ASSERT(static_cast<JSCell*>(this) != static_cast<JSCell*>(other));
185     
186     // 1) If the two arrays are non-overlapping, we can copy in any order we like
187     //    and we don't need an intermediate buffer. Arrays are definitely
188     //    non-overlapping if either one of them has no backing buffer (that means
189     //    that it *owns* its philosophical backing buffer) or if they have
190     //    different backing buffers.
191     // 2) If the two arrays overlap but have the same element size, we can do a
192     //    memmove-like copy where we flip-flop direction based on which vector
193     //    starts before the other:
194     //    A) If the destination vector is before the source vector, then a forward
195     //       copy is in order.
196     //    B) If the destination vector is after the source vector, then a backward
197     //       copy is in order.
198     // 3) If we have different element sizes and there is a chance of overlap then
199     //    we need an intermediate vector.
200     
201     // NB. Comparisons involving elementSize will be constant-folded by template
202     // specialization.
203
204     unsigned otherElementSize = sizeof(typename OtherAdaptor::Type);
205
206     // Handle cases (1) and (2A).
207     if (!hasArrayBuffer() || !other->hasArrayBuffer()
208         || existingBuffer() != other->existingBuffer()
209         || (elementSize == otherElementSize && vector() <= other->vector())
210         || type == CopyType::LeftToRight) {
211         for (unsigned i = 0; i < length; ++i) {
212             setIndexQuicklyToNativeValue(
213                 offset + i, OtherAdaptor::template convertTo<Adaptor>(
214                     other->getIndexQuicklyAsNativeValue(i + otherOffset)));
215         }
216         return true;
217     }
218
219     // Now we either have (2B) or (3) - so first we try to cover (2B).
220     if (elementSize == otherElementSize) {
221         for (unsigned i = length; i--;) {
222             setIndexQuicklyToNativeValue(
223                 offset + i, OtherAdaptor::template convertTo<Adaptor>(
224                     other->getIndexQuicklyAsNativeValue(i + otherOffset)));
225         }
226         return true;
227     }
228     
229     // Fail: we need an intermediate transfer buffer (i.e. case (3)).
230     Vector<typename Adaptor::Type, 32> transferBuffer(length);
231     for (unsigned i = length; i--;) {
232         transferBuffer[i] = OtherAdaptor::template convertTo<Adaptor>(
233             other->getIndexQuicklyAsNativeValue(i + otherOffset));
234     }
235     for (unsigned i = length; i--;)
236         setIndexQuicklyToNativeValue(offset + i, transferBuffer[i]);
237     
238     return true;
239 }
240
241 template<typename Adaptor>
242 bool JSGenericTypedArrayView<Adaptor>::set(
243     ExecState* exec, unsigned offset, JSObject* object, unsigned objectOffset, unsigned length, CopyType type)
244 {
245     VM& vm = exec->vm();
246     auto scope = DECLARE_THROW_SCOPE(vm);
247
248     const ClassInfo* ci = object->classInfo(vm);
249     if (ci->typedArrayStorageType == Adaptor::typeValue) {
250         // The super fast case: we can just memcpy since we're the same type.
251         JSGenericTypedArrayView* other = jsCast<JSGenericTypedArrayView*>(object);
252         length = std::min(length, other->length());
253         
254         RELEASE_ASSERT(other->canAccessRangeQuickly(objectOffset, length));
255         bool success = validateRange(exec, offset, length);
256         ASSERT(!scope.exception() == success);
257         if (!success)
258             return false;
259
260         memmove(typedVector() + offset, other->typedVector() + objectOffset, length * elementSize);
261         return true;
262     }
263     
264     switch (ci->typedArrayStorageType) {
265     case TypeInt8:
266         scope.release();
267         return setWithSpecificType<Int8Adaptor>(
268             exec, offset, jsCast<JSInt8Array*>(object), objectOffset, length, type);
269     case TypeInt16:
270         scope.release();
271         return setWithSpecificType<Int16Adaptor>(
272             exec, offset, jsCast<JSInt16Array*>(object), objectOffset, length, type);
273     case TypeInt32:
274         scope.release();
275         return setWithSpecificType<Int32Adaptor>(
276             exec, offset, jsCast<JSInt32Array*>(object), objectOffset, length, type);
277     case TypeUint8:
278         scope.release();
279         return setWithSpecificType<Uint8Adaptor>(
280             exec, offset, jsCast<JSUint8Array*>(object), objectOffset, length, type);
281     case TypeUint8Clamped:
282         scope.release();
283         return setWithSpecificType<Uint8ClampedAdaptor>(
284             exec, offset, jsCast<JSUint8ClampedArray*>(object), objectOffset, length, type);
285     case TypeUint16:
286         scope.release();
287         return setWithSpecificType<Uint16Adaptor>(
288             exec, offset, jsCast<JSUint16Array*>(object), objectOffset, length, type);
289     case TypeUint32:
290         scope.release();
291         return setWithSpecificType<Uint32Adaptor>(
292             exec, offset, jsCast<JSUint32Array*>(object), objectOffset, length, type);
293     case TypeFloat32:
294         scope.release();
295         return setWithSpecificType<Float32Adaptor>(
296             exec, offset, jsCast<JSFloat32Array*>(object), objectOffset, length, type);
297     case TypeFloat64:
298         scope.release();
299         return setWithSpecificType<Float64Adaptor>(
300             exec, offset, jsCast<JSFloat64Array*>(object), objectOffset, length, type);
301     case NotTypedArray:
302     case TypeDataView: {
303         bool success = validateRange(exec, offset, length);
304         ASSERT(!scope.exception() == success);
305         if (!success)
306             return false;
307
308         // We could optimize this case. But right now, we don't.
309         for (unsigned i = 0; i < length; ++i) {
310             JSValue value = object->get(exec, i + objectOffset);
311             RETURN_IF_EXCEPTION(scope, false);
312             bool success = setIndex(exec, offset + i, value);
313             ASSERT(!scope.exception() || !success);
314             if (!success)
315                 return false;
316         }
317         return true;
318     } }
319     
320     RELEASE_ASSERT_NOT_REACHED();
321     return false;
322 }
323
324 template<typename Adaptor>
325 PassRefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl()
326 {
327     return Adaptor::ViewType::create(possiblySharedBuffer(), byteOffset(), length());
328 }
329
330 template<typename Adaptor>
331 PassRefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl()
332 {
333     return Adaptor::ViewType::create(unsharedBuffer(), byteOffset(), length());
334 }
335
336 template<typename Adaptor>
337 ArrayBuffer* JSGenericTypedArrayView<Adaptor>::existingBuffer()
338 {
339     return existingBufferInButterfly();
340 }
341
342 template<typename Adaptor>
343 EncodedJSValue JSGenericTypedArrayView<Adaptor>::throwNeuteredTypedArrayTypeError(ExecState* exec, EncodedJSValue object, PropertyName)
344 {
345     VM& vm = exec->vm();
346     auto scope = DECLARE_THROW_SCOPE(vm);
347     ASSERT_UNUSED(object, jsCast<JSGenericTypedArrayView*>(JSValue::decode(object))->isNeutered());
348     return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
349 }
350
351 template<typename Adaptor>
352 bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot(
353     JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
354 {
355     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
356
357     if (std::optional<uint32_t> index = parseIndex(propertyName)) {
358         if (thisObject->isNeutered()) {
359             slot.setCustom(thisObject, None, throwNeuteredTypedArrayTypeError);
360             return true;
361         }
362
363         if (thisObject->canGetIndexQuickly(index.value()))
364             slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index.value()));
365         else
366             slot.setValue(thisObject, DontDelete | ReadOnly, jsUndefined());
367         return true;
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     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
379
380     // https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver
381     // Ignore the receiver even if the receiver is altered to non base value.
382     // 9.4.5.5-2-b-i Return ? IntegerIndexedElementSet(O, numericIndex, V).
383     if (std::optional<uint32_t> index = parseIndex(propertyName))
384         return putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
385     
386     return Base::put(thisObject, exec, propertyName, value, slot);
387 }
388
389 template<typename Adaptor>
390 bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty(
391     JSObject* object, ExecState* exec, PropertyName propertyName,
392     const PropertyDescriptor& descriptor, bool shouldThrow)
393 {
394     VM& vm = exec->vm();
395     auto scope = DECLARE_THROW_SCOPE(vm);
396     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
397
398     if (parseIndex(propertyName)) {
399         if (descriptor.isAccessorDescriptor())
400             return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to store accessor indexed property on a typed array."));
401
402         if (descriptor.configurable())
403             return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to configure non-configurable property."));
404
405         if (!descriptor.enumerable() || !descriptor.writable())
406             return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to store non-enumerable or non-writable indexed property on a typed array."));
407
408         if (descriptor.value()) {
409             PutPropertySlot unused(JSValue(thisObject), shouldThrow);
410             scope.release();
411             return thisObject->put(thisObject, exec, propertyName, descriptor.value(), unused);
412         }
413         return true;
414     }
415     
416     scope.release();
417     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
418 }
419
420 template<typename Adaptor>
421 bool JSGenericTypedArrayView<Adaptor>::deleteProperty(
422     JSCell* cell, ExecState* exec, PropertyName propertyName)
423 {
424     VM& vm = exec->vm();
425     auto scope = DECLARE_THROW_SCOPE(vm);
426     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
427
428     if (thisObject->isNeutered())
429         return typeError(exec, scope, true, ASCIILiteral(typedArrayBufferHasBeenDetachedErrorMessage));
430
431     if (parseIndex(propertyName))
432         return false;
433     
434     return Base::deleteProperty(thisObject, exec, propertyName);
435 }
436
437 template<typename Adaptor>
438 bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlotByIndex(
439     JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
440 {
441     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
442
443     if (thisObject->isNeutered()) {
444         slot.setCustom(thisObject, None, throwNeuteredTypedArrayTypeError);
445         return true;
446     }
447
448     if (propertyName > MAX_ARRAY_INDEX) {
449         return thisObject->methodTable()->getOwnPropertySlot(
450             thisObject, exec, Identifier::from(exec, propertyName), slot);
451     }
452     
453     if (!thisObject->canGetIndexQuickly(propertyName))
454         return false;
455     
456     slot.setValue(thisObject, None, thisObject->getIndexQuickly(propertyName));
457     return true;
458 }
459
460 template<typename Adaptor>
461 bool JSGenericTypedArrayView<Adaptor>::putByIndex(
462     JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
463 {
464     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
465
466     if (propertyName > MAX_ARRAY_INDEX) {
467         PutPropertySlot slot(JSValue(thisObject), shouldThrow);
468         return thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
469     }
470     
471     return thisObject->setIndex(exec, propertyName, value);
472 }
473
474 template<typename Adaptor>
475 bool JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex(
476     JSCell* cell, ExecState* exec, unsigned propertyName)
477 {
478     return cell->methodTable()->deleteProperty(cell, exec, Identifier::from(exec, propertyName));
479 }
480
481 template<typename Adaptor>
482 void JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames(
483     JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
484 {
485     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
486
487     if (array.includeStringProperties()) {
488         for (unsigned i = 0; i < thisObject->m_length; ++i)
489             array.add(Identifier::from(exec, i));
490     }
491     
492     return Base::getOwnPropertyNames(object, exec, array, mode);
493 }
494
495 template<typename Adaptor>
496 size_t JSGenericTypedArrayView<Adaptor>::estimatedSize(JSCell* cell)
497 {
498     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
499
500     if (thisObject->m_mode == OversizeTypedArray)
501         return Base::estimatedSize(thisObject) + thisObject->byteSize();
502     if (thisObject->m_mode == FastTypedArray && thisObject->m_vector)
503         return Base::estimatedSize(thisObject) + thisObject->byteSize();
504
505     return Base::estimatedSize(thisObject);
506 }
507
508 template<typename Adaptor>
509 void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor& visitor)
510 {
511     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
512     
513     switch (thisObject->m_mode) {
514     case FastTypedArray: {
515         if (void* vector = thisObject->m_vector.get())
516             visitor.markAuxiliary(vector);
517         break;
518     }
519         
520     case OversizeTypedArray: {
521         visitor.reportExtraMemoryVisited(thisObject->byteSize());
522         break;
523     }
524         
525     case WastefulTypedArray:
526         break;
527         
528     case DataViewMode:
529         RELEASE_ASSERT_NOT_REACHED();
530         break;
531     }
532     
533     Base::visitChildren(thisObject, visitor);
534 }
535
536 template<typename Adaptor>
537 ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView* object)
538 {
539     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
540     
541     // We play this game because we want this to be callable even from places that
542     // don't have access to ExecState* or the VM, and we only allocate so little
543     // memory here that it's not necessary to trigger a GC - just accounting what
544     // we have done is good enough. The sort of bizarro exception to the "allocating
545     // little memory" is when we transfer a backing buffer into the C heap; this
546     // will temporarily get counted towards heap footprint (incorrectly, in the case
547     // of adopting an oversize typed array) but we don't GC here anyway. That's
548     // almost certainly fine. The worst case is if you created a ton of fast typed
549     // arrays, and did nothing but caused all of them to slow down and waste memory.
550     // In that case, your memory footprint will double before the GC realizes what's
551     // up. But if you do *anything* to trigger a GC watermark check, it will know
552     // that you *had* done those allocations and it will GC appropriately.
553     Heap* heap = Heap::heap(thisObject);
554     VM& vm = *heap->vm();
555     DeferGCForAWhile deferGC(*heap);
556     
557     ASSERT(!thisObject->hasIndexingHeader());
558     
559     RELEASE_ASSERT(!thisObject->hasIndexingHeader());
560     thisObject->m_butterfly.set(vm, thisObject, Butterfly::createOrGrowArrayRight(
561         thisObject->butterfly(), vm, thisObject, thisObject->structure(),
562         thisObject->structure()->outOfLineCapacity(), false, 0, 0));
563
564     RefPtr<ArrayBuffer> buffer;
565     
566     switch (thisObject->m_mode) {
567     case FastTypedArray:
568         buffer = ArrayBuffer::create(thisObject->vector(), thisObject->byteLength());
569         break;
570         
571     case OversizeTypedArray:
572         // FIXME: consider doing something like "subtracting" from extra memory
573         // cost, since right now this case will cause the GC to think that we reallocated
574         // the whole buffer.
575         buffer = ArrayBuffer::createAdopted(thisObject->vector(), thisObject->byteLength());
576         break;
577         
578     default:
579         RELEASE_ASSERT_NOT_REACHED();
580         break;
581     }
582
583     thisObject->butterfly()->indexingHeader()->setArrayBuffer(buffer.get());
584     thisObject->m_vector.setWithoutBarrier(buffer->data());
585     WTF::storeStoreFence();
586     thisObject->m_mode = WastefulTypedArray;
587     heap->addReference(thisObject, buffer.get());
588     
589     return buffer.get();
590 }
591
592 template<typename Adaptor>
593 PassRefPtr<ArrayBufferView>
594 JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl(JSArrayBufferView* object)
595 {
596     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
597     return thisObject->possiblySharedTypedImpl();
598 }
599
600 } // namespace JSC