summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-10-09 18:10:02 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-10-09 18:10:03 +0200
commitee21e513f3ed68af68e529b43c8fda94dfcc49ff (patch)
tree37eff93fb4b1d5de70c99ec290c3a193bf44f9ca /Source/JavaScriptCore/runtime
parent880257678ae831d9b79937e8d8533a88a8f8325d (diff)
parentea46a149dc42a48c103833742a7a0d575576c14a (diff)
downloadqtwebkit-ee21e513f3ed68af68e529b43c8fda94dfcc49ff.tar.gz
Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: Ie2225337cb5eef39035146827484496a6b3690b3
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp60
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp30
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h13
-rw-r--r--Source/JavaScriptCore/runtime/NumericStrings.h6
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp6
5 files changed, 71 insertions, 44 deletions
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index f97ccedcd..bc6f73672 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -755,21 +755,21 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
// so only if it's not horribly slow.
if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
-
+
+ // Storing to a hole is fine since we're still having a good time. But reading from a hole
+ // is totally not fine, since we might have to read from the proto chain.
+ // We have to check for holes before we start moving things around so that we don't get halfway
+ // through shifting and then realize we should have been in ArrayStorage mode.
unsigned end = oldLength - count;
for (unsigned i = startIndex; i < end; ++i) {
- // Storing to a hole is fine since we're still having a good time. But reading
- // from a hole is totally not fine, since we might have to read from the proto
- // chain.
JSValue v = m_butterfly->contiguous()[i + count].get();
- if (UNLIKELY(!v)) {
- // The purpose of this path is to ensure that we don't make the same
- // mistake in the future: shiftCountWithArrayStorage() can't do anything
- // about holes (at least for now), but it can detect them quickly. So
- // we convert to array storage and then allow the array storage path to
- // figure it out.
+ if (UNLIKELY(!v))
return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
- }
+ }
+
+ for (unsigned i = startIndex; i < end; ++i) {
+ JSValue v = m_butterfly->contiguous()[i + count].get();
+ ASSERT(v);
// No need for a barrier since we're just moving data around in the same vector.
// This is in line with our standing assumption that we won't have a deletion
// barrier.
@@ -790,21 +790,21 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
// so only if it's not horribly slow.
if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
-
+
+ // Storing to a hole is fine since we're still having a good time. But reading from a hole
+ // is totally not fine, since we might have to read from the proto chain.
+ // We have to check for holes before we start moving things around so that we don't get halfway
+ // through shifting and then realize we should have been in ArrayStorage mode.
unsigned end = oldLength - count;
for (unsigned i = startIndex; i < end; ++i) {
- // Storing to a hole is fine since we're still having a good time. But reading
- // from a hole is totally not fine, since we might have to read from the proto
- // chain.
double v = m_butterfly->contiguousDouble()[i + count];
- if (UNLIKELY(v != v)) {
- // The purpose of this path is to ensure that we don't make the same
- // mistake in the future: shiftCountWithArrayStorage() can't do anything
- // about holes (at least for now), but it can detect them quickly. So
- // we convert to array storage and then allow the array storage path to
- // figure it out.
+ if (UNLIKELY(v != v))
return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
- }
+ }
+
+ for (unsigned i = startIndex; i < end; ++i) {
+ double v = m_butterfly->contiguousDouble()[i + count];
+ ASSERT(v == v);
// No need for a barrier since we're just moving data around in the same vector.
// This is in line with our standing assumption that we won't have a deletion
// barrier.
@@ -889,11 +889,18 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
ensureLength(exec->vm(), oldLength + count);
-
+
+ // We have to check for holes before we start moving things around so that we don't get halfway
+ // through shifting and then realize we should have been in ArrayStorage mode.
for (unsigned i = oldLength; i-- > startIndex;) {
JSValue v = m_butterfly->contiguous()[i].get();
if (UNLIKELY(!v))
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
+ }
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ ASSERT(v);
m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
}
@@ -915,10 +922,17 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
ensureLength(exec->vm(), oldLength + count);
+ // We have to check for holes before we start moving things around so that we don't get halfway
+ // through shifting and then realize we should have been in ArrayStorage mode.
for (unsigned i = oldLength; i-- > startIndex;) {
double v = m_butterfly->contiguousDouble()[i];
if (UNLIKELY(v != v))
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
+ }
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ double v = m_butterfly->contiguousDouble()[i];
+ ASSERT(v == v);
m_butterfly->contiguousDouble()[i + count] = v;
}
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 01dc96333..5637e2090 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -595,7 +595,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
if (mayInterceptIndexedAccesses())
return;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors), m_butterfly);
if (!vm.prototypeMap.isPrototype(this))
return;
@@ -681,7 +681,7 @@ ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
{
ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32), m_butterfly);
return m_butterfly->contiguousInt32();
}
@@ -692,14 +692,14 @@ ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
for (unsigned i = m_butterfly->vectorLength(); i--;)
m_butterfly->contiguousDouble()[i] = QNaN;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly);
return m_butterfly->contiguousDouble();
}
ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
{
ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
return m_butterfly->contiguous();
}
@@ -765,7 +765,7 @@ ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
*currentAsDouble = v.asInt32();
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly);
return m_butterfly->contiguousDouble();
}
@@ -773,7 +773,7 @@ ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
{
ASSERT(hasInt32(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
return m_butterfly->contiguous();
}
@@ -831,7 +831,7 @@ ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm)
currentAsValue->setWithoutWriteBarrier(v);
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
return m_butterfly->contiguous();
}
@@ -1129,7 +1129,7 @@ void JSObject::switchToSlowPutArrayStorage(VM& vm)
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
- setStructure(vm, newStructure);
+ setStructure(vm, newStructure, m_butterfly);
break;
}
@@ -1153,7 +1153,7 @@ void JSObject::setPrototype(VM& vm, JSValue prototype)
vm.prototypeMap.addPrototype(asObject(prototype));
Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
- setStructure(vm, newStructure);
+ setStructure(vm, newStructure, m_butterfly);
if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
return;
@@ -1213,7 +1213,7 @@ void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSV
// getters and setters, though, we also need to change our Structure
// if we override an existing non-getter or non-setter.
if (slot.type() != PutPropertySlot::NewProperty)
- setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes));
+ setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes), m_butterfly);
if (attributes & ReadOnly)
structure()->setContainsReadOnlyProperties();
@@ -1570,7 +1570,7 @@ void JSObject::seal(VM& vm)
if (isSealed(vm))
return;
preventExtensions(vm);
- setStructure(vm, Structure::sealTransition(vm, structure()));
+ setStructure(vm, Structure::sealTransition(vm, structure()), m_butterfly);
}
void JSObject::freeze(VM& vm)
@@ -1578,14 +1578,14 @@ void JSObject::freeze(VM& vm)
if (isFrozen(vm))
return;
preventExtensions(vm);
- setStructure(vm, Structure::freezeTransition(vm, structure()));
+ setStructure(vm, Structure::freezeTransition(vm, structure()), m_butterfly);
}
void JSObject::preventExtensions(VM& vm)
{
enterDictionaryIndexingMode(vm);
if (isExtensible())
- setStructure(vm, Structure::preventExtensionsTransition(vm, structure()));
+ setStructure(vm, Structure::preventExtensionsTransition(vm, structure()), m_butterfly);
}
// This presently will flatten to an uncachable dictionary; this is suitable
@@ -1603,7 +1603,7 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
}
if (!structure()->isUncacheableDictionary())
- setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()));
+ setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()), m_butterfly);
for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
@@ -1633,7 +1633,7 @@ bool JSObject::removeDirect(VM& vm, PropertyName propertyName)
return true;
}
- setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset));
+ setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset), m_butterfly);
if (offset == invalidOffset)
return false;
putDirectUndefined(offset);
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index c62dc2aec..7a78a46a6 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -595,6 +595,7 @@ public:
void setButterfly(VM&, Butterfly*, Structure*);
void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this.
+ void setStructure(VM&, Structure*, Butterfly* = 0);
void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*);
void setStructureAndReallocateStorageIfNecessary(VM&, Structure*);
@@ -1109,7 +1110,7 @@ inline void JSObject::setButterfly(VM& vm, Butterfly* butterfly, Structure* stru
{
ASSERT(structure);
ASSERT(!butterfly == (!structure->outOfLineCapacity() && !hasIndexingHeader(structure->indexingType())));
- setStructure(vm, structure);
+ setStructure(vm, structure, butterfly);
m_butterfly = butterfly;
}
@@ -1316,7 +1317,7 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal
return true;
}
// case (2) Despecify, fall through to (3).
- setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName));
+ setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName), m_butterfly);
}
// case (3) set the slot, do the put, return.
@@ -1344,12 +1345,18 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal
return true;
}
+inline void JSObject::setStructure(VM& vm, Structure* structure, Butterfly* butterfly)
+{
+ JSCell::setStructure(vm, structure);
+ ASSERT_UNUSED(butterfly, !butterfly == !(structure->outOfLineCapacity() || hasIndexingHeader(structure->indexingType())));
+}
+
inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsigned oldCapacity, Structure* newStructure)
{
ASSERT(oldCapacity <= newStructure->outOfLineCapacity());
if (oldCapacity == newStructure->outOfLineCapacity()) {
- setStructure(vm, newStructure);
+ setStructure(vm, newStructure, m_butterfly);
return;
}
diff --git a/Source/JavaScriptCore/runtime/NumericStrings.h b/Source/JavaScriptCore/runtime/NumericStrings.h
index 4cd92fc1f..68bfbd06a 100644
--- a/Source/JavaScriptCore/runtime/NumericStrings.h
+++ b/Source/JavaScriptCore/runtime/NumericStrings.h
@@ -37,7 +37,7 @@ namespace JSC {
ALWAYS_INLINE String add(double d)
{
CacheEntry<double>& entry = lookup(d);
- if (d == entry.key && !entry.value.isNull())
+ if (!entry.value.isNull() && d == entry.key)
return entry.value;
entry.key = d;
entry.value = String::numberToStringECMAScript(d);
@@ -49,7 +49,7 @@ namespace JSC {
if (static_cast<unsigned>(i) < cacheSize)
return lookupSmallString(static_cast<unsigned>(i));
CacheEntry<int>& entry = lookup(i);
- if (i == entry.key && !entry.value.isNull())
+ if (!entry.value.isNull() && i == entry.key)
return entry.value;
entry.key = i;
entry.value = String::number(i);
@@ -61,7 +61,7 @@ namespace JSC {
if (i < cacheSize)
return lookupSmallString(static_cast<unsigned>(i));
CacheEntry<unsigned>& entry = lookup(i);
- if (i == entry.key && !entry.value.isNull())
+ if (!entry.value.isNull() && i == entry.key)
return entry.value;
entry.key = i;
entry.value = String::number(i);
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index f551eaecc..950728cca 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -649,6 +649,12 @@ Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object)
}
m_dictionaryKind = NoneDictionaryKind;
+
+ // If the object had a Butterfly but after flattening/compacting we no longer have need of it,
+ // we need to zero it out because the collector depends on the Structure to know the size for copying.
+ if (object->butterfly() && !this->outOfLineCapacity() && !hasIndexingHeader(this->indexingType()))
+ object->setButterfly(vm, 0, this);
+
return this;
}