Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / JavaScriptCore / runtime / Arguments.h
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 "CodeOrigin.h"
28 #include "JSActivation.h"
29 #include "JSDestructibleObject.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
32 #include "Interpreter.h"
33 #include "ObjectConstructor.h"
34
35 namespace JSC {
36
37 class Arguments : public JSDestructibleObject {
38     friend class JIT;
39     friend class DFG::SpeculativeJIT;
40 public:
41     typedef JSDestructibleObject Base;
42
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     }
56
57     enum { MaxArguments = 0x10000 };
58
59 private:
60     enum NoParametersType { NoParameters };
61         
62     Arguments(CallFrame*);
63     Arguments(CallFrame*, NoParametersType);
64         
65     void tearOffForInlineCallFrame(VM& vm, Register*, InlineCallFrame*);
66
67 public:
68     DECLARE_INFO;
69
70     static void visitChildren(JSCell*, SlotVisitor&);
71
72     void fillArgList(ExecState*, MarkedArgumentBuffer&);
73
74     uint32_t length(ExecState* exec) const 
75     {
76         if (UNLIKELY(m_overrodeLength))
77             return get(exec, exec->propertyNames().length).toUInt32(exec);
78         return m_numArguments; 
79     }
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), info()); 
90     }
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(JSObject*, ExecState*, PropertyName, PropertySlot&);
101     static bool getOwnPropertySlotByIndex(JSObject*, 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::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);
168     }
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(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];
249     }
250
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(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 }
277
278 } // namespace JSC
279
280 #endif // Arguments_h