summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/StructureInlines.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/runtime/StructureInlines.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/runtime/StructureInlines.h')
-rw-r--r--Source/JavaScriptCore/runtime/StructureInlines.h302
1 files changed, 229 insertions, 73 deletions
diff --git a/Source/JavaScriptCore/runtime/StructureInlines.h b/Source/JavaScriptCore/runtime/StructureInlines.h
index 5895ecb20..c83113c4b 100644
--- a/Source/JavaScriptCore/runtime/StructureInlines.h
+++ b/Source/JavaScriptCore/runtime/StructureInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* 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
@@ -23,12 +23,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef StructureInlines_h
-#define StructureInlines_h
+#pragma once
#include "JSArrayBufferView.h"
+#include "JSCJSValueInlines.h"
+#include "JSGlobalObject.h"
#include "PropertyMapHashTable.h"
#include "Structure.h"
+#include "StructureChain.h"
namespace JSC {
@@ -49,10 +51,10 @@ inline Structure* Structure::createStructure(VM& vm)
return structure;
}
-inline Structure* Structure::create(VM& vm, const Structure* structure)
+inline Structure* Structure::create(VM& vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred)
{
ASSERT(vm.structureStructure);
- Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure);
+ Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure, deferred);
newStructure->finishCreation(vm);
return newStructure;
}
@@ -61,7 +63,7 @@ inline JSObject* Structure::storedPrototypeObject() const
{
JSValue value = m_prototype.get();
if (value.isNull())
- return 0;
+ return nullptr;
return asObject(value);
}
@@ -69,42 +71,74 @@ inline Structure* Structure::storedPrototypeStructure() const
{
JSObject* object = storedPrototypeObject();
if (!object)
- return 0;
+ return nullptr;
return object->structure();
}
-inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
+ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
{
- ASSERT(!isCompilationThread());
- ASSERT(structure()->classInfo() == info());
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
- return invalidOffset;
-
- PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
- return entry ? entry->offset : invalidOffset;
+ unsigned attributes;
+ bool hasInferredType;
+ return get(vm, propertyName, attributes, hasInferredType);
+}
+
+ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes)
+{
+ bool hasInferredType;
+ return get(vm, propertyName, attributes, hasInferredType);
}
-inline PropertyOffset Structure::get(VM& vm, const WTF::String& name)
+ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, bool& hasInferredType)
{
ASSERT(!isCompilationThread());
ASSERT(structure()->classInfo() == info());
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
+
+ PropertyTable* propertyTable = ensurePropertyTableIfNotEmpty(vm);
+ if (!propertyTable)
+ return invalidOffset;
+
+ PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
+ if (!entry)
return invalidOffset;
- PropertyMapEntry* entry = propertyTable()->findWithString(name.impl()).first;
- return entry ? entry->offset : invalidOffset;
+ attributes = entry->attributes;
+ hasInferredType = entry->hasInferredType;
+ return entry->offset;
}
+
+template<typename Functor>
+void Structure::forEachPropertyConcurrently(const Functor& functor)
+{
+ Vector<Structure*, 8> structures;
+ Structure* structure;
+ PropertyTable* table;
-inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid)
+ findStructuresAndMapForMaterialization(structures, structure, table);
+
+ if (table) {
+ for (auto& entry : *table) {
+ if (!functor(entry)) {
+ structure->m_lock.unlock();
+ return;
+ }
+ }
+ structure->m_lock.unlock();
+ }
+
+ for (unsigned i = structures.size(); i--;) {
+ structure = structures[i];
+ if (!structure->m_nameInPrevious)
+ continue;
+
+ if (!functor(PropertyMapEntry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious())))
+ return;
+ }
+}
+
+inline PropertyOffset Structure::getConcurrently(UniquedStringImpl* uid)
{
unsigned attributesIgnored;
- JSCell* specificValueIgnored;
- return getConcurrently(
- vm, uid, attributesIgnored, specificValueIgnored);
+ return getConcurrently(uid, attributesIgnored);
}
inline bool Structure::hasIndexingHeader(const JSCell* cell) const
@@ -112,7 +146,7 @@ inline bool Structure::hasIndexingHeader(const JSCell* cell) const
if (hasIndexedProperties(indexingType()))
return true;
- if (!isTypedView(m_classInfo->typedArrayStorageType))
+ if (!isTypedView(typedArrayTypeForType(m_blob.type())))
return false;
return jsCast<const JSArrayBufferView*>(cell)->mode() == WastefulTypedArray;
@@ -132,25 +166,12 @@ inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
return false;
}
-inline void Structure::setEnumerationCache(VM& vm, JSPropertyNameIterator* enumerationCache)
-{
- ASSERT(!isDictionary());
- if (!typeInfo().structureHasRareData())
- allocateRareData(vm);
- rareData()->setEnumerationCache(vm, this, enumerationCache);
-}
-
-inline JSPropertyNameIterator* Structure::enumerationCache()
-{
- if (!typeInfo().structureHasRareData())
- return 0;
- return rareData()->enumerationCache();
-}
-
inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
{
if (isObject())
return m_prototype.get();
+ if (typeInfo().type() == SymbolType)
+ return globalObject->symbolPrototype();
ASSERT(typeInfo().type() == StringType);
return globalObject->stringPrototype();
@@ -187,7 +208,7 @@ inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cac
if (asObject(prototype)->structure() != cachedStructure->get())
return false;
++cachedStructure;
- prototype = asObject(prototype)->prototype();
+ prototype = asObject(prototype)->getPrototypeDirect();
}
return prototype.isNull() && !*cachedStructure;
}
@@ -197,38 +218,72 @@ inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeC
return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
}
-inline bool Structure::putWillGrowOutOfLineStorage()
+inline void Structure::didReplaceProperty(PropertyOffset offset)
{
- checkOffsetConsistency();
-
- ASSERT(outOfLineCapacity() >= outOfLineSize());
-
- if (!propertyTable()) {
- unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
- ASSERT(outOfLineCapacity() >= currentSize);
- return currentSize == outOfLineCapacity();
- }
-
- ASSERT(totalStorageCapacity() >= propertyTable()->propertyStorageSize());
- if (propertyTable()->hasDeletedOffset())
- return false;
+ if (LIKELY(!hasRareData()))
+ return;
+ StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
+ if (LIKELY(!map))
+ return;
+ WatchpointSet* set = map->get(offset);
+ if (LIKELY(!set))
+ return;
+ set->fireAll(*vm(), "Property did get replaced");
+}
- ASSERT(totalStorageCapacity() >= propertyTable()->size());
- return propertyTable()->size() == totalStorageCapacity();
+inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset)
+{
+ ConcurrentJSLocker locker(m_lock);
+ if (!hasRareData())
+ return nullptr;
+ WTF::loadLoadFence();
+ StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
+ if (!map)
+ return nullptr;
+ return map->get(offset);
}
-ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable()
+template<typename DetailsFunc>
+ALWAYS_INLINE bool Structure::checkOffsetConsistency(PropertyTable* propertyTable, const DetailsFunc& detailsFunc) const
{
- ASSERT(!globalObject() || !globalObject()->vm().heap.isCollecting());
- return m_propertyTableUnsafe;
+ // We cannot reliably assert things about the property table in the concurrent
+ // compilation thread. It is possible for the table to be stolen and then have
+ // things added to it, which leads to the offsets being all messed up. We could
+ // get around this by grabbing a lock here, but I think that would be overkill.
+ if (isCompilationThread())
+ return true;
+
+ unsigned totalSize = propertyTable->propertyStorageSize();
+ unsigned inlineOverflowAccordingToTotalSize = totalSize < m_inlineCapacity ? 0 : totalSize - m_inlineCapacity;
+
+ auto fail = [&] (const char* description) {
+ dataLog("Detected offset inconsistency: ", description, "!\n");
+ dataLog("this = ", RawPointer(this), "\n");
+ dataLog("m_offset = ", m_offset, "\n");
+ dataLog("m_inlineCapacity = ", m_inlineCapacity, "\n");
+ dataLog("propertyTable = ", RawPointer(propertyTable), "\n");
+ dataLog("numberOfSlotsForLastOffset = ", numberOfSlotsForLastOffset(m_offset, m_inlineCapacity), "\n");
+ dataLog("totalSize = ", totalSize, "\n");
+ dataLog("inlineOverflowAccordingToTotalSize = ", inlineOverflowAccordingToTotalSize, "\n");
+ dataLog("numberOfOutOfLineSlotsForLastOffset = ", numberOfOutOfLineSlotsForLastOffset(m_offset), "\n");
+ detailsFunc();
+ UNREACHABLE_FOR_PLATFORM();
+ };
+
+ if (numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) != totalSize)
+ fail("numberOfSlotsForLastOffset doesn't match totalSize");
+ if (inlineOverflowAccordingToTotalSize != numberOfOutOfLineSlotsForLastOffset(m_offset))
+ fail("inlineOverflowAccordingToTotalSize doesn't match numberOfOutOfLineSlotsForLastOffset");
+
+ return true;
}
ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
{
- PropertyTable* propertyTable = m_propertyTableUnsafe.get();
+ PropertyTable* propertyTable = propertyTableOrNull();
if (!propertyTable) {
- ASSERT(!m_isPinnedPropertyTable);
+ ASSERT(!isPinnedPropertyTable());
return true;
}
@@ -238,15 +293,116 @@ ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
// get around this by grabbing a lock here, but I think that would be overkill.
if (isCompilationThread())
return true;
+
+ return checkOffsetConsistency(propertyTable, [] () { });
+}
+
+inline void Structure::checkConsistency()
+{
+ checkOffsetConsistency();
+}
+
+inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
+{
+ if (!currentCapacity)
+ return initialOutOfLineCapacity;
+ return currentCapacity * outOfLineGrowthFactor;
+}
+
+inline void Structure::setObjectToStringValue(ExecState* exec, VM& vm, JSString* value, PropertySlot toStringTagSymbolSlot)
+{
+ if (!hasRareData())
+ allocateRareData(vm);
+ rareData()->setObjectToStringValue(exec, vm, this, value, toStringTagSymbolSlot);
+}
+
+template<Structure::ShouldPin shouldPin, typename Func>
+inline PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attributes, const Func& func)
+{
+ PropertyTable* table = ensurePropertyTable(vm);
+
+ GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
+
+ switch (shouldPin) {
+ case ShouldPin::Yes:
+ pin(locker, vm, table);
+ break;
+ case ShouldPin::No:
+ setPropertyTable(vm, table);
+ break;
+ }
- RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == propertyTable->propertyStorageSize());
- unsigned totalSize = propertyTable->propertyStorageSize();
- RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset));
+ ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
- return true;
+ checkConsistency();
+ if (attributes & DontEnum || propertyName.isSymbol())
+ setIsQuickPropertyAccessAllowedForEnumeration(false);
+
+ auto rep = propertyName.uid();
+
+ PropertyOffset newOffset = table->nextOffset(m_inlineCapacity);
+
+ PropertyOffset newLastOffset = m_offset;
+ table->add(PropertyMapEntry(rep, newOffset, attributes), newLastOffset, PropertyTable::PropertyOffsetMayChange);
+
+ func(locker, newOffset, newLastOffset);
+
+ ASSERT(m_offset == newLastOffset);
+
+ checkConsistency();
+ return newOffset;
}
-} // namespace JSC
+template<typename Func>
+inline PropertyOffset Structure::remove(PropertyName propertyName, const Func& func)
+{
+ ConcurrentJSLocker locker(m_lock);
+
+ checkConsistency();
+
+ auto rep = propertyName.uid();
+
+ // We ONLY remove from uncacheable dictionaries, which will have a pinned property table.
+ // The only way for them not to have a table is if they are empty.
+ PropertyTable* table = propertyTableOrNull();
+
+ if (!table)
+ return invalidOffset;
-#endif // StructureInlines_h
+ PropertyTable::find_iterator position = table->find(rep);
+ if (!position.first)
+ return invalidOffset;
+
+ PropertyOffset offset = position.first->offset;
+
+ table->remove(position);
+ table->addDeletedOffset(offset);
+
+ checkConsistency();
+
+ func(locker, offset);
+ return offset;
+}
+template<typename Func>
+inline PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, const Func& func)
+{
+ return add<ShouldPin::Yes>(vm, propertyName, attributes, func);
+}
+
+template<typename Func>
+inline PropertyOffset Structure::removePropertyWithoutTransition(VM&, PropertyName propertyName, const Func& func)
+{
+ ASSERT(isUncacheableDictionary());
+ ASSERT(isPinnedPropertyTable());
+ ASSERT(propertyTableOrNull());
+
+ return remove(propertyName, func);
+}
+
+inline void Structure::setPropertyTable(VM& vm, PropertyTable* table)
+{
+ m_propertyTableUnsafe.setMayBeNull(vm, this, table);
+}
+
+} // namespace JSC