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 "JSDestructibleObject.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
32 #include "Interpreter.h"
33 #include "ObjectConstructor.h"
37 class Arguments
: public JSDestructibleObject
{
39 friend class DFG::SpeculativeJIT
;
41 typedef JSDestructibleObject Base
;
43 static Arguments
* create(VM
& vm
, CallFrame
* callFrame
)
45 Arguments
* arguments
= new (NotNull
, allocateCell
<Arguments
>(vm
.heap
)) Arguments(callFrame
);
46 arguments
->finishCreation(callFrame
);
50 static Arguments
* create(VM
& vm
, CallFrame
* callFrame
, InlineCallFrame
* inlineCallFrame
)
52 Arguments
* arguments
= new (NotNull
, allocateCell
<Arguments
>(vm
.heap
)) Arguments(callFrame
);
53 arguments
->finishCreation(callFrame
, inlineCallFrame
);
57 enum { MaxArguments
= 0x10000 };
60 enum NoParametersType
{ NoParameters
};
62 Arguments(CallFrame
*);
63 Arguments(CallFrame
*, NoParametersType
);
65 void tearOffForInlineCallFrame(VM
& vm
, Register
*, InlineCallFrame
*);
68 static const ClassInfo s_info
;
70 static void visitChildren(JSCell
*, SlotVisitor
&);
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 length
);
82 void tearOff(CallFrame
*);
83 void tearOff(CallFrame
*, InlineCallFrame
*);
84 bool isTornOff() const { return m_registerArray
; }
85 void didTearOffActivation(ExecState
*, JSActivation
*);
87 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
89 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), &s_info
);
93 static const unsigned StructureFlags
= OverridesGetOwnPropertySlot
| InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero
| OverridesVisitChildren
| OverridesGetPropertyNames
| JSObject::StructureFlags
;
95 void finishCreation(CallFrame
*);
96 void finishCreation(CallFrame
*, InlineCallFrame
*);
99 static void destroy(JSCell
*);
100 static bool getOwnPropertySlot(JSCell
*, ExecState
*, PropertyName
, PropertySlot
&);
101 static bool getOwnPropertySlotByIndex(JSCell
*, ExecState
*, unsigned propertyName
, PropertySlot
&);
102 static bool getOwnPropertyDescriptor(JSObject
*, ExecState
*, PropertyName
, PropertyDescriptor
&);
103 static void getOwnPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
104 static void put(JSCell
*, ExecState
*, PropertyName
, JSValue
, PutPropertySlot
&);
105 static void putByIndex(JSCell
*, ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
106 static bool deleteProperty(JSCell
*, ExecState
*, PropertyName
);
107 static bool deletePropertyByIndex(JSCell
*, ExecState
*, unsigned propertyName
);
108 static bool defineOwnProperty(JSObject
*, ExecState
*, PropertyName
, PropertyDescriptor
&, bool shouldThrow
);
109 void createStrictModeCallerIfNecessary(ExecState
*);
110 void createStrictModeCalleeIfNecessary(ExecState
*);
112 bool isArgument(size_t);
113 bool trySetArgument(VM
&, size_t argument
, JSValue
);
114 JSValue
tryGetArgument(size_t argument
);
115 bool isDeletedArgument(size_t);
116 bool tryDeleteArgument(size_t);
117 WriteBarrierBase
<Unknown
>& argument(size_t);
118 void allocateSlowArguments();
120 void init(CallFrame
*);
122 WriteBarrier
<JSActivation
> m_activation
;
124 unsigned m_numArguments
;
126 // We make these full byte booleans to make them easy to test from the JIT,
127 // and because even if they were single-bit booleans we still wouldn't save
129 bool m_overrodeLength
;
130 bool m_overrodeCallee
;
131 bool m_overrodeCaller
;
134 WriteBarrierBase
<Unknown
>* m_registers
;
135 OwnArrayPtr
<WriteBarrier
<Unknown
> > m_registerArray
;
137 OwnArrayPtr
<SlowArgument
> m_slowArguments
;
139 WriteBarrier
<JSFunction
> m_callee
;
142 Arguments
* asArguments(JSValue
);
144 inline Arguments
* asArguments(JSValue value
)
146 ASSERT(asObject(value
)->inherits(&Arguments::s_info
));
147 return static_cast<Arguments
*>(asObject(value
));
150 inline Arguments::Arguments(CallFrame
* callFrame
)
151 : JSDestructibleObject(callFrame
->vm(), callFrame
->lexicalGlobalObject()->argumentsStructure())
155 inline Arguments::Arguments(CallFrame
* callFrame
, NoParametersType
)
156 : JSDestructibleObject(callFrame
->vm(), callFrame
->lexicalGlobalObject()->argumentsStructure())
160 inline void Arguments::allocateSlowArguments()
164 m_slowArguments
= adoptArrayPtr(new SlowArgument
[m_numArguments
]);
165 for (size_t i
= 0; i
< m_numArguments
; ++i
) {
166 ASSERT(m_slowArguments
[i
].status
== SlowArgument::Normal
);
167 m_slowArguments
[i
].index
= CallFrame::argumentOffset(i
);
171 inline bool Arguments::tryDeleteArgument(size_t argument
)
173 if (!isArgument(argument
))
175 allocateSlowArguments();
176 m_slowArguments
[argument
].status
= SlowArgument::Deleted
;
180 inline bool Arguments::trySetArgument(VM
& vm
, size_t argument
, JSValue value
)
182 if (!isArgument(argument
))
184 this->argument(argument
).set(vm
, this, value
);
188 inline JSValue
Arguments::tryGetArgument(size_t argument
)
190 if (!isArgument(argument
))
192 return this->argument(argument
).get();
195 inline bool Arguments::isDeletedArgument(size_t argument
)
197 if (argument
>= m_numArguments
)
199 if (!m_slowArguments
)
201 if (m_slowArguments
[argument
].status
!= SlowArgument::Deleted
)
206 inline bool Arguments::isArgument(size_t argument
)
208 if (argument
>= m_numArguments
)
210 if (m_slowArguments
&& m_slowArguments
[argument
].status
== SlowArgument::Deleted
)
215 inline WriteBarrierBase
<Unknown
>& Arguments::argument(size_t argument
)
217 ASSERT(isArgument(argument
));
218 if (!m_slowArguments
)
219 return m_registers
[CallFrame::argumentOffset(argument
)];
221 int index
= m_slowArguments
[argument
].index
;
222 if (!m_activation
|| m_slowArguments
[argument
].status
!= SlowArgument::Captured
)
223 return m_registers
[index
];
225 return m_activation
->registerAt(index
);
228 inline void Arguments::finishCreation(CallFrame
* callFrame
)
230 Base::finishCreation(callFrame
->vm());
231 ASSERT(inherits(&s_info
));
233 JSFunction
* callee
= jsCast
<JSFunction
*>(callFrame
->callee());
234 m_numArguments
= callFrame
->argumentCount();
235 m_registers
= reinterpret_cast<WriteBarrierBase
<Unknown
>*>(callFrame
->registers());
236 m_callee
.set(callFrame
->vm(), this, callee
);
237 m_overrodeLength
= false;
238 m_overrodeCallee
= false;
239 m_overrodeCaller
= false;
240 m_isStrictMode
= callFrame
->codeBlock()->isStrictMode();
242 SharedSymbolTable
* symbolTable
= callFrame
->codeBlock()->symbolTable();
243 const SlowArgument
* slowArguments
= symbolTable
->slowArguments();
245 allocateSlowArguments();
246 size_t count
= std::min
<unsigned>(m_numArguments
, symbolTable
->parameterCount());
247 for (size_t i
= 0; i
< count
; ++i
)
248 m_slowArguments
[i
] = slowArguments
[i
];
251 // The bytecode generator omits op_tear_off_activation in cases of no
252 // declared parameters, so we need to tear off immediately.
253 if (m_isStrictMode
|| !callee
->jsExecutable()->parameterCount())
257 inline void Arguments::finishCreation(CallFrame
* callFrame
, InlineCallFrame
* inlineCallFrame
)
259 Base::finishCreation(callFrame
->vm());
260 ASSERT(inherits(&s_info
));
262 JSFunction
* callee
= inlineCallFrame
->calleeForCallFrame(callFrame
);
263 m_numArguments
= inlineCallFrame
->arguments
.size() - 1;
264 m_registers
= reinterpret_cast<WriteBarrierBase
<Unknown
>*>(callFrame
->registers()) + inlineCallFrame
->stackOffset
;
265 m_callee
.set(callFrame
->vm(), this, callee
);
266 m_overrodeLength
= false;
267 m_overrodeCallee
= false;
268 m_overrodeCaller
= false;
269 m_isStrictMode
= jsCast
<FunctionExecutable
*>(inlineCallFrame
->executable
.get())->isStrictMode();
270 ASSERT(!jsCast
<FunctionExecutable
*>(inlineCallFrame
->executable
.get())->symbolTable(inlineCallFrame
->isCall
? CodeForCall
: CodeForConstruct
)->slowArguments());
272 // The bytecode generator omits op_tear_off_activation in cases of no
273 // declared parameters, so we need to tear off immediately.
274 if (m_isStrictMode
|| !callee
->jsExecutable()->parameterCount())
275 tearOff(callFrame
, inlineCallFrame
);
280 #endif // Arguments_h