blob: 1966ffa20f2583a3daef9589855f360185918637 [file] [log] [blame]
/*
* Copyright (C) 2018 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 "BytecodeIndex.h"
#include "Instruction.h"
#include <wtf/Vector.h>
namespace JSC {
DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(InstructionStream);
class InstructionStream {
WTF_MAKE_FAST_ALLOCATED;
using InstructionBuffer = Vector<uint8_t, 0, UnsafeVectorOverflow, 16, InstructionStreamMalloc>;
friend class InstructionStreamWriter;
friend class CachedInstructionStream;
public:
size_t sizeInBytes() const;
using Offset = unsigned;
private:
template<class InstructionBuffer>
class BaseRef {
WTF_MAKE_FAST_ALLOCATED;
friend class InstructionStream;
public:
BaseRef(const BaseRef<InstructionBuffer>& other)
: m_instructions(other.m_instructions)
, m_index(other.m_index)
{ }
void operator=(const BaseRef<InstructionBuffer>& other)
{
m_instructions = other.m_instructions;
m_index = other.m_index;
}
inline const Instruction* operator->() const { return unwrap(); }
inline const Instruction* ptr() const { return unwrap(); }
bool operator!=(const BaseRef<InstructionBuffer>& other) const
{
return &m_instructions != &other.m_instructions || m_index != other.m_index;
}
BaseRef next() const
{
return BaseRef { m_instructions, m_index + ptr()->size() };
}
inline Offset offset() const { return m_index; }
inline BytecodeIndex index() const { return BytecodeIndex(offset()); }
bool isValid() const
{
return m_index < m_instructions.size();
}
private:
inline const Instruction* unwrap() const { return reinterpret_cast<const Instruction*>(&m_instructions[m_index]); }
protected:
BaseRef(InstructionBuffer& instructions, size_t index)
: m_instructions(instructions)
, m_index(index)
{ }
InstructionBuffer& m_instructions;
Offset m_index;
};
public:
using Ref = BaseRef<const InstructionBuffer>;
class MutableRef : public BaseRef<InstructionBuffer> {
friend class InstructionStreamWriter;
protected:
using BaseRef<InstructionBuffer>::BaseRef;
public:
Ref freeze() const { return Ref { m_instructions, m_index }; }
inline Instruction* operator->() { return unwrap(); }
inline Instruction* ptr() { return unwrap(); }
inline operator Ref()
{
return Ref { m_instructions, m_index };
}
private:
inline Instruction* unwrap() { return reinterpret_cast<Instruction*>(&m_instructions[m_index]); }
};
private:
class iterator : public Ref {
friend class InstructionStream;
public:
using Ref::Ref;
Ref& operator*()
{
return *this;
}
iterator& operator+=(size_t size)
{
m_index += size;
return *this;
}
iterator& operator++()
{
return *this += ptr()->size();
}
};
public:
inline iterator begin() const
{
return iterator { m_instructions, 0 };
}
inline iterator end() const
{
return iterator { m_instructions, m_instructions.size() };
}
inline const Ref at(BytecodeIndex index) const { return at(index.offset()); }
inline const Ref at(Offset offset) const
{
ASSERT(offset < m_instructions.size());
return Ref { m_instructions, offset };
}
inline size_t size() const
{
return m_instructions.size();
}
const void* rawPointer() const
{
return m_instructions.data();
}
bool contains(Instruction *) const;
protected:
explicit InstructionStream(InstructionBuffer&&);
InstructionBuffer m_instructions;
};
class InstructionStreamWriter : public InstructionStream {
friend class BytecodeRewriter;
public:
InstructionStreamWriter()
: InstructionStream({ })
{ }
inline MutableRef ref(Offset offset)
{
ASSERT(offset < m_instructions.size());
return MutableRef { m_instructions, offset };
}
void seek(unsigned position)
{
ASSERT(position <= m_instructions.size());
m_position = position;
}
unsigned position()
{
return m_position;
}
void write(uint8_t byte)
{
ASSERT(!m_finalized);
if (m_position < m_instructions.size())
m_instructions[m_position++] = byte;
else {
m_instructions.append(byte);
m_position++;
}
}
void write(uint16_t h)
{
ASSERT(!m_finalized);
uint8_t bytes[2];
std::memcpy(bytes, &h, sizeof(h));
// Though not always obvious, we don't have to invert the order of the
// bytes written here for CPU(BIG_ENDIAN). This is because the incoming
// i value is already ordered in big endian on CPU(BIG_EDNDIAN) platforms.
write(bytes[0]);
write(bytes[1]);
}
void write(uint32_t i)
{
ASSERT(!m_finalized);
uint8_t bytes[4];
std::memcpy(bytes, &i, sizeof(i));
// Though not always obvious, we don't have to invert the order of the
// bytes written here for CPU(BIG_ENDIAN). This is because the incoming
// i value is already ordered in big endian on CPU(BIG_EDNDIAN) platforms.
write(bytes[0]);
write(bytes[1]);
write(bytes[2]);
write(bytes[3]);
}
void rewind(MutableRef& ref)
{
ASSERT(ref.offset() < m_instructions.size());
m_instructions.shrink(ref.offset());
m_position = ref.offset();
}
std::unique_ptr<InstructionStream> finalize()
{
m_finalized = true;
m_instructions.shrinkToFit();
return std::unique_ptr<InstructionStream> { new InstructionStream(WTFMove(m_instructions)) };
}
MutableRef ref()
{
return MutableRef { m_instructions, m_position };
}
void swap(InstructionStreamWriter& other)
{
std::swap(m_finalized, other.m_finalized);
std::swap(m_position, other.m_position);
m_instructions.swap(other.m_instructions);
}
private:
class iterator : public MutableRef {
friend class InstructionStreamWriter;
protected:
using MutableRef::MutableRef;
public:
MutableRef& operator*()
{
return *this;
}
iterator& operator+=(size_t size)
{
m_index += size;
return *this;
}
iterator& operator++()
{
return *this += ptr()->size();
}
};
public:
iterator begin()
{
return iterator { m_instructions, 0 };
}
iterator end()
{
return iterator { m_instructions, m_instructions.size() };
}
private:
unsigned m_position { 0 };
bool m_finalized { false };
};
} // namespace JSC