X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..4be4e30906bcb8ee30b4d189205cb70bad6707ce:/runtime/Arguments.h?ds=inline diff --git a/runtime/Arguments.h b/runtime/Arguments.h index a1f36de..58ac782 100644 --- a/runtime/Arguments.h +++ b/runtime/Arguments.h @@ -26,6 +26,7 @@ #include "CodeOrigin.h" #include "JSActivation.h" +#include "JSDestructibleObject.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "Interpreter.h" @@ -33,145 +34,246 @@ namespace JSC { - struct ArgumentsData { - WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED; - public: - ArgumentsData() { } - WriteBarrier activation; +class Arguments : public JSDestructibleObject { + friend class JIT; + friend class DFG::SpeculativeJIT; +public: + typedef JSDestructibleObject Base; - unsigned numArguments; - - WriteBarrier* registers; - OwnArrayPtr > registerArray; - - OwnArrayPtr deletedArguments; - - WriteBarrier callee; - bool overrodeLength : 1; - bool overrodeCallee : 1; - bool overrodeCaller : 1; - bool isStrictMode : 1; - }; - - class Arguments : public JSNonFinalObject { - public: - typedef JSNonFinalObject Base; - - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) - { - Arguments* arguments = new (NotNull, allocateCell(globalData.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame); - return arguments; - } + static Arguments* create(VM& vm, CallFrame* callFrame) + { + Arguments* arguments = new (NotNull, allocateCell(vm.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame); + return arguments; + } + + static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) + { + Arguments* arguments = new (NotNull, allocateCell(vm.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame, inlineCallFrame); + return arguments; + } - enum { MaxArguments = 0x10000 }; + enum { MaxArguments = 0x10000 }; - private: - enum NoParametersType { NoParameters }; +private: + enum NoParametersType { NoParameters }; + + Arguments(CallFrame*); + Arguments(CallFrame*, NoParametersType); - Arguments(CallFrame*); - Arguments(CallFrame*, NoParametersType); + void tearOffForInlineCallFrame(VM& vm, Register*, InlineCallFrame*); - public: - static const ClassInfo s_info; +public: + static const ClassInfo s_info; - static void visitChildren(JSCell*, SlotVisitor&); + static void visitChildren(JSCell*, SlotVisitor&); - void fillArgList(ExecState*, MarkedArgumentBuffer&); + void fillArgList(ExecState*, MarkedArgumentBuffer&); - uint32_t length(ExecState* exec) const - { - if (UNLIKELY(d->overrodeLength)) - return get(exec, exec->propertyNames().length).toUInt32(exec); - return d->numArguments; - } - - void copyToArguments(ExecState*, CallFrame*, uint32_t length); - void tearOff(CallFrame*); - 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); - } - - 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 | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; - - void finishCreation(CallFrame*); - - private: - static void destroy(JSCell*); - static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); - void createStrictModeCallerIfNecessary(ExecState*); - void createStrictModeCalleeIfNecessary(ExecState*); - - WriteBarrier& argument(size_t); - - void init(CallFrame*); - - OwnPtr d; - }; - - Arguments* asArguments(JSValue); - - inline Arguments* asArguments(JSValue value) + uint32_t length(ExecState* exec) const { - ASSERT(asObject(value)->inherits(&Arguments::s_info)); - return static_cast(asObject(value)); + if (UNLIKELY(m_overrodeLength)) + return get(exec, exec->propertyNames().length).toUInt32(exec); + return m_numArguments; } - - inline Arguments::Arguments(CallFrame* callFrame) - : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) - , d(adoptPtr(new ArgumentsData)) - { + + 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(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - - inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) - , d(adoptPtr(new ArgumentsData)) - { + +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(VM&, size_t argument, JSValue); + JSValue tryGetArgument(size_t argument); + bool isDeletedArgument(size_t); + bool tryDeleteArgument(size_t); + WriteBarrierBase& argument(size_t); + void allocateSlowArguments(); + + void init(CallFrame*); + + WriteBarrier 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* m_registers; + OwnArrayPtr > m_registerArray; + + OwnArrayPtr m_slowArguments; + + WriteBarrier m_callee; +}; + +Arguments* asArguments(JSValue); + +inline Arguments* asArguments(JSValue value) +{ + ASSERT(asObject(value)->inherits(&Arguments::s_info)); + return static_cast(asObject(value)); +} + +inline Arguments::Arguments(CallFrame* callFrame) + : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) +{ +} + +inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) + : JSDestructibleObject(callFrame->vm(), 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 WriteBarrier& Arguments::argument(size_t i) - { - return d->registers[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(VM& vm, size_t argument, JSValue value) +{ + if (!isArgument(argument)) + return false; + this->argument(argument).set(vm, 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& 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->vm()); + ASSERT(inherits(&s_info)); + + JSFunction* callee = jsCast(callFrame->callee()); + m_numArguments = callFrame->argumentCount(); + m_registers = reinterpret_cast*>(callFrame->registers()); + m_callee.set(callFrame->vm(), 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(m_numArguments, symbolTable->parameterCount()); + for (size_t i = 0; i < count; ++i) + m_slowArguments[i] = slowArguments[i]; } - inline void Arguments::finishCreation(CallFrame* callFrame) - { - Base::finishCreation(callFrame->globalData()); - ASSERT(inherits(&s_info)); - - JSFunction* callee = jsCast(callFrame->callee()); - d->numArguments = callFrame->argumentCount(); - d->registers = reinterpret_cast*>(callFrame->registers()); - d->callee.set(callFrame->globalData(), this, callee); - d->overrodeLength = false; - d->overrodeCallee = false; - d->overrodeCaller = false; - d->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()) - tearOff(callFrame); - } + // 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->vm()); + ASSERT(inherits(&s_info)); + + JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame); + m_numArguments = inlineCallFrame->arguments.size() - 1; + m_registers = reinterpret_cast*>(callFrame->registers()) + inlineCallFrame->stackOffset; + m_callee.set(callFrame->vm(), this, callee); + m_overrodeLength = false; + m_overrodeCallee = false; + m_overrodeCaller = false; + m_isStrictMode = jsCast(inlineCallFrame->executable.get())->isStrictMode(); + ASSERT(!jsCast(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