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 "ScopedArguments.h"
28
29#include "GenericArgumentsInlines.h"
30#include "JSCInlines.h"
31
32namespace JSC {
33
34STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ScopedArguments);
35
36const ClassInfo ScopedArguments::s_info = { "Arguments", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ScopedArguments) };
37
38ScopedArguments::ScopedArguments(VM& vm, Structure* structure, WriteBarrier<Unknown>* storage)
39 : GenericArguments(vm, structure)
40 , m_storage(vm, this, storage)
41{
42 ASSERT(!storageHeader(storage).overrodeThings);
43}
44
45void ScopedArguments::finishCreation(VM& vm, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope)
46{
47 Base::finishCreation(vm);
48 m_callee.set(vm, this, callee);
49 m_table.set(vm, this, table);
50 m_scope.set(vm, this, scope);
51}
52
53ScopedArguments* ScopedArguments::createUninitialized(VM& vm, Structure* structure, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope, unsigned totalLength)
54{
55 unsigned overflowLength;
56 if (totalLength > table->length())
57 overflowLength = totalLength - table->length();
58 else
59 overflowLength = 0;
60
61 void* rawStoragePtr = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(
62 vm, storageSize(overflowLength), nullptr, AllocationFailureMode::Assert);
63 WriteBarrier<Unknown>* storage = static_cast<WriteBarrier<Unknown>*>(rawStoragePtr) + 1;
64 storageHeader(storage).overrodeThings = false;
65 storageHeader(storage).totalLength = totalLength;
66
67 ScopedArguments* result = new (
68 NotNull,
69 allocateCell<ScopedArguments>(vm.heap))
70 ScopedArguments(vm, structure, storage);
71 result->finishCreation(vm, callee, table, scope);
72 return result;
73}
74
75ScopedArguments* ScopedArguments::create(VM& vm, Structure* structure, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope, unsigned totalLength)
76{
77 ScopedArguments* result =
78 createUninitialized(vm, structure, callee, table, scope, totalLength);
79
80 unsigned namedLength = table->length();
81 for (unsigned i = namedLength; i < totalLength; ++i)
82 result->overflowStorage()[i - namedLength].clear();
83
84 return result;
85}
86
87ScopedArguments* ScopedArguments::createByCopying(ExecState* exec, ScopedArgumentsTable* table, JSLexicalEnvironment* scope)
88{
89 return createByCopyingFrom(
90 exec->vm(), exec->lexicalGlobalObject()->scopedArgumentsStructure(),
91 exec->registers() + CallFrame::argumentOffset(0), exec->argumentCount(),
92 jsCast<JSFunction*>(exec->jsCallee()), table, scope);
93}
94
95ScopedArguments* ScopedArguments::createByCopyingFrom(VM& vm, Structure* structure, Register* argumentsStart, unsigned totalLength, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope)
96{
97 ScopedArguments* result =
98 createUninitialized(vm, structure, callee, table, scope, totalLength);
99
100 unsigned namedLength = table->length();
101 for (unsigned i = namedLength; i < totalLength; ++i)
102 result->overflowStorage()[i - namedLength].set(vm, result, argumentsStart[i].jsValue());
103
104 return result;
105}
106
107void ScopedArguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
108{
109 ScopedArguments* thisObject = static_cast<ScopedArguments*>(cell);
110 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
111 Base::visitChildren(thisObject, visitor);
112
113 visitor.append(thisObject->m_callee);
114 visitor.append(thisObject->m_table);
115 visitor.append(thisObject->m_scope);
116
117 visitor.markAuxiliary(&thisObject->storageHeader());
118
119 if (thisObject->storageHeader().totalLength > thisObject->m_table->length()) {
120 visitor.appendValues(
121 thisObject->overflowStorage(), thisObject->storageHeader().totalLength - thisObject->m_table->length());
122 }
123}
124
125Structure* ScopedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
126{
127 return Structure::create(vm, globalObject, prototype, TypeInfo(ScopedArgumentsType, StructureFlags), info());
128}
129
130void ScopedArguments::overrideThings(VM& vm)
131{
132 RELEASE_ASSERT(!storageHeader().overrodeThings);
133
134 putDirect(vm, vm.propertyNames->length, jsNumber(m_table->length()), static_cast<unsigned>(PropertyAttribute::DontEnum));
135 putDirect(vm, vm.propertyNames->callee, m_callee.get(), static_cast<unsigned>(PropertyAttribute::DontEnum));
136 putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject(vm)->arrayProtoValuesFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
137
138 storageHeader().overrodeThings = true;
139}
140
141void ScopedArguments::overrideThingsIfNecessary(VM& vm)
142{
143 if (!storageHeader().overrodeThings)
144 overrideThings(vm);
145}
146
147void ScopedArguments::unmapArgument(VM& vm, uint32_t i)
148{
149 ASSERT_WITH_SECURITY_IMPLICATION(i < storageHeader().totalLength);
150 unsigned namedLength = m_table->length();
151 if (i < namedLength)
152 m_table.set(vm, this, m_table->set(vm, i, ScopeOffset()));
153 else
154 overflowStorage()[i - namedLength].clear();
155}
156
157void ScopedArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
158{
159 GenericArguments::copyToArguments(exec, firstElementDest, offset, length);
160}
161
162} // namespace JSC
163
164