summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/Arguments.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/Arguments.h')
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h164
1 files changed, 107 insertions, 57 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
index c3d25f962..ad0e651ea 100644
--- a/Source/JavaScriptCore/runtime/Arguments.h
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -33,31 +33,9 @@
namespace JSC {
- struct ArgumentsData {
- WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
- public:
- ArgumentsData() { }
- WriteBarrier<JSActivation> activation;
-
- unsigned 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 overrodeLength;
- bool overrodeCallee;
- bool overrodeCaller;
- bool isStrictMode;
-
- WriteBarrierBase<Unknown>* registers;
- OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
-
- OwnArrayPtr<bool> deletedArguments;
-
- WriteBarrier<JSFunction> callee;
- };
-
class Arguments : public JSNonFinalObject {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
public:
typedef JSNonFinalObject Base;
@@ -94,30 +72,22 @@ namespace JSC {
uint32_t length(ExecState* exec) const
{
- if (UNLIKELY(d->overrodeLength))
+ if (UNLIKELY(m_overrodeLength))
return get(exec, exec->propertyNames().length).toUInt32(exec);
- return d->numArguments;
+ return m_numArguments;
}
void copyToArguments(ExecState*, CallFrame*, uint32_t length);
void tearOff(CallFrame*);
void tearOff(CallFrame*, InlineCallFrame*);
- bool isTornOff() const { return d->registerArray; }
- void didTearOffActivation(JSGlobalData& globalData, JSActivation* activation)
- {
- if (isTornOff())
- return;
- d->activation.set(globalData, this, activation);
- d->registers = &activation->registerAt(0);
- }
+ 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);
}
- static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(Arguments, d); }
-
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
@@ -138,11 +108,34 @@ namespace JSC {
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*);
- OwnPtr<ArgumentsData> d;
+ 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);
@@ -155,19 +148,76 @@ namespace JSC {
inline Arguments::Arguments(CallFrame* callFrame)
: JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
- , d(adoptPtr(new ArgumentsData))
{
}
inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
: JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
- , d(adoptPtr(new ArgumentsData))
{
}
- inline WriteBarrierBase<Unknown>& Arguments::argument(size_t i)
+ inline void Arguments::allocateSlowArguments()
+ {
+ if (m_slowArguments)
+ return;
+ m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
+ }
+
+ inline bool Arguments::tryDeleteArgument(size_t argument)
{
- return d->registers[CallFrame::argumentOffset(i)];
+ 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 || m_slowArguments[argument].status == SlowArgument::Normal)
+ return m_registers[CallFrame::argumentOffset(argument)];
+
+ ASSERT(m_slowArguments[argument].status == SlowArgument::Captured);
+ if (!m_activation)
+ return m_registers[m_slowArguments[argument].indexIfCaptured];
+
+ return m_activation->registerAt(m_slowArguments[argument].indexIfCaptured);
}
inline void Arguments::finishCreation(CallFrame* callFrame)
@@ -176,17 +226,17 @@ namespace JSC {
ASSERT(inherits(&s_info));
JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
- d->numArguments = callFrame->argumentCount();
- d->registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
- d->callee.set(callFrame->globalData(), this, callee);
- d->overrodeLength = false;
- d->overrodeCallee = false;
- d->overrodeCaller = false;
- d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+ 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();
// The bytecode generator omits op_tear_off_activation in cases of no
// declared parameters, so we need to tear off immediately.
- if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
tearOff(callFrame);
}
@@ -196,17 +246,17 @@ namespace JSC {
ASSERT(inherits(&s_info));
JSFunction* callee = inlineCallFrame->callee.get();
- d->numArguments = inlineCallFrame->arguments.size() - 1;
- d->registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
- d->callee.set(callFrame->globalData(), this, callee);
- d->overrodeLength = false;
- d->overrodeCallee = false;
- d->overrodeCaller = false;
- d->isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
+ 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();
// The bytecode generator omits op_tear_off_activation in cases of no
// declared parameters, so we need to tear off immediately.
- if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
tearOff(callFrame, inlineCallFrame);
}