Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (167640 => 167641)
--- trunk/Source/_javascript_Core/ChangeLog 2014-04-22 01:34:46 UTC (rev 167640)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-04-22 01:37:34 UTC (rev 167641)
@@ -1,3 +1,45 @@
+2014-04-21 Mark Hahnenberg <[email protected]>
+
+ Arguments objects shouldn't need a destructor
+ https://bugs.webkit.org/show_bug.cgi?id=131899
+
+ Reviewed by Oliver Hunt.
+
+ This patch rids Arguments objects of their destructors. It does this by
+ switching their backing stores to use CopiedSpace rather than malloc memory.
+
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::emitAllocateArguments): Fix the code emitted for inline
+ Arguments allocation so that it only emits an extra write for strict mode code rather
+ than unconditionally.
+ * heap/CopyToken.h: New CopyTokens for the two different types of Arguments backing stores.
+ * runtime/Arguments.cpp:
+ (JSC::Arguments::visitChildren): We need to tell the collector to copy the back stores now.
+ (JSC::Arguments::copyBackingStore): Do the actual copying of the backing stores.
+ (JSC::Arguments::deletePropertyByIndex): Update all the accesses to SlowArgumentData and m_registerArray.
+ (JSC::Arguments::deleteProperty):
+ (JSC::Arguments::defineOwnProperty):
+ (JSC::Arguments::allocateRegisterArray):
+ (JSC::Arguments::tearOff):
+ (JSC::Arguments::destroy): Deleted. We don't need the destructor any more.
+ * runtime/Arguments.h:
+ (JSC::Arguments::registerArraySizeInBytes):
+ (JSC::Arguments::SlowArgumentData::SlowArgumentData): Switch SlowArgumentData to being allocated
+ in CopiedSpace. Now the SlowArgumentData and its backing store are a single contiguous CopiedSpace
+ allocation.
+ (JSC::Arguments::SlowArgumentData::slowArguments):
+ (JSC::Arguments::SlowArgumentData::bytecodeToMachineCaptureOffset):
+ (JSC::Arguments::SlowArgumentData::setBytecodeToMachineCaptureOffset):
+ (JSC::Arguments::SlowArgumentData::sizeForNumArguments):
+ (JSC::Arguments::Arguments):
+ (JSC::Arguments::allocateSlowArguments):
+ (JSC::Arguments::tryDeleteArgument):
+ (JSC::Arguments::isDeletedArgument):
+ (JSC::Arguments::isArgument):
+ (JSC::Arguments::argument):
+ (JSC::Arguments::finishCreation):
+ * runtime/SymbolTable.h:
+
2014-04-21 Eric Carlson <[email protected]>
[Mac] implement WebKitDataCue
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (167640 => 167641)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2014-04-22 01:34:46 UTC (rev 167640)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2014-04-22 01:37:34 UTC (rev 167641)
@@ -118,8 +118,8 @@
m_jit.store32(scratchGPR1, MacroAssembler::Address(resultGPR, Arguments::offsetOfNumArguments()));
m_jit.store32(TrustedImm32(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfOverrodeLength()));
- m_jit.store8(TrustedImm32(m_jit.isStrictModeFor(m_currentNode->origin.semantic)),
- MacroAssembler::Address(resultGPR, Arguments::offsetOfIsStrictMode()));
+ if (m_jit.isStrictModeFor(m_currentNode->origin.semantic))
+ m_jit.store8(TrustedImm32(1), MacroAssembler::Address(resultGPR, Arguments::offsetOfIsStrictMode()));
m_jit.storePtr(GPRInfo::callFrameRegister, MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisters()));
m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisterArray()));
Modified: trunk/Source/_javascript_Core/heap/CopyToken.h (167640 => 167641)
--- trunk/Source/_javascript_Core/heap/CopyToken.h 2014-04-22 01:34:46 UTC (rev 167640)
+++ trunk/Source/_javascript_Core/heap/CopyToken.h 2014-04-22 01:37:34 UTC (rev 167641)
@@ -31,7 +31,9 @@
enum CopyToken {
ButterflyCopyToken,
TypedArrayVectorCopyToken,
- MapBackingStoreCopyToken
+ MapBackingStoreCopyToken,
+ ArgumentsRegisterArrayCopyToken,
+ ArgumentsSlowArgumentDataCopyToken
};
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/Arguments.cpp (167640 => 167641)
--- trunk/Source/_javascript_Core/runtime/Arguments.cpp 2014-04-22 01:34:46 UTC (rev 167640)
+++ trunk/Source/_javascript_Core/runtime/Arguments.cpp 2014-04-22 01:37:34 UTC (rev 167641)
@@ -25,6 +25,7 @@
#include "config.h"
#include "Arguments.h"
+#include "CopyVisitorInlines.h"
#include "JSActivation.h"
#include "JSArgumentsIterator.h"
#include "JSFunction.h"
@@ -35,6 +36,8 @@
namespace JSC {
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(Arguments);
+
const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
@@ -45,18 +48,62 @@
ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSObject::visitChildren(thisObject, visitor);
- if (thisObject->m_registerArray)
+ if (thisObject->m_registerArray) {
+ visitor.copyLater(thisObject, ArgumentsRegisterArrayCopyToken,
+ thisObject->m_registerArray.get(), thisObject->registerArraySizeInBytes());
visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_numArguments);
+ }
+ if (thisObject->m_slowArgumentData) {
+ visitor.copyLater(thisObject, ArgumentsSlowArgumentDataCopyToken,
+ thisObject->m_slowArgumentData.get(), SlowArgumentData::sizeForNumArguments(thisObject->m_numArguments));
+ }
visitor.append(&thisObject->m_callee);
visitor.append(&thisObject->m_activation);
}
+
+void Arguments::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*);
-void Arguments::destroy(JSCell* cell)
-{
- static_cast<Arguments*>(cell)->Arguments::~Arguments();
+ switch (token) {
+ case ArgumentsRegisterArrayCopyToken: {
+ WriteBarrier<Unknown>* registerArray = thisObject->m_registerArray.get();
+ if (!registerArray)
+ return;
+
+ if (visitor.checkIfShouldCopy(registerArray)) {
+ size_t bytes = thisObject->registerArraySizeInBytes();
+ WriteBarrier<Unknown>* newRegisterArray = static_cast<WriteBarrier<Unknown>*>(visitor.allocateNewSpace(bytes));
+ memcpy(newRegisterArray, registerArray, bytes);
+ thisObject->m_registerArray.setWithoutWriteBarrier(newRegisterArray);
+ visitor.didCopy(registerArray, bytes);
+ }
+ return;
+ }
+
+ case ArgumentsSlowArgumentDataCopyToken: {
+ SlowArgumentData* slowArgumentData = thisObject->m_slowArgumentData.get();
+ if (!slowArgumentData)
+ return;
+
+ if (visitor.checkIfShouldCopy(slowArgumentData)) {
+ size_t bytes = SlowArgumentData::sizeForNumArguments(thisObject->m_numArguments);
+ SlowArgumentData* newSlowArgumentData = static_cast<SlowArgumentData*>(visitor.allocateNewSpace(bytes));
+ memcpy(newSlowArgumentData, slowArgumentData, bytes);
+ thisObject->m_slowArgumentData.setWithoutWriteBarrier(newSlowArgumentData);
+ visitor.didCopy(slowArgumentData, bytes);
+ }
+ return;
+ }
+
+ default:
+ return;
+ }
}
+
+static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*);
void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t copyLength, int32_t firstVarArgOffset)
{
@@ -226,7 +273,7 @@
if (i < thisObject->m_numArguments) {
if (!Base::deletePropertyByIndex(cell, exec, i))
return false;
- if (thisObject->tryDeleteArgument(i))
+ if (thisObject->tryDeleteArgument(exec->vm(), i))
return true;
}
return JSObject::deletePropertyByIndex(thisObject, exec, i);
@@ -243,7 +290,7 @@
RELEASE_ASSERT(i < PropertyName::NotAnIndex);
if (!Base::deleteProperty(cell, exec, propertyName))
return false;
- if (thisObject->tryDeleteArgument(i))
+ if (thisObject->tryDeleteArgument(exec->vm(), i))
return true;
}
@@ -288,7 +335,7 @@
// a. If IsAccessorDescriptor(Desc) is true, then
if (descriptor.isAccessorDescriptor()) {
// i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
- thisObject->tryDeleteArgument(i);
+ thisObject->tryDeleteArgument(exec->vm(), i);
} else { // b. Else
// i. If Desc.[[Value]] is present, then
// 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
@@ -297,7 +344,7 @@
// ii. If Desc.[[Writable]] is present and its value is false, then
// 1. Call the [[Delete]] internal method of map passing P and false as arguments.
if (descriptor.writablePresent() && !descriptor.writable())
- thisObject->tryDeleteArgument(i);
+ thisObject->tryDeleteArgument(exec->vm(), i);
}
}
return true;
@@ -315,6 +362,15 @@
return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
}
+void Arguments::allocateRegisterArray(VM& vm)
+{
+ ASSERT(!m_registerArray);
+ void* backingStore;
+ if (!vm.heap.tryAllocateStorage(this, registerArraySizeInBytes(), &backingStore))
+ RELEASE_ASSERT_NOT_REACHED();
+ m_registerArray.set(vm, this, static_cast<WriteBarrier<Unknown>*>(backingStore));
+}
+
void Arguments::tearOff(CallFrame* callFrame)
{
if (isTornOff())
@@ -326,7 +382,7 @@
// Must be called for the same call frame from which it was created.
ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers);
- m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(m_numArguments);
+ allocateRegisterArray(callFrame->vm());
m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
// If we have a captured argument that logically aliases activation storage,
@@ -334,10 +390,10 @@
// our storage. The simplest way to do this is to revert it to Normal status.
if (m_slowArgumentData && !m_activation) {
for (size_t i = 0; i < m_numArguments; ++i) {
- if (m_slowArgumentData->slowArguments[i].status != SlowArgument::Captured)
+ if (m_slowArgumentData->slowArguments()[i].status != SlowArgument::Captured)
continue;
- m_slowArgumentData->slowArguments[i].status = SlowArgument::Normal;
- m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i);
+ m_slowArgumentData->slowArguments()[i].status = SlowArgument::Normal;
+ m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
}
}
@@ -366,7 +422,7 @@
if (!m_numArguments)
return;
- m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(m_numArguments);
+ allocateRegisterArray(callFrame->vm());
m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
for (size_t i = 0; i < m_numArguments; ++i) {
Modified: trunk/Source/_javascript_Core/runtime/Arguments.h (167640 => 167641)
--- trunk/Source/_javascript_Core/runtime/Arguments.h 2014-04-22 01:34:46 UTC (rev 167640)
+++ trunk/Source/_javascript_Core/runtime/Arguments.h 2014-04-22 01:37:34 UTC (rev 167641)
@@ -26,7 +26,6 @@
#include "CodeOrigin.h"
#include "JSActivation.h"
-#include "JSDestructibleObject.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Interpreter.h"
@@ -36,11 +35,11 @@
namespace JSC {
-class Arguments : public JSDestructibleObject {
+class Arguments : public JSNonFinalObject {
friend class JIT;
friend class JSArgumentsIterator;
public:
- typedef JSDestructibleObject Base;
+ typedef JSNonFinalObject Base;
static Arguments* create(VM& vm, CallFrame* callFrame)
{
@@ -68,6 +67,7 @@
DECLARE_INFO;
static void visitChildren(JSCell*, SlotVisitor&);
+ static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
void fillArgList(ExecState*, MarkedArgumentBuffer&);
@@ -111,7 +111,6 @@
void finishCreation(CallFrame*, InlineCallFrame*);
private:
- static void destroy(JSCell*);
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
@@ -123,13 +122,15 @@
void createStrictModeCallerIfNecessary(ExecState*);
void createStrictModeCalleeIfNecessary(ExecState*);
+ size_t registerArraySizeInBytes() const { return sizeof(WriteBarrier<Unknown>) * m_numArguments; }
+ void allocateRegisterArray(VM&);
bool isArgument(size_t);
bool trySetArgument(VM&, size_t argument, JSValue);
JSValue tryGetArgument(size_t argument);
bool isDeletedArgument(size_t);
- bool tryDeleteArgument(size_t);
+ bool tryDeleteArgument(VM&, size_t);
WriteBarrierBase<Unknown>& argument(size_t);
- void allocateSlowArguments();
+ void allocateSlowArguments(VM&);
void init(CallFrame*);
@@ -146,19 +147,35 @@
bool m_isStrictMode;
WriteBarrierBase<Unknown>* m_registers;
- std::unique_ptr<WriteBarrier<Unknown>[]> m_registerArray;
+ CopyWriteBarrier<WriteBarrier<Unknown>> m_registerArray;
public:
struct SlowArgumentData {
- WTF_MAKE_FAST_ALLOCATED;
public:
+ SlowArgumentData()
+ : m_bytecodeToMachineCaptureOffset(0)
+ {
+ }
- std::unique_ptr<SlowArgument[]> slowArguments;
- int 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.
+ SlowArgument* slowArguments()
+ {
+ return reinterpret_cast<SlowArgument*>(WTF::roundUpToMultipleOf<8>(reinterpret_cast<size_t>(this + 1)));
+ }
+
+ int bytecodeToMachineCaptureOffset() const { return m_bytecodeToMachineCaptureOffset; }
+ void setBytecodeToMachineCaptureOffset(int newOffset) { m_bytecodeToMachineCaptureOffset = newOffset; }
+
+ static size_t sizeForNumArguments(unsigned numArguments)
+ {
+ return WTF::roundUpToMultipleOf<8>(sizeof(SlowArgumentData)) + sizeof(SlowArgument) * numArguments;
+ }
+
+ private:
+ 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.
};
private:
- std::unique_ptr<SlowArgumentData> m_slowArgumentData;
+ CopyWriteBarrier<SlowArgumentData> m_slowArgumentData;
WriteBarrier<JSFunction> m_callee;
};
@@ -172,34 +189,37 @@
}
inline Arguments::Arguments(CallFrame* callFrame)
- : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
{
}
inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
- : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ : Base(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure())
{
}
-inline void Arguments::allocateSlowArguments()
+inline void Arguments::allocateSlowArguments(VM& vm)
{
- if (m_slowArgumentData)
+ if (!!m_slowArgumentData)
return;
- m_slowArgumentData = std::make_unique<SlowArgumentData>();
- m_slowArgumentData->bytecodeToMachineCaptureOffset = 0;
- m_slowArgumentData->slowArguments = std::make_unique<SlowArgument[]>(m_numArguments);
+
+ void* backingStore;
+ if (!vm.heap.tryAllocateStorage(this, SlowArgumentData::sizeForNumArguments(m_numArguments), &backingStore))
+ RELEASE_ASSERT_NOT_REACHED();
+ m_slowArgumentData.set(vm, this, static_cast<SlowArgumentData*>(backingStore));
+
for (size_t i = 0; i < m_numArguments; ++i) {
- ASSERT(m_slowArgumentData->slowArguments[i].status == SlowArgument::Normal);
- m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i);
+ ASSERT(m_slowArgumentData->slowArguments()[i].status == SlowArgument::Normal);
+ m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
}
}
-inline bool Arguments::tryDeleteArgument(size_t argument)
+inline bool Arguments::tryDeleteArgument(VM& vm, size_t argument)
{
if (!isArgument(argument))
return false;
- allocateSlowArguments();
- m_slowArgumentData->slowArguments[argument].status = SlowArgument::Deleted;
+ allocateSlowArguments(vm);
+ m_slowArgumentData->slowArguments()[argument].status = SlowArgument::Deleted;
return true;
}
@@ -224,7 +244,7 @@
return false;
if (!m_slowArgumentData)
return false;
- if (m_slowArgumentData->slowArguments[argument].status != SlowArgument::Deleted)
+ if (m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Deleted)
return false;
return true;
}
@@ -233,7 +253,7 @@
{
if (argument >= m_numArguments)
return false;
- if (m_slowArgumentData && m_slowArgumentData->slowArguments[argument].status == SlowArgument::Deleted)
+ if (m_slowArgumentData && m_slowArgumentData->slowArguments()[argument].status == SlowArgument::Deleted)
return false;
return true;
}
@@ -244,11 +264,11 @@
if (!m_slowArgumentData)
return m_registers[CallFrame::argumentOffset(argument)];
- int index = m_slowArgumentData->slowArguments[argument].index;
- if (!m_activation || m_slowArgumentData->slowArguments[argument].status != SlowArgument::Captured)
+ int index = m_slowArgumentData->slowArguments()[argument].index;
+ if (!m_activation || m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
return m_registers[index];
- return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset);
+ return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
}
inline void Arguments::finishCreation(CallFrame* callFrame)
@@ -269,12 +289,12 @@
if (codeBlock->hasSlowArguments()) {
SymbolTable* symbolTable = codeBlock->symbolTable();
const SlowArgument* slowArguments = codeBlock->machineSlowArguments();
- allocateSlowArguments();
+ allocateSlowArguments(callFrame->vm());
size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
for (size_t i = 0; i < count; ++i)
- m_slowArgumentData->slowArguments[i] = slowArguments[i];
- m_slowArgumentData->bytecodeToMachineCaptureOffset =
- codeBlock->framePointerOffsetToGetActivationRegisters();
+ m_slowArgumentData->slowArguments()[i] = slowArguments[i];
+ m_slowArgumentData->setBytecodeToMachineCaptureOffset(
+ codeBlock->framePointerOffsetToGetActivationRegisters());
}
// The bytecode generator omits op_tear_off_activation in cases of no
Modified: trunk/Source/_javascript_Core/runtime/SymbolTable.h (167640 => 167641)
--- trunk/Source/_javascript_Core/runtime/SymbolTable.h 2014-04-22 01:34:46 UTC (rev 167640)
+++ trunk/Source/_javascript_Core/runtime/SymbolTable.h 2014-04-22 01:37:34 UTC (rev 167641)
@@ -39,9 +39,7 @@
namespace JSC {
struct SlowArgument {
- WTF_MAKE_FAST_ALLOCATED;
public:
-
enum Status {
Normal = 0,
Captured = 1,