/* | |
* 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 |