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::info = { "Arguments", 0, 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(reinterpret_cast<JSValue*>(d->registerArray.get()), d->numParameters);
     52 
     53     if (d->extraArguments) {
     54         unsigned numExtraArguments = d->numArguments - d->numParameters;
     55         markStack.appendValues(reinterpret_cast<JSValue*>(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].jsValue();
     78         for (; i < d->numArguments; ++i)
     79             buffer[i] = d->extraArguments[i - d->numParameters].jsValue();
     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].jsValue();
     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].jsValue();
     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].jsValue());
    123         for (; i < d->numArguments; ++i)
    124             args.append(d->extraArguments[i - d->numParameters].jsValue());
    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].jsValue());
    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].jsValue());
    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.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
    149         } else
    150             slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
    151         return true;
    152     }
    153 
    154     return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::from(i)), slot);
    155 }
    156 
    157 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    158 {
    159     bool isArrayIndex;
    160     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
    161     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
    162         if (i < d->numParameters) {
    163             slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
    164         } else
    165             slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
    166         return true;
    167     }
    168 
    169     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
    170         slot.setValue(jsNumber(exec, d->numArguments));
    171         return true;
    172     }
    173 
    174     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
    175         slot.setValue(d->callee);
    176         return true;
    177     }
    178 
    179     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
    180 }
    181 
    182 bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    183 {
    184     bool isArrayIndex;
    185     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
    186     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
    187         if (i < d->numParameters) {
    188             descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum);
    189         } else
    190             descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum);
    191         return true;
    192     }
    193 
    194     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
    195         descriptor.setDescriptor(jsNumber(exec, d->numArguments), DontEnum);
    196         return true;
    197     }
    198 
    199     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
    200         descriptor.setDescriptor(d->callee, DontEnum);
    201         return true;
    202     }
    203 
    204     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
    205 }
    206 
    207 void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    208 {
    209     if (mode == IncludeDontEnumProperties) {
    210         for (unsigned i = 0; i < d->numArguments; ++i) {
    211             if (!d->deletedArguments || !d->deletedArguments[i])
    212                 propertyNames.add(Identifier(exec, UString::from(i)));
    213         }
    214         propertyNames.add(exec->propertyNames().callee);
    215         propertyNames.add(exec->propertyNames().length);
    216     }
    217     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
    218 }
    219 
    220 void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
    221 {
    222     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
    223         if (i < d->numParameters)
    224             d->registers[d->firstParameterIndex + i] = JSValue(value);
    225         else
    226             d->extraArguments[i - d->numParameters] = JSValue(value);
    227         return;
    228     }
    229 
    230     JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot);
    231 }
    232 
    233 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    234 {
    235     bool isArrayIndex;
    236     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
    237     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
    238         if (i < d->numParameters)
    239             d->registers[d->firstParameterIndex + i] = JSValue(value);
    240         else
    241             d->extraArguments[i - d->numParameters] = JSValue(value);
    242         return;
    243     }
    244 
    245     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
    246         d->overrodeLength = true;
    247         putDirect(propertyName, value, DontEnum);
    248         return;
    249     }
    250 
    251     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
    252         d->overrodeCallee = true;
    253         putDirect(propertyName, value, DontEnum);
    254         return;
    255     }
    256 
    257     JSObject::put(exec, propertyName, value, slot);
    258 }
    259 
    260 bool Arguments::deleteProperty(ExecState* exec, unsigned i)
    261 {
    262     if (i < d->numArguments) {
    263         if (!d->deletedArguments) {
    264             d->deletedArguments.set(new bool[d->numArguments]);
    265             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
    266         }
    267         if (!d->deletedArguments[i]) {
    268             d->deletedArguments[i] = true;
    269             return true;
    270         }
    271     }
    272 
    273     return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)));
    274 }
    275 
    276 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
    277 {
    278     bool isArrayIndex;
    279     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
    280     if (isArrayIndex && i < d->numArguments) {
    281         if (!d->deletedArguments) {
    282             d->deletedArguments.set(new bool[d->numArguments]);
    283             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
    284         }
    285         if (!d->deletedArguments[i]) {
    286             d->deletedArguments[i] = true;
    287             return true;
    288         }
    289     }
    290 
    291     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
    292         d->overrodeLength = true;
    293         return true;
    294     }
    295 
    296     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
    297         d->overrodeCallee = true;
    298         return true;
    299     }
    300 
    301     return JSObject::deleteProperty(exec, propertyName);
    302 }
    303 
    304 } // namespace JSC
    305