DirectArguments::create needs to initialize to undefined instead of the empty value
[WebKit-https.git] / Source / JavaScriptCore / runtime / DirectArguments.cpp
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
33 namespace JSC {
34
35 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DirectArguments);
36
37 const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DirectArguments) };
38
39 DirectArguments::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
49 DirectArguments* 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
59 DirectArguments* 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
69 DirectArguments* DirectArguments::createByCopying(ExecState* exec)
70 {
71     VM& vm = exec->vm();
72     
73     unsigned length = exec->argumentCount();
74     unsigned capacity = std::max(length, static_cast<unsigned>(exec->codeBlock()->numParameters() - 1));
75     DirectArguments* result = createUninitialized(
76         vm, exec->lexicalGlobalObject()->directArgumentsStructure(), length, capacity);
77     
78     for (unsigned i = capacity; i--;)
79         result->storage()[i].set(vm, result, exec->getArgumentUnsafe(i));
80     
81     result->setCallee(vm, jsCast<JSFunction*>(exec->jsCallee()));
82     
83     return result;
84 }
85
86 size_t DirectArguments::estimatedSize(JSCell* cell)
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) + mappedArgumentsSize + modifiedArgumentsSize;
92 }
93
94 void 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());
105     GenericArguments<DirectArguments>::visitChildren(thisCell, visitor);
106 }
107
108 Structure* DirectArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
109 {
110     return Structure::create(vm, globalObject, prototype, TypeInfo(DirectArgumentsType, StructureFlags), info());
111 }
112
113 void 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);
124     for (unsigned i = m_length; i--;)
125         overrides[i] = false;
126 }
127
128 void DirectArguments::overrideThingsIfNecessary(VM& vm)
129 {
130     if (!m_mappedArguments)
131         overrideThings(vm);
132 }
133
134 void DirectArguments::unmapArgument(VM& vm, unsigned index)
135 {
136     overrideThingsIfNecessary(vm);
137     m_mappedArguments[index] = true;
138 }
139
140 void DirectArguments::copyToArguments(ExecState* exec, 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             exec->r(start + i) = storage()[i].get();
148         for (; i < length; ++i)
149             exec->r(start + i) = get(exec, i);
150         return;
151     }
152
153     GenericArguments::copyToArguments(exec, firstElementDest, offset, length);
154 }
155
156 unsigned 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