Disable function.arguments
[WebKit-https.git] / Source / JavaScriptCore / runtime / Arguments.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
5  *  Copyright (C) 2007 Maks Orlovich
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #ifndef Arguments_h
25 #define Arguments_h
26
27 #include "CodeOrigin.h"
28 #include "JSFunction.h"
29 #include "JSGlobalObject.h"
30 #include "JSLexicalEnvironment.h"
31 #include "Interpreter.h"
32 #include "ObjectConstructor.h"
33 #include "WriteBarrierInlines.h"
34 #include <wtf/StdLibExtras.h>
35
36 namespace JSC {
37
38 enum ArgumentsMode {
39     NormalArgumentsCreationMode,
40     FakeArgumentValuesCreationMode
41 };
42
43 class Arguments : public JSNonFinalObject {
44     friend class JIT;
45     friend class JSArgumentsIterator;
46 public:
47     typedef JSNonFinalObject Base;
48
49     static Arguments* create(VM& vm, CallFrame* callFrame, ArgumentsMode mode = NormalArgumentsCreationMode)
50     {
51         Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame);
52         arguments->finishCreation(callFrame, mode);
53         return arguments;
54     }
55         
56     static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode = NormalArgumentsCreationMode)
57     {
58         Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame);
59         arguments->finishCreation(callFrame, inlineCallFrame, mode);
60         return arguments;
61     }
62
63     enum { MaxArguments = 0x10000 };
64
65 private:
66     enum NoParametersType { NoParameters };
67         
68     Arguments(CallFrame*);
69     Arguments(CallFrame*, NoParametersType);
70         
71 public:
72     DECLARE_INFO;
73
74     static void visitChildren(JSCell*, SlotVisitor&);
75     static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
76
77     void fillArgList(ExecState*, MarkedArgumentBuffer&);
78
79     uint32_t length(ExecState* exec) const 
80     {
81         if (UNLIKELY(m_overrodeLength))
82             return get(exec, exec->propertyNames().length).toUInt32(exec);
83         return m_numArguments; 
84     }
85         
86     void copyToArguments(ExecState*, CallFrame*, uint32_t copyLength, int32_t firstArgumentOffset);
87     void tearOff(CallFrame*);
88     void tearOff(CallFrame*, InlineCallFrame*);
89     bool isTornOff() const { return m_registerArray.get(); }
90     void didTearOffActivation(ExecState*, JSLexicalEnvironment*);
91
92     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 
93     { 
94         return Structure::create(vm, globalObject, prototype, TypeInfo(ArgumentsType, StructureFlags), info()); 
95     }
96     
97     static ptrdiff_t offsetOfActivation() { return OBJECT_OFFSETOF(Arguments, m_lexicalEnvironment); }
98     static ptrdiff_t offsetOfNumArguments() { return OBJECT_OFFSETOF(Arguments, m_numArguments); }
99     static ptrdiff_t offsetOfOverrodeLength() { return OBJECT_OFFSETOF(Arguments, m_overrodeLength); }
100     static ptrdiff_t offsetOfIsStrictMode() { return OBJECT_OFFSETOF(Arguments, m_isStrictMode); }
101     static ptrdiff_t offsetOfRegisters() { return OBJECT_OFFSETOF(Arguments, m_registers); }
102     static ptrdiff_t offsetOfRegisterArray() { return OBJECT_OFFSETOF(Arguments, m_registerArray); }
103     static ptrdiff_t offsetOfSlowArgumentData() { return OBJECT_OFFSETOF(Arguments, m_slowArgumentData); }
104     static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(Arguments, m_callee); }
105
106     static size_t allocationSize(size_t inlineCapacity)
107     {
108         ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
109         return sizeof(Arguments);
110     }
111     
112 protected:
113     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSObject::StructureFlags;
114
115     void finishCreation(CallFrame*, ArgumentsMode);
116     void finishCreation(CallFrame*, InlineCallFrame*, ArgumentsMode);
117
118 private:
119     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
120     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
121     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
122     static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
123     static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
124     static bool deleteProperty(JSCell*, ExecState*, PropertyName);
125     static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
126     static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
127     void createStrictModeCallerIfNecessary(ExecState*);
128     void createStrictModeCalleeIfNecessary(ExecState*);
129
130     size_t registerArraySizeInBytes() const { return sizeof(WriteBarrier<Unknown>) * m_numArguments; }
131     void allocateRegisterArray(VM&);
132     bool isArgument(size_t);
133     bool trySetArgument(VM&, size_t argument, JSValue);
134     JSValue tryGetArgument(size_t argument);
135     bool isDeletedArgument(size_t);
136     bool tryDeleteArgument(VM&, size_t);
137     WriteBarrierBase<Unknown>& argument(size_t);
138     void allocateSlowArguments(VM&);
139
140     void init(CallFrame*);
141
142     WriteBarrier<JSLexicalEnvironment> m_lexicalEnvironment;
143
144     unsigned m_numArguments;
145
146     // We make these full byte booleans to make them easy to test from the JIT,
147     // and because even if they were single-bit booleans we still wouldn't save
148     // any space.
149     bool m_overrodeLength; 
150     bool m_overrodeCallee;
151     bool m_overrodeCaller;
152     bool m_isStrictMode;
153
154     WriteBarrierBase<Unknown>* m_registers;
155     CopyWriteBarrier<WriteBarrier<Unknown>> m_registerArray;
156
157 public:
158     struct SlowArgumentData {
159     public:
160         SlowArgumentData()
161             : m_bytecodeToMachineCaptureOffset(0)
162         {
163         }
164
165         SlowArgument* slowArguments()
166         {
167             return reinterpret_cast<SlowArgument*>(WTF::roundUpToMultipleOf<8>(reinterpret_cast<size_t>(this + 1)));
168         }
169
170         int bytecodeToMachineCaptureOffset() const { return m_bytecodeToMachineCaptureOffset; }
171         void setBytecodeToMachineCaptureOffset(int newOffset) { m_bytecodeToMachineCaptureOffset = newOffset; }
172
173         static size_t sizeForNumArguments(unsigned numArguments)
174         {
175             return WTF::roundUpToMultipleOf<8>(sizeof(SlowArgumentData)) + sizeof(SlowArgument) * numArguments;
176         }
177
178     private:
179         int m_bytecodeToMachineCaptureOffset; // Add this if you have a bytecode offset into captured registers and you want the machine offset instead. Subtract if you want to do the opposite. 
180     };
181     
182 private:
183     CopyWriteBarrier<SlowArgumentData> m_slowArgumentData;
184
185     WriteBarrier<JSFunction> m_callee;
186 };
187
188 Arguments* asArguments(JSValue);
189
190 inline Arguments* asArguments(JSValue value)
191 {
192     ASSERT(asObject(value)->inherits(Arguments::info()));
193     return static_cast<Arguments*>(asObject(value));
194 }
195
196 inline Arguments::Arguments(CallFrame* callFrame)
197     : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
198 {
199 }
200
201 inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
202     : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
203 {
204 }
205
206 inline void Arguments::allocateSlowArguments(VM& vm)
207 {
208     if (!!m_slowArgumentData)
209         return;
210
211     void* backingStore;
212     if (!vm.heap.tryAllocateStorage(this, SlowArgumentData::sizeForNumArguments(m_numArguments), &backingStore))
213         RELEASE_ASSERT_NOT_REACHED();
214     m_slowArgumentData.set(vm, this, static_cast<SlowArgumentData*>(backingStore));
215
216     for (size_t i = 0; i < m_numArguments; ++i) {
217         ASSERT(m_slowArgumentData->slowArguments()[i].status == SlowArgument::Normal);
218         m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
219     }
220 }
221
222 inline bool Arguments::tryDeleteArgument(VM& vm, size_t argument)
223 {
224     if (!isArgument(argument))
225         return false;
226     allocateSlowArguments(vm);
227     m_slowArgumentData->slowArguments()[argument].status = SlowArgument::Deleted;
228     return true;
229 }
230
231 inline bool Arguments::trySetArgument(VM& vm, size_t argument, JSValue value)
232 {
233     if (!isArgument(argument))
234         return false;
235     this->argument(argument).set(vm, this, value);
236     return true;
237 }
238
239 inline JSValue Arguments::tryGetArgument(size_t argument)
240 {
241     if (!isArgument(argument))
242         return JSValue();
243     return this->argument(argument).get();
244 }
245
246 inline bool Arguments::isDeletedArgument(size_t argument)
247 {
248     if (argument >= m_numArguments)
249         return false;
250     if (!m_slowArgumentData)
251         return false;
252     if (m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Deleted)
253         return false;
254     return true;
255 }
256
257 inline bool Arguments::isArgument(size_t argument)
258 {
259     if (argument >= m_numArguments)
260         return false;
261     if (m_slowArgumentData && m_slowArgumentData->slowArguments()[argument].status == SlowArgument::Deleted)
262         return false;
263     return true;
264 }
265
266 inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
267 {
268     ASSERT(isArgument(argument));
269     if (!m_slowArgumentData)
270         return m_registers[CallFrame::argumentOffset(argument)];
271
272     int index = m_slowArgumentData->slowArguments()[argument].index;
273     if (!m_lexicalEnvironment || m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
274         return m_registers[index];
275
276     return m_lexicalEnvironment->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
277 }
278
279 inline void Arguments::finishCreation(CallFrame* callFrame, ArgumentsMode mode)
280 {
281     Base::finishCreation(callFrame->vm());
282     ASSERT(inherits(info()));
283
284     JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
285     m_callee.set(callFrame->vm(), this, callee);
286     m_overrodeLength = false;
287     m_overrodeCallee = false;
288     m_overrodeCaller = false;
289     m_isStrictMode = callFrame->codeBlock()->isStrictMode();
290
291     switch (mode) {
292     case NormalArgumentsCreationMode: {
293         m_numArguments = callFrame->argumentCount();
294         m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
295
296         CodeBlock* codeBlock = callFrame->codeBlock();
297         if (codeBlock->hasSlowArguments()) {
298             SymbolTable* symbolTable = codeBlock->symbolTable();
299             const SlowArgument* slowArguments = codeBlock->machineSlowArguments();
300             allocateSlowArguments(callFrame->vm());
301             size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
302             for (size_t i = 0; i < count; ++i)
303                 m_slowArgumentData->slowArguments()[i] = slowArguments[i];
304             m_slowArgumentData->setBytecodeToMachineCaptureOffset(
305                 codeBlock->framePointerOffsetToGetActivationRegisters());
306         }
307
308         // The bytecode generator omits op_tear_off_lexical_environment in cases of no
309         // declared parameters, so we need to tear off immediately.
310         if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
311             tearOff(callFrame);
312         break;
313     }
314         
315     case FakeArgumentValuesCreationMode: {
316         m_numArguments = 0;
317         m_registers = nullptr;
318         tearOff(callFrame);
319         break;
320     } }
321         
322 }
323
324 inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode)
325 {
326     Base::finishCreation(callFrame->vm());
327     ASSERT(inherits(info()));
328
329     JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
330     m_callee.set(callFrame->vm(), this, callee);
331     m_overrodeLength = false;
332     m_overrodeCallee = false;
333     m_overrodeCaller = false;
334     m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
335
336     switch (mode) {
337     case NormalArgumentsCreationMode: {
338         m_numArguments = inlineCallFrame->arguments.size() - 1;
339         
340         if (m_numArguments) {
341             int offsetForArgumentOne = inlineCallFrame->arguments[1].virtualRegister().offset();
342             m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + offsetForArgumentOne - virtualRegisterForArgument(1).offset();
343         } else
344             m_registers = 0;
345         
346         ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->specializationKind())->slowArguments());
347         
348         // The bytecode generator omits op_tear_off_lexical_environment in cases of no
349         // declared parameters, so we need to tear off immediately.
350         if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
351             tearOff(callFrame, inlineCallFrame);
352         break;
353     }
354         
355     case FakeArgumentValuesCreationMode: {
356         m_numArguments = 0;
357         m_registers = nullptr;
358         tearOff(callFrame);
359         break;
360     } }
361 }
362
363 } // namespace JSC
364
365 #endif // Arguments_h