2008-10-13 Maciej Stachowiak <mjs@apple.com>
[WebKit.git] / JavaScriptCore / kjs / Arguments.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2006, 2007, 2008 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 "Machine.h"
31
32 namespace JSC {
33
34     struct ArgumentsData : Noncopyable {
35         JSActivation* activation;
36
37         unsigned numParameters;
38         ptrdiff_t firstParameterIndex;
39         unsigned numArguments;
40
41         Register* registers;
42         OwnArrayPtr<Register> registerArray;
43
44         Register* extraArguments;
45         OwnArrayPtr<bool> deletedArguments;
46         Register extraArgumentsFixedBuffer[4];
47
48         JSFunction* callee;
49         bool overrodeLength : 1;
50         bool overrodeCallee : 1;
51     };
52
53
54     class Arguments : public JSObject {
55     public:
56         Arguments(CallFrame*);
57         virtual ~Arguments();
58
59         static const ClassInfo info;
60
61         virtual void mark();
62
63         void fillArgList(ExecState*, ArgList&);
64
65         void copyRegisters();
66         bool isTornOff() const { return d->registerArray; }
67         void setActivation(JSActivation* activation)
68         {
69             d->activation = activation;
70             d->registers = &activation->registerAt(0);
71         }
72
73     private:
74         void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
75         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
76         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
77         virtual void put(ExecState*, const Identifier& propertyName, JSValue*, PutPropertySlot&);
78         virtual void put(ExecState*, unsigned propertyName, JSValue*, PutPropertySlot&);
79         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
80         virtual bool deleteProperty(ExecState*, unsigned propertyName);
81
82         virtual const ClassInfo* classInfo() const { return &info; }
83
84         void init(CallFrame*);
85
86         OwnPtr<ArgumentsData> d;
87     };
88
89     ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
90     {
91         function = callFrame->callee();
92     
93         CodeBlock* codeBlock = &function->m_body->generatedByteCode();
94         int numParameters = codeBlock->numParameters;
95         argc = callFrame->argumentCount();
96
97         if (argc <= numParameters)
98             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this"
99         else
100             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc + 1; // + 1 to skip "this"
101
102         argc -= 1; // - 1 to skip "this"
103         firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this"
104     }
105
106     inline Arguments::Arguments(CallFrame* callFrame)
107         : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure())
108         , d(new ArgumentsData)
109     {
110         JSFunction* callee;
111         ptrdiff_t firstParameterIndex;
112         Register* argv;
113         int numArguments;
114         getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
115
116         d->numParameters = callee->m_body->parameterCount();
117         d->firstParameterIndex = firstParameterIndex;
118         d->numArguments = numArguments;
119
120         d->activation = 0;
121         d->registers = callFrame->registers();
122
123         Register* extraArguments;
124         if (d->numArguments <= d->numParameters)
125             extraArguments = 0;
126         else {
127             unsigned numExtraArguments = d->numArguments - d->numParameters;
128             if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
129                 extraArguments = new Register[numExtraArguments];
130             else
131                 extraArguments = d->extraArgumentsFixedBuffer;
132             for (unsigned i = 0; i < numExtraArguments; ++i)
133                 extraArguments[i] = argv[d->numParameters + i];
134         }
135
136         d->extraArguments = extraArguments;
137
138         d->callee = callee;
139         d->overrodeLength = false;
140         d->overrodeCallee = false;
141     }
142
143     inline void Arguments::copyRegisters()
144     {
145         ASSERT(!isTornOff());
146
147         if (!d->numParameters)
148             return;
149
150         int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
151         size_t registerArraySize = d->numParameters;
152
153         Register* registerArray = new Register[registerArraySize];
154         memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register));
155         d->registerArray.set(registerArray);
156         d->registers = registerArray + registerOffset;
157     }
158
159     // This JSActivation function is defined here so it can get at Arguments::setRegisters.
160     inline void JSActivation::copyRegisters(Arguments* arguments)
161     {
162         ASSERT(!d()->registerArray);
163
164         size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
165         size_t numVars = d()->functionBody->generatedByteCode().numVars;
166         size_t numLocals = numVars + numParametersMinusThis;
167
168         if (!numLocals)
169             return;
170
171         int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
172         size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
173
174         Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
175         setRegisters(registerArray + registerOffset, registerArray);
176         if (arguments && !arguments->isTornOff())
177             static_cast<Arguments*>(arguments)->setActivation(this);
178     }
179
180 } // namespace JSC
181
182 #endif // Arguments_h