1 | /* |
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 |
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 "JSActivation.h" |
28 | #include "JSFunction.h" |
29 | #include "JSGlobalObject.h" |
30 | #include "Interpreter.h" |
31 | #include "ObjectConstructor.h" |
32 | #include "PrototypeFunction.h" |
33 | |
34 | namespace JSC { |
35 | |
36 | struct ArgumentsData : Noncopyable { |
37 | JSActivation* activation; |
38 | |
39 | unsigned numParameters; |
40 | ptrdiff_t firstParameterIndex; |
41 | unsigned numArguments; |
42 | |
43 | Register* registers; |
44 | OwnArrayPtr<Register> registerArray; |
45 | |
46 | Register* ; |
47 | OwnArrayPtr<bool> deletedArguments; |
48 | Register [4]; |
49 | |
50 | JSObject* callee; |
51 | bool overrodeLength : 1; |
52 | bool overrodeCallee : 1; |
53 | }; |
54 | |
55 | |
56 | class Arguments : public JSObject { |
57 | public: |
58 | enum NoParametersType { NoParameters }; |
59 | |
60 | Arguments(CallFrame*); |
61 | Arguments(CallFrame*, NoParametersType); |
62 | virtual ~Arguments(); |
63 | |
64 | static const ClassInfo info; |
65 | |
66 | virtual void markChildren(MarkStack&); |
67 | |
68 | void fillArgList(ExecState*, MarkedArgumentBuffer&); |
69 | |
70 | uint32_t numProvidedArguments(ExecState* exec) const |
71 | { |
72 | if (UNLIKELY(d->overrodeLength)) |
73 | return get(exec, propertyName: exec->propertyNames().length).toUInt32(exec); |
74 | return d->numArguments; |
75 | } |
76 | |
77 | void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize); |
78 | void copyRegisters(); |
79 | bool isTornOff() const { return d->registerArray; } |
80 | void setActivation(JSActivation* activation) |
81 | { |
82 | d->activation = activation; |
83 | d->registers = &activation->registerAt(index: 0); |
84 | } |
85 | |
86 | static PassRefPtr<Structure> createStructure(JSValue prototype) |
87 | { |
88 | return Structure::create(prototype, typeInfo: TypeInfo(ObjectType, StructureFlags)); |
89 | } |
90 | |
91 | protected: |
92 | static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; |
93 | |
94 | private: |
95 | void getArgumentsData(CallFrame*, JSObject*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); |
96 | virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); |
97 | virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); |
98 | virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); |
99 | virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); |
100 | virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); |
101 | virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&); |
102 | virtual bool deleteProperty(ExecState*, const Identifier& propertyName); |
103 | virtual bool deleteProperty(ExecState*, unsigned propertyName); |
104 | |
105 | virtual const ClassInfo* classInfo() const { return &info; } |
106 | |
107 | void init(CallFrame*); |
108 | |
109 | OwnPtr<ArgumentsData> d; |
110 | }; |
111 | |
112 | Arguments* asArguments(JSValue); |
113 | |
114 | inline Arguments* asArguments(JSValue value) |
115 | { |
116 | ASSERT(asObject(value)->inherits(&Arguments::info)); |
117 | return static_cast<Arguments*>(asObject(value)); |
118 | } |
119 | |
120 | ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSObject*& callee, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc) |
121 | { |
122 | callee = callFrame->callee(); |
123 | |
124 | int numParameters; |
125 | if (callee->inherits(info: &JSFunction::info)) |
126 | numParameters = JSC::asFunction(value: callee)->jsExecutable()->parameterCount(); |
127 | else |
128 | numParameters = 0; |
129 | |
130 | argc = callFrame->argumentCount(); |
131 | |
132 | if (argc <= numParameters) |
133 | argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters; |
134 | else |
135 | argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc; |
136 | |
137 | argc -= 1; // - 1 to skip "this" |
138 | firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters; |
139 | } |
140 | |
141 | inline Arguments::Arguments(CallFrame* callFrame) |
142 | : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) |
143 | , d(new ArgumentsData) |
144 | { |
145 | JSObject* callee; |
146 | ptrdiff_t firstParameterIndex; |
147 | Register* argv; |
148 | int numArguments; |
149 | getArgumentsData(callFrame, callee, firstParameterIndex, argv, argc&: numArguments); |
150 | |
151 | if (callee->inherits(info: &JSFunction::info)) |
152 | d->numParameters = JSC::asFunction(value: callee)->jsExecutable()->parameterCount(); |
153 | else |
154 | d->numParameters = 0; |
155 | d->firstParameterIndex = firstParameterIndex; |
156 | d->numArguments = numArguments; |
157 | |
158 | d->activation = 0; |
159 | d->registers = callFrame->registers(); |
160 | |
161 | Register* ; |
162 | if (d->numArguments <= d->numParameters) |
163 | extraArguments = 0; |
164 | else { |
165 | unsigned = d->numArguments - d->numParameters; |
166 | if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) |
167 | extraArguments = new Register[numExtraArguments]; |
168 | else |
169 | extraArguments = d->extraArgumentsFixedBuffer; |
170 | for (unsigned i = 0; i < numExtraArguments; ++i) |
171 | extraArguments[i] = argv[d->numParameters + i]; |
172 | } |
173 | |
174 | d->extraArguments = extraArguments; |
175 | |
176 | d->callee = callee; |
177 | d->overrodeLength = false; |
178 | d->overrodeCallee = false; |
179 | } |
180 | |
181 | inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) |
182 | : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) |
183 | , d(new ArgumentsData) |
184 | { |
185 | if (callFrame->callee() && callFrame->callee()->inherits(info: &JSC::JSFunction::info)) |
186 | ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount()); |
187 | |
188 | unsigned numArguments = callFrame->argumentCount() - 1; |
189 | |
190 | d->numParameters = 0; |
191 | d->numArguments = numArguments; |
192 | d->activation = 0; |
193 | |
194 | Register* ; |
195 | if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) |
196 | extraArguments = new Register[numArguments]; |
197 | else |
198 | extraArguments = d->extraArgumentsFixedBuffer; |
199 | |
200 | Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1; |
201 | if (callFrame->callee() && !callFrame->callee()->inherits(info: &JSC::JSFunction::info)) |
202 | ++argv; // ### off-by-one issue with native functions |
203 | for (unsigned i = 0; i < numArguments; ++i) |
204 | extraArguments[i] = argv[i]; |
205 | |
206 | d->extraArguments = extraArguments; |
207 | |
208 | d->callee = callFrame->callee(); |
209 | d->overrodeLength = false; |
210 | d->overrodeCallee = false; |
211 | } |
212 | |
213 | inline void Arguments::copyRegisters() |
214 | { |
215 | ASSERT(!isTornOff()); |
216 | |
217 | if (!d->numParameters) |
218 | return; |
219 | |
220 | int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize; |
221 | size_t registerArraySize = d->numParameters; |
222 | |
223 | Register* registerArray = new Register[registerArraySize]; |
224 | memcpy(dest: registerArray, src: d->registers - registerOffset, n: registerArraySize * sizeof(Register)); |
225 | d->registerArray.set(registerArray); |
226 | d->registers = registerArray + registerOffset; |
227 | } |
228 | |
229 | // This JSActivation function is defined here so it can get at Arguments::setRegisters. |
230 | inline void JSActivation::copyRegisters(Arguments* arguments) |
231 | { |
232 | ASSERT(!d()->registerArray); |
233 | |
234 | size_t numParametersMinusThis = d()->functionExecutable->generatedBytecode().m_numParameters - 1; |
235 | size_t numVars = d()->functionExecutable->generatedBytecode().m_numVars; |
236 | size_t numLocals = numVars + numParametersMinusThis; |
237 | |
238 | if (!numLocals) |
239 | return; |
240 | |
241 | int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize; |
242 | size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize; |
243 | |
244 | Register* registerArray = copyRegisterArray(src: d()->registers - registerOffset, count: registerArraySize); |
245 | setRegisters(registers: registerArray + registerOffset, registerArray); |
246 | if (arguments && !arguments->isTornOff()) |
247 | static_cast<Arguments*>(arguments)->setActivation(this); |
248 | } |
249 | |
250 | ALWAYS_INLINE Arguments* Register::arguments() const |
251 | { |
252 | if (jsValue() == JSValue()) |
253 | return 0; |
254 | return asArguments(value: jsValue()); |
255 | } |
256 | |
257 | |
258 | } // namespace JSC |
259 | |
260 | #endif // Arguments_h |
261 | |