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