2a78fd0fea3e83af1404005d6ac3be5be13a0cae
[WebKit-https.git] / Source / JavaScriptCore / runtime / DirectArguments.h
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 #pragma once
27
28 #include "CagedBarrierPtr.h"
29 #include "DirectArgumentsOffset.h"
30 #include "GenericArguments.h"
31 #include <wtf/CagedPtr.h>
32
33 namespace JSC {
34
35 // This is an Arguments-class object that we create when you say "arguments" inside a function,
36 // and none of the arguments are captured in the function's activation. The function will copy all
37 // of its arguments into this object, and all subsequent accesses to the arguments will go through
38 // this object thereafter. Special support is in place for mischevious events like the arguments
39 // being deleted (something like "delete arguments[0]") or reconfigured (broadly, we say deletions
40 // and reconfigurations mean that the respective argument was "overridden").
41 //
42 // To speed allocation, this object will hold all of the arguments in-place. The arguments as well
43 // as a table of flags saying which arguments were overridden.
44 class DirectArguments final : public GenericArguments<DirectArguments> {
45 private:
46     DirectArguments(VM&, Structure*, unsigned length, unsigned capacity);
47     
48 public:
49     template<typename CellType>
50     static CompleteSubspace* subspaceFor(VM& vm)
51     {
52         RELEASE_ASSERT(!CellType::needsDestruction);
53         return &vm.jsValueGigacageCellSpace;
54     }
55
56     // Creates an arguments object but leaves it uninitialized. This is dangerous if we GC right
57     // after allocation.
58     static DirectArguments* createUninitialized(VM&, Structure*, unsigned length, unsigned capacity);
59     
60     // Creates an arguments object and initializes everything to the empty value. Use this if you
61     // cannot guarantee that you'll immediately initialize all of the elements.
62     static DirectArguments* create(VM&, Structure*, unsigned length, unsigned capacity);
63     
64     // Creates an arguments object by copying the argumnets from the stack.
65     static DirectArguments* createByCopying(ExecState*);
66
67     static size_t estimatedSize(JSCell*, VM&);
68     static void visitChildren(JSCell*, SlotVisitor&);
69     
70     uint32_t internalLength() const
71     {
72         return m_length;
73     }
74     
75     uint32_t length(ExecState* exec) const
76     {
77         if (UNLIKELY(m_mappedArguments)) {
78             VM& vm = exec->vm();
79             auto scope = DECLARE_THROW_SCOPE(vm);
80             JSValue value = get(exec, vm.propertyNames->length);
81             RETURN_IF_EXCEPTION(scope, 0);
82             RELEASE_AND_RETURN(scope, value.toUInt32(exec));
83         }
84         return m_length;
85     }
86     
87     bool isMappedArgument(uint32_t i) const
88     {
89         return i < m_length && (!m_mappedArguments || !m_mappedArguments[i]);
90     }
91
92     bool isMappedArgumentInDFG(uint32_t i) const
93     {
94         return i < m_length && !overrodeThings();
95     }
96
97     JSValue getIndexQuickly(uint32_t i) const
98     {
99         ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i));
100         return const_cast<DirectArguments*>(this)->storage()[i].get();
101     }
102     
103     void setIndexQuickly(VM& vm, uint32_t i, JSValue value)
104     {
105         ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i));
106         storage()[i].set(vm, this, value);
107     }
108     
109     JSFunction* callee()
110     {
111         return m_callee.get();
112     }
113     
114     void setCallee(VM& vm, JSFunction* function)
115     {
116         m_callee.set(vm, this, function);
117     }
118     
119     WriteBarrier<Unknown>& argument(DirectArgumentsOffset offset)
120     {
121         ASSERT(offset);
122         ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity));
123         return storage()[offset.offset()];
124     }
125     
126     // Methods intended for use by the GenericArguments mixin.
127     bool overrodeThings() const { return !!m_mappedArguments; }
128     void overrideThings(VM&);
129     void overrideThingsIfNecessary(VM&);
130     void unmapArgument(VM&, unsigned index);
131
132     void initModifiedArgumentsDescriptorIfNecessary(VM& vm)
133     {
134         GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(vm, m_length);
135     }
136
137     void setModifiedArgumentDescriptor(VM& vm, unsigned index)
138     {
139         GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(vm, index, m_length);
140     }
141
142     bool isModifiedArgumentDescriptor(unsigned index)
143     {
144         return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, m_length);
145     }
146
147     void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
148
149     DECLARE_INFO;
150     
151     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
152     
153     static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(DirectArguments, m_callee); }
154     static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(DirectArguments, m_length); }
155     static ptrdiff_t offsetOfMinCapacity() { return OBJECT_OFFSETOF(DirectArguments, m_minCapacity); }
156     static ptrdiff_t offsetOfMappedArguments() { return OBJECT_OFFSETOF(DirectArguments, m_mappedArguments); }
157     static ptrdiff_t offsetOfModifiedArgumentsDescriptor() { return OBJECT_OFFSETOF(DirectArguments, m_modifiedArgumentsDescriptor); }
158     
159     static size_t storageOffset()
160     {
161         return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(DirectArguments));
162     }
163     
164     static size_t offsetOfSlot(Checked<size_t> index)
165     {
166         return (storageOffset() + sizeof(WriteBarrier<Unknown>) * index).unsafeGet();
167     }
168     
169     static size_t allocationSize(Checked<size_t> capacity)
170     {
171         return offsetOfSlot(capacity);
172     }
173     
174 private:
175     WriteBarrier<Unknown>* storage()
176     {
177         return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + storageOffset());
178     }
179     
180     unsigned mappedArgumentsSize();
181     
182     WriteBarrier<JSFunction> m_callee;
183     uint32_t m_length; // Always the actual length of captured arguments and never what was stored into the length property.
184     uint32_t m_minCapacity; // The max of this and length determines the capacity of this object. It may be the actual capacity, or maybe something smaller. We arrange it this way to be kind to the JITs.
185     CagedBarrierPtr<Gigacage::Primitive, bool> m_mappedArguments; // If non-null, it means that length, callee, and caller are fully materialized properties.
186 };
187
188 } // namespace JSC