1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten ([email protected]) |
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/CheckedArithmetic.h> |
26 | #include <wtf/ForbidHeapAllocation.h> |
27 | #include <wtf/HashSet.h> |
28 | |
29 | namespace JSC { |
30 | |
31 | class MarkedArgumentBuffer : public RecordOverflow { |
32 | WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer); |
33 | WTF_FORBID_HEAP_ALLOCATION; |
34 | friend class VM; |
35 | friend class ArgList; |
36 | |
37 | public: |
38 | using Base = RecordOverflow; |
39 | static const size_t inlineCapacity = 8; |
40 | typedef HashSet<MarkedArgumentBuffer*> ListSet; |
41 | |
42 | // Constructor for a read-write list, to which you may append values. |
43 | // FIXME: Remove all clients of this API, then remove this API. |
44 | MarkedArgumentBuffer() |
45 | : m_size(0) |
46 | , m_capacity(inlineCapacity) |
47 | , m_buffer(m_inlineBuffer) |
48 | , m_markSet(0) |
49 | { |
50 | } |
51 | |
52 | ~MarkedArgumentBuffer() |
53 | { |
54 | ASSERT(!m_needsOverflowCheck); |
55 | if (m_markSet) |
56 | m_markSet->remove(this); |
57 | |
58 | if (EncodedJSValue* base = mallocBase()) |
59 | Gigacage::free(Gigacage::JSValue, base); |
60 | } |
61 | |
62 | size_t size() const { return m_size; } |
63 | bool isEmpty() const { return !m_size; } |
64 | |
65 | JSValue at(int i) const |
66 | { |
67 | if (i >= m_size) |
68 | return jsUndefined(); |
69 | |
70 | return JSValue::decode(slotFor(i)); |
71 | } |
72 | |
73 | void clear() |
74 | { |
75 | ASSERT(!m_needsOverflowCheck); |
76 | clearOverflow(); |
77 | m_size = 0; |
78 | } |
79 | |
80 | enum OverflowCheckAction { |
81 | CrashOnOverflow, |
82 | WillCheckLater |
83 | }; |
84 | template<OverflowCheckAction action> |
85 | void appendWithAction(JSValue v) |
86 | { |
87 | ASSERT(m_size <= m_capacity); |
88 | if (m_size == m_capacity || mallocBase()) { |
89 | slowAppend(v); |
90 | if (action == CrashOnOverflow) |
91 | RELEASE_ASSERT(!hasOverflowed()); |
92 | return; |
93 | } |
94 | |
95 | slotFor(m_size) = JSValue::encode(v); |
96 | ++m_size; |
97 | } |
98 | void append(JSValue v) { appendWithAction<WillCheckLater>(v); } |
99 | void appendWithCrashOnOverflow(JSValue v) { appendWithAction<CrashOnOverflow>(v); } |
100 | |
101 | void removeLast() |
102 | { |
103 | ASSERT(m_size); |
104 | m_size--; |
105 | } |
106 | |
107 | JSValue last() |
108 | { |
109 | ASSERT(m_size); |
110 | return JSValue::decode(slotFor(m_size - 1)); |
111 | } |
112 | |
113 | JSValue takeLast() |
114 | { |
115 | JSValue result = last(); |
116 | removeLast(); |
117 | return result; |
118 | } |
119 | |
120 | static void markLists(SlotVisitor&, ListSet&); |
121 | |
122 | void ensureCapacity(size_t requestedCapacity) |
123 | { |
124 | if (requestedCapacity > static_cast<size_t>(m_capacity)) |
125 | slowEnsureCapacity(requestedCapacity); |
126 | } |
127 | |
128 | bool hasOverflowed() |
129 | { |
130 | clearNeedsOverflowCheck(); |
131 | return Base::hasOverflowed(); |
132 | } |
133 | |
134 | void overflowCheckNotNeeded() { clearNeedsOverflowCheck(); } |
135 | |
136 | private: |
137 | void expandCapacity(); |
138 | void expandCapacity(int newCapacity); |
139 | void slowEnsureCapacity(size_t requestedCapacity); |
140 | |
141 | void addMarkSet(JSValue); |
142 | |
143 | JS_EXPORT_PRIVATE void slowAppend(JSValue); |
144 | |
145 | EncodedJSValue& slotFor(int item) const |
146 | { |
147 | return m_buffer[item]; |
148 | } |
149 | |
150 | EncodedJSValue* mallocBase() |
151 | { |
152 | if (m_buffer == m_inlineBuffer) |
153 | return 0; |
154 | return &slotFor(0); |
155 | } |
156 | |
157 | #if ASSERT_DISABLED |
158 | void setNeedsOverflowCheck() { } |
159 | void clearNeedsOverflowCheck() { } |
160 | #else |
161 | void setNeedsOverflowCheck() { m_needsOverflowCheck = true; } |
162 | void clearNeedsOverflowCheck() { m_needsOverflowCheck = false; } |
163 | |
164 | bool m_needsOverflowCheck { false }; |
165 | #endif |
166 | int m_size; |
167 | int m_capacity; |
168 | EncodedJSValue m_inlineBuffer[inlineCapacity]; |
169 | EncodedJSValue* m_buffer; |
170 | ListSet* m_markSet; |
171 | }; |
172 | |
173 | class ArgList { |
174 | WTF_MAKE_FAST_ALLOCATED; |
175 | friend class Interpreter; |
176 | friend class JIT; |
177 | public: |
178 | ArgList() |
179 | : m_args(0) |
180 | , m_argCount(0) |
181 | { |
182 | } |
183 | |
184 | ArgList(ExecState* exec) |
185 | : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)])) |
186 | , m_argCount(exec->argumentCount()) |
187 | { |
188 | } |
189 | |
190 | ArgList(const MarkedArgumentBuffer& args) |
191 | : m_args(reinterpret_cast<JSValue*>(args.m_buffer)) |
192 | , m_argCount(args.size()) |
193 | { |
194 | } |
195 | |
196 | JSValue at(int i) const |
197 | { |
198 | if (i >= m_argCount) |
199 | return jsUndefined(); |
200 | return m_args[i]; |
201 | } |
202 | |
203 | bool isEmpty() const { return !m_argCount; } |
204 | size_t size() const { return m_argCount; } |
205 | |
206 | JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const; |
207 | |
208 | private: |
209 | JSValue* data() const { return m_args; } |
210 | |
211 | JSValue* m_args; |
212 | int m_argCount; |
213 | }; |
214 | |
215 | } // namespace JSC |
216 | |