/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2007, 2008, 2009 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.
*
*/
#ifndef ArgList_h
#define ArgList_h
#include "Register.h"
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
namespace JSC {
class MarkStack;
class MarkedArgumentBuffer : public Noncopyable {
private:
static const unsigned inlineCapacity = 8;
typedef Vector<Register, inlineCapacity> VectorType;
typedef HashSet<MarkedArgumentBuffer*> ListSet;
public:
typedef VectorType::iterator iterator;
typedef VectorType::const_iterator const_iterator;
// 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_isUsingInlineBuffer(true)
, m_markSet(0)
#ifndef NDEBUG
, m_isReadOnly(false)
#endif
{
m_buffer = m_vector.data();
m_size = 0;
}
// Constructor for a read-only list whose data has already been allocated elsewhere.
MarkedArgumentBuffer(Register* buffer, size_t size)
: m_buffer(buffer)
, m_size(size)
, m_isUsingInlineBuffer(true)
, m_markSet(0)
#ifndef NDEBUG
, m_isReadOnly(true)
#endif
{
}
void initialize(Register* buffer, size_t size)
{
ASSERT(!m_markSet);
ASSERT(isEmpty());
m_buffer = buffer;
m_size = size;
#ifndef NDEBUG
m_isReadOnly = true;
#endif
}
~MarkedArgumentBuffer()
{
if (m_markSet)
m_markSet->remove(this);
}
size_t size() const { return m_size; }
bool isEmpty() const { return !m_size; }
JSValue at(size_t i) const
{
if (i < m_size)
return m_buffer[i].jsValue();
return jsUndefined();
}
void clear()
{
m_vector.clear();
m_buffer = 0;
m_size = 0;
}
void append(JSValue v)
{
ASSERT(!m_isReadOnly);
#if ENABLE(JSC_ZOMBIES)
ASSERT(!v.isZombie());
#endif
if (m_isUsingInlineBuffer && m_size < inlineCapacity) {
m_vector.uncheckedAppend(v);
++m_size;
} else {
// Putting this case all in one function measurably improves
// the performance of the fast "just append to inline buffer" case.
slowAppend(v);
++m_size;
m_isUsingInlineBuffer = false;
}
}
void removeLast()
{
ASSERT(m_size);
m_size--;
m_vector.removeLast();
}
JSValue last()
{
ASSERT(m_size);
return m_buffer[m_size - 1].jsValue();
}
iterator begin() { return m_buffer; }
iterator end() { return m_buffer + m_size; }
const_iterator begin() const { return m_buffer; }
const_iterator end() const { return m_buffer + m_size; }
static void markLists(MarkStack&, ListSet&);
private:
void slowAppend(JSValue);
Register* m_buffer;
size_t m_size;
bool m_isUsingInlineBuffer;
VectorType m_vector;
ListSet* m_markSet;
#ifndef NDEBUG
bool m_isReadOnly;
#endif
private:
// Prohibits new / delete, which would break GC.
friend class JSGlobalData;
void* operator new(size_t size)
{
return fastMalloc(size);
}
void operator delete(void* p)
{
fastFree(p);
}
void* operator new[](size_t);
void operator delete[](void*);
void* operator new(size_t, void*);
void operator delete(void*, size_t);
};
class ArgList {
friend class JIT;
public:
typedef JSValue* iterator;
typedef const JSValue* const_iterator;
ArgList()
: m_args(0)
, m_argCount(0)
{
}
ArgList(JSValue* args, unsigned argCount)
: m_args(args)
, m_argCount(argCount)
{
#if ENABLE(JSC_ZOMBIES)
for (size_t i = 0; i < argCount; i++)
ASSERT(!m_args[i].isZombie());
#endif
}
ArgList(Register* args, int argCount)
: m_args(reinterpret_cast<JSValue*>(args))
, m_argCount(argCount)
{
ASSERT(argCount >= 0);
}
ArgList(const MarkedArgumentBuffer& args)
: m_args(reinterpret_cast<JSValue*>(const_cast<Register*>(args.begin())))
, m_argCount(args.size())
{
}
JSValue at(size_t idx) const
{
if (idx < m_argCount)
return m_args[idx];
return jsUndefined();
}
bool isEmpty() const { return !m_argCount; }
size_t size() const { return m_argCount; }
iterator begin() { return m_args; }
iterator end() { return m_args + m_argCount; }
const_iterator begin() const { return m_args; }
const_iterator end() const { return m_args + m_argCount; }
void getSlice(int startIndex, ArgList& result) const;
private:
JSValue* m_args;
size_t m_argCount;
};
} // namespace JSC
#endif // ArgList_h