blob: 8ae991422ef8b651fac1cb12b77e795ebf2dbae4 [file] [log] [blame]
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef Arguments_h
#define Arguments_h
#include "CodeOrigin.h"
#include "JSActivation.h"
#include "JSDestructibleObject.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Interpreter.h"
#include "ObjectConstructor.h"
namespace JSC {
class Arguments : public JSDestructibleObject {
friend class JIT;
friend class DFG::SpeculativeJIT;
public:
typedef JSDestructibleObject Base;
static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
{
Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
arguments->finishCreation(callFrame);
return arguments;
}
static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
{
Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
arguments->finishCreation(callFrame, inlineCallFrame);
return arguments;
}
enum { MaxArguments = 0x10000 };
private:
enum NoParametersType { NoParameters };
Arguments(CallFrame*);
Arguments(CallFrame*, NoParametersType);
void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*);
public:
static const ClassInfo s_info;
static void visitChildren(JSCell*, SlotVisitor&);
void fillArgList(ExecState*, MarkedArgumentBuffer&);
uint32_t length(ExecState* exec) const
{
if (UNLIKELY(m_overrodeLength))
return get(exec, exec->propertyNames().length).toUInt32(exec);
return m_numArguments;
}
void copyToArguments(ExecState*, CallFrame*, uint32_t length);
void tearOff(CallFrame*);
void tearOff(CallFrame*, InlineCallFrame*);
bool isTornOff() const { return m_registerArray; }
void didTearOffActivation(ExecState*, JSActivation*);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
{
return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
void finishCreation(CallFrame*);
void finishCreation(CallFrame*, InlineCallFrame*);
private:
static void destroy(JSCell*);
static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
void createStrictModeCallerIfNecessary(ExecState*);
void createStrictModeCalleeIfNecessary(ExecState*);
bool isArgument(size_t);
bool trySetArgument(JSGlobalData&, size_t argument, JSValue);
JSValue tryGetArgument(size_t argument);
bool isDeletedArgument(size_t);
bool tryDeleteArgument(size_t);
WriteBarrierBase<Unknown>& argument(size_t);
void allocateSlowArguments();
void init(CallFrame*);
WriteBarrier<JSActivation> m_activation;
unsigned m_numArguments;
// We make these full byte booleans to make them easy to test from the JIT,
// and because even if they were single-bit booleans we still wouldn't save
// any space.
bool m_overrodeLength;
bool m_overrodeCallee;
bool m_overrodeCaller;
bool m_isStrictMode;
WriteBarrierBase<Unknown>* m_registers;
OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray;
OwnArrayPtr<SlowArgument> m_slowArguments;
WriteBarrier<JSFunction> m_callee;
};
Arguments* asArguments(JSValue);
inline Arguments* asArguments(JSValue value)
{
ASSERT(asObject(value)->inherits(&Arguments::s_info));
return static_cast<Arguments*>(asObject(value));
}
inline Arguments::Arguments(CallFrame* callFrame)
: JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
{
}
inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
: JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
{
}
inline void Arguments::allocateSlowArguments()
{
if (m_slowArguments)
return;
m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
for (size_t i = 0; i < m_numArguments; ++i) {
ASSERT(m_slowArguments[i].status == SlowArgument::Normal);
m_slowArguments[i].index = CallFrame::argumentOffset(i);
}
}
inline bool Arguments::tryDeleteArgument(size_t argument)
{
if (!isArgument(argument))
return false;
allocateSlowArguments();
m_slowArguments[argument].status = SlowArgument::Deleted;
return true;
}
inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value)
{
if (!isArgument(argument))
return false;
this->argument(argument).set(globalData, this, value);
return true;
}
inline JSValue Arguments::tryGetArgument(size_t argument)
{
if (!isArgument(argument))
return JSValue();
return this->argument(argument).get();
}
inline bool Arguments::isDeletedArgument(size_t argument)
{
if (argument >= m_numArguments)
return false;
if (!m_slowArguments)
return false;
if (m_slowArguments[argument].status != SlowArgument::Deleted)
return false;
return true;
}
inline bool Arguments::isArgument(size_t argument)
{
if (argument >= m_numArguments)
return false;
if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted)
return false;
return true;
}
inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
{
ASSERT(isArgument(argument));
if (!m_slowArguments)
return m_registers[CallFrame::argumentOffset(argument)];
int index = m_slowArguments[argument].index;
if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured)
return m_registers[index];
return m_activation->registerAt(index);
}
inline void Arguments::finishCreation(CallFrame* callFrame)
{
Base::finishCreation(callFrame->globalData());
ASSERT(inherits(&s_info));
JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
m_numArguments = callFrame->argumentCount();
m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
m_callee.set(callFrame->globalData(), this, callee);
m_overrodeLength = false;
m_overrodeCallee = false;
m_overrodeCaller = false;
m_isStrictMode = callFrame->codeBlock()->isStrictMode();
SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable();
const SlowArgument* slowArguments = symbolTable->slowArguments();
if (slowArguments) {
allocateSlowArguments();
size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
for (size_t i = 0; i < count; ++i)
m_slowArguments[i] = slowArguments[i];
}
// The bytecode generator omits op_tear_off_activation in cases of no
// declared parameters, so we need to tear off immediately.
if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
tearOff(callFrame);
}
inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
{
Base::finishCreation(callFrame->globalData());
ASSERT(inherits(&s_info));
JSFunction* callee = inlineCallFrame->callee.get();
m_numArguments = inlineCallFrame->arguments.size() - 1;
m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
m_callee.set(callFrame->globalData(), this, callee);
m_overrodeLength = false;
m_overrodeCallee = false;
m_overrodeCaller = false;
m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments());
// The bytecode generator omits op_tear_off_activation in cases of no
// declared parameters, so we need to tear off immediately.
if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
tearOff(callFrame, inlineCallFrame);
}
} // namespace JSC
#endif // Arguments_h