Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (110126 => 110127)
--- trunk/Source/_javascript_Core/ChangeLog 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-03-08 02:14:38 UTC (rev 110127)
@@ -1,3 +1,38 @@
+2012-03-07 Mark Hahnenberg <mhahnenb...@apple.com>
+
+ Refactor recompileAllJSFunctions() to be less expensive
+ https://bugs.webkit.org/show_bug.cgi?id=80330
+
+ Reviewed by Geoffrey Garen.
+
+ This change is performance neutral on the JS benchmarks we track. It's mostly to improve page
+ load performance, which currently does at least a couple full GCs per navigation.
+
+ * heap/Heap.cpp:
+ (JSC::Heap::discardAllCompiledCode): Rename recompileAllJSFunctions to discardAllCompiledCode
+ because the function doesn't actually recompile anything (and never did); it simply throws code
+ away for it to be recompiled later if we determine we should do so.
+ (JSC):
+ (JSC::Heap::collectAllGarbage):
+ (JSC::Heap::addFunctionExecutable): Adds a newly created FunctionExecutable to the Heap's list.
+ (JSC::Heap::removeFunctionExecutable): Removes the specified FunctionExecutable from the Heap's list.
+ * heap/Heap.h:
+ (JSC):
+ (Heap):
+ * runtime/Executable.cpp: Added next and prev fields to FunctionExecutables so that they can
+ be used in DoublyLinkedLists.
+ (JSC::FunctionExecutable::FunctionExecutable):
+ (JSC::FunctionExecutable::finalize): Removes the FunctionExecutable from the Heap's list.
+ * runtime/Executable.h:
+ (FunctionExecutable):
+ (JSC::FunctionExecutable::create): Adds the FunctionExecutable to the Heap's list.
+ * runtime/JSGlobalData.cpp: Remove recompileAllJSFunctions, as it's the Heap's job to own and manage
+ the list of FunctionExecutables.
+ * runtime/JSGlobalData.h:
+ (JSGlobalData):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Use the new discardAllCompiledCode.
+
2012-03-06 Oliver Hunt <oli...@apple.com>
Further harden 64-bit JIT
Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (110126 => 110127)
--- trunk/Source/_javascript_Core/heap/Heap.cpp 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp 2012-03-08 02:14:38 UTC (rev 110127)
@@ -764,12 +764,22 @@
return m_objectSpace.forEachCell<RecordType>();
}
+void Heap::discardAllCompiledCode()
+{
+ // If _javascript_ is running, it's not safe to recompile, since we'll end
+ // up throwing away code that is live on the stack.
+ ASSERT(!m_globalData->dynamicGlobalObject);
+
+ for (FunctionExecutable* current = m_functions.head(); current; current = current->next())
+ current->discardCode();
+}
+
void Heap::collectAllGarbage()
{
if (!m_isSafeToCollect)
return;
if (!m_globalData->dynamicGlobalObject)
- m_globalData->recompileAllJSFunctions();
+ discardAllCompiledCode();
collect(DoSweep);
}
@@ -924,4 +934,14 @@
finalizer(weak.get());
}
+void Heap::addFunctionExecutable(FunctionExecutable* executable)
+{
+ m_functions.append(executable);
+}
+
+void Heap::removeFunctionExecutable(FunctionExecutable* executable)
+{
+ m_functions.remove(executable);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/Heap.h (110126 => 110127)
--- trunk/Source/_javascript_Core/heap/Heap.h 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/heap/Heap.h 2012-03-08 02:14:38 UTC (rev 110127)
@@ -42,6 +42,7 @@
class CopiedSpace;
class CodeBlock;
+ class FunctionExecutable;
class GCActivityCallback;
class GlobalCodeBlock;
class Heap;
@@ -105,6 +106,8 @@
typedef void (*Finalizer)(JSCell*);
JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
+ void addFunctionExecutable(FunctionExecutable*);
+ void removeFunctionExecutable(FunctionExecutable*);
void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
JS_EXPORT_PRIVATE void collectAllGarbage();
@@ -140,6 +143,8 @@
double lastGCLength() { return m_lastGCLength; }
+ void discardAllCompiledCode();
+
private:
friend class CodeBlock;
friend class LLIntOffsetsExtractor;
@@ -239,6 +244,8 @@
JSGlobalData* m_globalData;
double m_lastGCLength;
+
+ DoublyLinkedList<FunctionExecutable> m_functions;
};
bool Heap::isBusy()
Modified: trunk/Source/_javascript_Core/runtime/Executable.cpp (110126 => 110127)
--- trunk/Source/_javascript_Core/runtime/Executable.cpp 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/runtime/Executable.cpp 2012-03-08 02:14:38 UTC (rev 110127)
@@ -146,6 +146,8 @@
, m_name(name)
, m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName)
, m_symbolTable(0)
+ , m_next(0)
+ , m_prev(0)
{
}
@@ -157,6 +159,8 @@
, m_name(name)
, m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName)
, m_symbolTable(0)
+ , m_next(0)
+ , m_prev(0)
{
}
@@ -654,7 +658,9 @@
void FunctionExecutable::finalize(JSCell* cell)
{
- jsCast<FunctionExecutable*>(cell)->clearCode();
+ FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
+ Heap::heap(executable)->removeFunctionExecutable(executable);
+ executable->clearCode();
}
inline void FunctionExecutable::clearCode()
Modified: trunk/Source/_javascript_Core/runtime/Executable.h (110126 => 110127)
--- trunk/Source/_javascript_Core/runtime/Executable.h 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/runtime/Executable.h 2012-03-08 02:14:38 UTC (rev 110127)
@@ -463,9 +463,10 @@
OwnPtr<ProgramCodeBlock> m_programCodeBlock;
};
- class FunctionExecutable : public ScriptExecutable {
+ class FunctionExecutable : public ScriptExecutable, public DoublyLinkedListNode<FunctionExecutable> {
friend class JIT;
friend class LLIntOffsetsExtractor;
+ friend class DoublyLinkedListNode<FunctionExecutable>;
public:
typedef ScriptExecutable Base;
@@ -473,6 +474,7 @@
{
FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
+ exec->globalData().heap.addFunctionExecutable(executable);
exec->globalData().heap.addFinalizer(executable, &finalize);
return executable;
}
@@ -481,6 +483,7 @@
{
FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
executable->finishCreation(globalData, name, firstLine, lastLine);
+ globalData.heap.addFunctionExecutable(executable);
globalData.heap.addFinalizer(executable, &finalize);
return executable;
}
@@ -688,6 +691,8 @@
Identifier m_inferredName;
WriteBarrier<JSString> m_nameValue;
SharedSymbolTable* m_symbolTable;
+ FunctionExecutable* m_next;
+ FunctionExecutable* m_prev;
};
inline FunctionExecutable* JSFunction::jsExecutable() const
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalData.cpp (110126 => 110127)
--- trunk/Source/_javascript_Core/runtime/JSGlobalData.cpp 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalData.cpp 2012-03-08 02:14:38 UTC (rev 110127)
@@ -68,27 +68,6 @@
using namespace WTF;
-namespace {
-
-using namespace JSC;
-
-class Recompiler : public MarkedBlock::VoidFunctor {
-public:
- void operator()(JSCell*);
-};
-
-inline void Recompiler::operator()(JSCell* cell)
-{
- if (!cell->inherits(&JSFunction::s_info))
- return;
- JSFunction* function = asFunction(cell);
- if (!function->executable() || function->executable()->isHostFunction())
- return;
- function->jsExecutable()->discardCode();
-}
-
-} // namespace
-
namespace JSC {
extern const HashTable arrayConstructorTable;
@@ -443,15 +422,6 @@
#endif
}
-void JSGlobalData::recompileAllJSFunctions()
-{
- // If _javascript_ is running, it's not safe to recompile, since we'll end
- // up throwing away code that is live on the stack.
- ASSERT(!dynamicGlobalObject);
-
- heap.objectSpace().forEachCell<Recompiler>();
-}
-
struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
HashSet<FunctionExecutable*> currentlyExecutingFunctions;
void operator()(JSCell* cell)
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalData.h (110126 => 110127)
--- trunk/Source/_javascript_Core/runtime/JSGlobalData.h 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalData.h 2012-03-08 02:14:38 UTC (rev 110127)
@@ -324,7 +324,7 @@
JS_EXPORT_PRIVATE void startSampling();
JS_EXPORT_PRIVATE void stopSampling();
JS_EXPORT_PRIVATE void dumpSampleData(ExecState* exec);
- void recompileAllJSFunctions();
+ void discardAllCompiledCode();
RegExpCache* regExpCache() { return m_regExpCache; }
#if ENABLE(REGEXP_TRACING)
void addRegExpToTrace(PassRefPtr<RegExp> regExp);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (110126 => 110127)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2012-03-08 02:12:26 UTC (rev 110126)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2012-03-08 02:14:38 UTC (rev 110127)
@@ -460,7 +460,7 @@
if (!m_dynamicGlobalObjectSlot) {
#if ENABLE(ASSEMBLER)
if (ExecutableAllocator::underMemoryPressure())
- globalData.recompileAllJSFunctions();
+ globalData.heap.discardAllCompiledCode();
#endif
m_dynamicGlobalObjectSlot = dynamicGlobalObject;