CachedCall should let GC know to keep its arguments alive.
[WebKit-https.git] / Source / JavaScriptCore / runtime / ArgList.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003-2017 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 #pragma once
23
24 #include "CallFrame.h"
25 #include <wtf/ForbidHeapAllocation.h>
26 #include <wtf/HashSet.h>
27
28 namespace JSC {
29
30 class MarkedArgumentBuffer {
31     WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
32     WTF_FORBID_HEAP_ALLOCATION;
33     friend class VM;
34     friend class ArgList;
35
36 private:
37     static const size_t inlineCapacity = 8;
38     typedef HashSet<MarkedArgumentBuffer*> ListSet;
39
40 public:
41     // Constructor for a read-write list, to which you may append values.
42     // FIXME: Remove all clients of this API, then remove this API.
43     MarkedArgumentBuffer()
44         : m_size(0)
45         , m_capacity(inlineCapacity)
46         , m_buffer(m_inlineBuffer)
47         , m_markSet(0)
48     {
49     }
50
51     ~MarkedArgumentBuffer()
52     {
53         if (m_markSet)
54             m_markSet->remove(this);
55
56         if (EncodedJSValue* base = mallocBase())
57             fastFree(base);
58     }
59
60     size_t size() const { return m_size; }
61     bool isEmpty() const { return !m_size; }
62
63     JSValue at(int i) const
64     {
65         if (i >= m_size)
66             return jsUndefined();
67
68         return JSValue::decode(slotFor(i));
69     }
70
71     void clear()
72     {
73         m_size = 0;
74     }
75
76     void append(JSValue v)
77     {
78         if (m_size >= m_capacity || mallocBase())
79             return slowAppend(v);
80
81         slotFor(m_size) = JSValue::encode(v);
82         ++m_size;
83     }
84
85     void removeLast()
86     { 
87         ASSERT(m_size);
88         m_size--;
89     }
90
91     JSValue last() 
92     {
93         ASSERT(m_size);
94         return JSValue::decode(slotFor(m_size - 1));
95     }
96         
97     static void markLists(SlotVisitor&, ListSet&);
98
99     void ensureCapacity(size_t requestedCapacity)
100     {
101         if (requestedCapacity > static_cast<size_t>(m_capacity))
102             slowEnsureCapacity(requestedCapacity);
103     }
104
105 private:
106     void expandCapacity();
107     void expandCapacity(int newCapacity);
108     void slowEnsureCapacity(size_t requestedCapacity);
109
110     void addMarkSet(JSValue);
111
112     JS_EXPORT_PRIVATE void slowAppend(JSValue);
113         
114     EncodedJSValue& slotFor(int item) const
115     {
116         return m_buffer[item];
117     }
118         
119     EncodedJSValue* mallocBase()
120     {
121         if (m_buffer == m_inlineBuffer)
122             return 0;
123         return &slotFor(0);
124     }
125         
126     int m_size;
127     int m_capacity;
128     EncodedJSValue m_inlineBuffer[inlineCapacity];
129     EncodedJSValue* m_buffer;
130     ListSet* m_markSet;
131 };
132
133 class ArgList {
134     friend class Interpreter;
135     friend class JIT;
136 public:
137     ArgList()
138         : m_args(0)
139         , m_argCount(0)
140     {
141     }
142
143     ArgList(ExecState* exec)
144         : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)]))
145         , m_argCount(exec->argumentCount())
146     {
147     }
148
149     ArgList(const MarkedArgumentBuffer& args)
150         : m_args(reinterpret_cast<JSValue*>(args.m_buffer))
151         , m_argCount(args.size())
152     {
153     }
154
155     JSValue at(int i) const
156     {
157         if (i >= m_argCount)
158             return jsUndefined();
159         return m_args[i];
160     }
161
162     bool isEmpty() const { return !m_argCount; }
163     size_t size() const { return m_argCount; }
164         
165     JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const;
166
167 private:
168     JSValue* data() const { return m_args; }
169
170     JSValue* m_args;
171     int m_argCount;
172 };
173
174 } // namespace JSC