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