Don't de-allocate FunctionRareData
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Apr 2015 17:39:44 +0000 (17:39 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Apr 2015 17:39:44 +0000 (17:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144000

Patch by Basile Clement <basile_clement@apple.com> on 2015-04-22
Reviewed by Michael Saboff.

A function rare data (containing most notably its allocation profile) is currently
freed and re-allocated each time the function's prototype is cleared.
This is not optimal as it means we are invalidating the watchpoint and recompiling the
scope each time the prototype is cleared.

This makes it so that a single rare data is reused, clearing the underlying
ObjectAllocationProfile instead of throwing away the whole rare data on
.prototype updates.

* runtime/FunctionRareData.cpp:
(JSC::FunctionRareData::create):
(JSC::FunctionRareData::finishCreation):
* runtime/FunctionRareData.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::allocateAndInitializeRareData):
(JSC::JSFunction::initializeRareData):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183113 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/FunctionRareData.cpp
Source/JavaScriptCore/runtime/FunctionRareData.h
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.h

index c3969c9..2e98874 100644 (file)
@@ -1,3 +1,27 @@
+2015-04-22  Basile Clement  <basile_clement@apple.com>
+        Don't de-allocate FunctionRareData
+        https://bugs.webkit.org/show_bug.cgi?id=144000
+
+        Reviewed by Michael Saboff.
+
+        A function rare data (containing most notably its allocation profile) is currently
+        freed and re-allocated each time the function's prototype is cleared.
+        This is not optimal as it means we are invalidating the watchpoint and recompiling the
+        scope each time the prototype is cleared.
+
+        This makes it so that a single rare data is reused, clearing the underlying
+        ObjectAllocationProfile instead of throwing away the whole rare data on
+        .prototype updates.
+
+        * runtime/FunctionRareData.cpp:
+        (JSC::FunctionRareData::create):
+        (JSC::FunctionRareData::finishCreation):
+        * runtime/FunctionRareData.h:
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::allocateAndInitializeRareData):
+        (JSC::JSFunction::initializeRareData):
+
 2015-04-21  Filip Pizlo  <fpizlo@apple.com>
 
         Unreviewed, fix 32-bit. Forgot to make this simple change to 32_64 as well.
index 7cbe1d0..4d16de9 100644 (file)
@@ -3513,6 +3513,7 @@ void SpeculativeJIT::compile(Node* node)
         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
         m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
         m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
+        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
         emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
 
         addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node->inlineCapacity()));
index 669ee0e..d4ade4b 100644 (file)
@@ -3584,6 +3584,7 @@ void SpeculativeJIT::compile(Node* node)
         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
         m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
         m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
+        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
         emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
 
         addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node->inlineCapacity()));
index 4e821d0..577e426 100644 (file)
@@ -706,6 +706,7 @@ void JIT::emit_op_create_this(Instruction* currentInstruction)
     addSlowCase(branchTestPtr(Zero, rareDataReg));
     loadPtr(Address(rareDataReg, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg);
     loadPtr(Address(rareDataReg, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
+    addSlowCase(branchTestPtr(Zero, allocatorReg));
 
     emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
     emitPutVirtualRegister(currentInstruction[1].u.operand);
@@ -713,6 +714,7 @@ void JIT::emit_op_create_this(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
+    linkSlowCase(iter); // doesn't have rare data
     linkSlowCase(iter); // doesn't have an allocation profile
     linkSlowCase(iter); // allocation failed
 
index 4761657..910c21c 100644 (file)
@@ -925,6 +925,7 @@ void JIT::emit_op_create_this(Instruction* currentInstruction)
     addSlowCase(branchTestPtr(Zero, rareDataReg));
     loadPtr(Address(rareDataReg, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg);
     loadPtr(Address(rareDataReg, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
+    addSlowCase(branchTestPtr(Zero, allocatorReg));
 
     emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
     emitStoreCell(currentInstruction[1].u.operand, resultReg);
@@ -932,6 +933,7 @@ void JIT::emit_op_create_this(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
+    linkSlowCase(iter); // doesn't have rare data
     linkSlowCase(iter); // doesn't have an allocation profile
     linkSlowCase(iter); // allocation failed
 
index 390c1c0..3b47f0b 100644 (file)
@@ -744,6 +744,7 @@ _llint_op_create_this:
     btpz t4, .opCreateThisSlow
     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t4], t1
     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t4], t2
+    btpz t1, .opCreateThisSlow
     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
     loadi 4[PC], t1
     storei CellTag, TagOffset[cfr, t1, 8]
index 9035e0f..0d08438 100644 (file)
@@ -630,6 +630,7 @@ _llint_op_create_this:
     btpz t4, .opCreateThisSlow
     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t4], t1
     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t4], t2
+    btpz t1, .opCreateThisSlow
     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
     loadisFromInstruction(1, t1)
     storeq t0, [cfr, t1, 8]
index 1624f13..d44c323 100644 (file)
@@ -80,7 +80,18 @@ FunctionRareData::~FunctionRareData()
 void FunctionRareData::finishCreation(VM& vm, JSObject* prototype, size_t inlineCapacity)
 {
     Base::finishCreation(vm);
+    initialize(vm, prototype, inlineCapacity);
+}
+
+void FunctionRareData::initialize(VM& vm, JSObject* prototype, size_t inlineCapacity)
+{
     m_allocationProfile.initialize(vm, this, prototype, inlineCapacity);
 }
 
+void FunctionRareData::clear(const char* reason)
+{
+    m_allocationProfile.clear();
+    m_allocationProfileWatchpoint.fireAll(reason);
+}
+
 }
index 2423bce..f0a2db2 100644 (file)
@@ -77,6 +77,12 @@ public:
         return m_allocationProfileWatchpoint;
     }
 
+    void clear(const char* reason);
+
+    void initialize(VM&, JSObject* prototype, size_t inlineCapacity);
+
+    bool isInitialized() { return !m_allocationProfile.isNull(); }
+
 protected:
     FunctionRareData(VM&);
     ~FunctionRareData();
index ed706ea..0f07683 100644 (file)
@@ -108,8 +108,9 @@ JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* execut
     return function;
 }
 
-FunctionRareData* JSFunction::createRareData(ExecState* exec, size_t inlineCapacity)
+FunctionRareData* JSFunction::allocateAndInitializeRareData(ExecState* exec, size_t inlineCapacity)
 {
+    ASSERT(!m_rareData);
     VM& vm = exec->vm();
     JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
     if (!prototype)
@@ -119,6 +120,17 @@ FunctionRareData* JSFunction::createRareData(ExecState* exec, size_t inlineCapac
     return m_rareData.get();
 }
 
+FunctionRareData* JSFunction::initializeRareData(ExecState* exec, size_t inlineCapacity)
+{
+    ASSERT(!!m_rareData);
+    VM& vm = exec->vm();
+    JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
+    if (!prototype)
+        prototype = globalObject()->objectPrototype();
+    m_rareData->initialize(globalObject()->vm(), prototype, inlineCapacity);
+    return m_rareData.get();
+}
+
 String JSFunction::name(ExecState* exec)
 {
     return get(exec, exec->vm().propertyNames->name).toWTFString(exec);
@@ -389,10 +401,8 @@ void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, J
         // following the rules set out in ECMA-262 8.12.9.
         PropertySlot slot(thisObject);
         thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot);
-        if (thisObject->m_rareData) {
-            thisObject->m_rareData->allocationProfileWatchpointSet().fireAll("Store to prototype property of a function");
-            thisObject->m_rareData.clear();
-        }
+        if (thisObject->m_rareData)
+            thisObject->m_rareData->clear("Store to prototype property of a function");
         // Don't allow this to be cached, since a [[Put]] must clear m_rareData.
         PutPropertySlot dontCache(thisObject);
         Base::put(thisObject, exec, propertyName, value, dontCache);
@@ -438,10 +448,8 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa
         // following the rules set out in ECMA-262 8.12.9.
         PropertySlot slot(thisObject);
         thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot);
-        if (thisObject->m_rareData) {
-            thisObject->m_rareData->allocationProfileWatchpointSet().fireAll("Store to prototype property of a function");
-            thisObject->m_rareData.clear();
-        }
+        if (thisObject->m_rareData)
+            thisObject->m_rareData->clear("Store to prototype property of a function");
         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
     }
 
index a5d133d..4c3e29f 100644 (file)
@@ -112,7 +112,9 @@ public:
     FunctionRareData* rareData(ExecState* exec, unsigned inlineCapacity)
     {
         if (UNLIKELY(!m_rareData))
-            return createRareData(exec, inlineCapacity);
+            return allocateAndInitializeRareData(exec, inlineCapacity);
+        if (UNLIKELY(!m_rareData->isInitialized()))
+            return initializeRareData(exec, inlineCapacity);
         return m_rareData.get();
     }
 
@@ -138,7 +140,8 @@ protected:
     void finishCreation(VM&, NativeExecutable*, int length, const String& name);
     using Base::finishCreation;
 
-    FunctionRareData* createRareData(ExecState*, size_t inlineCapacity);
+    FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity);
+    FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity);
 
     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
     static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = EnumerationMode());