/*
* Copyright (C) 2008-2023 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
#include
#include
#include
#include
#include
#include
#include
namespace JSC {
class PCToCodeOriginMap;
namespace DFG {
class CommonData;
class JITCode;
}
namespace FTL {
class ForOSREntryJITCode;
class JITCode;
}
namespace DOMJIT {
class Signature;
}
class TrackedReferences;
class VM;
struct PropertyInlineCacheIndex {
explicit PropertyInlineCacheIndex(unsigned index)
: m_index(index)
{ }
unsigned m_index { 0 };
};
enum class JITType : uint8_t {
None = 0b000,
HostCallThunk = 0b001,
InterpreterThunk = 0b010,
BaselineJIT = 0b011,
DFGJIT = 0b100,
FTLJIT = 0b101,
};
static constexpr unsigned widthOfJITType = 3;
static_assert(WTF::getMSBSet(static_cast(JITType::FTLJIT)) + 1 == widthOfJITType);
#if ENABLE(JIT)
template
class JITConstant {
static_assert(sizeof(ByteSizedEnumType) == 1);
static constexpr uint64_t typeShift = 48;
static constexpr uint64_t typeMask = 0xffull typeShift); }
void setType(ByteSizedEnumType type) { m_encodedPointer = encode(pointer(), type); }
friend bool operator==(const JITConstant&, const JITConstant&) = default;
};
#endif // ENABLE(JIT)
class JITCode : public ThreadSafeRefCounted {
public:
template using CodeRef = MacroAssemblerCodeRef;
static ASCIILiteral typeName(JITType);
static JITType bottomTierJIT()
{
return JITType::BaselineJIT;
}
static JITType topTierJIT()
{
return JITType::FTLJIT;
}
static JITType nextTierJIT(JITType jitType)
{
switch (jitType) {
case JITType::BaselineJIT:
return JITType::DFGJIT;
case JITType::DFGJIT:
return JITType::FTLJIT;
default:
RELEASE_ASSERT_NOT_REACHED();
return JITType::None;
}
}
static bool isExecutableScript(JITType jitType)
{
switch (jitType) {
case JITType::None:
case JITType::HostCallThunk:
return false;
default:
return true;
}
}
static bool couldBeInterpreted(JITType jitType)
{
switch (jitType) {
case JITType::InterpreterThunk:
case JITType::BaselineJIT:
return true;
default:
return false;
}
}
static bool isJIT(JITType jitType)
{
switch (jitType) {
case JITType::BaselineJIT:
case JITType::DFGJIT:
case JITType::FTLJIT:
return true;
default:
return false;
}
}
static bool isLowerTierPrecise(JITType expectedLower, JITType expectedHigher)
{
RELEASE_ASSERT(isExecutableScript(expectedLower));
RELEASE_ASSERT(isExecutableScript(expectedHigher));
return expectedLower < expectedHigher;
}
static bool isHigherTier(JITType expectedHigher, JITType expectedLower)
{
return isLowerTierPrecise(expectedLower, expectedHigher);
}
static bool isLowerOrSameTier(JITType expectedLower, JITType expectedHigher)
{
return !isHigherTier(expectedLower, expectedHigher);
}
static bool isHigherOrSameTier(JITType expectedHigher, JITType expectedLower)
{
return isLowerOrSameTier(expectedLower, expectedHigher);
}
static bool isOptimizingJIT(JITType jitType)
{
return jitType == JITType::DFGJIT || jitType == JITType::FTLJIT;
}
static bool isBaselineCode(JITType jitType)
{
return jitType == JITType::InterpreterThunk || jitType == JITType::BaselineJIT;
}
virtual const DOMJIT::Signature* signature() const { return nullptr; }
virtual bool canSwapCodeRefForDebugger() const { return false; }
virtual CodeRef swapCodeRefForDebugger(CodeRef);
virtual bool canSwapCodePtrWithArityCheckForDebugger() const { return false; }
virtual CodePtr swapCodePtrWithArityCheckForDebugger(CodePtr);
enum class ShareAttribute : uint8_t {
NotShared,
Shared
};
protected:
JITCode(JITType, CodePtr = nullptr, JITCode::ShareAttribute = JITCode::ShareAttribute::NotShared);
public:
virtual ~JITCode();
JITType jitType() const
{
return m_jitType;
}
bool NODELETE isUnlinked() const;
template
static JITType jitTypeFor(PointerType jitCode)
{
if (!jitCode)
return JITType::None;
return jitCode->jitType();
}
void* addressForCall() const { return m_addressForCall.taggedPtr(); }
virtual CodePtr addressForCall(ArityCheckMode) = 0;
virtual void* executableAddressAtOffset(size_t offset) = 0;
void* executableAddress() { return executableAddressAtOffset(0); }
virtual void* dataAddressAtOffset(size_t offset) = 0;
virtual unsigned offsetOf(void* pointerIntoCode) = 0;
virtual DFG::CommonData* dfgCommon();
virtual const DFG::CommonData* dfgCommon() const;
virtual DFG::JITCode* dfg();
virtual FTL::JITCode* ftl();
virtual FTL::ForOSREntryJITCode* ftlForOSREntry();
virtual void shrinkToFit();
virtual void validateReferences(const TrackedReferences&);
void* start() { return dataAddressAtOffset(0); }
virtual size_t size() = 0;
void* end() { return reinterpret_cast(reinterpret_cast(start()) + size()); }
virtual bool contains(void*) = 0;
#if ENABLE(JIT)
virtual RegisterSet liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex);
virtual std::optional findPC(CodeBlock*, void* pc) { UNUSED_PARAM(pc); return std::nullopt; }
#endif
Intrinsic intrinsic() { return m_intrinsic; }
bool isShared() const { return m_shareAttribute == ShareAttribute::Shared; }
virtual PCToCodeOriginMap* pcToCodeOriginMap() { return nullptr; }
const RegisterAtOffsetList* calleeSaveRegisters() const;
static constexpr ptrdiff_t offsetOfJITType() { return OBJECT_OFFSETOF(JSC::JITCode, m_jitType); }
private:
const JITType m_jitType;
const ShareAttribute m_shareAttribute;
protected:
Intrinsic m_intrinsic { NoIntrinsic }; // Effective only in NativeExecutable.
CodePtr m_addressForCall;
};
class JITCodeWithCodeRef : public JSC::JITCode {
protected:
JITCodeWithCodeRef(JITType);
JITCodeWithCodeRef(CodeRef, JITType, JITCode::ShareAttribute);
public:
~JITCodeWithCodeRef() override;
void* executableAddressAtOffset(size_t offset) override;
void* dataAddressAtOffset(size_t offset) override;
unsigned offsetOf(void* pointerIntoCode) override;
size_t size() override;
bool contains(void*) override;
CodeRef swapCodeRefForDebugger(CodeRef) override;
protected:
RefPtr m_executableMemory;
};
DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(DirectJITCode);
class DirectJITCode : public JITCodeWithCodeRef {
WTF_DEPRECATED_MAKE_STRUCT_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(DirectJITCode, DirectJITCode);
public:
DirectJITCode(JITType);
DirectJITCode(CodeRef, CodePtr withArityCheck, JITType, JITCode::ShareAttribute = JITCode::ShareAttribute::NotShared);
DirectJITCode(CodeRef, CodePtr withArityCheck, JITType, Intrinsic, JITCode::ShareAttribute = JITCode::ShareAttribute::NotShared); // For generated thunk.
~DirectJITCode() override;
CodePtr addressForCall(ArityCheckMode) override;
bool canSwapCodeRefForDebugger() const override { return jitType() == JITType::HostCallThunk; }
bool canSwapCodePtrWithArityCheckForDebugger() const override { return jitType() == JITType::HostCallThunk; }
CodePtr swapCodePtrWithArityCheckForDebugger(CodePtr) override;
protected:
void initializeCodeRefForDFG(CodeRef, CodePtr withArityCheck);
private:
CodePtr m_withArityCheck;
};
class NativeJITCode : public JITCodeWithCodeRef {
public:
NativeJITCode(JITType);
NativeJITCode(CodeRef, JITType, Intrinsic, JITCode::ShareAttribute = JITCode::ShareAttribute::NotShared);
~NativeJITCode() override;
CodePtr addressForCall(ArityCheckMode) override;
bool canSwapCodeRefForDebugger() const override { return true; }
};
class NativeDOMJITCode final : public NativeJITCode {
public:
NativeDOMJITCode(CodeRef, JITType, Intrinsic, const DOMJIT::Signature*);
~NativeDOMJITCode() final = default;
const DOMJIT::Signature* signature() const final { return m_signature; }
private:
const DOMJIT::Signature* m_signature;
};
} // namespace JSC
namespace WTF {
class PrintStream;
void printInternal(PrintStream&, JSC::JITType);
} // namespace WTF