blob: 4f47c8bccf8e5748aa9b0f36e6f36305adc30011 [file] [log] [blame]
/*
* Copyright (C) 2020 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 "ArrayProfile.h"
#include "BytecodeStructs.h"
#include "ValueProfile.h"
namespace JSC {
template<typename BytecodeMetadata>
ArrayProfile* arrayProfileForImpl(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
return &metadata.m_callLinkInfo.m_arrayProfile;
}
template<typename BytecodeMetadata>
bool hasArrayProfileFor(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
return arrayProfileForImpl(metadata, checkpointIndex);
}
template<typename BytecodeMetadata>
ArrayProfile& arrayProfileFor(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
ASSERT(hasArrayProfileFor(metadata, checkpointIndex));
return *arrayProfileForImpl(metadata, checkpointIndex);
}
template<typename BytecodeMetadata>
ValueProfile* valueProfileForImpl(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
if constexpr (BytecodeMetadata::opcodeID == op_iterator_open) {
switch (checkpointIndex) {
case OpIteratorOpen::symbolCall: return &metadata.m_iteratorProfile;
case OpIteratorOpen::getNext: return &metadata.m_nextProfile;
default: RELEASE_ASSERT_NOT_REACHED();
}
} else if constexpr (BytecodeMetadata::opcodeID == op_iterator_next) {
switch (checkpointIndex) {
case OpIteratorNext::computeNext: return &metadata.m_nextResultProfile;
case OpIteratorNext::getDone: return &metadata.m_doneProfile;
case OpIteratorNext::getValue: return &metadata.m_valueProfile;
default: RELEASE_ASSERT_NOT_REACHED();
}
} else
return &metadata.m_profile;
}
template <typename Bytecode>
uintptr_t valueProfileOffsetFor(unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
if constexpr (Bytecode::opcodeID == op_iterator_open) {
switch (checkpointIndex) {
case OpIteratorOpen::symbolCall: return Bytecode::Metadata::offsetOfIteratorProfile();
case OpIteratorOpen::getNext: return Bytecode::Metadata::offsetOfNextProfile();
default: RELEASE_ASSERT_NOT_REACHED();
}
} else if constexpr (Bytecode::opcodeID == op_iterator_next) {
switch (checkpointIndex) {
case OpIteratorNext::computeNext: return Bytecode::Metadata::offsetOfNextResultProfile();
case OpIteratorNext::getDone: return Bytecode::Metadata::offsetOfDoneProfile();
case OpIteratorNext::getValue: return Bytecode::Metadata::offsetOfValueProfile();
default: RELEASE_ASSERT_NOT_REACHED();
}
} else
return Bytecode::Metadata::offsetOfProfile();
}
template<typename BytecodeMetadata>
bool hasValueProfileFor(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
return valueProfileForImpl(metadata, checkpointIndex);
}
template<typename BytecodeMetadata>
ValueProfile& valueProfileFor(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
ASSERT(hasValueProfileFor(metadata, checkpointIndex));
return *valueProfileForImpl(metadata, checkpointIndex);
}
template<typename Bytecode>
Operand destinationFor(const Bytecode& bytecode, unsigned checkpointIndex, JITType type = JITType::None)
{
UNUSED_PARAM(checkpointIndex);
if constexpr (Bytecode::opcodeID == op_iterator_open) {
switch (checkpointIndex) {
case OpIteratorOpen::symbolCall: return bytecode.m_iterator;
case OpIteratorOpen::getNext: return bytecode.m_next;
default: RELEASE_ASSERT_NOT_REACHED();
}
return { };
} else if constexpr (Bytecode::opcodeID == op_iterator_next) {
switch (checkpointIndex) {
case OpIteratorNext::computeNext: {
if (type == JITType::DFGJIT || type == JITType::FTLJIT)
return Operand::tmp(OpIteratorNext::nextResult);
return bytecode.m_value; // We reuse value as a temp because its either not used in subsequent bytecodes or written as the temp object .
}
case OpIteratorNext::getDone: return bytecode.m_done;
case OpIteratorNext::getValue: return bytecode.m_value;
default: RELEASE_ASSERT_NOT_REACHED();
}
return { };
} else
return bytecode.m_dst;
}
// Call-like opcode locations
template<typename Bytecode>
VirtualRegister calleeFor(const Bytecode& bytecode, unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
if constexpr (Bytecode::opcodeID == op_iterator_open) {
ASSERT(checkpointIndex == OpIteratorOpen::symbolCall);
return bytecode.m_symbolIterator;
} else if constexpr (Bytecode::opcodeID == op_iterator_next) {
ASSERT(checkpointIndex == OpIteratorNext::computeNext);
return bytecode.m_next;
} else
return bytecode.m_callee;
}
template<typename Bytecode>
unsigned argumentCountIncludingThisFor(const Bytecode& bytecode, unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
if constexpr (Bytecode::opcodeID == op_iterator_open) {
ASSERT(checkpointIndex == OpIteratorOpen::symbolCall);
return 1;
} else if constexpr (Bytecode::opcodeID == op_iterator_next) {
ASSERT(checkpointIndex == OpIteratorNext::computeNext);
return 1;
} else
return bytecode.m_argc;
}
template<typename Bytecode>
ptrdiff_t stackOffsetInRegistersForCall(const Bytecode& bytecode, unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
if constexpr (Bytecode::opcodeID == op_iterator_open) {
ASSERT(checkpointIndex == OpIteratorOpen::symbolCall);
return CallFrame::headerSizeInRegisters - bytecode.m_iterable.offset();
} else if constexpr (Bytecode::opcodeID == op_iterator_next) {
ASSERT(checkpointIndex == OpIteratorNext::computeNext);
return CallFrame::headerSizeInRegisters - bytecode.m_iterator.offset();
} else
return bytecode.m_argv;
}
template<typename BytecodeMetadata>
LLIntCallLinkInfo& callLinkInfoFor(BytecodeMetadata& metadata, unsigned checkpointIndex)
{
UNUSED_PARAM(checkpointIndex);
return metadata.m_callLinkInfo;
}
} // namespace JSC