diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/runtime/StructureInlines.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/runtime/StructureInlines.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/StructureInlines.h | 302 |
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 |