Title: [232951] trunk
Revision
232951
Author
[email protected]
Date
2018-06-18 16:53:27 -0700 (Mon, 18 Jun 2018)

Log Message

Properly zero unused property storage offsets
https://bugs.webkit.org/show_bug.cgi?id=186692

Reviewed by Filip Pizlo.

JSTests:

* stress/butterfly-zero-unused-butterfly-properties.js: Added.

Source/_javascript_Core:

Since the concurrent GC might see a property slot before the mutator has actually
stored the value there, we need to ensure that slot doesn't have garbage in it.

Right now when calling constructConvertedArrayStorageWithoutCopyingElements
or creating a RegExp matches array, we never cleared the unused
property storage. ObjectIntializationScope has also been upgraded
to look for our invariants around property storage. Additionally,
a new assertion has been added to check for JSValue() when adding
a new property.

We used to put undefined into deleted property offsets. To
make things simpler, this patch causes us to store JSValue() there
instead.

Lastly, this patch fixes an issue where we would initialize the
array storage of RegExpMatchesArray twice. First with 0 and
secondly with the actual result. Now we only zero memory between
vector length and public length.

* runtime/Butterfly.h:
(JSC::Butterfly::offsetOfVectorLength):
* runtime/ButterflyInlines.h:
(JSC::Butterfly::tryCreateUninitialized):
(JSC::Butterfly::createUninitialized):
(JSC::Butterfly::tryCreate):
(JSC::Butterfly::create):
(JSC::Butterfly::createOrGrowPropertyStorage):
(JSC::Butterfly::createOrGrowArrayRight):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
* runtime/JSArray.cpp:
(JSC::JSArray::tryCreateUninitializedRestricted):
(JSC::createArrayButterflyInDictionaryIndexingMode): Deleted.
* runtime/JSArray.h:
(JSC::tryCreateArrayButterfly):
* runtime/JSObject.cpp:
(JSC::JSObject::createArrayStorageButterfly):
(JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::shiftButterflyAfterFlattening):
* runtime/JSObject.h:
* runtime/JSObjectInlines.h:
(JSC::JSObject::prepareToPutDirectWithoutTransition):
* runtime/ObjectInitializationScope.cpp:
(JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
* runtime/ObjectInitializationScope.h:
(JSC::ObjectInitializationScope::release):
* runtime/RegExpMatchesArray.h:
(JSC::tryCreateUninitializedRegExpMatchesArray):
(JSC::createRegExpMatchesArray):

* runtime/Butterfly.h:
(JSC::Butterfly::offsetOfVectorLength):
* runtime/ButterflyInlines.h:
(JSC::Butterfly::tryCreateUninitialized):
(JSC::Butterfly::createUninitialized):
(JSC::Butterfly::tryCreate):
(JSC::Butterfly::create):
(JSC::Butterfly::createOrGrowPropertyStorage):
(JSC::Butterfly::createOrGrowArrayRight):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
* runtime/JSArray.cpp:
(JSC::JSArray::tryCreateUninitializedRestricted):
(JSC::createArrayButterflyInDictionaryIndexingMode): Deleted.
* runtime/JSArray.h:
(JSC::tryCreateArrayButterfly):
* runtime/JSObject.cpp:
(JSC::JSObject::createArrayStorageButterfly):
(JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::shiftButterflyAfterFlattening):
* runtime/JSObject.h:
* runtime/JSObjectInlines.h:
(JSC::JSObject::prepareToPutDirectWithoutTransition):
* runtime/ObjectInitializationScope.cpp:
(JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
* runtime/RegExpMatchesArray.cpp:
(JSC::createEmptyRegExpMatchesArray):
* runtime/RegExpMatchesArray.h:
(JSC::tryCreateUninitializedRegExpMatchesArray):
(JSC::createRegExpMatchesArray):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (232950 => 232951)


--- trunk/JSTests/ChangeLog	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/JSTests/ChangeLog	2018-06-18 23:53:27 UTC (rev 232951)
@@ -1,3 +1,12 @@
+2018-06-18  Keith Miller  <[email protected]>
+
+        Properly zero unused property storage offsets
+        https://bugs.webkit.org/show_bug.cgi?id=186692
+
+        Reviewed by Filip Pizlo.
+
+        * stress/butterfly-zero-unused-butterfly-properties.js: Added.
+
 2018-06-18  Michael Saboff  <[email protected]>
 
         Support Unicode 11 in RegExp

Added: trunk/JSTests/stress/butterfly-zero-unused-butterfly-properties.js (0 => 232951)


--- trunk/JSTests/stress/butterfly-zero-unused-butterfly-properties.js	                        (rev 0)
+++ trunk/JSTests/stress/butterfly-zero-unused-butterfly-properties.js	2018-06-18 23:53:27 UTC (rev 232951)
@@ -0,0 +1,9 @@
+//@ runDefault("--jitPolicyScale=0", "--gcMaxHeapSize=2000")
+
+// This test happened to catch a case where we failed to zero the space in the butterfly before m_lastOffset when reallocating.
+
+var array = Array(1000);
+for (var i = 0; i < 100000; ++i) {
+    array[i - array.length] = '';
+    array[i ^ array.length] = '';
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (232950 => 232951)


--- trunk/Source/_javascript_Core/ChangeLog	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-06-18 23:53:27 UTC (rev 232951)
@@ -1,3 +1,93 @@
+2018-06-18  Keith Miller  <[email protected]>
+
+        Properly zero unused property storage offsets
+        https://bugs.webkit.org/show_bug.cgi?id=186692
+
+        Reviewed by Filip Pizlo.
+
+        Since the concurrent GC might see a property slot before the mutator has actually
+        stored the value there, we need to ensure that slot doesn't have garbage in it.
+
+        Right now when calling constructConvertedArrayStorageWithoutCopyingElements
+        or creating a RegExp matches array, we never cleared the unused
+        property storage. ObjectIntializationScope has also been upgraded
+        to look for our invariants around property storage. Additionally,
+        a new assertion has been added to check for JSValue() when adding
+        a new property.
+
+        We used to put undefined into deleted property offsets. To
+        make things simpler, this patch causes us to store JSValue() there
+        instead.
+
+        Lastly, this patch fixes an issue where we would initialize the
+        array storage of RegExpMatchesArray twice. First with 0 and
+        secondly with the actual result. Now we only zero memory between
+        vector length and public length.
+
+        * runtime/Butterfly.h:
+        (JSC::Butterfly::offsetOfVectorLength):
+        * runtime/ButterflyInlines.h:
+        (JSC::Butterfly::tryCreateUninitialized):
+        (JSC::Butterfly::createUninitialized):
+        (JSC::Butterfly::tryCreate):
+        (JSC::Butterfly::create):
+        (JSC::Butterfly::createOrGrowPropertyStorage):
+        (JSC::Butterfly::createOrGrowArrayRight):
+        (JSC::Butterfly::growArrayRight):
+        (JSC::Butterfly::resizeArray):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::tryCreateUninitializedRestricted):
+        (JSC::createArrayButterflyInDictionaryIndexingMode): Deleted.
+        * runtime/JSArray.h:
+        (JSC::tryCreateArrayButterfly):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::createArrayStorageButterfly):
+        (JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
+        (JSC::JSObject::deleteProperty):
+        (JSC::JSObject::shiftButterflyAfterFlattening):
+        * runtime/JSObject.h:
+        * runtime/JSObjectInlines.h:
+        (JSC::JSObject::prepareToPutDirectWithoutTransition):
+        * runtime/ObjectInitializationScope.cpp:
+        (JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
+        * runtime/ObjectInitializationScope.h:
+        (JSC::ObjectInitializationScope::release):
+        * runtime/RegExpMatchesArray.h:
+        (JSC::tryCreateUninitializedRegExpMatchesArray):
+        (JSC::createRegExpMatchesArray):
+
+        * runtime/Butterfly.h:
+        (JSC::Butterfly::offsetOfVectorLength):
+        * runtime/ButterflyInlines.h:
+        (JSC::Butterfly::tryCreateUninitialized):
+        (JSC::Butterfly::createUninitialized):
+        (JSC::Butterfly::tryCreate):
+        (JSC::Butterfly::create):
+        (JSC::Butterfly::createOrGrowPropertyStorage):
+        (JSC::Butterfly::createOrGrowArrayRight):
+        (JSC::Butterfly::growArrayRight):
+        (JSC::Butterfly::resizeArray):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::tryCreateUninitializedRestricted):
+        (JSC::createArrayButterflyInDictionaryIndexingMode): Deleted.
+        * runtime/JSArray.h:
+        (JSC::tryCreateArrayButterfly):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::createArrayStorageButterfly):
+        (JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
+        (JSC::JSObject::deleteProperty):
+        (JSC::JSObject::shiftButterflyAfterFlattening):
+        * runtime/JSObject.h:
+        * runtime/JSObjectInlines.h:
+        (JSC::JSObject::prepareToPutDirectWithoutTransition):
+        * runtime/ObjectInitializationScope.cpp:
+        (JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
+        * runtime/RegExpMatchesArray.cpp:
+        (JSC::createEmptyRegExpMatchesArray):
+        * runtime/RegExpMatchesArray.h:
+        (JSC::tryCreateUninitializedRegExpMatchesArray):
+        (JSC::createRegExpMatchesArray):
+
 2018-06-18  Tadeu Zagallo  <[email protected]>
 
         Share structure across instances of classes exported through the ObjC API

Modified: trunk/Source/_javascript_Core/runtime/Butterfly.h (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/Butterfly.h	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/Butterfly.h	2018-06-18 23:53:27 UTC (rev 232951)
@@ -35,6 +35,7 @@
 
 class VM;
 class CopyVisitor;
+class GCDeferralContext;
 struct ArrayStorage;
 
 template <typename T>
@@ -159,12 +160,13 @@
     static ptrdiff_t offsetOfArrayBuffer() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfArrayBuffer(); }
     static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
     static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
-    
-    static Butterfly* createUninitialized(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
 
-    static Butterfly* tryCreate(VM& vm, JSCell*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes);
-    static Butterfly* create(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
-    static Butterfly* create(VM&, JSCell* intendedOwner, Structure*);
+    static Butterfly* tryCreateUninitialized(VM&, JSObject* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, GCDeferralContext* = nullptr);
+    static Butterfly* createUninitialized(VM&, JSObject* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
+
+    static Butterfly* tryCreate(VM& vm, JSObject*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes);
+    static Butterfly* create(VM&, JSObject* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
+    static Butterfly* create(VM&, JSObject* intendedOwner, Structure*);
     
     IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
     const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); }
@@ -203,7 +205,7 @@
     void* base(Structure*);
 
     static Butterfly* createOrGrowArrayRight(
-        Butterfly*, VM&, JSCell* intendedOwner, Structure* oldStructure,
+        Butterfly*, VM&, JSObject* intendedOwner, Structure* oldStructure,
         size_t propertyCapacity, bool hadIndexingHeader,
         size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); 
 
@@ -212,11 +214,11 @@
     // methods is not exhaustive and is not intended to encapsulate all possible allocation
     // modes of butterflies - there are code paths that allocate butterflies by calling
     // directly into Heap::tryAllocateStorage.
-    static Butterfly* createOrGrowPropertyStorage(Butterfly*, VM&, JSCell* intendedOwner, Structure*, size_t oldPropertyCapacity, size_t newPropertyCapacity);
-    Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
-    Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes);
-    Butterfly* resizeArray(VM&, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
-    Butterfly* resizeArray(VM&, JSCell* intendedOwner, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
+    static Butterfly* createOrGrowPropertyStorage(Butterfly*, VM&, JSObject* intendedOwner, Structure*, size_t oldPropertyCapacity, size_t newPropertyCapacity);
+    Butterfly* growArrayRight(VM&, JSObject* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
+    Butterfly* growArrayRight(VM&, JSObject* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes);
+    Butterfly* resizeArray(VM&, JSObject* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
+    Butterfly* resizeArray(VM&, JSObject* intendedOwner, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
     Butterfly* unshift(Structure*, size_t numberOfSlots);
     Butterfly* shift(Structure*, size_t numberOfSlots);
 };

Modified: trunk/Source/_javascript_Core/runtime/ButterflyInlines.h (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/ButterflyInlines.h	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/ButterflyInlines.h	2018-06-18 23:53:27 UTC (rev 232951)
@@ -28,8 +28,8 @@
 #include "ArrayStorage.h"
 #include "Butterfly.h"
 #include "JSObject.h"
+#include "Structure.h"
 #include "VM.h"
-#include "Structure.h"
 
 namespace JSC {
 
@@ -74,15 +74,28 @@
     return optimalContiguousVectorLength(structure ? structure->outOfLineCapacity() : 0, vectorLength);
 }
 
-inline Butterfly* Butterfly::createUninitialized(VM& vm, JSCell*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::tryCreateUninitialized(VM& vm, JSObject*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, GCDeferralContext* deferralContext)
 {
     size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+    void* base = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, size, deferralContext, AllocationFailureMode::ReturnNull);
+    if (UNLIKELY(!base))
+        return nullptr;
+
+    Butterfly* result = fromBase(base, preCapacity, propertyCapacity);
+
+    return result;
+}
+
+inline Butterfly* Butterfly::createUninitialized(VM& vm, JSObject*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+{
+    size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
     void* base = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, size, nullptr, AllocationFailureMode::Assert);
     Butterfly* result = fromBase(base, preCapacity, propertyCapacity);
+
     return result;
 }
 
-inline Butterfly* Butterfly::tryCreate(VM& vm, JSCell*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::tryCreate(VM& vm, JSObject*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
 {
     size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
     void* base = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, size, nullptr, AllocationFailureMode::ReturnNull);
@@ -95,7 +108,7 @@
     return result;
 }
 
-inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::create(VM& vm, JSObject* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
 {
     Butterfly* result = tryCreate(vm, intendedOwner, preCapacity, propertyCapacity, hasIndexingHeader, indexingHeader, indexingPayloadSizeInBytes);
 
@@ -103,7 +116,7 @@
     return result;
 }
 
-inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, Structure* structure)
+inline Butterfly* Butterfly::create(VM& vm, JSObject* intendedOwner, Structure* structure)
 {
     return create(
         vm, intendedOwner, 0, structure->outOfLineCapacity(),
@@ -116,7 +129,7 @@
 }
 
 inline Butterfly* Butterfly::createOrGrowPropertyStorage(
-    Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity)
+    Butterfly* oldButterfly, VM& vm, JSObject* intendedOwner, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity)
 {
     RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity);
     if (!oldButterfly)
@@ -125,8 +138,7 @@
     size_t preCapacity = oldButterfly->indexingHeader()->preCapacity(structure);
     size_t indexingPayloadSizeInBytes = oldButterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
     bool hasIndexingHeader = structure->hasIndexingHeader(intendedOwner);
-    Butterfly* result = createUninitialized(
-        vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+    Butterfly* result = createUninitialized(vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
     memcpy(
         result->propertyStorage() - oldPropertyCapacity,
         oldButterfly->propertyStorage() - oldPropertyCapacity,
@@ -139,7 +151,7 @@
 }
 
 inline Butterfly* Butterfly::createOrGrowArrayRight(
-    Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* oldStructure,
+    Butterfly* oldButterfly, VM& vm, JSObject* intendedOwner, Structure* oldStructure,
     size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes,
     size_t newIndexingPayloadSizeInBytes)
 {
@@ -154,7 +166,7 @@
 }
 
 inline Butterfly* Butterfly::growArrayRight(
-    VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity,
+    VM& vm, JSObject* intendedOwner, Structure* oldStructure, size_t propertyCapacity,
     bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes,
     size_t newIndexingPayloadSizeInBytes)
 {
@@ -172,7 +184,7 @@
 }
 
 inline Butterfly* Butterfly::growArrayRight(
-    VM& vm, JSCell* intendedOwner, Structure* oldStructure,
+    VM& vm, JSObject* intendedOwner, Structure* oldStructure,
     size_t newIndexingPayloadSizeInBytes)
 {
     return growArrayRight(
@@ -183,13 +195,11 @@
 }
 
 inline Butterfly* Butterfly::resizeArray(
-    VM& vm, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader,
+    VM& vm, JSObject* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader,
     size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader,
     size_t newIndexingPayloadSizeInBytes)
 {
-    Butterfly* result = createUninitialized(
-        vm, intendedOwner, newPreCapacity, propertyCapacity, newHasIndexingHeader,
-        newIndexingPayloadSizeInBytes);
+    Butterfly* result = createUninitialized(vm, intendedOwner, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes);
     // FIXME: This could be made much more efficient if we used the property size,
     // not the capacity.
     void* to = result->propertyStorage() - propertyCapacity;
@@ -202,7 +212,7 @@
 }
 
 inline Butterfly* Butterfly::resizeArray(
-    VM& vm, JSCell* intendedOwner, Structure* structure, size_t newPreCapacity,
+    VM& vm, JSObject* intendedOwner, Structure* structure, size_t newPreCapacity,
     size_t newIndexingPayloadSizeInBytes)
 {
     bool hasIndexingHeader = structure->hasIndexingHeader(intendedOwner);

Modified: trunk/Source/_javascript_Core/runtime/JSArray.cpp (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/JSArray.cpp	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/JSArray.cpp	2018-06-18 23:53:27 UTC (rev 232951)
@@ -43,20 +43,6 @@
 
 const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSArray)};
 
-Butterfly* createArrayButterflyInDictionaryIndexingMode(
-    VM& vm, JSCell* intendedOwner, unsigned initialLength)
-{
-    Butterfly* butterfly = Butterfly::create(
-        vm, intendedOwner, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0));
-    ArrayStorage* storage = butterfly->arrayStorage();
-    storage->setLength(initialLength);
-    storage->setVectorLength(0);
-    storage->m_indexBias = 0;
-    storage->m_sparseMap.clear();
-    storage->m_numValuesInVector = 0;
-    return butterfly;
-}
-
 JSArray* JSArray::tryCreateUninitializedRestricted(ObjectInitializationScope& scope, GCDeferralContext* deferralContext, Structure* structure, unsigned initialLength)
 {
     VM& vm = scope.vm();
@@ -64,9 +50,9 @@
     if (UNLIKELY(initialLength > MAX_STORAGE_VECTOR_LENGTH))
         return 0;
 
+    unsigned outOfLineStorage = structure->outOfLineCapacity();
     JSGlobalObject* globalObject = structure->globalObject();
-    bool createUninitialized = globalObject->isOriginalArrayStructure(structure);
-    unsigned outOfLineStorage = structure->outOfLineCapacity();
+    ASSERT_UNUSED(globalObject, globalObject->isOriginalArrayStructure(structure) || structure == globalObject->regExpMatchesArrayStructure() || structure == globalObject->regExpMatchesArrayWithGroupsStructure());
 
     Butterfly* butterfly;
     IndexingType indexingType = structure->indexingType();
@@ -87,12 +73,11 @@
         butterfly = Butterfly::fromBase(temp, 0, outOfLineStorage);
         butterfly->setVectorLength(vectorLength);
         butterfly->setPublicLength(initialLength);
-        unsigned i = (createUninitialized ? initialLength : 0);
         if (hasDouble(indexingType)) {
-            for (; i < vectorLength; ++i)
+            for (unsigned i = initialLength; i < vectorLength; ++i)
                 butterfly->contiguousDouble().atUnsafe(i) = PNaN;
         } else {
-            for (; i < vectorLength; ++i)
+            for (unsigned i = initialLength; i < vectorLength; ++i)
                 butterfly->contiguous().atUnsafe(i).clear();
         }
     } else {
@@ -110,12 +95,13 @@
         storage->m_indexBias = indexBias;
         storage->m_sparseMap.clear();
         storage->m_numValuesInVector = initialLength;
-        unsigned i = (createUninitialized ? initialLength : 0);
-        for (; i < vectorLength; ++i)
+        for (unsigned i = initialLength; i < vectorLength; ++i)
             storage->m_vector[i].clear();
     }
 
     JSArray* result = createWithButterfly(vm, deferralContext, structure, butterfly);
+
+    const bool createUninitialized = true;
     scope.notifyAllocated(result, createUninitialized);
     return result;
 }

Modified: trunk/Source/_javascript_Core/runtime/JSArray.h (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/JSArray.h	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/JSArray.h	2018-06-18 23:53:27 UTC (rev 232951)
@@ -203,7 +203,7 @@
     void setLengthWritable(ExecState*, bool writable);
 };
 
-inline Butterfly* tryCreateArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
+inline Butterfly* tryCreateArrayButterfly(VM& vm, JSObject* intendedOwner, unsigned initialLength)
 {
     Butterfly* butterfly = Butterfly::tryCreate(
         vm, intendedOwner, 0, 0, true, baseIndexingHeaderForArrayStorage(initialLength),
@@ -217,9 +217,6 @@
     return butterfly;
 }
 
-Butterfly* createArrayButterflyInDictionaryIndexingMode(
-    VM&, JSCell* intendedOwner, unsigned initialLength);
-
 inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength, unsigned vectorLengthHint)
 {
     ASSERT(vectorLengthHint >= initialLength);

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2018-06-18 23:53:27 UTC (rev 232951)
@@ -1089,7 +1089,7 @@
     return newButterfly->contiguous();
 }
 
-Butterfly* JSObject::createArrayStorageButterfly(VM& vm, JSCell* intendedOwner, Structure* structure, unsigned length, unsigned vectorLength, Butterfly* oldButterfly)
+Butterfly* JSObject::createArrayStorageButterfly(VM& vm, JSObject* intendedOwner, Structure* structure, unsigned length, unsigned vectorLength, Butterfly* oldButterfly)
 {
     Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
         oldButterfly, vm, intendedOwner, structure, structure->outOfLineCapacity(), false, 0,
@@ -1172,16 +1172,14 @@
     Structure* structure = this->structure(vm);
     unsigned publicLength = m_butterfly->publicLength();
     unsigned propertyCapacity = structure->outOfLineCapacity();
-    unsigned propertySize = structure->outOfLineSize();
+
+    Butterfly* newButterfly = Butterfly::createUninitialized(vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
     
-    Butterfly* newButterfly = Butterfly::createUninitialized(
-        vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
-    
     memcpy(
-        newButterfly->propertyStorage() - propertySize,
-        m_butterfly->propertyStorage() - propertySize,
-        propertySize * sizeof(EncodedJSValue));
-    
+        newButterfly->base(0, propertyCapacity),
+        m_butterfly->base(0, propertyCapacity),
+        propertyCapacity * sizeof(EncodedJSValue));
+
     ArrayStorage* newStorage = newButterfly->arrayStorage();
     newStorage->setVectorLength(neededLength);
     newStorage->setLength(publicLength);
@@ -1912,7 +1910,7 @@
             thisObject->setStructure(vm, Structure::removePropertyTransition(vm, structure, propertyName, offset));
 
         if (offset != invalidOffset)
-            thisObject->putDirectUndefined(offset);
+            thisObject->locationForOffset(offset)->clear();
     }
 
     return true;
@@ -3629,7 +3627,7 @@
     // This could interleave visitChildren because some old structure could have been a non
     // dictionary structure. We have to be crazy careful. But, we are guaranteed to be holding
     // the structure's lock right now, and that helps a bit.
-    
+
     Butterfly* oldButterfly = this->butterfly();
     size_t preCapacity;
     size_t indexingPayloadSizeInBytes;

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2018-06-18 23:53:27 UTC (rev 232951)
@@ -943,7 +943,7 @@
     void convertDoubleForValue(VM&, JSValue);
     void convertFromCopyOnWrite(VM&);
 
-    static Butterfly* createArrayStorageButterfly(VM&, JSCell* intendedOwner, Structure*, unsigned length, unsigned vectorLength, Butterfly* oldButterfly = nullptr);
+    static Butterfly* createArrayStorageButterfly(VM&, JSObject* intendedOwner, Structure*, unsigned length, unsigned vectorLength, Butterfly* oldButterfly = nullptr);
     ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength);
     ArrayStorage* createInitialArrayStorage(VM&);
         

Modified: trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/JSObjectInlines.h	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/JSObjectInlines.h	2018-06-18 23:53:27 UTC (rev 232951)
@@ -203,6 +203,7 @@
                 setStructureIDDirectly(structureID);
             } else
                 structure->setLastOffset(newLastOffset);
+            ASSERT(!getDirect(offset));
             result = offset;
         });
     return result;

Modified: trunk/Source/_javascript_Core/runtime/ObjectInitializationScope.cpp (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/ObjectInitializationScope.cpp	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/ObjectInitializationScope.cpp	2018-06-18 23:53:27 UTC (rev 232951)
@@ -60,15 +60,16 @@
 void ObjectInitializationScope::verifyPropertiesAreInitialized(JSObject* object)
 {
     Butterfly* butterfly = object->butterfly();
-    IndexingType indexingType = object->structure(m_vm)->indexingType();
+    Structure* structure = object->structure(m_vm);
+    IndexingType indexingType = structure->indexingType();
     unsigned vectorLength = butterfly->vectorLength();
-    if (UNLIKELY(hasUndecided(indexingType))) {
+    if (UNLIKELY(hasUndecided(indexingType)) || !hasIndexedProperties(indexingType)) {
         // Nothing to verify.
     } else if (LIKELY(!hasAnyArrayStorage(indexingType))) {
         auto data = ""
         for (unsigned i = 0; i < vectorLength; ++i) {
             if (isScribbledValue(data[i].get())) {
-                dataLog("Found scribbled value at i = ", i, "\n");
+                dataLogLn("Found scribbled value at i = ", i);
                 ASSERT_NOT_REACHED();
             }
         }
@@ -76,11 +77,21 @@
         ArrayStorage* storage = butterfly->arrayStorage();
         for (unsigned i = 0; i < vectorLength; ++i) {
             if (isScribbledValue(storage->m_vector[i].get())) {
-                dataLog("Found scribbled value at i = ", i, "\n");
+                dataLogLn("Found scribbled value at i = ", i);
                 ASSERT_NOT_REACHED();
             }
         }
     }
+
+    for (int64_t i = 0; i < static_cast<int64_t>(structure->outOfLineCapacity()); i++) {
+        // We rely on properties past the last offset be zero for concurrent GC.
+        if (i + firstOutOfLineOffset > structure->lastOffset())
+            ASSERT(!butterfly->propertyStorage()[-i - 1].get());
+        else if (isScribbledValue(butterfly->propertyStorage()[-i - 1].get())) {
+            dataLogLn("Found scribbled property at i = ", -i - 1);
+            ASSERT_NOT_REACHED();
+        }
+    }
 }
 #endif
 

Modified: trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.cpp (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.cpp	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.cpp	2018-06-18 23:53:27 UTC (rev 232951)
@@ -37,9 +37,9 @@
     // https://bugs.webkit.org/show_bug.cgi?id=155144
     
     GCDeferralContext deferralContext(vm.heap);
-    
+    ObjectInitializationScope scope(vm);
+
     if (UNLIKELY(globalObject->isHavingABadTime())) {
-        ObjectInitializationScope scope(vm);
         array = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
         // FIXME: we should probably throw an out of memory error here, but
         // when making this change we should check that all clients of this

Modified: trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h (232950 => 232951)


--- trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h	2018-06-18 22:26:58 UTC (rev 232950)
+++ trunk/Source/_javascript_Core/runtime/RegExpMatchesArray.h	2018-06-18 23:53:27 UTC (rev 232951)
@@ -40,20 +40,20 @@
     if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
         return 0;
 
-    JSGlobalObject* globalObject = structure->globalObject();
-    bool createUninitialized = globalObject->isOriginalArrayStructure(structure);
-    void* temp = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)), deferralContext, AllocationFailureMode::ReturnNull);
-    if (UNLIKELY(!temp))
+    const bool hasIndexingHeader = true;
+    Butterfly* butterfly = Butterfly::tryCreateUninitialized(vm, nullptr, 0, structure->outOfLineCapacity(), hasIndexingHeader, vectorLength * sizeof(EncodedJSValue), deferralContext);
+    if (UNLIKELY(!butterfly))
         return nullptr;
-    Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity());
+
     butterfly->setVectorLength(vectorLength);
     butterfly->setPublicLength(initialLength);
 
-    unsigned i = (createUninitialized ? initialLength : 0);
-    for (; i < vectorLength; ++i)
+    for (unsigned i = initialLength; i < vectorLength; ++i)
         butterfly->contiguous().atUnsafe(i).clear();
 
     JSArray* result = JSArray::createWithButterfly(vm, deferralContext, structure, butterfly);
+
+    const bool createUninitialized = true;
     scope.notifyAllocated(result, createUninitialized);
     return result;
 }
@@ -80,23 +80,29 @@
     unsigned numSubpatterns = regExp->numSubpatterns();
     bool hasNamedCaptures = regExp->hasNamedCaptures();
     JSObject* groups = nullptr;
+    Structure* matchStructure = globalObject->regExpMatchesArrayStructure();
+    if (hasNamedCaptures) {
+        groups = JSFinalObject::create(vm, JSFinalObject::createStructure(vm, globalObject, globalObject->objectPrototype(), 0));
+        matchStructure = globalObject->regExpMatchesArrayWithGroupsStructure();
+    }
 
     auto setProperties = [&] () {
         array->putDirect(vm, RegExpMatchesArrayIndexPropertyOffset, jsNumber(result.start));
         array->putDirect(vm, RegExpMatchesArrayInputPropertyOffset, input);
-        if (hasNamedCaptures) {
-            groups = JSFinalObject::create(vm, JSFinalObject::createStructure(vm, globalObject, globalObject->objectPrototype(), 0));
+        if (hasNamedCaptures)
             array->putDirect(vm, RegExpMatchesArrayGroupsPropertyOffset, groups);
-        }
+
+        ASSERT(!array->butterfly()->indexingHeader()->preCapacity(matchStructure));
+        auto capacity = matchStructure->outOfLineCapacity();
+        auto size = matchStructure->outOfLineSize();
+        memset(array->butterfly()->base(0, capacity), 0, (capacity - size) * sizeof(JSValue));
     };
 
-    GCDeferralContext deferralContext(vm.heap);
-
-    Structure* matchStructure = hasNamedCaptures ? globalObject->regExpMatchesArrayWithGroupsStructure() : globalObject->regExpMatchesArrayStructure();
-
     if (UNLIKELY(globalObject->isHavingABadTime())) {
+        GCDeferralContext deferralContext(vm.heap);
         ObjectInitializationScope scope(vm);
         array = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext, matchStructure, numSubpatterns + 1);
+
         // FIXME: we should probably throw an out of memory error here, but
         // when making this change we should check that all clients of this
         // function will correctly handle an exception being thrown from here.
@@ -115,21 +121,20 @@
             else
                 value = jsUndefined();
             array->initializeIndexWithoutBarrier(scope, i, value);
-            if (groups) {
-                String groupName = regExp->getCaptureGroupName(i);
-                if (!groupName.isEmpty())
-                    groups->putDirect(vm, Identifier::fromString(&vm, groupName), value);
-            }
         }
     } else {
+        GCDeferralContext deferralContext(vm.heap);
         ObjectInitializationScope scope(vm);
         array = tryCreateUninitializedRegExpMatchesArray(scope, &deferralContext, matchStructure, numSubpatterns + 1);
+
+        // FIXME: we should probably throw an out of memory error here, but
+        // when making this change we should check that all clients of this
+        // function will correctly handle an exception being thrown from here.
+        // https://bugs.webkit.org/show_bug.cgi?id=169786
         RELEASE_ASSERT(array);
         
         setProperties();
         
-        // Now the object is safe to scan by GC.
-
         array->initializeIndexWithoutBarrier(scope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start), ArrayWithContiguous);
         
         for (unsigned i = 1; i <= numSubpatterns; ++i) {
@@ -140,13 +145,20 @@
             else
                 value = jsUndefined();
             array->initializeIndexWithoutBarrier(scope, i, value, ArrayWithContiguous);
-            if (groups) {
-                String groupName = regExp->getCaptureGroupName(i);
-                if (!groupName.isEmpty())
-                    groups->putDirect(vm, Identifier::fromString(&vm, groupName), value);
-            }
         }
     }
+
+    // Now the object is safe to scan by GC.
+
+    // We initialize the groups object late as it could allocate, which with the current API could cause
+    // allocations.
+    if (groups) {
+        for (unsigned i = 1; i <= numSubpatterns; ++i) {
+            String groupName = regExp->getCaptureGroupName(i);
+            if (!groupName.isEmpty())
+                groups->putDirect(vm, Identifier::fromString(&vm, groupName), array->getIndexQuickly(i));
+        }
+    }
     return array;
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to