Rename activation to be more in line with spec language
[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 class Arguments : public JSNonFinalObject {
39     friend class JIT;
40     friend class JSArgumentsIterator;
41 public:
42     typedef JSNonFinalObject Base;
43
44     static Arguments* create(VM& vm, CallFrame* callFrame)
45     {
46         Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame);
47         arguments->finishCreation(callFrame);
48         return arguments;
49     }
50         
51     static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
52     {
53         Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame);
54         arguments->finishCreation(callFrame, inlineCallFrame);
55         return arguments;
56     }
57
58     enum { MaxArguments = 0x10000 };
59
60 private:
61     enum NoParametersType { NoParameters };
62         
63     Arguments(CallFrame*);
64     Arguments(CallFrame*, NoParametersType);
65         
66 public:
67     DECLARE_INFO;
68
69     static void visitChildren(JSCell*, SlotVisitor&);
70     static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
71
72     void fillArgList(ExecState*, MarkedArgumentBuffer&);
73
74     uint32_t length(ExecState* exec) const 
75     {
76         if (UNLIKELY(m_overrodeLength))
77             return get(exec, exec->propertyNames().length).toUInt32(exec);
78         return m_numArguments; 
79     }
80         
81     void copyToArguments(ExecState*, CallFrame*, uint32_t copyLength, int32_t firstArgumentOffset);
82     void tearOff(CallFrame*);
83     void tearOff(CallFrame*, InlineCallFrame*);
84     bool isTornOff() const { return m_registerArray.get(); }
85     void didTearOffActivation(ExecState*, JSLexicalEnvironment*);
86
87     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 
88     { 
89         return Structure::create(vm, globalObject, prototype, TypeInfo(ArgumentsType, StructureFlags), info()); 
90     }
91     
92     static ptrdiff_t offsetOfActivation() { return OBJECT_OFFSETOF(Arguments, m_lexicalEnvironment); }
93     static ptrdiff_t offsetOfNumArguments() { return OBJECT_OFFSETOF(Arguments, m_numArguments); }
94     static ptrdiff_t offsetOfOverrodeLength() { return OBJECT_OFFSETOF(Arguments, m_overrodeLength); }
95     static ptrdiff_t offsetOfIsStrictMode() { return OBJECT_OFFSETOF(Arguments, m_isStrictMode); }
96     static ptrdiff_t offsetOfRegisters() { return OBJECT_OFFSETOF(Arguments, m_registers); }
97     static ptrdiff_t offsetOfRegisterArray() { return OBJECT_OFFSETOF(Arguments, m_registerArray); }
98     static ptrdiff_t offsetOfSlowArgumentData() { return OBJECT_OFFSETOF(Arguments, m_slowArgumentData); }
99     static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(Arguments, m_callee); }
100
101     static size_t allocationSize(size_t inlineCapacity)
102     {
103         ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
104         return sizeof(Arguments);
105     }
106     
107 protected:
108     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSObject::StructureFlags;
109
110     void finishCreation(CallFrame*);
111     void finishCreation(CallFrame*, InlineCallFrame*);
112
113 private:
114     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
115     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
116     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
117     static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
118     static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
119     static bool deleteProperty(JSCell*, ExecState*, PropertyName);
120     static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
121     static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
122     void createStrictModeCallerIfNecessary(ExecState*);
123     void createStrictModeCalleeIfNecessary(ExecState*);
124
125     size_t registerArraySizeInBytes() const { return sizeof(WriteBarrier<Unknown>) * m_numArguments; }
126     void allocateRegisterArray(VM&);
127     bool isArgument(size_t);
128     bool trySetArgument(VM&, size_t argument, JSValue);
129     JSValue tryGetArgument(size_t argument);
130     bool isDeletedArgument(size_t);
131     bool tryDeleteArgument(VM&, size_t);
132     WriteBarrierBase<Unknown>& argument(size_t);
133     void allocateSlowArguments(VM&);
134
135     void init(CallFrame*);
136
137     WriteBarrier<JSLexicalEnvironment> m_lexicalEnvironment;
138
139     unsigned m_numArguments;
140
141     // We make these full byte booleans to make them easy to test from the JIT,
142     // and because even if they were single-bit booleans we still wouldn't save
143     // any space.
144     bool m_overrodeLength; 
145     bool m_overrodeCallee;
146     bool m_overrodeCaller;
147     bool m_isStrictMode;
148
149     WriteBarrierBase<Unknown>* m_registers;
150     CopyWriteBarrier<WriteBarrier<Unknown>> m_registerArray;
151
152 public:
153     struct SlowArgumentData {
154     public:
155         SlowArgumentData()
156             : m_bytecodeToMachineCaptureOffset(0)
157         {
158         }
159
160         SlowArgument* slowArguments()
161         {
162             return reinterpret_cast<SlowArgument*>(WTF::roundUpToMultipleOf<8>(reinterpret_cast<size_t>(this + 1)));
163         }
164
165         int bytecodeToMachineCaptureOffset() const { return m_bytecodeToMachineCaptureOffset; }
166         void setBytecodeToMachineCaptureOffset(int newOffset) { m_bytecodeToMachineCaptureOffset = newOffset; }
167
168         static size_t sizeForNumArguments(unsigned numArguments)
169         {
170             return WTF::roundUpToMultipleOf<8>(sizeof(SlowArgumentData)) + sizeof(SlowArgument) * numArguments;
171         }
172
173     private:
174         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. 
175     };
176     
177 private:
178     CopyWriteBarrier<SlowArgumentData> m_slowArgumentData;
179
180     WriteBarrier<JSFunction> m_callee;
181 };
182
183 Arguments* asArguments(JSValue);
184
185 inline Arguments* asArguments(JSValue value)
186 {
187     ASSERT(asObject(value)->inherits(Arguments::info()));
188     return static_cast<Arguments*>(asObject(value));
189 }
190
191 inline Arguments::Arguments(CallFrame* callFrame)
192     : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
193 {
194 }
195
196 inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
197     : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
198 {
199 }
200
201 inline void Arguments::allocateSlowArguments(VM& vm)
202 {
203     if (!!m_slowArgumentData)
204         return;
205
206     void* backingStore;
207     if (!vm.heap.tryAllocateStorage(this, SlowArgumentData::sizeForNumArguments(m_numArguments), &backingStore))
208         RELEASE_ASSERT_NOT_REACHED();
209     m_slowArgumentData.set(vm, this, static_cast<SlowArgumentData*>(backingStore));
210
211     for (size_t i = 0; i < m_numArguments; ++i) {
212         ASSERT(m_slowArgumentData->slowArguments()[i].status == SlowArgument::Normal);
213         m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
214     }
215 }
216
217 inline bool Arguments::tryDeleteArgument(VM& vm, size_t argument)
218 {
219     if (!isArgument(argument))
220         return false;
221     allocateSlowArguments(vm);
222     m_slowArgumentData->slowArguments()[argument].status = SlowArgument::Deleted;
223     return true;
224 }
225
226 inline bool Arguments::trySetArgument(VM& vm, size_t argument, JSValue value)
227 {
228     if (!isArgument(argument))
229         return false;
230     this->argument(argument).set(vm, this, value);
231     return true;
232 }
233
234 inline JSValue Arguments::tryGetArgument(size_t argument)
235 {
236     if (!isArgument(argument))
237         return JSValue();
238     return this->argument(argument).get();
239 }
240
241 inline bool Arguments::isDeletedArgument(size_t argument)
242 {
243     if (argument >= m_numArguments)
244         return false;
245     if (!m_slowArgumentData)
246         return false;
247     if (m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Deleted)
248         return false;
249     return true;
250 }
251
252 inline bool Arguments::isArgument(size_t argument)
253 {
254     if (argument >= m_numArguments)
255         return false;
256     if (m_slowArgumentData && m_slowArgumentData->slowArguments()[argument].status == SlowArgument::Deleted)
257         return false;
258     return true;
259 }
260
261 inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
262 {
263     ASSERT(isArgument(argument));
264     if (!m_slowArgumentData)
265         return m_registers[CallFrame::argumentOffset(argument)];
266
267     int index = m_slowArgumentData->slowArguments()[argument].index;
268     if (!m_lexicalEnvironment || m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
269         return m_registers[index];
270
271     return m_lexicalEnvironment->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
272 }
273
274 inline void Arguments::finishCreation(CallFrame* callFrame)
275 {
276     Base::finishCreation(callFrame->vm());
277     ASSERT(inherits(info()));
278
279     JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
280     m_numArguments = callFrame->argumentCount();
281     m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
282     m_callee.set(callFrame->vm(), this, callee);
283     m_overrodeLength = false;
284     m_overrodeCallee = false;
285     m_overrodeCaller = false;
286     m_isStrictMode = callFrame->codeBlock()->isStrictMode();
287
288     CodeBlock* codeBlock = callFrame->codeBlock();
289     if (codeBlock->hasSlowArguments()) {
290         SymbolTable* symbolTable = codeBlock->symbolTable();
291         const SlowArgument* slowArguments = codeBlock->machineSlowArguments();
292         allocateSlowArguments(callFrame->vm());
293         size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
294         for (size_t i = 0; i < count; ++i)
295             m_slowArgumentData->slowArguments()[i] = slowArguments[i];
296         m_slowArgumentData->setBytecodeToMachineCaptureOffset(
297             codeBlock->framePointerOffsetToGetActivationRegisters());
298     }
299
300     // The bytecode generator omits op_tear_off_lexical_environment in cases of no
301     // declared parameters, so we need to tear off immediately.
302     if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
303         tearOff(callFrame);
304 }
305
306 inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
307 {
308     Base::finishCreation(callFrame->vm());
309     ASSERT(inherits(info()));
310
311     JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
312     m_numArguments = inlineCallFrame->arguments.size() - 1;
313     
314     if (m_numArguments) {
315         int offsetForArgumentOne = inlineCallFrame->arguments[1].virtualRegister().offset();
316         m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + offsetForArgumentOne - virtualRegisterForArgument(1).offset();
317     } else
318         m_registers = 0;
319     m_callee.set(callFrame->vm(), this, callee);
320     m_overrodeLength = false;
321     m_overrodeCallee = false;
322     m_overrodeCaller = false;
323     m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
324     ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->specializationKind())->slowArguments());
325
326     // The bytecode generator omits op_tear_off_lexical_environment in cases of no
327     // declared parameters, so we need to tear off immediately.
328     if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
329         tearOff(callFrame, inlineCallFrame);
330 }
331
332 } // namespace JSC
333
334 #endif // Arguments_h