]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Arguments.h
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / runtime / Arguments.h
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
f9bf01c6 3 * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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
6fe7ccc8 27#include "CodeOrigin.h"
9dae56ea
A
28#include "JSActivation.h"
29#include "JSFunction.h"
30#include "JSGlobalObject.h"
31#include "Interpreter.h"
f9bf01c6 32#include "ObjectConstructor.h"
81345200
A
33#include "WriteBarrierInlines.h"
34#include <wtf/StdLibExtras.h>
9dae56ea
A
35
36namespace JSC {
37
81345200 38class Arguments : public JSNonFinalObject {
93a37866 39 friend class JIT;
81345200 40 friend class JSArgumentsIterator;
93a37866 41public:
81345200 42 typedef JSNonFinalObject Base;
9dae56ea 43
93a37866
A
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 }
6fe7ccc8 57
93a37866 58 enum { MaxArguments = 0x10000 };
fb8617cd 59
93a37866
A
60private:
61 enum NoParametersType { NoParameters };
62
63 Arguments(CallFrame*);
64 Arguments(CallFrame*, NoParametersType);
6fe7ccc8 65
93a37866 66public:
81345200 67 DECLARE_INFO;
9dae56ea 68
93a37866 69 static void visitChildren(JSCell*, SlotVisitor&);
81345200 70 static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
9dae56ea 71
93a37866 72 void fillArgList(ExecState*, MarkedArgumentBuffer&);
9dae56ea 73
93a37866 74 uint32_t length(ExecState* exec) const
9dae56ea 75 {
93a37866
A
76 if (UNLIKELY(m_overrodeLength))
77 return get(exec, exec->propertyNames().length).toUInt32(exec);
78 return m_numArguments;
9dae56ea 79 }
93a37866 80
81345200 81 void copyToArguments(ExecState*, CallFrame*, uint32_t copyLength, int32_t firstArgumentOffset);
93a37866
A
82 void tearOff(CallFrame*);
83 void tearOff(CallFrame*, InlineCallFrame*);
81345200 84 bool isTornOff() const { return m_registerArray.get(); }
93a37866
A
85 void didTearOffActivation(ExecState*, JSActivation*);
86
87 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
88 {
81345200 89 return Structure::create(vm, globalObject, prototype, TypeInfo(ArgumentsType, StructureFlags), info());
9dae56ea 90 }
81345200
A
91
92 static ptrdiff_t offsetOfActivation() { return OBJECT_OFFSETOF(Arguments, m_activation); }
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
93a37866
A
107protected:
108 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
109
110 void finishCreation(CallFrame*);
111 void finishCreation(CallFrame*, InlineCallFrame*);
112
113private:
81345200
A
114 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
115 static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
93a37866
A
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);
81345200 121 static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
93a37866
A
122 void createStrictModeCallerIfNecessary(ExecState*);
123 void createStrictModeCalleeIfNecessary(ExecState*);
124
81345200
A
125 size_t registerArraySizeInBytes() const { return sizeof(WriteBarrier<Unknown>) * m_numArguments; }
126 void allocateRegisterArray(VM&);
93a37866
A
127 bool isArgument(size_t);
128 bool trySetArgument(VM&, size_t argument, JSValue);
129 JSValue tryGetArgument(size_t argument);
130 bool isDeletedArgument(size_t);
81345200 131 bool tryDeleteArgument(VM&, size_t);
93a37866 132 WriteBarrierBase<Unknown>& argument(size_t);
81345200 133 void allocateSlowArguments(VM&);
93a37866
A
134
135 void init(CallFrame*);
136
137 WriteBarrier<JSActivation> m_activation;
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;
81345200 150 CopyWriteBarrier<WriteBarrier<Unknown>> m_registerArray;
93a37866 151
81345200
A
152public:
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
177private:
178 CopyWriteBarrier<SlowArgumentData> m_slowArgumentData;
93a37866
A
179
180 WriteBarrier<JSFunction> m_callee;
181};
182
183Arguments* asArguments(JSValue);
184
185inline Arguments* asArguments(JSValue value)
186{
81345200 187 ASSERT(asObject(value)->inherits(Arguments::info()));
93a37866
A
188 return static_cast<Arguments*>(asObject(value));
189}
190
191inline Arguments::Arguments(CallFrame* callFrame)
81345200 192 : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
93a37866
A
193{
194}
195
196inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
81345200 197 : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
93a37866
A
198{
199}
200
81345200 201inline void Arguments::allocateSlowArguments(VM& vm)
93a37866 202{
81345200 203 if (!!m_slowArgumentData)
93a37866 204 return;
81345200
A
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
93a37866 211 for (size_t i = 0; i < m_numArguments; ++i) {
81345200
A
212 ASSERT(m_slowArgumentData->slowArguments()[i].status == SlowArgument::Normal);
213 m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
9dae56ea 214 }
93a37866
A
215}
216
81345200 217inline bool Arguments::tryDeleteArgument(VM& vm, size_t argument)
93a37866
A
218{
219 if (!isArgument(argument))
220 return false;
81345200
A
221 allocateSlowArguments(vm);
222 m_slowArgumentData->slowArguments()[argument].status = SlowArgument::Deleted;
93a37866
A
223 return true;
224}
225
226inline 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
234inline JSValue Arguments::tryGetArgument(size_t argument)
235{
236 if (!isArgument(argument))
237 return JSValue();
238 return this->argument(argument).get();
239}
240
241inline bool Arguments::isDeletedArgument(size_t argument)
242{
243 if (argument >= m_numArguments)
244 return false;
81345200 245 if (!m_slowArgumentData)
93a37866 246 return false;
81345200 247 if (m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Deleted)
93a37866
A
248 return false;
249 return true;
250}
251
252inline bool Arguments::isArgument(size_t argument)
253{
254 if (argument >= m_numArguments)
255 return false;
81345200 256 if (m_slowArgumentData && m_slowArgumentData->slowArguments()[argument].status == SlowArgument::Deleted)
93a37866
A
257 return false;
258 return true;
259}
260
261inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
262{
263 ASSERT(isArgument(argument));
81345200 264 if (!m_slowArgumentData)
93a37866
A
265 return m_registers[CallFrame::argumentOffset(argument)];
266
81345200
A
267 int index = m_slowArgumentData->slowArguments()[argument].index;
268 if (!m_activation || m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
93a37866
A
269 return m_registers[index];
270
81345200 271 return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
93a37866
A
272}
273
274inline void Arguments::finishCreation(CallFrame* callFrame)
275{
276 Base::finishCreation(callFrame->vm());
81345200 277 ASSERT(inherits(info()));
93a37866
A
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
81345200
A
288 CodeBlock* codeBlock = callFrame->codeBlock();
289 if (codeBlock->hasSlowArguments()) {
290 SymbolTable* symbolTable = codeBlock->symbolTable();
291 const SlowArgument* slowArguments = codeBlock->machineSlowArguments();
292 allocateSlowArguments(callFrame->vm());
93a37866
A
293 size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
294 for (size_t i = 0; i < count; ++i)
81345200
A
295 m_slowArgumentData->slowArguments()[i] = slowArguments[i];
296 m_slowArgumentData->setBytecodeToMachineCaptureOffset(
297 codeBlock->framePointerOffsetToGetActivationRegisters());
9dae56ea
A
298 }
299
93a37866
A
300 // The bytecode generator omits op_tear_off_activation 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
306inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
307{
308 Base::finishCreation(callFrame->vm());
81345200 309 ASSERT(inherits(info()));
93a37866
A
310
311 JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
312 m_numArguments = inlineCallFrame->arguments.size() - 1;
81345200
A
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;
93a37866
A
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->isCall ? CodeForCall : CodeForConstruct)->slowArguments());
325
326 // The bytecode generator omits op_tear_off_activation 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}
ba379fdc 331
9dae56ea
A
332} // namespace JSC
333
334#endif // Arguments_h