mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2024-11-26 21:50:53 +00:00
297 lines
10 KiB
C++
297 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2008-2019 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. ``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
|
|
* 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "IndexingType.h"
|
|
#include "WeakGCMap.h"
|
|
#include <wtf/HashFunctions.h>
|
|
#include <wtf/text/UniquedStringImpl.h>
|
|
|
|
namespace JSC {
|
|
|
|
class JSCell;
|
|
class Structure;
|
|
|
|
using TransitionPropertyAttributes = uint8_t;
|
|
|
|
enum class TransitionKind : uint8_t {
|
|
Unknown,
|
|
PropertyAddition,
|
|
PropertyDeletion,
|
|
PropertyAttributeChange,
|
|
|
|
// Support for transitions not related to properties.
|
|
// If any of these are used, the string portion of the key should be 0.
|
|
AllocateUndecided,
|
|
AllocateInt32,
|
|
AllocateDouble,
|
|
AllocateContiguous,
|
|
AllocateArrayStorage,
|
|
AllocateSlowPutArrayStorage,
|
|
SwitchToSlowPutArrayStorage,
|
|
AddIndexedAccessors,
|
|
PreventExtensions,
|
|
Seal,
|
|
Freeze
|
|
};
|
|
|
|
static constexpr auto FirstNonPropertyTransitionKind = TransitionKind::AllocateUndecided;
|
|
|
|
inline bool changesIndexingType(TransitionKind transition)
|
|
{
|
|
switch (transition) {
|
|
case TransitionKind::AllocateUndecided:
|
|
case TransitionKind::AllocateInt32:
|
|
case TransitionKind::AllocateDouble:
|
|
case TransitionKind::AllocateContiguous:
|
|
case TransitionKind::AllocateArrayStorage:
|
|
case TransitionKind::AllocateSlowPutArrayStorage:
|
|
case TransitionKind::SwitchToSlowPutArrayStorage:
|
|
case TransitionKind::AddIndexedAccessors:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline IndexingType newIndexingType(IndexingType oldType, TransitionKind transition)
|
|
{
|
|
switch (transition) {
|
|
case TransitionKind::AllocateUndecided:
|
|
ASSERT(!hasIndexedProperties(oldType));
|
|
return oldType | UndecidedShape;
|
|
case TransitionKind::AllocateInt32:
|
|
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || oldType == CopyOnWriteArrayWithInt32);
|
|
return (oldType & ~IndexingShapeAndWritabilityMask) | Int32Shape;
|
|
case TransitionKind::AllocateDouble:
|
|
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || oldType == CopyOnWriteArrayWithDouble);
|
|
return (oldType & ~IndexingShapeAndWritabilityMask) | DoubleShape;
|
|
case TransitionKind::AllocateContiguous:
|
|
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || oldType == CopyOnWriteArrayWithContiguous);
|
|
return (oldType & ~IndexingShapeAndWritabilityMask) | ContiguousShape;
|
|
case TransitionKind::AllocateArrayStorage:
|
|
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
|
|
return (oldType & ~IndexingShapeAndWritabilityMask) | ArrayStorageShape;
|
|
case TransitionKind::AllocateSlowPutArrayStorage:
|
|
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
|
|
return (oldType & ~IndexingShapeAndWritabilityMask) | SlowPutArrayStorageShape;
|
|
case TransitionKind::SwitchToSlowPutArrayStorage:
|
|
ASSERT(hasArrayStorage(oldType));
|
|
return (oldType & ~IndexingShapeAndWritabilityMask) | SlowPutArrayStorageShape;
|
|
case TransitionKind::AddIndexedAccessors:
|
|
return oldType | MayHaveIndexedAccessors;
|
|
default:
|
|
return oldType;
|
|
}
|
|
}
|
|
|
|
inline bool preventsExtensions(TransitionKind transition)
|
|
{
|
|
switch (transition) {
|
|
case TransitionKind::PreventExtensions:
|
|
case TransitionKind::Seal:
|
|
case TransitionKind::Freeze:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline bool setsDontDeleteOnAllProperties(TransitionKind transition)
|
|
{
|
|
switch (transition) {
|
|
case TransitionKind::Seal:
|
|
case TransitionKind::Freeze:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline bool setsReadOnlyOnNonAccessorProperties(TransitionKind transition)
|
|
{
|
|
switch (transition) {
|
|
case TransitionKind::Freeze:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class StructureTransitionTable {
|
|
static constexpr intptr_t UsingSingleSlotFlag = 1;
|
|
|
|
|
|
#if CPU(ADDRESS64)
|
|
struct Hash {
|
|
// Logically, Key is a tuple of (1) UniquedStringImpl*, (2) unsigned attributes, and (3) transitionKind.
|
|
struct Key {
|
|
friend struct Hash;
|
|
static_assert(WTF_OS_CONSTANT_EFFECTIVE_ADDRESS_WIDTH <= 48);
|
|
static constexpr unsigned attributesShift = 48;
|
|
static constexpr unsigned transitionKindShift = 56;
|
|
static constexpr uintptr_t stringMask = (1ULL << attributesShift) - 1;
|
|
static constexpr uintptr_t hashTableDeletedValue = 0x2;
|
|
static_assert(sizeof(TransitionPropertyAttributes) * 8 <= 8);
|
|
static_assert(sizeof(TransitionKind) * 8 <= 8);
|
|
static_assert(hashTableDeletedValue < alignof(UniquedStringImpl));
|
|
|
|
// Highest 8 bits are for TransitionKind; next 8 belong to TransitionPropertyAttributes.
|
|
// Remaining bits are for UniquedStringImpl*.
|
|
Key(UniquedStringImpl* impl, unsigned attributes, TransitionKind transitionKind)
|
|
: m_encodedData(bitwise_cast<uintptr_t>(impl) | (static_cast<uintptr_t>(attributes) << attributesShift) | (static_cast<uintptr_t>(transitionKind) << transitionKindShift))
|
|
{
|
|
ASSERT(impl == this->impl());
|
|
ASSERT(attributes <= UINT8_MAX);
|
|
ASSERT(attributes == this->attributes());
|
|
ASSERT(transitionKind != TransitionKind::Unknown);
|
|
ASSERT(transitionKind == this->transitionKind());
|
|
}
|
|
|
|
Key() = default;
|
|
|
|
Key(WTF::HashTableDeletedValueType)
|
|
: m_encodedData(hashTableDeletedValue)
|
|
{ }
|
|
|
|
bool isHashTableDeletedValue() const { return m_encodedData == hashTableDeletedValue; }
|
|
|
|
UniquedStringImpl* impl() const { return bitwise_cast<UniquedStringImpl*>(m_encodedData & stringMask); }
|
|
TransitionPropertyAttributes attributes() const { return (m_encodedData >> attributesShift) & UINT8_MAX; }
|
|
TransitionKind transitionKind() const { return static_cast<TransitionKind>(m_encodedData >> transitionKindShift); }
|
|
|
|
friend bool operator==(const Key& a, const Key& b)
|
|
{
|
|
return a.m_encodedData == b.m_encodedData;
|
|
}
|
|
|
|
friend bool operator!=(const Key& a, const Key& b)
|
|
{
|
|
return a.m_encodedData != b.m_encodedData;
|
|
}
|
|
|
|
private:
|
|
uintptr_t m_encodedData { 0 };
|
|
};
|
|
using KeyTraits = SimpleClassHashTraits<Key>;
|
|
|
|
static unsigned hash(const Key& p)
|
|
{
|
|
return IntHash<uintptr_t>::hash(p.m_encodedData);
|
|
}
|
|
|
|
static bool equal(const Key& a, const Key& b)
|
|
{
|
|
return a == b;
|
|
}
|
|
|
|
static constexpr bool safeToCompareToEmptyOrDeleted = true;
|
|
};
|
|
#else
|
|
struct Hash {
|
|
using Key = std::tuple<UniquedStringImpl*, unsigned, TransitionKind>;
|
|
using KeyTraits = HashTraits<Key>;
|
|
|
|
static unsigned hash(const Key& p)
|
|
{
|
|
return PtrHash<UniquedStringImpl*>::hash(std::get<0>(p)) + std::get<1>(p) + static_cast<unsigned>(std::get<2>(p));
|
|
}
|
|
|
|
static bool equal(const Key& a, const Key& b)
|
|
{
|
|
return a == b;
|
|
}
|
|
|
|
static constexpr bool safeToCompareToEmptyOrDeleted = true;
|
|
};
|
|
#endif
|
|
|
|
typedef WeakGCMap<Hash::Key, Structure, Hash, Hash::KeyTraits> TransitionMap;
|
|
|
|
public:
|
|
StructureTransitionTable()
|
|
: m_data(UsingSingleSlotFlag)
|
|
{
|
|
}
|
|
|
|
~StructureTransitionTable()
|
|
{
|
|
if (!isUsingSingleSlot()) {
|
|
delete map();
|
|
return;
|
|
}
|
|
|
|
WeakImpl* impl = this->weakImpl();
|
|
if (!impl)
|
|
return;
|
|
WeakSet::deallocate(impl);
|
|
}
|
|
|
|
void add(VM&, Structure*);
|
|
bool contains(UniquedStringImpl*, unsigned attributes, TransitionKind) const;
|
|
Structure* get(UniquedStringImpl*, unsigned attributes, TransitionKind) const;
|
|
|
|
private:
|
|
friend class SingleSlotTransitionWeakOwner;
|
|
|
|
bool isUsingSingleSlot() const
|
|
{
|
|
return m_data & UsingSingleSlotFlag;
|
|
}
|
|
|
|
TransitionMap* map() const
|
|
{
|
|
ASSERT(!isUsingSingleSlot());
|
|
return bitwise_cast<TransitionMap*>(m_data);
|
|
}
|
|
|
|
WeakImpl* weakImpl() const
|
|
{
|
|
ASSERT(isUsingSingleSlot());
|
|
return bitwise_cast<WeakImpl*>(m_data & ~UsingSingleSlotFlag);
|
|
}
|
|
|
|
void setMap(TransitionMap* map)
|
|
{
|
|
ASSERT(isUsingSingleSlot());
|
|
|
|
if (WeakImpl* impl = this->weakImpl())
|
|
WeakSet::deallocate(impl);
|
|
|
|
// This implicitly clears the flag that indicates we're using a single transition
|
|
m_data = bitwise_cast<intptr_t>(map);
|
|
|
|
ASSERT(!isUsingSingleSlot());
|
|
}
|
|
|
|
Structure* singleTransition() const;
|
|
void setSingleTransition(Structure*);
|
|
|
|
intptr_t m_data;
|
|
};
|
|
|
|
} // namespace JSC
|