1/*
2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DirectArguments.h"
28
29#include "CodeBlock.h"
30#include "GenericArgumentsInlines.h"
31#include "JSCInlines.h"
32
33namespace JSC {
34
35STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DirectArguments);
36
37const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DirectArguments) };
38
39DirectArguments::DirectArguments(VM& vm, Structure* structure, unsigned length, unsigned capacity)
40 : GenericArguments(vm, structure)
41 , m_length(length)
42 , m_minCapacity(capacity)
43{
44 // When we construct the object from C++ code, we expect the capacity to be at least as large as
45 // length. JIT-allocated DirectArguments objects play evil tricks, though.
46 ASSERT(capacity >= length);
47}
48
49DirectArguments* DirectArguments::createUninitialized(
50 VM& vm, Structure* structure, unsigned length, unsigned capacity)
51{
52 DirectArguments* result =
53 new (NotNull, allocateCell<DirectArguments>(vm.heap, allocationSize(capacity)))
54 DirectArguments(vm, structure, length, capacity);
55 result->finishCreation(vm);
56 return result;
57}
58
59DirectArguments* DirectArguments::create(VM& vm, Structure* structure, unsigned length, unsigned capacity)
60{
61 DirectArguments* result = createUninitialized(vm, structure, length, capacity);
62
63 for (unsigned i = capacity; i--;)
64 result->storage()[i].setUndefined();
65
66 return result;
67}
68
69DirectArguments* DirectArguments::createByCopying(JSGlobalObject* globalObject, CallFrame* callFrame)
70{
71 VM& vm = globalObject->vm();
72
73 unsigned length = callFrame->argumentCount();
74 unsigned capacity = std::max(length, static_cast<unsigned>(callFrame->codeBlock()->numParameters() - 1));
75 DirectArguments* result = createUninitialized(
76 vm, globalObject->directArgumentsStructure(), length, capacity);
77
78 for (unsigned i = capacity; i--;)
79 result->storage()[i].set(vm, result, callFrame->getArgumentUnsafe(i));
80
81 result->setCallee(vm, jsCast<JSFunction*>(callFrame->jsCallee()));
82
83 return result;
84}
85
86size_t DirectArguments::estimatedSize(JSCell* cell, VM& vm)
87{
88 DirectArguments* thisObject = jsCast<DirectArguments*>(cell);
89 size_t mappedArgumentsSize = thisObject->m_mappedArguments ? thisObject->mappedArgumentsSize() * sizeof(bool) : 0;
90 size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject->m_length * sizeof(bool) : 0;
91 return Base::estimatedSize(cell, vm) + mappedArgumentsSize + modifiedArgumentsSize;
92}
93
94void DirectArguments::visitChildren(JSCell* thisCell, SlotVisitor& visitor)
95{
96 DirectArguments* thisObject = static_cast<DirectArguments*>(thisCell);
97 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
98 Base::visitChildren(thisObject, visitor);
99
100 visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity));
101 visitor.append(thisObject->m_callee);
102
103 if (thisObject->m_mappedArguments)
104 visitor.markAuxiliary(thisObject->m_mappedArguments.get(thisObject->internalLength()));
105 GenericArguments<DirectArguments>::visitChildren(thisCell, visitor);
106}
107
108Structure* DirectArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
109{
110 return Structure::create(vm, globalObject, prototype, TypeInfo(DirectArgumentsType, StructureFlags), info());
111}
112
113void DirectArguments::overrideThings(VM& vm)
114{
115 RELEASE_ASSERT(!m_mappedArguments);
116
117 putDirect(vm, vm.propertyNames->length, jsNumber(m_length), static_cast<unsigned>(PropertyAttribute::DontEnum));
118 putDirect(vm, vm.propertyNames->callee, m_callee.get(), static_cast<unsigned>(PropertyAttribute::DontEnum));
119 putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject(vm)->arrayProtoValuesFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
120
121 void* backingStore = vm.gigacageAuxiliarySpace(m_mappedArguments.kind).allocateNonVirtual(vm, mappedArgumentsSize(), nullptr, AllocationFailureMode::Assert);
122 bool* overrides = static_cast<bool*>(backingStore);
123 m_mappedArguments.set(vm, this, overrides, internalLength());
124 for (unsigned i = internalLength(); i--;)
125 overrides[i] = false;
126}
127
128void DirectArguments::overrideThingsIfNecessary(VM& vm)
129{
130 if (!m_mappedArguments)
131 overrideThings(vm);
132}
133
134void DirectArguments::unmapArgument(VM& vm, unsigned index)
135{
136 overrideThingsIfNecessary(vm);
137 m_mappedArguments.at(index, internalLength()) = true;
138}
139
140void DirectArguments::copyToArguments(JSGlobalObject* globalObject, CallFrame* callFrame, VirtualRegister firstElementDest, unsigned offset, unsigned length)
141{
142 if (!m_mappedArguments) {
143 unsigned limit = std::min(length + offset, m_length);
144 unsigned i;
145 VirtualRegister start = firstElementDest - offset;
146 for (i = offset; i < limit; ++i)
147 callFrame->r(start + i) = storage()[i].get();
148 for (; i < length; ++i)
149 callFrame->r(start + i) = get(globalObject, i);
150 return;
151 }
152
153 GenericArguments::copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
154}
155
156unsigned DirectArguments::mappedArgumentsSize()
157{
158 // We always allocate something; in the relatively uncommon case of overriding an empty argument we
159 // still allocate so that m_mappedArguments is non-null. We use that to indicate that the other properties
160 // (length, etc) are overridden.
161 return WTF::roundUpToMultipleOf<8>(m_length ? m_length : 1);
162}
163
164} // namespace JSC
165
166