1 /* 2 * Copyright (C) 1999-2001 Harri Porten (porten (at) kde.org) 3 * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 * 20 */ 21 22 #ifndef ArgList_h 23 #define ArgList_h 24 25 #include "Register.h" 26 #include <wtf/HashSet.h> 27 #include <wtf/Noncopyable.h> 28 #include <wtf/Vector.h> 29 30 namespace JSC { 31 32 class MarkStack; 33 34 class MarkedArgumentBuffer : public Noncopyable { 35 private: 36 static const unsigned inlineCapacity = 8; 37 typedef Vector<Register, inlineCapacity> VectorType; 38 typedef HashSet<MarkedArgumentBuffer*> ListSet; 39 40 public: 41 typedef VectorType::iterator iterator; 42 typedef VectorType::const_iterator const_iterator; 43 44 // Constructor for a read-write list, to which you may append values. 45 // FIXME: Remove all clients of this API, then remove this API. 46 MarkedArgumentBuffer() 47 : m_isUsingInlineBuffer(true) 48 , m_markSet(0) 49 #ifndef NDEBUG 50 , m_isReadOnly(false) 51 #endif 52 { 53 m_buffer = m_vector.data(); 54 m_size = 0; 55 } 56 57 // Constructor for a read-only list whose data has already been allocated elsewhere. 58 MarkedArgumentBuffer(Register* buffer, size_t size) 59 : m_buffer(buffer) 60 , m_size(size) 61 , m_isUsingInlineBuffer(true) 62 , m_markSet(0) 63 #ifndef NDEBUG 64 , m_isReadOnly(true) 65 #endif 66 { 67 } 68 69 void initialize(Register* buffer, size_t size) 70 { 71 ASSERT(!m_markSet); 72 ASSERT(isEmpty()); 73 74 m_buffer = buffer; 75 m_size = size; 76 #ifndef NDEBUG 77 m_isReadOnly = true; 78 #endif 79 } 80 81 ~MarkedArgumentBuffer() 82 { 83 if (m_markSet) 84 m_markSet->remove(this); 85 } 86 87 size_t size() const { return m_size; } 88 bool isEmpty() const { return !m_size; } 89 90 JSValue at(size_t i) const 91 { 92 if (i < m_size) 93 return m_buffer[i].jsValue(); 94 return jsUndefined(); 95 } 96 97 void clear() 98 { 99 m_vector.clear(); 100 m_buffer = 0; 101 m_size = 0; 102 } 103 104 void append(JSValue v) 105 { 106 ASSERT(!m_isReadOnly); 107 108 #if ENABLE(JSC_ZOMBIES) 109 ASSERT(!v.isZombie()); 110 #endif 111 112 if (m_isUsingInlineBuffer && m_size < inlineCapacity) { 113 m_vector.uncheckedAppend(v); 114 ++m_size; 115 } else { 116 // Putting this case all in one function measurably improves 117 // the performance of the fast "just append to inline buffer" case. 118 slowAppend(v); 119 ++m_size; 120 m_isUsingInlineBuffer = false; 121 } 122 } 123 124 void removeLast() 125 { 126 ASSERT(m_size); 127 m_size--; 128 m_vector.removeLast(); 129 } 130 131 JSValue last() 132 { 133 ASSERT(m_size); 134 return m_buffer[m_size - 1].jsValue(); 135 } 136 137 iterator begin() { return m_buffer; } 138 iterator end() { return m_buffer + m_size; } 139 140 const_iterator begin() const { return m_buffer; } 141 const_iterator end() const { return m_buffer + m_size; } 142 143 static void markLists(MarkStack&, ListSet&); 144 145 private: 146 void slowAppend(JSValue); 147 148 Register* m_buffer; 149 size_t m_size; 150 bool m_isUsingInlineBuffer; 151 152 VectorType m_vector; 153 ListSet* m_markSet; 154 #ifndef NDEBUG 155 bool m_isReadOnly; 156 #endif 157 158 private: 159 // Prohibits new / delete, which would break GC. 160 friend class JSGlobalData; 161 162 void* operator new(size_t size) 163 { 164 return fastMalloc(size); 165 } 166 void operator delete(void* p) 167 { 168 fastFree(p); 169 } 170 171 void* operator new[](size_t); 172 void operator delete[](void*); 173 174 void* operator new(size_t, void*); 175 void operator delete(void*, size_t); 176 }; 177 178 class ArgList { 179 friend class JIT; 180 public: 181 typedef JSValue* iterator; 182 typedef const JSValue* const_iterator; 183 184 ArgList() 185 : m_args(0) 186 , m_argCount(0) 187 { 188 } 189 190 ArgList(JSValue* args, unsigned argCount) 191 : m_args(args) 192 , m_argCount(argCount) 193 { 194 #if ENABLE(JSC_ZOMBIES) 195 for (size_t i = 0; i < argCount; i++) 196 ASSERT(!m_args[i].isZombie()); 197 #endif 198 } 199 200 ArgList(Register* args, int argCount) 201 : m_args(reinterpret_cast<JSValue*>(args)) 202 , m_argCount(argCount) 203 { 204 ASSERT(argCount >= 0); 205 } 206 207 ArgList(const MarkedArgumentBuffer& args) 208 : m_args(reinterpret_cast<JSValue*>(const_cast<Register*>(args.begin()))) 209 , m_argCount(args.size()) 210 { 211 } 212 213 JSValue at(size_t idx) const 214 { 215 if (idx < m_argCount) 216 return m_args[idx]; 217 return jsUndefined(); 218 } 219 220 bool isEmpty() const { return !m_argCount; } 221 222 size_t size() const { return m_argCount; } 223 224 iterator begin() { return m_args; } 225 iterator end() { return m_args + m_argCount; } 226 227 const_iterator begin() const { return m_args; } 228 const_iterator end() const { return m_args + m_argCount; } 229 230 void getSlice(int startIndex, ArgList& result) const; 231 private: 232 JSValue* m_args; 233 size_t m_argCount; 234 }; 235 236 } // namespace JSC 237 238 #endif // ArgList_h 239