Home | History | Annotate | Download | only in runtime
      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 "CallFrame.h"
     26 #include "Register.h"
     27 #include <wtf/HashSet.h>
     28 #include <wtf/Vector.h>
     29 
     30 namespace JSC {
     31 
     32     class MarkStack;
     33 
     34     class MarkedArgumentBuffer {
     35         WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
     36     private:
     37         static const unsigned inlineCapacity = 8;
     38         typedef Vector<Register, inlineCapacity> VectorType;
     39         typedef HashSet<MarkedArgumentBuffer*> ListSet;
     40 
     41     public:
     42         typedef VectorType::iterator iterator;
     43         typedef VectorType::const_iterator const_iterator;
     44 
     45         // Constructor for a read-write list, to which you may append values.
     46         // FIXME: Remove all clients of this API, then remove this API.
     47         MarkedArgumentBuffer()
     48             : m_isUsingInlineBuffer(true)
     49             , m_markSet(0)
     50 #ifndef NDEBUG
     51             , m_isReadOnly(false)
     52 #endif
     53         {
     54             m_buffer = m_vector.data();
     55             m_size = 0;
     56         }
     57 
     58         // Constructor for a read-only list whose data has already been allocated elsewhere.
     59         MarkedArgumentBuffer(Register* buffer, size_t size)
     60             : m_buffer(buffer)
     61             , m_size(size)
     62             , m_isUsingInlineBuffer(true)
     63             , m_markSet(0)
     64 #ifndef NDEBUG
     65             , m_isReadOnly(true)
     66 #endif
     67         {
     68         }
     69 
     70         void initialize(WriteBarrier<Unknown>* buffer, size_t size)
     71         {
     72             ASSERT(!m_markSet);
     73             ASSERT(isEmpty());
     74 
     75             m_buffer = reinterpret_cast<Register*>(buffer);
     76             m_size = size;
     77 #ifndef NDEBUG
     78             m_isReadOnly = true;
     79 #endif
     80         }
     81 
     82         ~MarkedArgumentBuffer()
     83         {
     84             if (m_markSet)
     85                 m_markSet->remove(this);
     86         }
     87 
     88         size_t size() const { return m_size; }
     89         bool isEmpty() const { return !m_size; }
     90 
     91         JSValue at(size_t i) const
     92         {
     93             if (i < m_size)
     94                 return m_buffer[i].jsValue();
     95             return jsUndefined();
     96         }
     97 
     98         void clear()
     99         {
    100             m_vector.clear();
    101             m_buffer = 0;
    102             m_size = 0;
    103         }
    104 
    105         void append(JSValue v)
    106         {
    107             ASSERT(!m_isReadOnly);
    108 
    109 #if ENABLE(JSC_ZOMBIES)
    110             ASSERT(!v.isZombie());
    111 #endif
    112 
    113             if (m_isUsingInlineBuffer && m_size < inlineCapacity) {
    114                 m_vector.uncheckedAppend(v);
    115                 ++m_size;
    116             } else {
    117                 // Putting this case all in one function measurably improves
    118                 // the performance of the fast "just append to inline buffer" case.
    119                 slowAppend(v);
    120                 ++m_size;
    121                 m_isUsingInlineBuffer = false;
    122             }
    123         }
    124 
    125         void removeLast()
    126         {
    127             ASSERT(m_size);
    128             m_size--;
    129             m_vector.removeLast();
    130         }
    131 
    132         JSValue last()
    133         {
    134             ASSERT(m_size);
    135             return m_buffer[m_size - 1].jsValue();
    136         }
    137 
    138         iterator begin() { return m_buffer; }
    139         iterator end() { return m_buffer + m_size; }
    140 
    141         const_iterator begin() const { return m_buffer; }
    142         const_iterator end() const { return m_buffer + m_size; }
    143 
    144         static void markLists(HeapRootMarker&, ListSet&);
    145 
    146     private:
    147         void slowAppend(JSValue);
    148 
    149         Register* m_buffer;
    150         size_t m_size;
    151         bool m_isUsingInlineBuffer;
    152 
    153         VectorType m_vector;
    154         ListSet* m_markSet;
    155 #ifndef NDEBUG
    156         bool m_isReadOnly;
    157 #endif
    158 
    159     private:
    160         // Prohibits new / delete, which would break GC.
    161         friend class JSGlobalData;
    162 
    163         void* operator new(size_t size)
    164         {
    165             return fastMalloc(size);
    166         }
    167         void operator delete(void* p)
    168         {
    169             fastFree(p);
    170         }
    171 
    172         void* operator new[](size_t);
    173         void operator delete[](void*);
    174 
    175         void* operator new(size_t, void*);
    176         void operator delete(void*, size_t);
    177     };
    178 
    179     class ArgList {
    180         friend class JIT;
    181     public:
    182         typedef JSValue* iterator;
    183         typedef const JSValue* const_iterator;
    184 
    185         ArgList()
    186             : m_args(0)
    187             , m_argCount(0)
    188         {
    189         }
    190 
    191         ArgList(ExecState* exec)
    192             : m_args(reinterpret_cast<JSValue*>(&exec[exec->hostThisRegister() + 1]))
    193             , m_argCount(exec->argumentCount())
    194         {
    195         }
    196 
    197         ArgList(JSValue* args, unsigned argCount)
    198             : m_args(args)
    199             , m_argCount(argCount)
    200         {
    201 #if ENABLE(JSC_ZOMBIES)
    202             for (size_t i = 0; i < argCount; i++)
    203                 ASSERT(!m_args[i].isZombie());
    204 #endif
    205         }
    206 
    207         ArgList(Register* args, int argCount)
    208             : m_args(reinterpret_cast<JSValue*>(args))
    209             , m_argCount(argCount)
    210         {
    211             ASSERT(argCount >= 0);
    212         }
    213 
    214         ArgList(const MarkedArgumentBuffer& args)
    215             : m_args(reinterpret_cast<JSValue*>(const_cast<Register*>(args.begin())))
    216             , m_argCount(args.size())
    217         {
    218         }
    219 
    220         JSValue at(size_t idx) const
    221         {
    222             if (idx < m_argCount)
    223                 return m_args[idx];
    224             return jsUndefined();
    225         }
    226 
    227         bool isEmpty() const { return !m_argCount; }
    228 
    229         size_t size() const { return m_argCount; }
    230 
    231         iterator begin() { return m_args; }
    232         iterator end() { return m_args + m_argCount; }
    233 
    234         const_iterator begin() const { return m_args; }
    235         const_iterator end() const { return m_args + m_argCount; }
    236 
    237         void getSlice(int startIndex, ArgList& result) const;
    238     private:
    239         JSValue* m_args;
    240         size_t m_argCount;
    241     };
    242 
    243 } // namespace JSC
    244 
    245 #endif // ArgList_h
    246