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 "JSActivation.h"
28 #include "JSFunction.h"
29 #include "JSGlobalObject.h"
30 #include "Interpreter.h"
31 #include "ObjectConstructor.h"
35 struct ArgumentsData {
36 WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
39 WriteBarrier<JSActivation> activation;
41 unsigned numParameters;
42 ptrdiff_t firstParameterIndex;
43 unsigned numArguments;
45 WriteBarrier<Unknown>* registers;
46 OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
48 WriteBarrier<Unknown>* extraArguments;
49 OwnArrayPtr<bool> deletedArguments;
50 WriteBarrier<Unknown> extraArgumentsFixedBuffer[4];
52 WriteBarrier<JSFunction> callee;
53 bool overrodeLength : 1;
54 bool overrodeCallee : 1;
55 bool overrodeCaller : 1;
56 bool isStrictMode : 1;
60 class Arguments : public JSNonFinalObject {
62 typedef JSNonFinalObject Base;
64 static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
66 Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
67 arguments->finishCreation(callFrame);
71 static Arguments* createNoParameters(JSGlobalData& globalData, CallFrame* callFrame)
73 Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame, NoParameters);
74 arguments->finishCreation(callFrame, NoParameters);
78 // Use an enum because otherwise gcc insists on doing a memory
80 enum { MaxArguments = 0x10000 };
83 enum NoParametersType { NoParameters };
85 Arguments(CallFrame*);
86 Arguments(CallFrame*, NoParametersType);
91 static const ClassInfo s_info;
93 virtual void visitChildren(SlotVisitor&);
95 void fillArgList(ExecState*, MarkedArgumentBuffer&);
97 uint32_t numProvidedArguments(ExecState* exec) const
99 if (UNLIKELY(d->overrodeLength))
100 return get(exec, exec->propertyNames().length).toUInt32(exec);
101 return d->numArguments;
104 void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize);
105 void copyRegisters(JSGlobalData&);
106 bool isTornOff() const { return d->registerArray; }
107 void setActivation(JSGlobalData& globalData, JSActivation* activation)
109 ASSERT(!d->registerArray);
110 d->activation.set(globalData, this, activation);
111 d->registers = &activation->registerAt(0);
114 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
116 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
120 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
122 void finishCreation(CallFrame*);
123 void finishCreation(CallFrame*, NoParametersType);
126 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
127 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
128 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
129 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
130 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
131 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
132 virtual void put(ExecState*, unsigned propertyName, JSValue);
133 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
134 virtual bool deleteProperty(ExecState*, unsigned propertyName);
135 void createStrictModeCallerIfNecessary(ExecState*);
136 void createStrictModeCalleeIfNecessary(ExecState*);
138 void init(CallFrame*);
140 OwnPtr<ArgumentsData> d;
143 Arguments* asArguments(JSValue);
145 inline Arguments* asArguments(JSValue value)
147 ASSERT(asObject(value)->inherits(&Arguments::s_info));
148 return static_cast<Arguments*>(asObject(value));
151 ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
153 function = asFunction(callFrame->callee());
155 int numParameters = function->jsExecutable()->parameterCount();
156 argc = callFrame->argumentCountIncludingThis();
158 if (argc <= numParameters)
159 argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters;
161 argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc;
163 argc -= 1; // - 1 to skip "this"
164 firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters;
167 inline Arguments::Arguments(CallFrame* callFrame)
168 : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
169 , d(adoptPtr(new ArgumentsData))
173 inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
174 : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
175 , d(adoptPtr(new ArgumentsData))
179 inline void Arguments::finishCreation(CallFrame* callFrame)
181 Base::finishCreation(callFrame->globalData());
182 ASSERT(inherits(&s_info));
185 ptrdiff_t firstParameterIndex;
188 getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
190 d->numParameters = callee->jsExecutable()->parameterCount();
191 d->firstParameterIndex = firstParameterIndex;
192 d->numArguments = numArguments;
194 d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
196 WriteBarrier<Unknown>* extraArguments;
197 if (d->numArguments <= d->numParameters)
200 unsigned numExtraArguments = d->numArguments - d->numParameters;
201 if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
202 extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
204 extraArguments = d->extraArgumentsFixedBuffer;
205 for (unsigned i = 0; i < numExtraArguments; ++i)
206 extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
209 d->extraArguments = extraArguments;
211 d->callee.set(callFrame->globalData(), this, callee);
212 d->overrodeLength = false;
213 d->overrodeCallee = false;
214 d->overrodeCaller = false;
215 d->isStrictMode = callFrame->codeBlock()->isStrictMode();
217 copyRegisters(callFrame->globalData());
220 inline void Arguments::finishCreation(CallFrame* callFrame, NoParametersType)
222 Base::finishCreation(callFrame->globalData());
223 ASSERT(inherits(&s_info));
224 ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount());
226 unsigned numArguments = callFrame->argumentCount();
228 d->numParameters = 0;
229 d->numArguments = numArguments;
231 WriteBarrier<Unknown>* extraArguments;
232 if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
233 extraArguments = new WriteBarrier<Unknown>[numArguments];
235 extraArguments = d->extraArgumentsFixedBuffer;
237 Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1;
238 for (unsigned i = 0; i < numArguments; ++i)
239 extraArguments[i].set(callFrame->globalData(), this, argv[i].jsValue());
241 d->extraArguments = extraArguments;
243 d->callee.set(callFrame->globalData(), this, asFunction(callFrame->callee()));
244 d->overrodeLength = false;
245 d->overrodeCallee = false;
246 d->overrodeCaller = false;
247 d->isStrictMode = callFrame->codeBlock()->isStrictMode();
249 copyRegisters(callFrame->globalData());
252 inline void Arguments::copyRegisters(JSGlobalData& globalData)
254 ASSERT(!isTornOff());
256 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 for (size_t i = 0; i < registerArraySize; i++)
264 registerArray[i].set(globalData, this, d->registers[i - registerOffset].get());
265 d->registers = registerArray.get() + registerOffset;
266 d->registerArray = registerArray.release();
269 // This JSActivation function is defined here so it can get at Arguments::setRegisters.
270 inline void JSActivation::copyRegisters(JSGlobalData& globalData)
272 ASSERT(!m_registerArray);
274 size_t numLocals = m_numCapturedVars + m_numParametersMinusThis;
279 int registerOffset = m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
280 size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
282 OwnArrayPtr<WriteBarrier<Unknown> > registerArray = copyRegisterArray(globalData, m_registers - registerOffset, registerArraySize, m_numParametersMinusThis + 1);
283 WriteBarrier<Unknown>* registers = registerArray.get() + registerOffset;
284 setRegisters(registers, registerArray.release());
289 #endif // Arguments_h