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