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
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.
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.
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.
27 #include "CodeOrigin.h"
28 #include "JSActivation.h"
29 #include "JSFunction.h"
30 #include "JSGlobalObject.h"
31 #include "Interpreter.h"
32 #include "ObjectConstructor.h"
33 #include "WriteBarrierInlines.h"
34 #include <wtf/StdLibExtras.h>
38 class Arguments
: public JSNonFinalObject
{
40 friend class JSArgumentsIterator
;
42 typedef JSNonFinalObject Base
;
44 static Arguments
* create(VM
& vm
, CallFrame
* callFrame
)
46 Arguments
* arguments
= new (NotNull
, allocateCell
<Arguments
>(vm
.heap
)) Arguments(callFrame
);
47 arguments
->finishCreation(callFrame
);
51 static Arguments
* create(VM
& vm
, CallFrame
* callFrame
, InlineCallFrame
* inlineCallFrame
)
53 Arguments
* arguments
= new (NotNull
, allocateCell
<Arguments
>(vm
.heap
)) Arguments(callFrame
);
54 arguments
->finishCreation(callFrame
, inlineCallFrame
);
58 enum { MaxArguments
= 0x10000 };
61 enum NoParametersType
{ NoParameters
};
63 Arguments(CallFrame
*);
64 Arguments(CallFrame
*, NoParametersType
);
69 static void visitChildren(JSCell
*, SlotVisitor
&);
70 static void copyBackingStore(JSCell
*, CopyVisitor
&, CopyToken
);
72 void fillArgList(ExecState
*, MarkedArgumentBuffer
&);
74 uint32_t length(ExecState
* exec
) const
76 if (UNLIKELY(m_overrodeLength
))
77 return get(exec
, exec
->propertyNames().length
).toUInt32(exec
);
78 return m_numArguments
;
81 void copyToArguments(ExecState
*, CallFrame
*, uint32_t copyLength
, int32_t firstArgumentOffset
);
82 void tearOff(CallFrame
*);
83 void tearOff(CallFrame
*, InlineCallFrame
*);
84 bool isTornOff() const { return m_registerArray
.get(); }
85 void didTearOffActivation(ExecState
*, JSActivation
*);
87 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
89 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ArgumentsType
, StructureFlags
), info());
92 static ptrdiff_t offsetOfActivation() { return OBJECT_OFFSETOF(Arguments
, m_activation
); }
93 static ptrdiff_t offsetOfNumArguments() { return OBJECT_OFFSETOF(Arguments
, m_numArguments
); }
94 static ptrdiff_t offsetOfOverrodeLength() { return OBJECT_OFFSETOF(Arguments
, m_overrodeLength
); }
95 static ptrdiff_t offsetOfIsStrictMode() { return OBJECT_OFFSETOF(Arguments
, m_isStrictMode
); }
96 static ptrdiff_t offsetOfRegisters() { return OBJECT_OFFSETOF(Arguments
, m_registers
); }
97 static ptrdiff_t offsetOfRegisterArray() { return OBJECT_OFFSETOF(Arguments
, m_registerArray
); }
98 static ptrdiff_t offsetOfSlowArgumentData() { return OBJECT_OFFSETOF(Arguments
, m_slowArgumentData
); }
99 static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(Arguments
, m_callee
); }
101 static size_t allocationSize(size_t inlineCapacity
)
103 ASSERT_UNUSED(inlineCapacity
, !inlineCapacity
);
104 return sizeof(Arguments
);
108 static const unsigned StructureFlags
= OverridesGetOwnPropertySlot
| InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero
| OverridesVisitChildren
| OverridesGetPropertyNames
| JSObject::StructureFlags
;
110 void finishCreation(CallFrame
*);
111 void finishCreation(CallFrame
*, InlineCallFrame
*);
114 static bool getOwnPropertySlot(JSObject
*, ExecState
*, PropertyName
, PropertySlot
&);
115 static bool getOwnPropertySlotByIndex(JSObject
*, ExecState
*, unsigned propertyName
, PropertySlot
&);
116 static void getOwnPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
117 static void put(JSCell
*, ExecState
*, PropertyName
, JSValue
, PutPropertySlot
&);
118 static void putByIndex(JSCell
*, ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
119 static bool deleteProperty(JSCell
*, ExecState
*, PropertyName
);
120 static bool deletePropertyByIndex(JSCell
*, ExecState
*, unsigned propertyName
);
121 static bool defineOwnProperty(JSObject
*, ExecState
*, PropertyName
, const PropertyDescriptor
&, bool shouldThrow
);
122 void createStrictModeCallerIfNecessary(ExecState
*);
123 void createStrictModeCalleeIfNecessary(ExecState
*);
125 size_t registerArraySizeInBytes() const { return sizeof(WriteBarrier
<Unknown
>) * m_numArguments
; }
126 void allocateRegisterArray(VM
&);
127 bool isArgument(size_t);
128 bool trySetArgument(VM
&, size_t argument
, JSValue
);
129 JSValue
tryGetArgument(size_t argument
);
130 bool isDeletedArgument(size_t);
131 bool tryDeleteArgument(VM
&, size_t);
132 WriteBarrierBase
<Unknown
>& argument(size_t);
133 void allocateSlowArguments(VM
&);
135 void init(CallFrame
*);
137 WriteBarrier
<JSActivation
> m_activation
;
139 unsigned m_numArguments
;
141 // We make these full byte booleans to make them easy to test from the JIT,
142 // and because even if they were single-bit booleans we still wouldn't save
144 bool m_overrodeLength
;
145 bool m_overrodeCallee
;
146 bool m_overrodeCaller
;
149 WriteBarrierBase
<Unknown
>* m_registers
;
150 CopyWriteBarrier
<WriteBarrier
<Unknown
>> m_registerArray
;
153 struct SlowArgumentData
{
156 : m_bytecodeToMachineCaptureOffset(0)
160 SlowArgument
* slowArguments()
162 return reinterpret_cast<SlowArgument
*>(WTF::roundUpToMultipleOf
<8>(reinterpret_cast<size_t>(this + 1)));
165 int bytecodeToMachineCaptureOffset() const { return m_bytecodeToMachineCaptureOffset
; }
166 void setBytecodeToMachineCaptureOffset(int newOffset
) { m_bytecodeToMachineCaptureOffset
= newOffset
; }
168 static size_t sizeForNumArguments(unsigned numArguments
)
170 return WTF::roundUpToMultipleOf
<8>(sizeof(SlowArgumentData
)) + sizeof(SlowArgument
) * numArguments
;
174 int m_bytecodeToMachineCaptureOffset
; // Add this if you have a bytecode offset into captured registers and you want the machine offset instead. Subtract if you want to do the opposite.
178 CopyWriteBarrier
<SlowArgumentData
> m_slowArgumentData
;
180 WriteBarrier
<JSFunction
> m_callee
;
183 Arguments
* asArguments(JSValue
);
185 inline Arguments
* asArguments(JSValue value
)
187 ASSERT(asObject(value
)->inherits(Arguments::info()));
188 return static_cast<Arguments
*>(asObject(value
));
191 inline Arguments::Arguments(CallFrame
* callFrame
)
192 : Base(callFrame
->vm(), callFrame
->lexicalGlobalObject()->argumentsStructure())
196 inline Arguments::Arguments(CallFrame
* callFrame
, NoParametersType
)
197 : Base(callFrame
->vm(), callFrame
->lexicalGlobalObject()->argumentsStructure())
201 inline void Arguments::allocateSlowArguments(VM
& vm
)
203 if (!!m_slowArgumentData
)
207 if (!vm
.heap
.tryAllocateStorage(this, SlowArgumentData::sizeForNumArguments(m_numArguments
), &backingStore
))
208 RELEASE_ASSERT_NOT_REACHED();
209 m_slowArgumentData
.set(vm
, this, static_cast<SlowArgumentData
*>(backingStore
));
211 for (size_t i
= 0; i
< m_numArguments
; ++i
) {
212 ASSERT(m_slowArgumentData
->slowArguments()[i
].status
== SlowArgument::Normal
);
213 m_slowArgumentData
->slowArguments()[i
].index
= CallFrame::argumentOffset(i
);
217 inline bool Arguments::tryDeleteArgument(VM
& vm
, size_t argument
)
219 if (!isArgument(argument
))
221 allocateSlowArguments(vm
);
222 m_slowArgumentData
->slowArguments()[argument
].status
= SlowArgument::Deleted
;
226 inline bool Arguments::trySetArgument(VM
& vm
, size_t argument
, JSValue value
)
228 if (!isArgument(argument
))
230 this->argument(argument
).set(vm
, this, value
);
234 inline JSValue
Arguments::tryGetArgument(size_t argument
)
236 if (!isArgument(argument
))
238 return this->argument(argument
).get();
241 inline bool Arguments::isDeletedArgument(size_t argument
)
243 if (argument
>= m_numArguments
)
245 if (!m_slowArgumentData
)
247 if (m_slowArgumentData
->slowArguments()[argument
].status
!= SlowArgument::Deleted
)
252 inline bool Arguments::isArgument(size_t argument
)
254 if (argument
>= m_numArguments
)
256 if (m_slowArgumentData
&& m_slowArgumentData
->slowArguments()[argument
].status
== SlowArgument::Deleted
)
261 inline WriteBarrierBase
<Unknown
>& Arguments::argument(size_t argument
)
263 ASSERT(isArgument(argument
));
264 if (!m_slowArgumentData
)
265 return m_registers
[CallFrame::argumentOffset(argument
)];
267 int index
= m_slowArgumentData
->slowArguments()[argument
].index
;
268 if (!m_activation
|| m_slowArgumentData
->slowArguments()[argument
].status
!= SlowArgument::Captured
)
269 return m_registers
[index
];
271 return m_activation
->registerAt(index
- m_slowArgumentData
->bytecodeToMachineCaptureOffset());
274 inline void Arguments::finishCreation(CallFrame
* callFrame
)
276 Base::finishCreation(callFrame
->vm());
277 ASSERT(inherits(info()));
279 JSFunction
* callee
= jsCast
<JSFunction
*>(callFrame
->callee());
280 m_numArguments
= callFrame
->argumentCount();
281 m_registers
= reinterpret_cast<WriteBarrierBase
<Unknown
>*>(callFrame
->registers());
282 m_callee
.set(callFrame
->vm(), this, callee
);
283 m_overrodeLength
= false;
284 m_overrodeCallee
= false;
285 m_overrodeCaller
= false;
286 m_isStrictMode
= callFrame
->codeBlock()->isStrictMode();
288 CodeBlock
* codeBlock
= callFrame
->codeBlock();
289 if (codeBlock
->hasSlowArguments()) {
290 SymbolTable
* symbolTable
= codeBlock
->symbolTable();
291 const SlowArgument
* slowArguments
= codeBlock
->machineSlowArguments();
292 allocateSlowArguments(callFrame
->vm());
293 size_t count
= std::min
<unsigned>(m_numArguments
, symbolTable
->parameterCount());
294 for (size_t i
= 0; i
< count
; ++i
)
295 m_slowArgumentData
->slowArguments()[i
] = slowArguments
[i
];
296 m_slowArgumentData
->setBytecodeToMachineCaptureOffset(
297 codeBlock
->framePointerOffsetToGetActivationRegisters());
300 // The bytecode generator omits op_tear_off_activation in cases of no
301 // declared parameters, so we need to tear off immediately.
302 if (m_isStrictMode
|| !callee
->jsExecutable()->parameterCount())
306 inline void Arguments::finishCreation(CallFrame
* callFrame
, InlineCallFrame
* inlineCallFrame
)
308 Base::finishCreation(callFrame
->vm());
309 ASSERT(inherits(info()));
311 JSFunction
* callee
= inlineCallFrame
->calleeForCallFrame(callFrame
);
312 m_numArguments
= inlineCallFrame
->arguments
.size() - 1;
314 if (m_numArguments
) {
315 int offsetForArgumentOne
= inlineCallFrame
->arguments
[1].virtualRegister().offset();
316 m_registers
= reinterpret_cast<WriteBarrierBase
<Unknown
>*>(callFrame
->registers()) + offsetForArgumentOne
- virtualRegisterForArgument(1).offset();
319 m_callee
.set(callFrame
->vm(), this, callee
);
320 m_overrodeLength
= false;
321 m_overrodeCallee
= false;
322 m_overrodeCaller
= false;
323 m_isStrictMode
= jsCast
<FunctionExecutable
*>(inlineCallFrame
->executable
.get())->isStrictMode();
324 ASSERT(!jsCast
<FunctionExecutable
*>(inlineCallFrame
->executable
.get())->symbolTable(inlineCallFrame
->isCall
? CodeForCall
: CodeForConstruct
)->slowArguments());
326 // The bytecode generator omits op_tear_off_activation in cases of no
327 // declared parameters, so we need to tear off immediately.
328 if (m_isStrictMode
|| !callee
->jsExecutable()->parameterCount())
329 tearOff(callFrame
, inlineCallFrame
);
334 #endif // Arguments_h