• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3   *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4   *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5   *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6   *  Copyright (C) 2007 Maks Orlovich
7   *
8   *  This library is free software; you can redistribute it and/or
9   *  modify it under the terms of the GNU Library General Public
10   *  License as published by the Free Software Foundation; either
11   *  version 2 of the License, or (at your option) any later version.
12   *
13   *  This library is distributed in the hope that it will be useful,
14   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   *  Library General Public License for more details.
17   *
18   *  You should have received a copy of the GNU Library General Public License
19   *  along with this library; see the file COPYING.LIB.  If not, write to
20   *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21   *  Boston, MA 02110-1301, USA.
22   *
23   */
24  
25  #include "config.h"
26  #include "Arguments.h"
27  
28  #include "JSActivation.h"
29  #include "JSFunction.h"
30  #include "JSGlobalObject.h"
31  
32  using namespace std;
33  
34  namespace JSC {
35  
36  ASSERT_CLASS_FITS_IN_CELL(Arguments);
37  
38  const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0 };
39  
~Arguments()40  Arguments::~Arguments()
41  {
42      if (d->extraArguments != d->extraArgumentsFixedBuffer)
43          delete [] d->extraArguments;
44  }
45  
markChildren(MarkStack & markStack)46  void Arguments::markChildren(MarkStack& markStack)
47  {
48      JSObject::markChildren(markStack);
49  
50      if (d->registerArray)
51          markStack.appendValues(d->registerArray.get(), d->numParameters);
52  
53      if (d->extraArguments) {
54          unsigned numExtraArguments = d->numArguments - d->numParameters;
55          markStack.appendValues(d->extraArguments, numExtraArguments);
56      }
57  
58      markStack.append(&d->callee);
59  
60      if (d->activation)
61          markStack.append(&d->activation);
62  }
63  
copyToRegisters(ExecState * exec,Register * buffer,uint32_t maxSize)64  void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
65  {
66      if (UNLIKELY(d->overrodeLength)) {
67          unsigned length = min(get(exec, exec->propertyNames().length).toUInt32(exec), maxSize);
68          for (unsigned i = 0; i < length; i++)
69              buffer[i] = get(exec, i);
70          return;
71      }
72  
73      if (LIKELY(!d->deletedArguments)) {
74          unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
75          unsigned i = 0;
76          for (; i < parametersLength; ++i)
77              buffer[i] = d->registers[d->firstParameterIndex + i].get();
78          for (; i < d->numArguments; ++i)
79              buffer[i] = d->extraArguments[i - d->numParameters].get();
80          return;
81      }
82  
83      unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
84      unsigned i = 0;
85      for (; i < parametersLength; ++i) {
86          if (!d->deletedArguments[i])
87              buffer[i] = d->registers[d->firstParameterIndex + i].get();
88          else
89              buffer[i] = get(exec, i);
90      }
91      for (; i < d->numArguments; ++i) {
92          if (!d->deletedArguments[i])
93              buffer[i] = d->extraArguments[i - d->numParameters].get();
94          else
95              buffer[i] = get(exec, i);
96      }
97  }
98  
fillArgList(ExecState * exec,MarkedArgumentBuffer & args)99  void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
100  {
101      if (UNLIKELY(d->overrodeLength)) {
102          unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec);
103          for (unsigned i = 0; i < length; i++)
104              args.append(get(exec, i));
105          return;
106      }
107  
108      if (LIKELY(!d->deletedArguments)) {
109          if (LIKELY(!d->numParameters)) {
110              args.initialize(d->extraArguments, d->numArguments);
111              return;
112          }
113  
114          if (d->numParameters == d->numArguments) {
115              args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
116              return;
117          }
118  
119          unsigned parametersLength = min(d->numParameters, d->numArguments);
120          unsigned i = 0;
121          for (; i < parametersLength; ++i)
122              args.append(d->registers[d->firstParameterIndex + i].get());
123          for (; i < d->numArguments; ++i)
124              args.append(d->extraArguments[i - d->numParameters].get());
125          return;
126      }
127  
128      unsigned parametersLength = min(d->numParameters, d->numArguments);
129      unsigned i = 0;
130      for (; i < parametersLength; ++i) {
131          if (!d->deletedArguments[i])
132              args.append(d->registers[d->firstParameterIndex + i].get());
133          else
134              args.append(get(exec, i));
135      }
136      for (; i < d->numArguments; ++i) {
137          if (!d->deletedArguments[i])
138              args.append(d->extraArguments[i - d->numParameters].get());
139          else
140              args.append(get(exec, i));
141      }
142  }
143  
getOwnPropertySlot(ExecState * exec,unsigned i,PropertySlot & slot)144  bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
145  {
146      if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
147          if (i < d->numParameters) {
148              slot.setValue(d->registers[d->firstParameterIndex + i].get());
149          } else
150              slot.setValue(d->extraArguments[i - d->numParameters].get());
151          return true;
152      }
153  
154      return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
155  }
156  
createStrictModeCallerIfNecessary(ExecState * exec)157  void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
158  {
159      if (d->overrodeCaller)
160          return;
161  
162      d->overrodeCaller = true;
163      PropertyDescriptor descriptor;
164      JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
165      descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
166      defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
167  }
168  
createStrictModeCalleeIfNecessary(ExecState * exec)169  void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
170  {
171      if (d->overrodeCallee)
172          return;
173  
174      d->overrodeCallee = true;
175      PropertyDescriptor descriptor;
176      JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
177      descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
178      defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
179  }
180  
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)181  bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
182  {
183      bool isArrayIndex;
184      unsigned i = propertyName.toArrayIndex(isArrayIndex);
185      if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
186          if (i < d->numParameters) {
187              slot.setValue(d->registers[d->firstParameterIndex + i].get());
188          } else
189              slot.setValue(d->extraArguments[i - d->numParameters].get());
190          return true;
191      }
192  
193      if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
194          slot.setValue(jsNumber(d->numArguments));
195          return true;
196      }
197  
198      if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
199          if (!d->isStrictMode) {
200              slot.setValue(d->callee.get());
201              return true;
202          }
203          createStrictModeCalleeIfNecessary(exec);
204      }
205  
206      if (propertyName == exec->propertyNames().caller && d->isStrictMode)
207          createStrictModeCallerIfNecessary(exec);
208  
209      return JSObject::getOwnPropertySlot(exec, propertyName, slot);
210  }
211  
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)212  bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
213  {
214      bool isArrayIndex;
215      unsigned i = propertyName.toArrayIndex(isArrayIndex);
216      if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
217          if (i < d->numParameters) {
218              descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].get(), DontEnum);
219          } else
220              descriptor.setDescriptor(d->extraArguments[i - d->numParameters].get(), DontEnum);
221          return true;
222      }
223  
224      if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
225          descriptor.setDescriptor(jsNumber(d->numArguments), DontEnum);
226          return true;
227      }
228  
229      if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
230          if (!d->isStrictMode) {
231              descriptor.setDescriptor(d->callee.get(), DontEnum);
232              return true;
233          }
234          createStrictModeCalleeIfNecessary(exec);
235      }
236  
237      if (propertyName == exec->propertyNames().caller && d->isStrictMode)
238          createStrictModeCallerIfNecessary(exec);
239  
240      return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
241  }
242  
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)243  void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
244  {
245      if (mode == IncludeDontEnumProperties) {
246          for (unsigned i = 0; i < d->numArguments; ++i) {
247              if (!d->deletedArguments || !d->deletedArguments[i])
248                  propertyNames.add(Identifier(exec, UString::number(i)));
249          }
250          propertyNames.add(exec->propertyNames().callee);
251          propertyNames.add(exec->propertyNames().length);
252      }
253      JSObject::getOwnPropertyNames(exec, propertyNames, mode);
254  }
255  
put(ExecState * exec,unsigned i,JSValue value)256  void Arguments::put(ExecState* exec, unsigned i, JSValue value)
257  {
258      if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
259          if (i < d->numParameters)
260              d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
261          else
262              d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
263          return;
264      }
265  
266      PutPropertySlot slot;
267      JSObject::put(exec, Identifier(exec, UString::number(i)), value, slot);
268  }
269  
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)270  void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
271  {
272      bool isArrayIndex;
273      unsigned i = propertyName.toArrayIndex(isArrayIndex);
274      if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
275          if (i < d->numParameters)
276              d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
277          else
278              d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
279          return;
280      }
281  
282      if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
283          d->overrodeLength = true;
284          putDirect(exec->globalData(), propertyName, value, DontEnum);
285          return;
286      }
287  
288      if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
289          if (!d->isStrictMode) {
290              d->overrodeCallee = true;
291              putDirect(exec->globalData(), propertyName, value, DontEnum);
292              return;
293          }
294          createStrictModeCalleeIfNecessary(exec);
295      }
296  
297      if (propertyName == exec->propertyNames().caller && d->isStrictMode)
298          createStrictModeCallerIfNecessary(exec);
299  
300      JSObject::put(exec, propertyName, value, slot);
301  }
302  
deleteProperty(ExecState * exec,unsigned i)303  bool Arguments::deleteProperty(ExecState* exec, unsigned i)
304  {
305      if (i < d->numArguments) {
306          if (!d->deletedArguments) {
307              d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
308              memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
309          }
310          if (!d->deletedArguments[i]) {
311              d->deletedArguments[i] = true;
312              return true;
313          }
314      }
315  
316      return JSObject::deleteProperty(exec, Identifier(exec, UString::number(i)));
317  }
318  
deleteProperty(ExecState * exec,const Identifier & propertyName)319  bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
320  {
321      bool isArrayIndex;
322      unsigned i = propertyName.toArrayIndex(isArrayIndex);
323      if (isArrayIndex && i < d->numArguments) {
324          if (!d->deletedArguments) {
325              d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
326              memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
327          }
328          if (!d->deletedArguments[i]) {
329              d->deletedArguments[i] = true;
330              return true;
331          }
332      }
333  
334      if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
335          d->overrodeLength = true;
336          return true;
337      }
338  
339      if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
340          if (!d->isStrictMode) {
341              d->overrodeCallee = true;
342              return true;
343          }
344          createStrictModeCalleeIfNecessary(exec);
345      }
346  
347      if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
348          createStrictModeCallerIfNecessary(exec);
349  
350      return JSObject::deleteProperty(exec, propertyName);
351  }
352  
353  } // namespace JSC
354