tizen beta release
[framework/web/webkit-efl.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 "JSFunction.h"
30 #include "JSGlobalObject.h"
31 #include "Interpreter.h"
32 #include "ObjectConstructor.h"
33
34 namespace JSC {
35
36     struct ArgumentsData {
37         WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
38     public:
39         ArgumentsData() { }
40         WriteBarrier<JSActivation> activation;
41
42         unsigned numParameters;
43         ptrdiff_t firstParameterIndex;
44         unsigned numArguments;
45
46         WriteBarrier<Unknown>* registers;
47         OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
48
49         WriteBarrier<Unknown>* extraArguments;
50         OwnArrayPtr<bool> deletedArguments;
51         WriteBarrier<Unknown> extraArgumentsFixedBuffer[4];
52
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.
59     };
60
61
62     class Arguments : public JSNonFinalObject {
63     public:
64         typedef JSNonFinalObject Base;
65
66         static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
67         {
68             Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
69             arguments->finishCreation(callFrame);
70             return arguments;
71         }
72         
73         static Arguments* createAndTearOff(JSGlobalData& globalData, CallFrame* callFrame)
74         {
75             Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
76             arguments->finishCreationAndTearOff(callFrame);
77             return arguments;
78         }
79         
80         static Arguments* createNoParameters(JSGlobalData& globalData, CallFrame* callFrame)
81         {
82             Arguments* arguments = new (allocateCell<Arguments>(globalData.heap)) Arguments(callFrame, NoParameters);
83             arguments->finishCreation(callFrame, NoParameters);
84             return arguments;
85         }
86
87         // Use an enum because otherwise gcc insists on doing a memory
88         // read.
89         enum { MaxArguments = 0x10000 };
90
91     private:
92         enum NoParametersType { NoParameters };
93         
94         Arguments(CallFrame*);
95         Arguments(CallFrame*, NoParametersType);
96
97     public:
98         virtual ~Arguments();
99
100         static const ClassInfo s_info;
101
102         static void visitChildren(JSCell*, SlotVisitor&);
103
104         void fillArgList(ExecState*, MarkedArgumentBuffer&);
105
106         uint32_t length(ExecState* exec) const 
107         {
108             if (UNLIKELY(d->overrodeLength))
109                 return get(exec, exec->propertyNames().length).toUInt32(exec);
110             return d->numArguments; 
111         }
112         
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)
117         {
118             if (isTornOff())
119                 return;
120             d->activation.set(globalData, this, activation);
121             d->registers = &activation->registerAt(0);
122         }
123
124         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) 
125         { 
126             return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); 
127         }
128
129     protected:
130         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
131
132         void finishCreationButDontTearOff(CallFrame*);
133         void finishCreation(CallFrame*);
134         void finishCreationAndTearOff(CallFrame*);
135         void finishCreation(CallFrame*, NoParametersType);
136
137     private:
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*);
149
150         void init(CallFrame*);
151
152         OwnPtr<ArgumentsData> d;
153     };
154
155     Arguments* asArguments(JSValue);
156
157     inline Arguments* asArguments(JSValue value)
158     {
159         ASSERT(asObject(value)->inherits(&Arguments::s_info));
160         return static_cast<Arguments*>(asObject(value));
161     }
162
163     ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
164     {
165         function = asFunction(callFrame->callee());
166
167         int numParameters = function->jsExecutable()->parameterCount();
168         argc = callFrame->argumentCountIncludingThis();
169         
170         if (callFrame->isInlineCallFrame())
171             ASSERT(argc == numParameters + 1);
172
173         if (argc <= numParameters)
174             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters;
175         else
176             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc;
177
178         argc -= 1; // - 1 to skip "this"
179         firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters;
180     }
181
182     inline Arguments::Arguments(CallFrame* callFrame)
183         : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
184         , d(adoptPtr(new ArgumentsData))
185     {
186     }
187
188     inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
189         : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
190         , d(adoptPtr(new ArgumentsData))
191     {
192     }
193     
194     inline void Arguments::finishCreationButDontTearOff(CallFrame* callFrame)
195     {
196         Base::finishCreation(callFrame->globalData());
197         ASSERT(inherits(&s_info));
198
199         JSFunction* callee;
200         ptrdiff_t firstParameterIndex;
201         Register* argv;
202         int numArguments;
203         getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
204
205         d->numParameters = callee->jsExecutable()->parameterCount();
206         d->firstParameterIndex = firstParameterIndex;
207         d->numArguments = numArguments;
208         d->isInlineFrame = false;
209
210         d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
211
212         WriteBarrier<Unknown>* extraArguments;
213         if (d->numArguments <= d->numParameters)
214             extraArguments = 0;
215         else {
216             unsigned numExtraArguments = d->numArguments - d->numParameters;
217             if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
218                 extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
219             else
220                 extraArguments = d->extraArgumentsFixedBuffer;
221             for (unsigned i = 0; i < numExtraArguments; ++i)
222                 extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
223         }
224
225         d->extraArguments = extraArguments;
226
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();
232     }
233
234     inline void Arguments::finishCreation(CallFrame* callFrame)
235     {
236         ASSERT(!callFrame->isInlineCallFrame());
237         finishCreationButDontTearOff(callFrame);
238         if (d->isStrictMode)
239             tearOff(callFrame->globalData());
240     }
241
242     inline void Arguments::finishCreationAndTearOff(CallFrame* callFrame)
243     {
244         Base::finishCreation(callFrame->globalData());
245         ASSERT(inherits(&s_info));
246         
247         JSFunction* callee;
248
249         ptrdiff_t firstParameterIndex;
250         Register* argv;
251         int numArguments;
252         getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
253         
254         d->numParameters = callee->jsExecutable()->parameterCount();
255         d->firstParameterIndex = firstParameterIndex;
256         d->numArguments = numArguments;
257         
258         if (d->numParameters) {
259             int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
260             size_t registerArraySize = d->numParameters;
261             
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.
272                     JSValue value;
273                     Register* location = callFrame->registers() + i - registerOffset;
274                     switch (recovery.technique()) {
275                     case AlreadyInRegisterFile:
276                         value = location->jsValue();
277                         break;
278                     case AlreadyInRegisterFileAsUnboxedInt32:
279                         value = jsNumber(location->unboxedInt32());
280                         break;
281                     case AlreadyInRegisterFileAsUnboxedCell:
282                         value = location->unboxedCell();
283                         break;
284                     case AlreadyInRegisterFileAsUnboxedBoolean:
285                         value = jsBoolean(location->unboxedBoolean());
286                         break;
287                     case Constant:
288                         value = recovery.constant();
289                         break;
290                     default:
291                         ASSERT_NOT_REACHED();
292                         break;
293                     }
294                     registerArray[i].set(callFrame->globalData(), this, value);
295                 }
296             } else {
297                 for (size_t i = 0; i < registerArraySize; ++i)
298                     registerArray[i].set(callFrame->globalData(), this, callFrame->registers()[i - registerOffset].jsValue());
299             }
300             d->registers = registerArray.get() + d->numParameters + RegisterFile::CallFrameHeaderSize;
301             d->registerArray = registerArray.release();
302         }
303         
304         WriteBarrier<Unknown>* extraArguments;
305         if (callFrame->isInlineCallFrame())
306             ASSERT(d->numArguments == d->numParameters);
307         if (d->numArguments <= d->numParameters)
308             extraArguments = 0;
309         else {
310             unsigned numExtraArguments = d->numArguments - d->numParameters;
311             if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
312                 extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
313             else
314                 extraArguments = d->extraArgumentsFixedBuffer;
315             for (unsigned i = 0; i < numExtraArguments; ++i)
316                 extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
317         }
318         
319         d->extraArguments = extraArguments;
320
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();
327     }
328
329     inline void Arguments::finishCreation(CallFrame* callFrame, NoParametersType)
330     {
331         ASSERT(!callFrame->isInlineCallFrame());
332         Base::finishCreation(callFrame->globalData());
333         ASSERT(inherits(&s_info));
334         ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount());
335
336         unsigned numArguments = callFrame->argumentCount();
337
338         d->numParameters = 0;
339         d->numArguments = numArguments;
340         d->isInlineFrame = false;
341
342         WriteBarrier<Unknown>* extraArguments;
343         if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
344             extraArguments = new WriteBarrier<Unknown>[numArguments];
345         else
346             extraArguments = d->extraArgumentsFixedBuffer;
347
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());
351
352         d->extraArguments = extraArguments;
353
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();
359         if (d->isStrictMode)
360             tearOff(callFrame->globalData());
361     }
362
363     inline void Arguments::tearOff(JSGlobalData& globalData)
364     {
365         ASSERT(!isTornOff());
366
367         if (!d->numParameters)
368             return;
369
370         int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
371         size_t registerArraySize = d->numParameters;
372
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();
378     }
379
380 } // namespace JSC
381
382 #endif // Arguments_h