2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
5 * Copyright (C) 2007 Maks Orlovich
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.
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.
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.
27 #include "CodeOrigin.h"
28 #include "JSActivation.h"
29 #include "JSFunction.h"
30 #include "JSGlobalObject.h"
31 #include "Interpreter.h"
32 #include "ObjectConstructor.h"
36 struct ArgumentsData {
37 WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
40 WriteBarrier<JSActivation> activation;
42 unsigned numParameters;
43 ptrdiff_t firstParameterIndex;
44 unsigned numArguments;
46 WriteBarrier<Unknown>* registers;
47 OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
49 WriteBarrier<Unknown>* extraArguments;
50 OwnArrayPtr<bool> deletedArguments;
51 WriteBarrier<Unknown> extraArgumentsFixedBuffer[4];
53 WriteBarrier<JSFunction> callee;
54 bool overrodeLength : 1;
55 bool overrodeCallee : 1;
56 bool overrodeCaller : 1;
57 bool isStrictMode : 1;
58 bool isInlineFrame : 1; // If true, all arguments are in the extraArguments buffer.
62 class Arguments : public JSNonFinalObject {
64 typedef JSNonFinalObject Base;
66 static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
68 Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
69 arguments->finishCreation(callFrame);
73 static Arguments* createAndTearOff(JSGlobalData& globalData, CallFrame* callFrame)
75 Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
76 arguments->finishCreationAndTearOff(callFrame);
80 static Arguments* createNoParameters(JSGlobalData& globalData, CallFrame* callFrame)
82 Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame, NoParameters);
83 arguments->finishCreation(callFrame, NoParameters);
87 // Use an enum because otherwise gcc insists on doing a memory
89 enum { MaxArguments = 0x10000 };
92 enum NoParametersType { NoParameters };
94 Arguments(CallFrame*);
95 Arguments(CallFrame*, NoParametersType);
100 static const ClassInfo s_info;
102 static void visitChildren(JSCell*, SlotVisitor&);
104 void fillArgList(ExecState*, MarkedArgumentBuffer&);
106 uint32_t length(ExecState* exec) const
108 if (UNLIKELY(d->overrodeLength))
109 return get(exec, exec->propertyNames().length).toUInt32(exec);
110 return d->numArguments;
113 void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize);
114 void tearOff(JSGlobalData&);
115 bool isTornOff() const { return d->registerArray; }
116 void didTearOffActivation(JSGlobalData& globalData, JSActivation* activation)
120 d->activation.set(globalData, this, activation);
121 d->registers = &activation->registerAt(0);
124 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
126 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
130 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
132 void finishCreationButDontTearOff(CallFrame*);
133 void finishCreation(CallFrame*);
134 void finishCreationAndTearOff(CallFrame*);
135 void finishCreation(CallFrame*, NoParametersType);
138 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
139 static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
140 static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
141 static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
142 static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
143 static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
144 static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
145 static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
146 static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
147 void createStrictModeCallerIfNecessary(ExecState*);
148 void createStrictModeCalleeIfNecessary(ExecState*);
150 void init(CallFrame*);
152 OwnPtr<ArgumentsData> d;
155 Arguments* asArguments(JSValue);
157 inline Arguments* asArguments(JSValue value)
159 ASSERT(asObject(value)->inherits(&Arguments::s_info));
160 return static_cast<Arguments*>(asObject(value));
163 ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
165 function = asFunction(callFrame->callee());
167 int numParameters = function->jsExecutable()->parameterCount();
168 argc = callFrame->argumentCountIncludingThis();
170 if (callFrame->isInlineCallFrame())
171 ASSERT(argc == numParameters + 1);
173 if (argc <= numParameters)
174 argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters;
176 argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc;
178 argc -= 1; // - 1 to skip "this"
179 firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters;
182 inline Arguments::Arguments(CallFrame* callFrame)
183 : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
184 , d(adoptPtr(new ArgumentsData))
188 inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
189 : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
190 , d(adoptPtr(new ArgumentsData))
194 inline void Arguments::finishCreationButDontTearOff(CallFrame* callFrame)
196 Base::finishCreation(callFrame->globalData());
197 ASSERT(inherits(&s_info));
200 ptrdiff_t firstParameterIndex;
203 getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
205 d->numParameters = callee->jsExecutable()->parameterCount();
206 d->firstParameterIndex = firstParameterIndex;
207 d->numArguments = numArguments;
208 d->isInlineFrame = false;
210 d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
212 WriteBarrier<Unknown>* extraArguments;
213 if (d->numArguments <= d->numParameters)
216 unsigned numExtraArguments = d->numArguments - d->numParameters;
217 if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
218 extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
220 extraArguments = d->extraArgumentsFixedBuffer;
221 for (unsigned i = 0; i < numExtraArguments; ++i)
222 extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
225 d->extraArguments = extraArguments;
227 d->callee.set(callFrame->globalData(), this, callee);
228 d->overrodeLength = false;
229 d->overrodeCallee = false;
230 d->overrodeCaller = false;
231 d->isStrictMode = callFrame->codeBlock()->isStrictMode();
234 inline void Arguments::finishCreation(CallFrame* callFrame)
236 ASSERT(!callFrame->isInlineCallFrame());
237 finishCreationButDontTearOff(callFrame);
239 tearOff(callFrame->globalData());
242 inline void Arguments::finishCreationAndTearOff(CallFrame* callFrame)
244 Base::finishCreation(callFrame->globalData());
245 ASSERT(inherits(&s_info));
249 ptrdiff_t firstParameterIndex;
252 getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
254 d->numParameters = callee->jsExecutable()->parameterCount();
255 d->firstParameterIndex = firstParameterIndex;
256 d->numArguments = numArguments;
258 if (d->numParameters) {
259 int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
260 size_t registerArraySize = d->numParameters;
262 OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[registerArraySize]);
263 if (callFrame->isInlineCallFrame()) {
264 InlineCallFrame* inlineCallFrame = callFrame->inlineCallFrame();
265 for (size_t i = 0; i < registerArraySize; ++i) {
266 ValueRecovery& recovery = inlineCallFrame->arguments[i + 1];
267 // In the future we'll support displaced recoveries (indicating that the
268 // argument was flushed to a different location), but for now we don't do
269 // that so this code will fail if that were to happen. On the other hand,
270 // it's much less likely that we'll support in-register recoveries since
271 // this code does not (easily) have access to registers.
273 Register* location = callFrame->registers() + i - registerOffset;
274 switch (recovery.technique()) {
275 case AlreadyInRegisterFile:
276 value = location->jsValue();
278 case AlreadyInRegisterFileAsUnboxedInt32:
279 value = jsNumber(location->unboxedInt32());
281 case AlreadyInRegisterFileAsUnboxedCell:
282 value = location->unboxedCell();
284 case AlreadyInRegisterFileAsUnboxedBoolean:
285 value = jsBoolean(location->unboxedBoolean());
288 value = recovery.constant();
291 ASSERT_NOT_REACHED();
294 registerArray[i].set(callFrame->globalData(), this, value);
297 for (size_t i = 0; i < registerArraySize; ++i)
298 registerArray[i].set(callFrame->globalData(), this, callFrame->registers()[i - registerOffset].jsValue());
300 d->registers = registerArray.get() + d->numParameters + RegisterFile::CallFrameHeaderSize;
301 d->registerArray = registerArray.release();
304 WriteBarrier<Unknown>* extraArguments;
305 if (callFrame->isInlineCallFrame())
306 ASSERT(d->numArguments == d->numParameters);
307 if (d->numArguments <= d->numParameters)
310 unsigned numExtraArguments = d->numArguments - d->numParameters;
311 if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
312 extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
314 extraArguments = d->extraArgumentsFixedBuffer;
315 for (unsigned i = 0; i < numExtraArguments; ++i)
316 extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
319 d->extraArguments = extraArguments;
321 d->callee.set(callFrame->globalData(), this, callee);
322 d->overrodeLength = false;
323 d->overrodeCallee = false;
324 d->overrodeCaller = false;
325 d->isInlineFrame = callFrame->isInlineCallFrame();
326 d->isStrictMode = callFrame->codeBlock()->isStrictMode();
329 inline void Arguments::finishCreation(CallFrame* callFrame, NoParametersType)
331 ASSERT(!callFrame->isInlineCallFrame());
332 Base::finishCreation(callFrame->globalData());
333 ASSERT(inherits(&s_info));
334 ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount());
336 unsigned numArguments = callFrame->argumentCount();
338 d->numParameters = 0;
339 d->numArguments = numArguments;
340 d->isInlineFrame = false;
342 WriteBarrier<Unknown>* extraArguments;
343 if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
344 extraArguments = new WriteBarrier<Unknown>[numArguments];
346 extraArguments = d->extraArgumentsFixedBuffer;
348 Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1;
349 for (unsigned i = 0; i < numArguments; ++i)
350 extraArguments[i].set(callFrame->globalData(), this, argv[i].jsValue());
352 d->extraArguments = extraArguments;
354 d->callee.set(callFrame->globalData(), this, asFunction(callFrame->callee()));
355 d->overrodeLength = false;
356 d->overrodeCallee = false;
357 d->overrodeCaller = false;
358 d->isStrictMode = callFrame->codeBlock()->isStrictMode();
360 tearOff(callFrame->globalData());
363 inline void Arguments::tearOff(JSGlobalData& globalData)
365 ASSERT(!isTornOff());
367 if (!d->numParameters)
370 int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
371 size_t registerArraySize = d->numParameters;
373 OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[registerArraySize]);
374 for (size_t i = 0; i < registerArraySize; i++)
375 registerArray[i].set(globalData, this, d->registers[i - registerOffset].get());
376 d->registers = registerArray.get() + registerOffset;
377 d->registerArray = registerArray.release();
382 #endif // Arguments_h