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