Commit ebf01914 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

Storing new CopiedSpace memory into a JSObject should fire a write barrier

https://bugs.webkit.org/show_bug.cgi?id=126025

Reviewed by Filip Pizlo.

Technically this is creating a pointer between a (potentially) old generation object and a young
generation chunk of memory, thus there needs to be a barrier.

* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGOperations.cpp:
* heap/CopyWriteBarrier.h: Added. This class functions similarly to the WriteBarrier class. It
acts as a proxy for pointers to CopiedSpace. Assignments to the field cause a write barrier to
fire for the object that is the owner of the CopiedSpace memory. This is to ensure during nursery
collections that objects with new backing stores are visited, even if they are old generation objects.
(JSC::CopyWriteBarrier::CopyWriteBarrier):
(JSC::CopyWriteBarrier::operator!):
(JSC::CopyWriteBarrier::operator UnspecifiedBoolType*):
(JSC::CopyWriteBarrier::get):
(JSC::CopyWriteBarrier::operator*):
(JSC::CopyWriteBarrier::operator->):
(JSC::CopyWriteBarrier::set):
(JSC::CopyWriteBarrier::setWithoutWriteBarrier):
(JSC::CopyWriteBarrier::clear):
* heap/Heap.h:
* runtime/JSArray.cpp:
(JSC::JSArray::unshiftCountSlowCase):
(JSC::JSArray::shiftCountWithArrayStorage):
(JSC::JSArray::unshiftCountWithArrayStorage):
* runtime/JSCell.h:
(JSC::JSCell::unvalidatedStructure):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory):
* runtime/JSObject.cpp:
(JSC::JSObject::copyButterfly):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
(JSC::JSObject::createInitialIndexedStorage):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
(JSC::JSObject::countElements):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::ensureLengthSlow):
* runtime/JSObject.h:
(JSC::JSObject::butterfly):
(JSC::JSObject::setStructureAndButterfly):
(JSC::JSObject::setButterflyWithoutChangingStructure):
(JSC::JSObject::JSObject):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::putDirectWithoutTransition):
* runtime/MapData.cpp:
(JSC::MapData::ensureSpaceForAppend):
* runtime/Structure.cpp:
(JSC::Structure::materializePropertyMap):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@161230 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 2f3625cd
2014-01-02 Mark Hahnenberg <mhahnenberg@apple.com>
Storing new CopiedSpace memory into a JSObject should fire a write barrier
https://bugs.webkit.org/show_bug.cgi?id=126025
Reviewed by Filip Pizlo.
Technically this is creating a pointer between a (potentially) old generation object and a young
generation chunk of memory, thus there needs to be a barrier.
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGOperations.cpp:
* heap/CopyWriteBarrier.h: Added. This class functions similarly to the WriteBarrier class. It
acts as a proxy for pointers to CopiedSpace. Assignments to the field cause a write barrier to
fire for the object that is the owner of the CopiedSpace memory. This is to ensure during nursery
collections that objects with new backing stores are visited, even if they are old generation objects.
(JSC::CopyWriteBarrier::CopyWriteBarrier):
(JSC::CopyWriteBarrier::operator!):
(JSC::CopyWriteBarrier::operator UnspecifiedBoolType*):
(JSC::CopyWriteBarrier::get):
(JSC::CopyWriteBarrier::operator*):
(JSC::CopyWriteBarrier::operator->):
(JSC::CopyWriteBarrier::set):
(JSC::CopyWriteBarrier::setWithoutWriteBarrier):
(JSC::CopyWriteBarrier::clear):
* heap/Heap.h:
* runtime/JSArray.cpp:
(JSC::JSArray::unshiftCountSlowCase):
(JSC::JSArray::shiftCountWithArrayStorage):
(JSC::JSArray::unshiftCountWithArrayStorage):
* runtime/JSCell.h:
(JSC::JSCell::unvalidatedStructure):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory):
* runtime/JSObject.cpp:
(JSC::JSObject::copyButterfly):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
(JSC::JSObject::createInitialIndexedStorage):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
(JSC::JSObject::countElements):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::ensureLengthSlow):
* runtime/JSObject.h:
(JSC::JSObject::butterfly):
(JSC::JSObject::setStructureAndButterfly):
(JSC::JSObject::setButterflyWithoutChangingStructure):
(JSC::JSObject::JSObject):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::putDirectWithoutTransition):
* runtime/MapData.cpp:
(JSC::MapData::ensureSpaceForAppend):
* runtime/Structure.cpp:
(JSC::Structure::materializePropertyMap):
2013-12-23 Oliver Hunt <oliver@apple.com>
Refactor PutPropertySlot to be aware of custom properties
......
......@@ -502,6 +502,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/CopyVisitorInlines.h \
Source/JavaScriptCore/heap/CopyVisitor.cpp \
Source/JavaScriptCore/heap/CopyWorkList.h \
Source/JavaScriptCore/heap/CopyWriteBarrier.h \
Source/JavaScriptCore/heap/ConservativeRoots.cpp \
Source/JavaScriptCore/heap/ConservativeRoots.h \
Source/JavaScriptCore/heap/DeferGC.cpp \
......
......@@ -984,6 +984,7 @@
<ClInclude Include="..\heap\CopyVisitor.h" />
<ClInclude Include="..\heap\CopyVisitorInlines.h" />
<ClInclude Include="..\heap\CopyWorkList.h" />
<ClInclude Include="..\heap\CopyWriteBarrier.h" />
<ClInclude Include="..\heap\DeferGC.h" />
<ClInclude Include="..\heap\DelayedReleaseScope.h" />
<ClInclude Include="..\heap\GCAssertions.h" />
......
......@@ -1628,6 +1628,9 @@
<ClInclude Include="..\heap\CopyWorkList.h">
<Filter>heap</Filter>
</ClInclude>
<ClInclude Include="..\heap\CopyWriteBarrier.h">
<Filter>heap</Filter>
</ClInclude>
<ClInclude Include="..\heap\DeferGC.h">
<Filter>heap</Filter>
</ClInclude>
......
......@@ -720,6 +720,7 @@
2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; };
2A4EC90B1860D6C20094F782 /* WriteBarrierBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A4EC9091860D6C20094F782 /* WriteBarrierBuffer.cpp */; };
2A4EC90C1860D6C20094F782 /* WriteBarrierBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A4EC90A1860D6C20094F782 /* WriteBarrierBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A68295B1875F80500B6C3E2 /* CopyWriteBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A68295A1875F80500B6C3E2 /* CopyWriteBarrier.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6F462517E959CE00C45C98 /* HeapOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */; };
2AAD964A18569417001F93BE /* RecursiveAllocationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AAD964918569417001F93BE /* RecursiveAllocationScope.h */; };
......@@ -2027,6 +2028,7 @@
2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedReleaseScope.h; sourceTree = "<group>"; };
2A4EC9091860D6C20094F782 /* WriteBarrierBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WriteBarrierBuffer.cpp; sourceTree = "<group>"; };
2A4EC90A1860D6C20094F782 /* WriteBarrierBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierBuffer.h; sourceTree = "<group>"; };
2A68295A1875F80500B6C3E2 /* CopyWriteBarrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyWriteBarrier.h; sourceTree = "<group>"; };
2A6F462517E959CE00C45C98 /* HeapOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapOperation.h; sourceTree = "<group>"; };
2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeferGC.cpp; sourceTree = "<group>"; };
2AAD964918569417001F93BE /* RecursiveAllocationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursiveAllocationScope.h; sourceTree = "<group>"; };
......@@ -3212,6 +3214,7 @@
0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */,
2AAD964918569417001F93BE /* RecursiveAllocationScope.h */,
2A68295A1875F80500B6C3E2 /* CopyWriteBarrier.h */,
);
path = heap;
sourceTree = "<group>";
......@@ -4373,6 +4376,7 @@
86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
65C0285D1717966800351E35 /* ARMv7DOpcode.h in Headers */,
2A68295B1875F80500B6C3E2 /* CopyWriteBarrier.h in Headers */,
2A4EC90C1860D6C20094F782 /* WriteBarrierBuffer.h in Headers */,
A532439218569709002ED692 /* CodeGeneratorInspector.py in Headers */,
A532439318569709002ED692 /* CodeGeneratorInspectorStrings.py in Headers */,
......
......@@ -851,7 +851,7 @@ char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitial
ASSERT(!object->structure()->outOfLineCapacity());
Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity);
object->setButterflyWithoutChangingStructure(result);
object->setButterflyWithoutChangingStructure(vm, result);
return reinterpret_cast<char*>(result);
}
......@@ -861,7 +861,7 @@ char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState*
NativeCallFrameTracer tracer(&vm, exec);
Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize);
object->setButterflyWithoutChangingStructure(result);
object->setButterflyWithoutChangingStructure(vm, result);
return reinterpret_cast<char*>(result);
}
......
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CopyWriteBarrier_h
#define CopyWriteBarrier_h
#include "Heap.h"
namespace JSC {
template <typename T>
class CopyWriteBarrier {
public:
CopyWriteBarrier()
: m_value(0)
{
}
CopyWriteBarrier(VM& vm, const JSCell* owner, T& value)
{
this->set(vm, owner, &value);
}
CopyWriteBarrier(VM& vm, const JSCell* owner, T* value)
{
this->set(vm, owner, value);
}
bool operator!() const { return !m_value; }
typedef T* (CopyWriteBarrier::*UnspecifiedBoolType);
operator UnspecifiedBoolType*() const { return m_value ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
T* get() const
{
return m_value;
}
T* operator*() const
{
return get();
}
T* operator->() const
{
return get();
}
void set(VM&, const JSCell* owner, T* value)
{
this->m_value = value;
Heap::writeBarrier(owner);
}
void setWithoutWriteBarrier(T* value)
{
this->m_value = value;
}
void clear() { m_value = 0; }
private:
T* m_value;
};
} // namespace JSC
#endif // CopyWriteBarrier_h
......@@ -321,8 +321,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
newButterfly->arrayStorage()->m_indexBias = newIndexBias;
m_butterfly = newButterfly;
setButterflyWithoutChangingStructure(vm, newButterfly);
return true;
}
......@@ -720,7 +719,7 @@ bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, Ar
// Adjust the Butterfly and the index bias. We only need to do this here because we're changing
// the start of the Butterfly, which needs to point at the first indexed property in the used
// portion of the vector.
m_butterfly = m_butterfly->shift(structure(), count);
m_butterfly.setWithoutWriteBarrier(m_butterfly->shift(structure(), count));
storage = m_butterfly->arrayStorage();
storage->m_indexBias += count;
......@@ -857,10 +856,11 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex,
unsigned vectorLength = storage->vectorLength();
if (moveFront && storage->m_indexBias >= count) {
m_butterfly = storage->butterfly()->unshift(structure(), count);
storage = m_butterfly->arrayStorage();
Butterfly* newButterfly = storage->butterfly()->unshift(structure(), count);
storage = newButterfly->arrayStorage();
storage->m_indexBias -= count;
storage->setVectorLength(vectorLength + count);
setButterflyWithoutChangingStructure(exec->vm(), newButterfly);
} else if (!moveFront && vectorLength - length >= count)
storage = storage->butterfly()->arrayStorage();
else if (unshiftCountSlowCase(exec->vm(), moveFront, count))
......
......@@ -146,7 +146,7 @@ public:
}
#if ENABLE(GC_VALIDATION)
Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
Structure* unvalidatedStructure() const { return m_structure.unvalidatedGet(); }
#endif
static const TypedArrayType TypedArrayStorageType = NotTypedArray;
......
......@@ -506,15 +506,16 @@ ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBuf
size_t size = thisObject->byteSize();
if (thisObject->m_mode == FastTypedArray
&& !thisObject->m_butterfly && size >= sizeof(IndexingHeader)) {
&& !thisObject->butterfly() && size >= sizeof(IndexingHeader)) {
ASSERT(thisObject->m_vector);
// Reuse already allocated memory if at all possible.
thisObject->m_butterfly =
static_cast<IndexingHeader*>(thisObject->m_vector)->butterfly();
thisObject->m_butterfly.setWithoutWriteBarrier(
static_cast<IndexingHeader*>(thisObject->m_vector)->butterfly());
} else {
thisObject->m_butterfly = Butterfly::createOrGrowArrayRight(
thisObject->m_butterfly, *heap->vm(), thisObject, thisObject->structure(),
thisObject->structure()->outOfLineCapacity(), false, 0, 0);
VM& vm = *heap->vm();
thisObject->m_butterfly.set(vm, thisObject, Butterfly::createOrGrowArrayRight(
thisObject->butterfly(), vm, thisObject, thisObject->structure(),
thisObject->structure()->outOfLineCapacity(), false, 0, 0));
}
RefPtr<ArrayBuffer> buffer;
......
......@@ -159,7 +159,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
}
m_butterfly = newButterfly;
m_butterfly.setWithoutWriteBarrier(newButterfly);
visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
}
}
......@@ -283,7 +283,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec,
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return false;
......@@ -297,7 +297,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec,
}
case ALL_DOUBLE_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return false;
......@@ -437,7 +437,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
}
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
Butterfly* butterfly = thisObject->butterfly();
if (propertyName >= butterfly->vectorLength())
break;
butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value);
......@@ -460,7 +460,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
putByIndex(cell, exec, propertyName, value, shouldThrow);
return;
}
Butterfly* butterfly = thisObject->m_butterfly;
Butterfly* butterfly = thisObject->butterfly();
if (propertyName >= butterfly->vectorLength())
break;
butterfly->contiguousDouble()[propertyName] = valueAsDouble;
......@@ -549,11 +549,10 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(0));
RELEASE_ASSERT(newButterfly);
m_butterfly = newButterfly;
newButterfly->arrayStorage()->m_indexBias = 0;
newButterfly->arrayStorage()->setVectorLength(0);
newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
setButterflyWithoutChangingStructure(vm, newButterfly);
return newButterfly->arrayStorage();
}
......@@ -601,7 +600,7 @@ Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t
ASSERT(!indexingShouldBeSparse());
unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
m_butterfly, vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
m_butterfly.get(), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
elementSize * vectorLength);
newButterfly->setPublicLength(length);
newButterfly->setVectorLength(vectorLength);
......@@ -652,7 +651,7 @@ ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vec
IndexingType oldType = structure()->indexingType();
ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
m_butterfly, vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
m_butterfly.get(), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
ArrayStorage::sizeFor(vectorLength));
RELEASE_ASSERT(newButterfly);
......@@ -1296,7 +1295,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return true;
butterfly->contiguous()[i].clear();
......@@ -1304,7 +1303,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
}
case ALL_DOUBLE_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return true;
butterfly->contiguousDouble()[i] = QNaN;
......@@ -1480,7 +1479,7 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = object->m_butterfly;
Butterfly* butterfly = object->butterfly();
unsigned usedLength = butterfly->publicLength();
for (unsigned i = 0; i < usedLength; ++i) {
if (!butterfly->contiguous()[i])
......@@ -1491,7 +1490,7 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
}
case ALL_DOUBLE_INDEXING_TYPES: {
Butterfly* butterfly = object->m_butterfly;
Butterfly* butterfly = object->butterfly();
unsigned usedLength = butterfly->publicLength();
for (unsigned i = 0; i < usedLength; ++i) {
double value = butterfly->contiguousDouble()[i];
......@@ -1875,7 +1874,7 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un
if (i >= MAX_ARRAY_INDEX - 1
|| (i >= MIN_SPARSE_ARRAY_INDEX
&& !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))
&& !isDenseEnoughForVector(i, countElements<indexingShape>(butterfly())))
|| indexIsSufficientlyBeyondLengthForSparseMap(i, m_butterfly->vectorLength())) {
ASSERT(i <= MAX_ARRAY_INDEX);
ensureArrayStorageSlow(vm);
......@@ -2312,13 +2311,13 @@ unsigned JSObject::countElements()
return 0;
case ALL_INT32_INDEXING_TYPES:
return countElements<Int32Shape>(m_butterfly);
return countElements<Int32Shape>(butterfly());
case ALL_DOUBLE_INDEXING_TYPES:
return countElements<DoubleShape>(m_butterfly);
return countElements<DoubleShape>(butterfly());
case ALL_CONTIGUOUS_INDEXING_TYPES:
return countElements<ContiguousShape>(m_butterfly);
return countElements<ContiguousShape>(butterfly());
default:
CRASH();
......@@ -2352,8 +2351,8 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
if (!newButterfly)
return false;
m_butterfly = newButterfly;
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
setButterflyWithoutChangingStructure(vm, newButterfly);
return true;
}
......@@ -2366,10 +2365,9 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
newIndexBias, true, ArrayStorage::sizeFor(newVectorLength));
if (!newButterfly)
return false;
m_butterfly = newButterfly;
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
newButterfly->arrayStorage()->m_indexBias = newIndexBias;
setButterflyWithoutChangingStructure(vm, newButterfly);
return true;
}
......@@ -2384,15 +2382,17 @@ void JSObject::ensureLengthSlow(VM& vm, unsigned length)
MAX_STORAGE_VECTOR_LENGTH);
unsigned oldVectorLength = m_butterfly->vectorLength();
DeferGC deferGC(vm.heap);
m_butterfly = m_butterfly->growArrayRight(
m_butterfly.set(vm, this, m_butterfly->growArrayRight(
vm, this, structure(), structure()->outOfLineCapacity(), true,
oldVectorLength * sizeof(EncodedJSValue),
newVectorLength * sizeof(EncodedJSValue));
newVectorLength * sizeof(EncodedJSValue)));
m_butterfly->setVectorLength(newVectorLength);
if (hasDouble(structure()->indexingType())) {
for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
m_butterfly->contiguousDouble().data()[i] = QNaN;
}
m_butterfly->setVectorLength(newVectorLength);
}
Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize)
......
......@@ -27,10 +27,13 @@
#include "ArrayConventions.h"
#include "ArrayStorage.h"
#include "Butterfly.h"
#include "CallFrame.h"
#include "ClassInfo.h"
#include "CommonIdentifiers.h"
#include "CallFrame.h"
#include "CopyWriteBarrier.h"
#include "DeferGC.h"
#include "Heap.h"
#include "IndexingHeaderInlines.h"
#include "JSCell.h"
#include "PropertySlot.h"
#include "PropertyStorage.h"
......@@ -539,8 +542,8 @@ public:
return inlineStorageUnsafe();
}
const Butterfly* butterfly() const { return m_butterfly; }
Butterfly* butterfly() { return m_butterfly; }
const Butterfly* butterfly() const { return m_butterfly.get(); }
Butterfly* butterfly() { return m_butterfly.get(); }
ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
......@@ -605,7 +608,7 @@ public:
void reifyStaticFunctionsForDelete(ExecState* exec);
JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(VM&, size_t oldSize, size_t newSize);
void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this.
void setButterflyWithoutChangingStructure(VM&, Butterfly*);
void setStructure(VM&, Structure*);
void setStructureAndButterfly(VM&, Structure*, Butterfly*);
......@@ -975,7 +978,7 @@ private:
ContiguousJSValues ensureContiguousSlow(VM&, DoubleToContiguousMode);
protected:
Butterfly* m_butterfly;
CopyWriteBarrier<Butterfly> m_butterfly;
};
// JSNonFinalObject is a type of JSObject that has some internal storage,
......@@ -1135,7 +1138,9 @@ inline bool JSObject::isErrorInstance() const
inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
{
m_butterfly = butterfly;
ASSERT(structure);
ASSERT(!butterfly == (!structure->outOfLineCapacity() && !structure->hasIndexingHeader(this)));
m_butterfly.set(vm, this, butterfly);
setStructure(vm, structure);
}
......@@ -1146,9 +1151,9 @@ inline void JSObject::setStructure(VM& vm, Structure* structure)
JSCell::setStructure(vm, structure);
}
inline void JSObject::setButterflyWithoutChangingStructure(Butterfly* butterfly)
inline void JSObject::setButterflyWithoutChangingStructure(VM& vm, Butterfly* butterfly)
{
m_butterfly = butterfly;
m_butterfly.set(vm, this, butterfly);
}
inline CallType getCallData(JSValue value, CallData& callData)
......@@ -1178,7 +1183,7 @@ inline JSObject* asObject(JSValue value)
inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly)
: JSCell(vm, structure)
, m_butterfly(butterfly)
, m_butterfly(vm, this, butterfly)
{
vm.heap.ascribeOwner(this, butterfly);
}
......@@ -1302,7 +1307,7 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal
return false;
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = m_butterfly;
Butterfly* newButterfly = butterfly();
if (structure()->putWillGrowOutOfLineStorage())
newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction);
......@@ -1323,9 +1328,11 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal
size_t currentCapacity = structure()->outOfLineCapacity();
if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = m_butterfly;
if (currentCapacity != structure->outOfLineCapacity())
Butterfly* newButterfly = butterfly();
if (currentCapacity != structure->outOfLineCapacity()) {
ASSERT(structure != this->structure());
newButterfly = growOutOfLineStorage(vm, currentCapacity, structure->outOfLineCapacity());
}
validateOffset(offset);
ASSERT(structure->isValidOffset(offset));
......@@ -1436,7 +1443,7 @@ inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyNa
{
DeferGC deferGC(vm.heap);
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
Butterfly* newButterfly = m_butterfly;
Butterfly* newButterfly = m_butterfly.get();
if (structure()->putWillGrowOutOfLineStorage())
newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value));
......
......@@ -198,16 +198,17 @@ CheckedBoolean MapData::ensureSpaceForAppend(CallFrame* callFrame)
size_t requiredSize = std::max(m_capacity + (m_capacity / 2) + 1, minimumMapSize);
void* newStorage = 0;
DeferGC defer(*callFrame->heap());
if (!callFrame->heap()->tryAllocateStorage(this, requiredSize * sizeof(Entry), &newStorage)) {
throwOutOfMemoryError(callFrame);
return false;
}
DeferGC defer(*callFrame->heap());
Entry* newEntries = static_cast<Entry*>(newStorage);
if (shouldPack())
replaceAndPackBackingStore(newEntries, requiredSize);
else
replaceBackingStore(newEntries, requiredSize);
Heap::writeBarrier(this);
return true;
}
......
......@@ -273,7 +273,7 @@ void Structure::materializePropertyMap(VM& vm)
findStructuresAndMapForMaterialization(structures, structure, table);
if (table) {
table = table->copy(vm, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
table = table->copy(vm, structure, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
structure->m_lock.unlock();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment