]>
Commit | Line | Data |
---|---|---|
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 | 28 | #include "JSActivation.h" |
93a37866 | 29 | #include "JSDestructibleObject.h" |
9dae56ea A |
30 | #include "JSFunction.h" |
31 | #include "JSGlobalObject.h" | |
32 | #include "Interpreter.h" | |
f9bf01c6 | 33 | #include "ObjectConstructor.h" |
9dae56ea A |
34 | |
35 | namespace JSC { | |
36 | ||
93a37866 A |
37 | class Arguments : public JSDestructibleObject { |
38 | friend class JIT; | |
39 | friend class DFG::SpeculativeJIT; | |
40 | public: | |
41 | typedef JSDestructibleObject Base; | |
9dae56ea | 42 | |
93a37866 A |
43 | static Arguments* create(VM& vm, CallFrame* callFrame) |
44 | { | |
45 | Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame); | |
46 | arguments->finishCreation(callFrame); | |
47 | return arguments; | |
48 | } | |
49 | ||
50 | static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) | |
51 | { | |
52 | Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame); | |
53 | arguments->finishCreation(callFrame, inlineCallFrame); | |
54 | return arguments; | |
55 | } | |
6fe7ccc8 | 56 | |
93a37866 | 57 | enum { MaxArguments = 0x10000 }; |
fb8617cd | 58 | |
93a37866 A |
59 | private: |
60 | enum NoParametersType { NoParameters }; | |
61 | ||
62 | Arguments(CallFrame*); | |
63 | Arguments(CallFrame*, NoParametersType); | |
6fe7ccc8 | 64 | |
93a37866 | 65 | void tearOffForInlineCallFrame(VM& vm, Register*, InlineCallFrame*); |
9dae56ea | 66 | |
93a37866 A |
67 | public: |
68 | static const ClassInfo s_info; | |
9dae56ea | 69 | |
93a37866 | 70 | static void visitChildren(JSCell*, SlotVisitor&); |
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 A |
80 | |
81 | void copyToArguments(ExecState*, CallFrame*, uint32_t length); | |
82 | void tearOff(CallFrame*); | |
83 | void tearOff(CallFrame*, InlineCallFrame*); | |
84 | bool isTornOff() const { return m_registerArray; } | |
85 | void didTearOffActivation(ExecState*, JSActivation*); | |
86 | ||
87 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) | |
88 | { | |
89 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); | |
9dae56ea | 90 | } |
93a37866 A |
91 | |
92 | protected: | |
93 | static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; | |
94 | ||
95 | void finishCreation(CallFrame*); | |
96 | void finishCreation(CallFrame*, InlineCallFrame*); | |
97 | ||
98 | private: | |
99 | static void destroy(JSCell*); | |
100 | static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); | |
101 | static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); | |
102 | static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); | |
103 | static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); | |
104 | static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); | |
105 | static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); | |
106 | static bool deleteProperty(JSCell*, ExecState*, PropertyName); | |
107 | static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); | |
108 | static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); | |
109 | void createStrictModeCallerIfNecessary(ExecState*); | |
110 | void createStrictModeCalleeIfNecessary(ExecState*); | |
111 | ||
112 | bool isArgument(size_t); | |
113 | bool trySetArgument(VM&, size_t argument, JSValue); | |
114 | JSValue tryGetArgument(size_t argument); | |
115 | bool isDeletedArgument(size_t); | |
116 | bool tryDeleteArgument(size_t); | |
117 | WriteBarrierBase<Unknown>& argument(size_t); | |
118 | void allocateSlowArguments(); | |
119 | ||
120 | void init(CallFrame*); | |
121 | ||
122 | WriteBarrier<JSActivation> m_activation; | |
123 | ||
124 | unsigned m_numArguments; | |
125 | ||
126 | // We make these full byte booleans to make them easy to test from the JIT, | |
127 | // and because even if they were single-bit booleans we still wouldn't save | |
128 | // any space. | |
129 | bool m_overrodeLength; | |
130 | bool m_overrodeCallee; | |
131 | bool m_overrodeCaller; | |
132 | bool m_isStrictMode; | |
133 | ||
134 | WriteBarrierBase<Unknown>* m_registers; | |
135 | OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; | |
136 | ||
137 | OwnArrayPtr<SlowArgument> m_slowArguments; | |
138 | ||
139 | WriteBarrier<JSFunction> m_callee; | |
140 | }; | |
141 | ||
142 | Arguments* asArguments(JSValue); | |
143 | ||
144 | inline Arguments* asArguments(JSValue value) | |
145 | { | |
146 | ASSERT(asObject(value)->inherits(&Arguments::s_info)); | |
147 | return static_cast<Arguments*>(asObject(value)); | |
148 | } | |
149 | ||
150 | inline Arguments::Arguments(CallFrame* callFrame) | |
151 | : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) | |
152 | { | |
153 | } | |
154 | ||
155 | inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) | |
156 | : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) | |
157 | { | |
158 | } | |
159 | ||
160 | inline void Arguments::allocateSlowArguments() | |
161 | { | |
162 | if (m_slowArguments) | |
163 | return; | |
164 | m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]); | |
165 | for (size_t i = 0; i < m_numArguments; ++i) { | |
166 | ASSERT(m_slowArguments[i].status == SlowArgument::Normal); | |
167 | m_slowArguments[i].index = CallFrame::argumentOffset(i); | |
9dae56ea | 168 | } |
93a37866 A |
169 | } |
170 | ||
171 | inline bool Arguments::tryDeleteArgument(size_t argument) | |
172 | { | |
173 | if (!isArgument(argument)) | |
174 | return false; | |
175 | allocateSlowArguments(); | |
176 | m_slowArguments[argument].status = SlowArgument::Deleted; | |
177 | return true; | |
178 | } | |
179 | ||
180 | inline bool Arguments::trySetArgument(VM& vm, size_t argument, JSValue value) | |
181 | { | |
182 | if (!isArgument(argument)) | |
183 | return false; | |
184 | this->argument(argument).set(vm, this, value); | |
185 | return true; | |
186 | } | |
187 | ||
188 | inline JSValue Arguments::tryGetArgument(size_t argument) | |
189 | { | |
190 | if (!isArgument(argument)) | |
191 | return JSValue(); | |
192 | return this->argument(argument).get(); | |
193 | } | |
194 | ||
195 | inline bool Arguments::isDeletedArgument(size_t argument) | |
196 | { | |
197 | if (argument >= m_numArguments) | |
198 | return false; | |
199 | if (!m_slowArguments) | |
200 | return false; | |
201 | if (m_slowArguments[argument].status != SlowArgument::Deleted) | |
202 | return false; | |
203 | return true; | |
204 | } | |
205 | ||
206 | inline bool Arguments::isArgument(size_t argument) | |
207 | { | |
208 | if (argument >= m_numArguments) | |
209 | return false; | |
210 | if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted) | |
211 | return false; | |
212 | return true; | |
213 | } | |
214 | ||
215 | inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument) | |
216 | { | |
217 | ASSERT(isArgument(argument)); | |
218 | if (!m_slowArguments) | |
219 | return m_registers[CallFrame::argumentOffset(argument)]; | |
220 | ||
221 | int index = m_slowArguments[argument].index; | |
222 | if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured) | |
223 | return m_registers[index]; | |
224 | ||
225 | return m_activation->registerAt(index); | |
226 | } | |
227 | ||
228 | inline void Arguments::finishCreation(CallFrame* callFrame) | |
229 | { | |
230 | Base::finishCreation(callFrame->vm()); | |
231 | ASSERT(inherits(&s_info)); | |
232 | ||
233 | JSFunction* callee = jsCast<JSFunction*>(callFrame->callee()); | |
234 | m_numArguments = callFrame->argumentCount(); | |
235 | m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()); | |
236 | m_callee.set(callFrame->vm(), this, callee); | |
237 | m_overrodeLength = false; | |
238 | m_overrodeCallee = false; | |
239 | m_overrodeCaller = false; | |
240 | m_isStrictMode = callFrame->codeBlock()->isStrictMode(); | |
241 | ||
242 | SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable(); | |
243 | const SlowArgument* slowArguments = symbolTable->slowArguments(); | |
244 | if (slowArguments) { | |
245 | allocateSlowArguments(); | |
246 | size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount()); | |
247 | for (size_t i = 0; i < count; ++i) | |
248 | m_slowArguments[i] = slowArguments[i]; | |
9dae56ea A |
249 | } |
250 | ||
93a37866 A |
251 | // The bytecode generator omits op_tear_off_activation in cases of no |
252 | // declared parameters, so we need to tear off immediately. | |
253 | if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) | |
254 | tearOff(callFrame); | |
255 | } | |
256 | ||
257 | inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) | |
258 | { | |
259 | Base::finishCreation(callFrame->vm()); | |
260 | ASSERT(inherits(&s_info)); | |
261 | ||
262 | JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame); | |
263 | m_numArguments = inlineCallFrame->arguments.size() - 1; | |
264 | m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset; | |
265 | m_callee.set(callFrame->vm(), this, callee); | |
266 | m_overrodeLength = false; | |
267 | m_overrodeCallee = false; | |
268 | m_overrodeCaller = false; | |
269 | m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode(); | |
270 | ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments()); | |
271 | ||
272 | // The bytecode generator omits op_tear_off_activation in cases of no | |
273 | // declared parameters, so we need to tear off immediately. | |
274 | if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) | |
275 | tearOff(callFrame, inlineCallFrame); | |
276 | } | |
ba379fdc | 277 | |
9dae56ea A |
278 | } // namespace JSC |
279 | ||
280 | #endif // Arguments_h |