[JSC] Move slowDownAndWasteMemory function to JSArrayBufferView
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Jul 2018 17:50:12 +0000 (17:50 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Jul 2018 17:50:12 +0000 (17:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=187290

Reviewed by Saam Barati.

slowDownAndWasteMemory is just overridden by typed arrays. Since they are limited,
we do not need to add this function to MethodTable: just dispatching it in JSArrayBufferView
is fine. And slowDownAndWasteMemory only requires the sizeof(element), which can be
easily calculated from JSType.
This patch removes slowDownAndWasteMemory from MethodTable, and moves it to JSArrayBufferView.

* runtime/ClassInfo.h:
* runtime/JSArrayBufferView.cpp:
(JSC::elementSize):
(JSC::JSArrayBufferView::slowDownAndWasteMemory):
* runtime/JSArrayBufferView.h:
* runtime/JSArrayBufferViewInlines.h:
(JSC::JSArrayBufferView::possiblySharedBuffer):
* runtime/JSCell.cpp:
(JSC::JSCell::slowDownAndWasteMemory): Deleted.
* runtime/JSCell.h:
* runtime/JSDataView.cpp:
(JSC::JSDataView::slowDownAndWasteMemory): Deleted.
* runtime/JSDataView.h:
* runtime/JSGenericTypedArrayView.h:
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233467 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ClassInfo.h
Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
Source/JavaScriptCore/runtime/JSArrayBufferView.h
Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
Source/JavaScriptCore/runtime/JSCell.cpp
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/JSDataView.cpp
Source/JavaScriptCore/runtime/JSDataView.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h

index 3ddec00..8a5f4e2 100644 (file)
@@ -1,3 +1,33 @@
+2018-07-03  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Move slowDownAndWasteMemory function to JSArrayBufferView
+        https://bugs.webkit.org/show_bug.cgi?id=187290
+
+        Reviewed by Saam Barati.
+
+        slowDownAndWasteMemory is just overridden by typed arrays. Since they are limited,
+        we do not need to add this function to MethodTable: just dispatching it in JSArrayBufferView
+        is fine. And slowDownAndWasteMemory only requires the sizeof(element), which can be
+        easily calculated from JSType.
+        This patch removes slowDownAndWasteMemory from MethodTable, and moves it to JSArrayBufferView.
+
+        * runtime/ClassInfo.h:
+        * runtime/JSArrayBufferView.cpp:
+        (JSC::elementSize):
+        (JSC::JSArrayBufferView::slowDownAndWasteMemory):
+        * runtime/JSArrayBufferView.h:
+        * runtime/JSArrayBufferViewInlines.h:
+        (JSC::JSArrayBufferView::possiblySharedBuffer):
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::slowDownAndWasteMemory): Deleted.
+        * runtime/JSCell.h:
+        * runtime/JSDataView.cpp:
+        (JSC::JSDataView::slowDownAndWasteMemory): Deleted.
+        * runtime/JSDataView.h:
+        * runtime/JSGenericTypedArrayView.h:
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory): Deleted.
+
 2018-07-02  Sukolsak Sakshuwong  <sukolsak@gmail.com>
 
         Regular expressions with ".?" expressions at the start and the end match the entire string
index 42b39e1..f0faf34 100644 (file)
@@ -101,9 +101,6 @@ struct MethodTable {
     using DefineOwnPropertyFunctionPtr = bool (*)(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool);
     DefineOwnPropertyFunctionPtr WTF_METHOD_TABLE_ENTRY(defineOwnProperty);
 
-    using SlowDownAndWasteMemory = ArrayBuffer* (*)(JSArrayBufferView*);
-    SlowDownAndWasteMemory WTF_METHOD_TABLE_ENTRY(slowDownAndWasteMemory);
-
     using GetTypedArrayImpl = RefPtr<ArrayBufferView> (*)(JSArrayBufferView*);
     GetTypedArrayImpl WTF_METHOD_TABLE_ENTRY(getTypedArrayImpl);
 
@@ -174,7 +171,6 @@ struct MethodTable {
         &ClassName::toStringName, \
         &ClassName::customHasInstance, \
         &ClassName::defineOwnProperty, \
-        &ClassName::slowDownAndWasteMemory, \
         &ClassName::getTypedArrayImpl, \
         &ClassName::preventExtensions, \
         &ClassName::isExtensible, \
index 9cdbc16..79c88c2 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "JSArrayBuffer.h"
 #include "JSCInlines.h"
+#include "JSTypedArrays.h"
 #include "TypeError.h"
 #include "TypedArrayController.h"
 #include <wtf/Gigacage.h>
@@ -217,6 +218,92 @@ void JSArrayBufferView::neuter()
     m_vector.clear();
 }
 
+static const constexpr size_t ElementSizeData[] = {
+    sizeof(typename Int8Adaptor::Type), // Int8ArrayType
+    sizeof(typename Uint8Adaptor::Type), // Uint8ArrayType
+    sizeof(typename Uint8ClampedAdaptor::Type), // Uint8ClampedArrayType
+    sizeof(typename Int16Adaptor::Type), // Int16ArrayType
+    sizeof(typename Uint16Adaptor::Type), // Uint16ArrayType
+    sizeof(typename Int32Adaptor::Type), // Int32ArrayType
+    sizeof(typename Uint32Adaptor::Type), // Uint32ArrayType
+    sizeof(typename Float32Adaptor::Type), // Float32ArrayType
+    sizeof(typename Float64Adaptor::Type), // Float64ArrayType
+};
+
+static_assert(std::is_final<JSInt8Array>::value, "");
+static_assert(std::is_final<JSUint8Array>::value, "");
+static_assert(std::is_final<JSUint8ClampedArray>::value, "");
+static_assert(std::is_final<JSInt16Array>::value, "");
+static_assert(std::is_final<JSUint16Array>::value, "");
+static_assert(std::is_final<JSInt32Array>::value, "");
+static_assert(std::is_final<JSUint32Array>::value, "");
+static_assert(std::is_final<JSFloat32Array>::value, "");
+static_assert(std::is_final<JSFloat64Array>::value, "");
+
+static inline size_t elementSize(JSType type)
+{
+    ASSERT(type >= Int8ArrayType && type <= Float64ArrayType);
+    return ElementSizeData[type - Int8ArrayType];
+}
+
+ArrayBuffer* JSArrayBufferView::slowDownAndWasteMemory()
+{
+    ASSERT(m_mode == FastTypedArray || m_mode == OversizeTypedArray);
+
+    // We play this game because we want this to be callable even from places that
+    // don't have access to ExecState* or the VM, and we only allocate so little
+    // memory here that it's not necessary to trigger a GC - just accounting what
+    // we have done is good enough. The sort of bizarre exception to the "allocating
+    // little memory" is when we transfer a backing buffer into the C heap; this
+    // will temporarily get counted towards heap footprint (incorrectly, in the case
+    // of adopting an oversize typed array) but we don't GC here anyway. That's
+    // almost certainly fine. The worst case is if you created a ton of fast typed
+    // arrays, and did nothing but caused all of them to slow down and waste memory.
+    // In that case, your memory footprint will double before the GC realizes what's
+    // up. But if you do *anything* to trigger a GC watermark check, it will know
+    // that you *had* done those allocations and it will GC appropriately.
+    Heap* heap = Heap::heap(this);
+    VM& vm = *heap->vm();
+    DeferGCForAWhile deferGC(*heap);
+
+    RELEASE_ASSERT(!hasIndexingHeader(vm));
+    Structure* structure = this->structure(vm);
+    setButterfly(vm, Butterfly::createOrGrowArrayRight(
+        butterfly(), vm, this, structure,
+        structure->outOfLineCapacity(), false, 0, 0));
+
+    RefPtr<ArrayBuffer> buffer;
+    unsigned byteLength = m_length * elementSize(type());
+
+    switch (m_mode) {
+    case FastTypedArray:
+        buffer = ArrayBuffer::create(vector(), byteLength);
+        break;
+
+    case OversizeTypedArray:
+        // FIXME: consider doing something like "subtracting" from extra memory
+        // cost, since right now this case will cause the GC to think that we reallocated
+        // the whole buffer.
+        buffer = ArrayBuffer::createAdopted(vector(), byteLength);
+        break;
+
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+
+    {
+        auto locker = holdLock(cellLock());
+        butterfly()->indexingHeader()->setArrayBuffer(buffer.get());
+        m_vector.setWithoutBarrier(buffer->data());
+        WTF::storeStoreFence();
+        m_mode = WastefulTypedArray;
+    }
+    heap->addReference(this, buffer.get());
+
+    return buffer.get();
+}
+
 } // namespace JSC
 
 namespace WTF {
index 24426d0..1c0d90a 100644 (file)
@@ -181,6 +181,7 @@ public:
     static RefPtr<ArrayBufferView> toWrapped(VM&, JSValue);
 
 private:
+    JS_EXPORT_PRIVATE ArrayBuffer* slowDownAndWasteMemory();
     static void finalize(JSCell*);
 
 protected:
index d5c727f..7622349 100644 (file)
@@ -50,9 +50,12 @@ inline ArrayBuffer* JSArrayBufferView::possiblySharedBuffer()
         return existingBufferInButterfly();
     case DataViewMode:
         return jsCast<JSDataView*>(this)->possiblySharedBuffer();
-    default:
-        return methodTable()->slowDownAndWasteMemory(this);
+    case FastTypedArray:
+    case OversizeTypedArray:
+        return slowDownAndWasteMemory();
     }
+    ASSERT_NOT_REACHED();
+    return nullptr;
 }
 
 inline ArrayBuffer* JSArrayBufferView::existingBufferInButterfly()
index 1d0b5cc..94532ff 100644 (file)
@@ -256,12 +256,6 @@ bool JSCell::defineOwnProperty(JSObject*, ExecState*, PropertyName, const Proper
     return false;
 }
 
-ArrayBuffer* JSCell::slowDownAndWasteMemory(JSArrayBufferView*)
-{
-    RELEASE_ASSERT_NOT_REACHED();
-    return nullptr;
-}
-
 RefPtr<ArrayBufferView> JSCell::getTypedArrayImpl(JSArrayBufferView*)
 {
     RELEASE_ASSERT_NOT_REACHED();
index ae6ef6c..e5e888d 100644 (file)
@@ -265,7 +265,6 @@ protected:
     static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
-    JS_EXPORT_PRIVATE static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
     JS_EXPORT_PRIVATE static RefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
 
 private:
index 6be56e9..6225878 100644 (file)
@@ -180,12 +180,6 @@ void JSDataView::getOwnNonIndexPropertyNames(
     Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
 }
 
-ArrayBuffer* JSDataView::slowDownAndWasteMemory(JSArrayBufferView*)
-{
-    UNREACHABLE_FOR_PLATFORM();
-    return 0;
-}
-
 RefPtr<ArrayBufferView> JSDataView::getTypedArrayImpl(JSArrayBufferView* object)
 {
     JSDataView* thisObject = jsCast<JSDataView*>(object);
index 2eab272..920eb28 100644 (file)
@@ -70,7 +70,6 @@ protected:
 
     static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
 
-    static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
     static RefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
     
 public:
index f35553c..544b669 100644 (file)
@@ -290,7 +290,6 @@ protected:
 
     // Allocates the full-on native buffer and moves data into the C heap if
     // necessary. Note that this never allocates in the GC heap.
-    static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
     static RefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
 
 private:
index d1e6bc5..55fdc05 100644 (file)
@@ -549,63 +549,6 @@ void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor&
 }
 
 template<typename Adaptor>
-ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBufferView* object)
-{
-    JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
-    
-    // We play this game because we want this to be callable even from places that
-    // don't have access to ExecState* or the VM, and we only allocate so little
-    // memory here that it's not necessary to trigger a GC - just accounting what
-    // we have done is good enough. The sort of bizarro exception to the "allocating
-    // little memory" is when we transfer a backing buffer into the C heap; this
-    // will temporarily get counted towards heap footprint (incorrectly, in the case
-    // of adopting an oversize typed array) but we don't GC here anyway. That's
-    // almost certainly fine. The worst case is if you created a ton of fast typed
-    // arrays, and did nothing but caused all of them to slow down and waste memory.
-    // In that case, your memory footprint will double before the GC realizes what's
-    // up. But if you do *anything* to trigger a GC watermark check, it will know
-    // that you *had* done those allocations and it will GC appropriately.
-    Heap* heap = Heap::heap(thisObject);
-    VM& vm = *heap->vm();
-    DeferGCForAWhile deferGC(*heap);
-    
-    RELEASE_ASSERT(!thisObject->hasIndexingHeader(vm));
-    thisObject->setButterfly(vm, Butterfly::createOrGrowArrayRight(
-        thisObject->butterfly(), vm, thisObject, thisObject->structure(vm),
-        thisObject->structure(vm)->outOfLineCapacity(), false, 0, 0));
-
-    RefPtr<ArrayBuffer> buffer;
-    
-    switch (thisObject->m_mode) {
-    case FastTypedArray:
-        buffer = ArrayBuffer::create(thisObject->vector(), thisObject->byteLength());
-        break;
-        
-    case OversizeTypedArray:
-        // FIXME: consider doing something like "subtracting" from extra memory
-        // cost, since right now this case will cause the GC to think that we reallocated
-        // the whole buffer.
-        buffer = ArrayBuffer::createAdopted(thisObject->vector(), thisObject->byteLength());
-        break;
-        
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        break;
-    }
-
-    {
-        auto locker = holdLock(thisObject->cellLock());
-        thisObject->butterfly()->indexingHeader()->setArrayBuffer(buffer.get());
-        thisObject->m_vector.setWithoutBarrier(buffer->data());
-        WTF::storeStoreFence();
-        thisObject->m_mode = WastefulTypedArray;
-    }
-    heap->addReference(thisObject, buffer.get());
-    
-    return buffer.get();
-}
-
-template<typename Adaptor>
 RefPtr<ArrayBufferView> JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl(JSArrayBufferView* object)
 {
     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);