1/*
2 * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21#include "config.h"
22#include "ArgList.h"
23
24#include "JSCJSValue.h"
25#include "JSObject.h"
26#include "JSCInlines.h"
27
28using std::min;
29
30namespace JSC {
31
32void MarkedArgumentBuffer::addMarkSet(JSValue v)
33{
34 if (m_markSet)
35 return;
36
37 Heap* heap = Heap::heap(v);
38 if (!heap)
39 return;
40
41 m_markSet = &heap->markListSet();
42 m_markSet->add(this);
43}
44
45void ArgList::getSlice(int startIndex, ArgList& result) const
46{
47 if (startIndex <= 0 || startIndex >= m_argCount) {
48 result = ArgList();
49 return;
50 }
51
52 result.m_args = m_args + startIndex;
53 result.m_argCount = m_argCount - startIndex;
54}
55
56void MarkedArgumentBuffer::markLists(SlotVisitor& visitor, ListSet& markSet)
57{
58 ListSet::iterator end = markSet.end();
59 for (ListSet::iterator it = markSet.begin(); it != end; ++it) {
60 MarkedArgumentBuffer* list = *it;
61 for (int i = 0; i < list->m_size; ++i)
62 visitor.appendUnbarriered(JSValue::decode(list->slotFor(i)));
63 }
64}
65
66void MarkedArgumentBuffer::slowEnsureCapacity(size_t requestedCapacity)
67{
68 setNeedsOverflowCheck();
69 auto checkedNewCapacity = Checked<int, RecordOverflow>(requestedCapacity);
70 if (UNLIKELY(checkedNewCapacity.hasOverflowed()))
71 return this->overflowed();
72 expandCapacity(checkedNewCapacity.unsafeGet());
73}
74
75void MarkedArgumentBuffer::expandCapacity()
76{
77 setNeedsOverflowCheck();
78 auto checkedNewCapacity = Checked<int, RecordOverflow>(m_capacity) * 2;
79 if (UNLIKELY(checkedNewCapacity.hasOverflowed()))
80 return this->overflowed();
81 expandCapacity(checkedNewCapacity.unsafeGet());
82}
83
84void MarkedArgumentBuffer::expandCapacity(int newCapacity)
85{
86 setNeedsOverflowCheck();
87 ASSERT(m_capacity < newCapacity);
88 auto checkedSize = Checked<size_t, RecordOverflow>(newCapacity) * sizeof(EncodedJSValue);
89 if (UNLIKELY(checkedSize.hasOverflowed()))
90 return this->overflowed();
91 EncodedJSValue* newBuffer = static_cast<EncodedJSValue*>(Gigacage::malloc(Gigacage::JSValue, checkedSize.unsafeGet()));
92 for (int i = 0; i < m_size; ++i) {
93 newBuffer[i] = m_buffer[i];
94 addMarkSet(JSValue::decode(m_buffer[i]));
95 }
96
97 if (EncodedJSValue* base = mallocBase())
98 Gigacage::free(Gigacage::JSValue, base);
99
100 m_buffer = newBuffer;
101 m_capacity = newCapacity;
102}
103
104void MarkedArgumentBuffer::slowAppend(JSValue v)
105{
106 ASSERT(m_size <= m_capacity);
107 if (m_size == m_capacity)
108 expandCapacity();
109 if (UNLIKELY(Base::hasOverflowed())) {
110 ASSERT(m_needsOverflowCheck);
111 return;
112 }
113
114 slotFor(m_size) = JSValue::encode(v);
115 ++m_size;
116 addMarkSet(v);
117}
118
119} // namespace JSC
120