Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 1999-2002 Harri Porten (porten (at) kde.org)
      3  *  Copyright (C) 2001 Peter Kelly (pmk (at) post.com)
      4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      5  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich (at) 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 
     40 Arguments::~Arguments()
     41 {
     42     if (d->extraArguments != d->extraArgumentsFixedBuffer)
     43         delete [] d->extraArguments;
     44 }
     45 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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