mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2024-11-23 04:09:40 +00:00
228 lines
5.7 KiB
C++
228 lines
5.7 KiB
C++
/*
|
|
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
|
|
* Copyright (C) 2003-2017 Apple Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "CallFrame.h"
|
|
#include <wtf/CheckedArithmetic.h>
|
|
#include <wtf/ForbidHeapAllocation.h>
|
|
#include <wtf/HashSet.h>
|
|
|
|
namespace JSC {
|
|
|
|
class MarkedArgumentBuffer : public RecordOverflow {
|
|
WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
|
|
WTF_MAKE_NONMOVABLE(MarkedArgumentBuffer);
|
|
WTF_FORBID_HEAP_ALLOCATION;
|
|
friend class VM;
|
|
friend class ArgList;
|
|
|
|
public:
|
|
using Base = RecordOverflow;
|
|
static constexpr size_t inlineCapacity = 8;
|
|
typedef HashSet<MarkedArgumentBuffer*> ListSet;
|
|
|
|
// Constructor for a read-write list, to which you may append values.
|
|
// FIXME: Remove all clients of this API, then remove this API.
|
|
MarkedArgumentBuffer()
|
|
: m_size(0)
|
|
, m_capacity(inlineCapacity)
|
|
, m_buffer(m_inlineBuffer)
|
|
, m_markSet(nullptr)
|
|
{
|
|
}
|
|
|
|
~MarkedArgumentBuffer()
|
|
{
|
|
ASSERT(!m_needsOverflowCheck);
|
|
if (m_markSet)
|
|
m_markSet->remove(this);
|
|
|
|
if (EncodedJSValue* base = mallocBase())
|
|
Gigacage::free(Gigacage::JSValue, base);
|
|
}
|
|
|
|
size_t size() const { return m_size; }
|
|
bool isEmpty() const { return !m_size; }
|
|
|
|
JSValue at(int i) const
|
|
{
|
|
if (i >= m_size)
|
|
return jsUndefined();
|
|
|
|
return JSValue::decode(slotFor(i));
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
ASSERT(!m_needsOverflowCheck);
|
|
clearOverflow();
|
|
m_size = 0;
|
|
}
|
|
|
|
enum OverflowCheckAction {
|
|
CrashOnOverflow,
|
|
WillCheckLater
|
|
};
|
|
template<OverflowCheckAction action>
|
|
void appendWithAction(JSValue v)
|
|
{
|
|
ASSERT(m_size <= m_capacity);
|
|
if (m_size == m_capacity || mallocBase()) {
|
|
slowAppend(v);
|
|
if (action == CrashOnOverflow)
|
|
RELEASE_ASSERT(!hasOverflowed());
|
|
return;
|
|
}
|
|
|
|
slotFor(m_size) = JSValue::encode(v);
|
|
++m_size;
|
|
}
|
|
void append(JSValue v) { appendWithAction<WillCheckLater>(v); }
|
|
void appendWithCrashOnOverflow(JSValue v) { appendWithAction<CrashOnOverflow>(v); }
|
|
|
|
void removeLast()
|
|
{
|
|
ASSERT(m_size);
|
|
m_size--;
|
|
}
|
|
|
|
JSValue last()
|
|
{
|
|
ASSERT(m_size);
|
|
return JSValue::decode(slotFor(m_size - 1));
|
|
}
|
|
|
|
JSValue takeLast()
|
|
{
|
|
JSValue result = last();
|
|
removeLast();
|
|
return result;
|
|
}
|
|
|
|
static void markLists(SlotVisitor&, ListSet&);
|
|
|
|
void ensureCapacity(size_t requestedCapacity)
|
|
{
|
|
if (requestedCapacity > static_cast<size_t>(m_capacity))
|
|
slowEnsureCapacity(requestedCapacity);
|
|
}
|
|
|
|
bool hasOverflowed()
|
|
{
|
|
clearNeedsOverflowCheck();
|
|
return Base::hasOverflowed();
|
|
}
|
|
|
|
void overflowCheckNotNeeded() { clearNeedsOverflowCheck(); }
|
|
|
|
template<typename Functor>
|
|
void fill(size_t count, const Functor& func)
|
|
{
|
|
ASSERT(!m_size);
|
|
ensureCapacity(count);
|
|
if (Base::hasOverflowed())
|
|
return;
|
|
m_size = count;
|
|
func(reinterpret_cast<JSValue*>(&slotFor(0)));
|
|
}
|
|
|
|
private:
|
|
void expandCapacity();
|
|
void expandCapacity(int newCapacity);
|
|
void slowEnsureCapacity(size_t requestedCapacity);
|
|
|
|
void addMarkSet(JSValue);
|
|
|
|
JS_EXPORT_PRIVATE void slowAppend(JSValue);
|
|
|
|
EncodedJSValue& slotFor(int item) const
|
|
{
|
|
return m_buffer[item];
|
|
}
|
|
|
|
EncodedJSValue* mallocBase()
|
|
{
|
|
if (m_buffer == m_inlineBuffer)
|
|
return nullptr;
|
|
return &slotFor(0);
|
|
}
|
|
|
|
#if ASSERT_ENABLED
|
|
void setNeedsOverflowCheck() { m_needsOverflowCheck = true; }
|
|
void clearNeedsOverflowCheck() { m_needsOverflowCheck = false; }
|
|
|
|
bool m_needsOverflowCheck { false };
|
|
#else
|
|
void setNeedsOverflowCheck() { }
|
|
void clearNeedsOverflowCheck() { }
|
|
#endif // ASSERT_ENABLED
|
|
int m_size;
|
|
int m_capacity;
|
|
EncodedJSValue m_inlineBuffer[inlineCapacity];
|
|
EncodedJSValue* m_buffer;
|
|
ListSet* m_markSet;
|
|
};
|
|
|
|
class ArgList {
|
|
WTF_MAKE_FAST_ALLOCATED;
|
|
friend class Interpreter;
|
|
friend class JIT;
|
|
public:
|
|
ArgList()
|
|
: m_args(nullptr)
|
|
, m_argCount(0)
|
|
{
|
|
}
|
|
|
|
ArgList(CallFrame* callFrame)
|
|
: m_args(reinterpret_cast<JSValue*>(&callFrame[CallFrame::argumentOffset(0)]))
|
|
, m_argCount(callFrame->argumentCount())
|
|
{
|
|
}
|
|
|
|
ArgList(const MarkedArgumentBuffer& args)
|
|
: m_args(reinterpret_cast<JSValue*>(args.m_buffer))
|
|
, m_argCount(args.size())
|
|
{
|
|
}
|
|
|
|
JSValue at(int i) const
|
|
{
|
|
if (i >= m_argCount)
|
|
return jsUndefined();
|
|
return m_args[i];
|
|
}
|
|
|
|
bool isEmpty() const { return !m_argCount; }
|
|
size_t size() const { return m_argCount; }
|
|
|
|
JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const;
|
|
|
|
private:
|
|
JSValue* data() const { return m_args; }
|
|
|
|
JSValue* m_args;
|
|
int m_argCount;
|
|
};
|
|
|
|
} // namespace JSC
|