mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2025-02-17 02:18:14 +00:00
286 lines
9.2 KiB
C++
286 lines
9.2 KiB
C++
/*
|
|
* Copyright (C) 2011-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
|
|
|
|
#if ENABLE(DFG_JIT)
|
|
|
|
#include "DFGRegisteredStructureSet.h"
|
|
#include "DFGTransition.h"
|
|
#include "DumpContext.h"
|
|
#include "JSCast.h"
|
|
#include "SpeculatedType.h"
|
|
#include "StructureSet.h"
|
|
|
|
namespace JSC {
|
|
|
|
class TrackedReferences;
|
|
|
|
namespace DFG {
|
|
|
|
class StructureAbstractValue {
|
|
public:
|
|
StructureAbstractValue() { }
|
|
StructureAbstractValue(RegisteredStructure structure)
|
|
: m_set(structure)
|
|
{
|
|
setClobbered(false);
|
|
}
|
|
StructureAbstractValue(const RegisteredStructureSet& other)
|
|
: m_set(other)
|
|
{
|
|
setClobbered(false);
|
|
}
|
|
ALWAYS_INLINE StructureAbstractValue(const StructureAbstractValue& other)
|
|
: m_set(other.m_set)
|
|
{
|
|
setClobbered(other.isClobbered());
|
|
}
|
|
|
|
ALWAYS_INLINE StructureAbstractValue& operator=(RegisteredStructure structure)
|
|
{
|
|
m_set = RegisteredStructureSet(structure);
|
|
setClobbered(false);
|
|
return *this;
|
|
}
|
|
ALWAYS_INLINE StructureAbstractValue& operator=(const RegisteredStructureSet& other)
|
|
{
|
|
m_set = other;
|
|
setClobbered(false);
|
|
return *this;
|
|
}
|
|
ALWAYS_INLINE StructureAbstractValue& operator=(const StructureAbstractValue& other)
|
|
{
|
|
m_set = other.m_set;
|
|
setClobbered(other.isClobbered());
|
|
return *this;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
m_set.clear();
|
|
setClobbered(false);
|
|
}
|
|
|
|
void makeTop()
|
|
{
|
|
m_set.deleteListIfNecessary();
|
|
m_set.m_pointer = topValue;
|
|
}
|
|
|
|
#if ASSERT_ENABLED
|
|
void assertIsRegistered(Graph&) const;
|
|
#else
|
|
void assertIsRegistered(Graph&) const { }
|
|
#endif
|
|
|
|
void clobber();
|
|
void observeInvalidationPoint() { setClobbered(false); }
|
|
|
|
void observeTransition(RegisteredStructure from, RegisteredStructure to);
|
|
void observeTransitions(const TransitionVector&);
|
|
|
|
static StructureAbstractValue top()
|
|
{
|
|
StructureAbstractValue result;
|
|
result.m_set.m_pointer = topValue;
|
|
return result;
|
|
}
|
|
|
|
bool isClear() const { return m_set.isEmpty(); }
|
|
bool isTop() const { return m_set.m_pointer == topValue; }
|
|
bool isNeitherClearNorTop() const { return !isClear() && !isTop(); }
|
|
|
|
// A clobbered abstract value means that the set currently contains the m_set set of
|
|
// structures plus TOP, except that the "plus TOP" will go away at the next invalidation
|
|
// point. Note that it's tempting to think of this as "the set of structures in m_set plus
|
|
// the set of structures transition-reachable from m_set" - but this isn't really correct,
|
|
// since if we add an unwatchable structure after clobbering, the two definitions are not
|
|
// equivalent. If we do this, the new unwatchable structure will be added to m_set.
|
|
// Invalidation points do not try to "clip" the set of transition-reachable structures from
|
|
// m_set by looking at reachability as this would mean that the new set is TOP. Instead they
|
|
// literally assume that the set is just m_set rather than m_set plus TOP.
|
|
bool isClobbered() const { return m_set.getReservedFlag(); }
|
|
|
|
// A finite structure abstract value is one where enumerating over it will yield all
|
|
// of the structures that the value may have right now. This is true so long as we're
|
|
// neither top nor clobbered.
|
|
bool isFinite() const { return !isTop() && !isClobbered(); }
|
|
|
|
// An infinite structure abstract value may currently have any structure.
|
|
bool isInfinite() const { return !isFinite(); }
|
|
|
|
bool add(RegisteredStructure);
|
|
|
|
bool merge(const RegisteredStructureSet& other);
|
|
|
|
ALWAYS_INLINE bool merge(const StructureAbstractValue& other)
|
|
{
|
|
if (other.isClear())
|
|
return false;
|
|
|
|
if (isTop())
|
|
return false;
|
|
|
|
if (other.isTop()) {
|
|
makeTop();
|
|
return true;
|
|
}
|
|
|
|
return mergeSlow(other);
|
|
}
|
|
|
|
void filter(const RegisteredStructureSet& other);
|
|
void filter(const StructureAbstractValue& other);
|
|
|
|
ALWAYS_INLINE void filter(SpeculatedType type)
|
|
{
|
|
if (!(type & SpecCell)) {
|
|
clear();
|
|
return;
|
|
}
|
|
if (isNeitherClearNorTop())
|
|
filterSlow(type);
|
|
}
|
|
|
|
ALWAYS_INLINE void filterClassInfo(const ClassInfo* classInfo)
|
|
{
|
|
if (isNeitherClearNorTop())
|
|
filterClassInfoSlow(classInfo);
|
|
}
|
|
|
|
ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const
|
|
{
|
|
if ((m_set.isThin() && other.m_set.isThin()) || isTop() || other.isTop())
|
|
return m_set.m_pointer == other.m_set.m_pointer;
|
|
|
|
return equalsSlow(other);
|
|
}
|
|
|
|
const RegisteredStructureSet& set() const
|
|
{
|
|
ASSERT(!isTop());
|
|
return m_set;
|
|
}
|
|
|
|
StructureSet toStructureSet() const
|
|
{
|
|
RELEASE_ASSERT(isFinite());
|
|
return m_set.toStructureSet();
|
|
}
|
|
|
|
size_t size() const
|
|
{
|
|
ASSERT(!isTop());
|
|
return m_set.size();
|
|
}
|
|
|
|
RegisteredStructure at(size_t i) const
|
|
{
|
|
ASSERT(!isTop());
|
|
return m_set.at(i);
|
|
}
|
|
|
|
RegisteredStructure operator[](size_t i) const { return at(i); }
|
|
|
|
// In most cases, what you really want to do is verify whether the set is top or clobbered, and
|
|
// if not, enumerate the set of structures. Use this only in cases where the singleton case is
|
|
// meaningfully special, like for transitions.
|
|
RegisteredStructure onlyStructure() const
|
|
{
|
|
if (isInfinite())
|
|
return RegisteredStructure();
|
|
return m_set.onlyStructure();
|
|
}
|
|
|
|
template<typename Functor>
|
|
void forEach(const Functor& functor) const
|
|
{
|
|
ASSERT(!isTop());
|
|
m_set.forEach(functor);
|
|
}
|
|
|
|
void dumpInContext(PrintStream&, DumpContext*) const;
|
|
void dump(PrintStream&) const;
|
|
|
|
// The methods below are all conservative and err on the side of making 'this' appear bigger
|
|
// than it is. For example, contains() may return true if the set is clobbered or TOP.
|
|
// isSubsetOf() may return false in case of ambiguities. Therefore you should only perform
|
|
// optimizations as a consequence of the "this is smaller" return value - so false for
|
|
// contains(), true for isSubsetOf(), false for isSupersetOf(), and false for overlaps().
|
|
|
|
bool contains(RegisteredStructure) const;
|
|
JS_EXPORT_PRIVATE bool contains(Structure* structure) const;
|
|
|
|
bool isSubsetOf(const RegisteredStructureSet& other) const;
|
|
bool isSubsetOf(const StructureAbstractValue& other) const;
|
|
|
|
bool isSupersetOf(const RegisteredStructureSet& other) const;
|
|
bool isSupersetOf(const StructureAbstractValue& other) const
|
|
{
|
|
return other.isSubsetOf(*this);
|
|
}
|
|
|
|
bool overlaps(const RegisteredStructureSet& other) const;
|
|
bool overlaps(const StructureAbstractValue& other) const;
|
|
|
|
bool isSubClassOf(const ClassInfo*) const;
|
|
bool isNotSubClassOf(const ClassInfo*) const;
|
|
|
|
void validateReferences(const TrackedReferences&) const;
|
|
|
|
private:
|
|
static constexpr uintptr_t clobberedFlag = RegisteredStructureSet::reservedFlag;
|
|
static constexpr uintptr_t topValue = RegisteredStructureSet::reservedValue;
|
|
static constexpr unsigned polymorphismLimit = 10;
|
|
static constexpr unsigned clobberedSupremacyThreshold = 2;
|
|
|
|
void filterSlow(SpeculatedType type);
|
|
void filterClassInfoSlow(const ClassInfo*);
|
|
bool mergeSlow(const StructureAbstractValue& other);
|
|
|
|
bool equalsSlow(const StructureAbstractValue& other) const;
|
|
|
|
void makeTopWhenThin()
|
|
{
|
|
ASSERT(m_set.isThin());
|
|
m_set.m_pointer = topValue;
|
|
}
|
|
|
|
bool mergeNotTop(const RegisteredStructureSet& other);
|
|
|
|
void setClobbered(bool clobbered)
|
|
{
|
|
ASSERT(!isTop() || !clobbered);
|
|
m_set.setReservedFlag(clobbered);
|
|
}
|
|
|
|
RegisteredStructureSet m_set;
|
|
};
|
|
|
|
} } // namespace JSC::DFG
|
|
|
|
#endif // ENABLE(DFG_JIT)
|