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/JSCellInlines.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSCellInlines.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSCellInlines.h | 265 |
1 files changed, 206 insertions, 59 deletions
diff --git a/Source/JavaScriptCore/runtime/JSCellInlines.h b/Source/JavaScriptCore/runtime/JSCellInlines.h index f7c844645..38a2ecfb0 100644 --- a/Source/JavaScriptCore/runtime/JSCellInlines.h +++ b/Source/JavaScriptCore/runtime/JSCellInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,40 +23,51 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSCellInlines_h -#define JSCellInlines_h +#pragma once +#include "CPU.h" #include "CallFrame.h" #include "DeferGC.h" #include "Handle.h" #include "JSCell.h" +#include "JSDestructibleObject.h" #include "JSObject.h" #include "JSString.h" +#include "MarkedBlock.h" #include "Structure.h" +#include "Symbol.h" #include <wtf/CompilationThread.h> namespace JSC { inline JSCell::JSCell(CreatingEarlyCellTag) + : m_cellState(CellState::DefinitelyWhite) { ASSERT(!isCompilationThread()); } -inline JSCell::JSCell(VM& vm, Structure* structure) - : m_structure(vm, this, structure) +inline JSCell::JSCell(VM&, Structure* structure) + : m_structureID(structure->id()) + , m_indexingTypeAndMisc(structure->indexingTypeIncludingHistory()) + , m_type(structure->typeInfo().type()) + , m_flags(structure->typeInfo().inlineTypeFlags()) + , m_cellState(CellState::DefinitelyWhite) { ASSERT(!isCompilationThread()); } inline void JSCell::finishCreation(VM& vm) { + // This object is ready to be escaped so the concurrent GC may see it at any time. We have + // to make sure that none of our stores sink below here. + vm.heap.mutatorFence(); #if ENABLE(GC_VALIDATION) ASSERT(vm.isInitializingObject()); vm.setInitializingObjectClass(0); #else UNUSED_PARAM(vm); #endif - ASSERT(m_structure); + ASSERT(m_structureID); } inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCellTag) @@ -64,23 +75,70 @@ inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCe #if ENABLE(GC_VALIDATION) ASSERT(vm.isInitializingObject()); vm.setInitializingObjectClass(0); - if (structure) + if (structure) { +#endif + m_structureID = structure->id(); + m_indexingTypeAndMisc = structure->indexingTypeIncludingHistory(); + m_type = structure->typeInfo().type(); + m_flags = structure->typeInfo().inlineTypeFlags(); +#if ENABLE(GC_VALIDATION) + } +#else + UNUSED_PARAM(vm); #endif - m_structure.setEarlyValue(vm, this, structure); // Very first set of allocations won't have a real structure. - ASSERT(m_structure || !vm.structureStructure); + ASSERT(m_structureID || !vm.structureStructure); } -inline Structure* JSCell::structure() const +inline JSType JSCell::type() const { - return m_structure.get(); + return m_type; +} + +inline IndexingType JSCell::indexingTypeAndMisc() const +{ + return m_indexingTypeAndMisc; +} + +inline IndexingType JSCell::indexingType() const +{ + return indexingTypeAndMisc() & AllArrayTypes; +} + +ALWAYS_INLINE Structure* JSCell::structure() const +{ + return structure(*vm()); +} + +ALWAYS_INLINE Structure* JSCell::structure(VM& vm) const +{ + return vm.getStructure(m_structureID); } inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) { - MARK_LOG_PARENT(visitor, cell); + visitor.appendUnbarriered(cell->structure(visitor.vm())); +} - visitor.append(&cell->m_structure); +inline void JSCell::visitOutputConstraints(JSCell*, SlotVisitor&) +{ +} + +ALWAYS_INLINE VM& ExecState::vm() const +{ + ASSERT(callee()); + ASSERT(callee()->vm()); + ASSERT(!callee()->isLargeAllocation()); + // This is an important optimization since we access this so often. + return *callee()->markedBlock().vm(); +} + +template<typename CellType> +Subspace* JSCell::subspaceFor(VM& vm) +{ + if (CellType::needsDestruction) + return &vm.destructibleCellSpace; + return &vm.cellSpace; } template<typename T> @@ -88,13 +146,7 @@ void* allocateCell(Heap& heap, size_t size) { ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread()); ASSERT(size >= sizeof(T)); - JSCell* result = 0; - if (T::needsDestruction && T::hasImmortalStructure) - result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size)); - else if (T::needsDestruction) - result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size)); - else - result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); + JSCell* result = static_cast<JSCell*>(subspaceFor<T>(*heap.vm())->allocate(size)); #if ENABLE(GC_VALIDATION) ASSERT(!heap.vm()->isInitializingObject()); heap.vm()->setInitializingObjectClass(T::info()); @@ -109,94 +161,189 @@ void* allocateCell(Heap& heap) return allocateCell<T>(heap, sizeof(T)); } -inline bool isZapped(const JSCell* cell) +template<typename T> +void* allocateCell(Heap& heap, GCDeferralContext* deferralContext, size_t size) { - return cell->isZapped(); + ASSERT(size >= sizeof(T)); + JSCell* result = static_cast<JSCell*>(subspaceFor<T>(*heap.vm())->allocate(deferralContext, size)); +#if ENABLE(GC_VALIDATION) + ASSERT(!heap.vm()->isInitializingObject()); + heap.vm()->setInitializingObjectClass(T::info()); +#endif + result->clearStructure(); + return result; } - + +template<typename T> +void* allocateCell(Heap& heap, GCDeferralContext* deferralContext) +{ + return allocateCell<T>(heap, deferralContext, sizeof(T)); +} + inline bool JSCell::isObject() const { - return m_structure->isObject(); + return TypeInfo::isObject(m_type); } inline bool JSCell::isString() const { - return m_structure->typeInfo().type() == StringType; + return m_type == StringType; +} + +inline bool JSCell::isSymbol() const +{ + return m_type == SymbolType; } inline bool JSCell::isGetterSetter() const { - return m_structure->typeInfo().type() == GetterSetterType; + return m_type == GetterSetterType; +} + +inline bool JSCell::isCustomGetterSetter() const +{ + return m_type == CustomGetterSetterType; } inline bool JSCell::isProxy() const { - return structure()->typeInfo().type() == ProxyType; + return m_type == ImpureProxyType || m_type == PureForwardingProxyType; } inline bool JSCell::isAPIValueWrapper() const { - return m_structure->typeInfo().type() == APIValueWrapperType; + return m_type == APIValueWrapperType; } -inline void JSCell::setStructure(VM& vm, Structure* structure) +ALWAYS_INLINE void JSCell::setStructure(VM& vm, Structure* structure) { - ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren()); - ASSERT(structure->classInfo() == m_structure->classInfo()); - ASSERT(!m_structure - || m_structure->transitionWatchpointSetHasBeenInvalidated() - || m_structure.get() == structure); - m_structure.set(vm, this, structure); + ASSERT(structure->classInfo() == this->structure()->classInfo()); + ASSERT(!this->structure() + || this->structure()->transitionWatchpointSetHasBeenInvalidated() + || Heap::heap(this)->structureIDTable().get(structure->id()) == structure); + m_structureID = structure->id(); + m_flags = structure->typeInfo().inlineTypeFlags(); + m_type = structure->typeInfo().type(); + IndexingType newIndexingType = structure->indexingTypeIncludingHistory(); + if (m_indexingTypeAndMisc != newIndexingType) { + ASSERT(!(newIndexingType & ~AllArrayTypesAndHistory)); + for (;;) { + IndexingType oldValue = m_indexingTypeAndMisc; + IndexingType newValue = (oldValue & ~AllArrayTypesAndHistory) | structure->indexingTypeIncludingHistory(); + if (WTF::atomicCompareExchangeWeakRelaxed(&m_indexingTypeAndMisc, oldValue, newValue)) + break; + } + } + vm.heap.writeBarrier(this, structure); } -inline const MethodTable* JSCell::methodTableForDestruction() const +inline const MethodTable* JSCell::methodTable() const { - return &classInfo()->methodTable; + VM& vm = *Heap::heap(this)->vm(); + return methodTable(vm); } -inline const MethodTable* JSCell::methodTable() const +inline const MethodTable* JSCell::methodTable(VM& vm) const { - if (Structure* rootStructure = m_structure->structure()) - RELEASE_ASSERT(rootStructure == rootStructure->structure()); + Structure* structure = this->structure(vm); + if (Structure* rootStructure = structure->structure(vm)) + ASSERT_UNUSED(rootStructure, rootStructure == rootStructure->structure(vm)); - return &classInfo()->methodTable; + return &structure->classInfo()->methodTable; } -inline bool JSCell::inherits(const ClassInfo* info) const +inline bool JSCell::inherits(VM& vm, const ClassInfo* info) const { - return classInfo()->isSubClassOf(info); + return classInfo(vm)->isSubClassOf(info); } -// Fast call to get a property where we may not yet have converted the string to an -// identifier. The first time we perform a property access with a given string, try -// performing the property map lookup without forming an identifier. We detect this -// case by checking whether the hash has yet been set for this string. -ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const String& name) +ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, PropertyName name) { - if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) { - PropertyOffset offset = name.impl()->hasHash() - ? structure()->get(exec->vm(), Identifier(exec, name)) - : structure()->get(exec->vm(), name); - if (offset != invalidOffset) - return asObject(this)->locationForOffset(offset)->get(); - } + ASSERT(canUseFastGetOwnProperty(structure)); + PropertyOffset offset = structure.get(vm, name); + if (offset != invalidOffset) + return asObject(this)->locationForOffset(offset)->get(); return JSValue(); } +inline bool JSCell::canUseFastGetOwnProperty(const Structure& structure) +{ + return !structure.hasGetterSetterProperties() + && !structure.hasCustomGetterSetterProperties() + && !structure.typeInfo().overridesGetOwnPropertySlot(); +} + +ALWAYS_INLINE const ClassInfo* JSCell::classInfo(VM& vm) const +{ + // What we really want to assert here is that we're not currently destructing this object (which makes its classInfo + // invalid). If mutatorState() == MutatorState::Running, then we're not currently sweeping, and therefore cannot be + // destructing the object. The GC thread or JIT threads, unlike the mutator thread, are able to access classInfo + // independent of whether the mutator thread is sweeping or not. Hence, we also check for ownerThread() != + // std::this_thread::get_id() to allow the GC thread or JIT threads to pass this assertion. + ASSERT(vm.heap.mutatorState() != MutatorState::Sweeping || vm.apiLock().ownerThread() != std::this_thread::get_id()); + return structure(vm)->classInfo(); +} + inline bool JSCell::toBoolean(ExecState* exec) const { - if (isString()) + if (isString()) return static_cast<const JSString*>(this)->toBoolean(); return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); } inline TriState JSCell::pureToBoolean() const { - if (isString()) + if (isString()) return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState; + if (isSymbol()) + return TrueTriState; return MixedTriState; } -} // namespace JSC +inline void JSCell::callDestructor(VM& vm) +{ + if (isZapped()) + return; + ASSERT(structureID()); + if (inlineTypeFlags() & StructureIsImmortal) { + Structure* structure = this->structure(vm); + const ClassInfo* classInfo = structure->classInfo(); + MethodTable::DestroyFunctionPtr destroy = classInfo->methodTable.destroy; + destroy(this); + } else + static_cast<JSDestructibleObject*>(this)->classInfo()->methodTable.destroy(this); + zap(); +} + +inline void JSCell::lock() +{ + Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc); + IndexingTypeLockAlgorithm::lock(*lock); +} + +inline bool JSCell::tryLock() +{ + Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc); + return IndexingTypeLockAlgorithm::tryLock(*lock); +} + +inline void JSCell::unlock() +{ + Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc); + IndexingTypeLockAlgorithm::unlock(*lock); +} + +inline bool JSCell::isLocked() const +{ + Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc); + return IndexingTypeLockAlgorithm::isLocked(*lock); +} -#endif // JSCellInlines_h +inline JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const +{ + if (isObject()) + return jsCast<JSObject*>(const_cast<JSCell*>(this)); + return toObjectSlow(exec, globalObject); +} + +} // namespace JSC |